Skip to content

Commit

Permalink
Merge pull request #16 from multiversx/chain-factory
Browse files Browse the repository at this point in the history
Chain factory
  • Loading branch information
dorin-iancu authored Jan 17, 2024
2 parents 352deb8 + 1a29c5d commit 738baf5
Show file tree
Hide file tree
Showing 15 changed files with 754 additions and 4 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[workspace]
members = [
"chain-factory",
"chain-factory/meta",
"esdt-safe",
"esdt-safe/meta",
]
7 changes: 7 additions & 0 deletions chain-factory/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
*/target/

# The mxpy output
/output*/
18 changes: 18 additions & 0 deletions chain-factory/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "chain-factory"
version = "0.0.0"
authors = [ "you",]
edition = "2018"
publish = false

[lib]
path = "src/lib.rs"

[dev-dependencies]
num-bigint = "0.4.2"

[dependencies.multiversx-sc]
version = "=0.43.5"

[dev-dependencies.multiversx-sc-scenario]
version = "=0.43.5"
14 changes: 14 additions & 0 deletions chain-factory/meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "chain-factory-meta"
version = "0.0.0"
edition = "2018"
publish = false
authors = [ "you",]

[dev-dependencies]

[dependencies.chain-factory]
path = ".."

[dependencies.multiversx-sc-meta]
version = "=0.43.5"
3 changes: 3 additions & 0 deletions chain-factory/meta/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
multiversx_sc_meta::cli_main::<chain_factory::AbiProvider>();
}
3 changes: 3 additions & 0 deletions chain-factory/multiversx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"language": "rust"
}
51 changes: 51 additions & 0 deletions chain-factory/src/factory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
multiversx_sc::imports!();

#[multiversx_sc::module]
pub trait FactoryModule {
// TODO: Typed args
#[payable("EGLD")]
#[endpoint(deploySovereignChainConfigContract)]
fn deploy_sovereign_chain_config_contract(&self, args: MultiValueEncoded<ManagedBuffer>) {
let payment_amount = self.call_value().egld_value().clone_value();
let deploy_cost = self.deploy_cost().get();
require!(payment_amount == deploy_cost, "Invalid payment amount");

let mut serialized_args = ManagedArgBuffer::new();
for arg in args {
serialized_args.push_arg(arg);
}

// TODO: add caller as admin
// let caller = self.blockchain().get_caller();

// TODO: Typed call based on proxy
let source_address = self.chain_config_template().get();
let gas_left = self.blockchain().get_gas_left();
let metadata =
CodeMetadata::PAYABLE_BY_SC | CodeMetadata::UPGRADEABLE | CodeMetadata::READABLE;
let (sc_address, _) = self.send_raw().deploy_from_source_contract(
gas_left,
&BigUint::zero(),
&source_address,
metadata,
&serialized_args,
);
let _ = self.all_deployed_contracts().insert(sc_address);
}

#[only_owner]
#[endpoint(blacklistSovereignChainSc)]
fn blacklist_sovereign_chain_sc(&self, sc_address: ManagedAddress) {
let _ = self.all_deployed_contracts().swap_remove(&sc_address);
}

#[view(getDeployCost)]
#[storage_mapper("deployCost")]
fn deploy_cost(&self) -> SingleValueMapper<BigUint>;

#[storage_mapper("chainConfigTemplate")]
fn chain_config_template(&self) -> SingleValueMapper<ManagedAddress>;

#[storage_mapper("allDeployedContracts")]
fn all_deployed_contracts(&self) -> UnorderedSetMapper<ManagedAddress>;
}
35 changes: 35 additions & 0 deletions chain-factory/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#![no_std]

multiversx_sc::imports!();

pub mod factory;
pub mod slash;

#[multiversx_sc::contract]
pub trait ChainFactoryContract: factory::FactoryModule + slash::SlashModule {
#[init]
fn init(
&self,
validators_contract_address: ManagedAddress,
chain_config_template: ManagedAddress,
deploy_cost: BigUint,
) {
self.require_sc_address(&validators_contract_address);
self.require_sc_address(&chain_config_template);

self.validators_contract_address()
.set(validators_contract_address);
self.chain_config_template().set(chain_config_template);
self.deploy_cost().set(deploy_cost);
}

#[endpoint]
fn upgrade(&self) {}

fn require_sc_address(&self, address: &ManagedAddress) {
require!(
!address.is_zero() && self.blockchain().is_smart_contract(address),
"Invalid SC address"
);
}
}
61 changes: 61 additions & 0 deletions chain-factory/src/slash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
multiversx_sc::imports!();

pub type DestAmountPairs<M> = MultiValueEncoded<M, MultiValue2<ManagedAddress<M>, BigUint<M>>>;

mod validators_contract_proxy {
use super::DestAmountPairs;

multiversx_sc::imports!();

#[multiversx_sc::proxy]
pub trait ValidatorsContractProxy {
#[endpoint]
fn slash(&self, validator_address: ManagedAddress, value: BigUint);

#[endpoint(distributeSlashed)]
fn distribute_slashed(&self, dest_amount_pairs: DestAmountPairs<Self::Api>);
}
}

#[multiversx_sc::module]
pub trait SlashModule: crate::factory::FactoryModule {
#[endpoint]
fn slash(&self, validator_address: ManagedAddress, value: BigUint) {
let caller = self.blockchain().get_caller();
self.require_deployed_sc(&caller);

let validators_contract_address = self.validators_contract_address().get();
let _: IgnoreValue = self
.validator_proxy(validators_contract_address)
.slash(validator_address, value)
.execute_on_dest_context();
}

#[endpoint(distributeSlashed)]
fn distribute_slashed(&self, dest_amount_pairs: DestAmountPairs<Self::Api>) {
let caller = self.blockchain().get_caller();
self.require_deployed_sc(&caller);

let validators_contract_address = self.validators_contract_address().get();
let _: IgnoreValue = self
.validator_proxy(validators_contract_address)
.distribute_slashed(dest_amount_pairs)
.execute_on_dest_context();
}

fn require_deployed_sc(&self, address: &ManagedAddress) {
require!(
self.all_deployed_contracts().contains(address),
"Only deployed contracts may call this endpoint"
);
}

#[proxy]
fn validator_proxy(
&self,
sc_address: ManagedAddress,
) -> validators_contract_proxy::Proxy<Self::Api>;

#[storage_mapper("validatorsContractAddress")]
fn validators_contract_address(&self) -> SingleValueMapper<ManagedAddress>;
}
Loading

0 comments on commit 738baf5

Please sign in to comment.