diff --git a/Cargo.lock b/Cargo.lock index 03ac3ef6..e48fc283 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,13 +304,33 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", + "multiversx-sc-scenario", + "num-bigint", +] + +[[package]] +name = "chain-config-meta" +version = "0.0.0" +dependencies = [ + "chain-config", + "multiversx-sc-meta", +] + [[package]] name = "chain-factory" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", "multiversx-sc-scenario", "num-bigint", + "utils", ] [[package]] @@ -2388,6 +2408,13 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "utils" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 389cadef..91a04456 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,7 @@ [workspace] members = [ + "chain-config", + "chain-config/meta", "chain-factory", "chain-factory/meta", "esdt-safe", diff --git a/chain-config/.gitignore b/chain-config/.gitignore new file mode 100644 index 00000000..2c76bc98 --- /dev/null +++ b/chain-config/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The mxpy output +/output*/ diff --git a/chain-config/Cargo.toml b/chain-config/Cargo.toml new file mode 100644 index 00000000..3b945b00 --- /dev/null +++ b/chain-config/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "chain-config" +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" + +[dependencies.multiversx-sc-modules] +version = "=0.43.5" + +[dev-dependencies.multiversx-sc-scenario] +version = "=0.43.5" diff --git a/chain-config/meta/Cargo.toml b/chain-config/meta/Cargo.toml new file mode 100644 index 00000000..00febf9c --- /dev/null +++ b/chain-config/meta/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "chain-config-meta" +version = "0.0.0" +edition = "2018" +publish = false +authors = [ "you",] + +[dev-dependencies] + +[dependencies.chain-config] +path = ".." + +[dependencies.multiversx-sc-meta] +version = "=0.43.5" diff --git a/chain-config/meta/src/main.rs b/chain-config/meta/src/main.rs new file mode 100644 index 00000000..5aeb10d5 --- /dev/null +++ b/chain-config/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta::cli_main::(); +} diff --git a/chain-config/multiversx.json b/chain-config/multiversx.json new file mode 100644 index 00000000..73655396 --- /dev/null +++ b/chain-config/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/chain-config/src/bridge.rs b/chain-config/src/bridge.rs new file mode 100644 index 00000000..5af92cae --- /dev/null +++ b/chain-config/src/bridge.rs @@ -0,0 +1,40 @@ +multiversx_sc::imports!(); + +mod bridge_proxy { + multiversx_sc::imports!(); + + #[multiversx_sc::proxy] + pub trait BridgeProxy { + #[init] + fn init(&self, min_valid_signers: u32, signers: MultiValueEncoded); + } +} + +#[multiversx_sc::module] +pub trait BridgeModule { + #[only_owner] + #[endpoint(deployBridge)] + fn deploy_bridge( + &self, + code: ManagedBuffer, + min_valid_signers: u32, + signers: MultiValueEncoded, + ) { + require!(self.bridge_address().is_empty(), "Bridge already deployed"); + + let metadata = + CodeMetadata::PAYABLE_BY_SC | CodeMetadata::UPGRADEABLE | CodeMetadata::READABLE; + let (sc_address, _) = self + .bridge_proxy() + .init(min_valid_signers, signers) + .deploy_contract::(&code, metadata); + + self.bridge_address().set(sc_address); + } + + #[proxy] + fn bridge_proxy(&self) -> bridge_proxy::Proxy; + + #[storage_mapper("bridgeAddress")] + fn bridge_address(&self) -> SingleValueMapper; +} diff --git a/chain-config/src/lib.rs b/chain-config/src/lib.rs new file mode 100644 index 00000000..181b1f3c --- /dev/null +++ b/chain-config/src/lib.rs @@ -0,0 +1,49 @@ +#![no_std] + +use validator_rules::TokenIdAmountPair; + +multiversx_sc::imports!(); + +pub mod bridge; +pub mod validator_rules; + +pub type StakeMultiArg = MultiValue2, BigUint>; + +#[multiversx_sc::contract] +pub trait ChainConfigContract: + bridge::BridgeModule + + validator_rules::ValidatorRulesModule + + multiversx_sc_modules::only_admin::OnlyAdminModule +{ + #[init] + fn init( + &self, + min_validators: usize, + max_validators: usize, + min_stake: BigUint, + admin: ManagedAddress, + additional_stake_required: MultiValueEncoded>, + ) { + require!( + min_validators <= max_validators, + "Invalid min/max validator numbers" + ); + + let mut additional_stake_vec = ManagedVec::new(); + for multi_value in additional_stake_required { + let (token_id, amount) = multi_value.into_tuple(); + let value = TokenIdAmountPair { token_id, amount }; + + additional_stake_vec.push(value); + } + + self.min_validators().set(min_validators); + self.max_validators().set(max_validators); + self.min_stake().set(min_stake); + self.add_admin(admin); + self.additional_stake_required().set(additional_stake_vec); + } + + #[endpoint] + fn upgrade(&self) {} +} diff --git a/chain-config/src/validator_rules.rs b/chain-config/src/validator_rules.rs new file mode 100644 index 00000000..210ef669 --- /dev/null +++ b/chain-config/src/validator_rules.rs @@ -0,0 +1,38 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +// TODO: What to fill here? +pub enum SlashableOffenses {} + +#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem)] +pub struct TokenIdAmountPair { + pub token_id: TokenIdentifier, + pub amount: BigUint, +} + +#[multiversx_sc::module] +pub trait ValidatorRulesModule { + #[view(getMinValidators)] + #[storage_mapper("minValidators")] + fn min_validators(&self) -> SingleValueMapper; + + #[view(getMaxValidators)] + #[storage_mapper("maxValidators")] + fn max_validators(&self) -> SingleValueMapper; + + // TODO: Read user stake and verify + #[view(getMinStake)] + #[storage_mapper("minStake")] + fn min_stake(&self) -> SingleValueMapper; + + // TODO: Read user stake and verify + #[view(getAdditionalStakeRequired)] + #[storage_mapper("additionalStakeRequired")] + fn additional_stake_required( + &self, + ) -> SingleValueMapper>>; + + #[view(wasPreviouslySlashed)] + #[storage_mapper("wasPreviouslySlashed")] + fn was_previously_slashed(&self, validator: &ManagedAddress) -> SingleValueMapper; +} diff --git a/chain-config/wasm/Cargo.lock b/chain-config/wasm/Cargo.lock new file mode 100644 index 00000000..c82e4c97 --- /dev/null +++ b/chain-config/wasm/Cargo.lock @@ -0,0 +1,229 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + +[[package]] +name = "chain-config-wasm" +version = "0.0.0" +dependencies = [ + "chain-config", + "multiversx-sc-wasm-adapter", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "multiversx-sc" +version = "0.43.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adbdd41a744caa562646c6d593df35caed84889e0d35df8b9ad8efc45457b5bd" +dependencies = [ + "bitflags", + "hashbrown", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e15b46c17b87c0c7cdd79b041a4abd7f3a2b45f3c993f6ce38c0f233e82b6" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7bc0762cd6d88f8bc54805bc652b042a61cd7fbc2d0a325010f088b78fb2ac" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.43.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebdaec412a272d8fd6668bc0b4b8674a5e03148aa72041a4705d502b86f4d9ce" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-modules" +version = "0.43.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a02a1c14d05986661eff35beab26f5e72cdc44753b1f415eff64d6c4e4bc98" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.43.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2befd4545b5b47adf1df89313b76a2282873fd9163b70badd727d8dfce83c588" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/chain-config/wasm/Cargo.toml b/chain-config/wasm/Cargo.toml new file mode 100644 index 00000000..1febafa6 --- /dev/null +++ b/chain-config/wasm/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "chain-config-wasm" +version = "0.0.0" +edition = "2018" +publish = false +authors = [ "you",] + +[lib] +crate-type = [ "cdylib",] + +[workspace] +members = [ ".",] + +[dev-dependencies] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" + +[dependencies.chain-config] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "=0.43.5" diff --git a/chain-config/wasm/src/lib.rs b/chain-config/wasm/src/lib.rs new file mode 100644 index 00000000..6c10475f --- /dev/null +++ b/chain-config/wasm/src/lib.rs @@ -0,0 +1,39 @@ +// Code generated by the multiversx-sc multi-contract system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Endpoints: 11 +// Async Callback (empty): 1 +// Total number of exported functions: 13 + +#![no_std] + +// Configuration that works with rustc < 1.73.0. +// TODO: Recommended rustc version: 1.73.0 or newer. +#![feature(lang_items)] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + chain_config + ( + init => init + upgrade => upgrade + deployBridge => deploy_bridge + getMinValidators => min_validators + getMaxValidators => max_validators + getMinStake => min_stake + getAdditionalStakeRequired => additional_stake_required + wasPreviouslySlashed => was_previously_slashed + isAdmin => is_admin + addAdmin => add_admin + removeAdmin => remove_admin + getAdmins => admins + ) +} + +multiversx_sc_wasm_adapter::async_callback_empty! {} diff --git a/chain-factory/Cargo.toml b/chain-factory/Cargo.toml index cb74c255..9cd51afa 100644 --- a/chain-factory/Cargo.toml +++ b/chain-factory/Cargo.toml @@ -14,5 +14,11 @@ num-bigint = "0.4.2" [dependencies.multiversx-sc] version = "=0.43.5" +[dependencies.utils] +path = "../common/utils" + +[dependencies.chain-config] +path = "../chain-config" + [dev-dependencies.multiversx-sc-scenario] version = "=0.43.5" diff --git a/chain-factory/src/factory.rs b/chain-factory/src/factory.rs index 45c2f531..c63512a8 100644 --- a/chain-factory/src/factory.rs +++ b/chain-factory/src/factory.rs @@ -1,35 +1,38 @@ +use chain_config::StakeMultiArg; + 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) { + fn deploy_sovereign_chain_config_contract( + &self, + min_validators: usize, + max_validators: usize, + min_stake: BigUint, + additional_stake_required: MultiValueEncoded>, + ) { 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 caller = self.blockchain().get_caller(); 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 (sc_address, _) = self + .chain_config_proxy() + .init( + min_validators, + max_validators, + min_stake, + caller, + additional_stake_required, + ) + .deploy_from_source::(&source_address, metadata); + let _ = self.all_deployed_contracts().insert(sc_address); } @@ -39,6 +42,9 @@ pub trait FactoryModule { let _ = self.all_deployed_contracts().swap_remove(&sc_address); } + #[proxy] + fn chain_config_proxy(&self) -> chain_config::Proxy; + #[view(getDeployCost)] #[storage_mapper("deployCost")] fn deploy_cost(&self) -> SingleValueMapper; diff --git a/chain-factory/src/lib.rs b/chain-factory/src/lib.rs index 13c9785f..41bd11d9 100644 --- a/chain-factory/src/lib.rs +++ b/chain-factory/src/lib.rs @@ -6,7 +6,9 @@ pub mod factory; pub mod slash; #[multiversx_sc::contract] -pub trait ChainFactoryContract: factory::FactoryModule + slash::SlashModule { +pub trait ChainFactoryContract: + factory::FactoryModule + slash::SlashModule + utils::UtilsModule +{ #[init] fn init( &self, @@ -25,11 +27,4 @@ pub trait ChainFactoryContract: factory::FactoryModule + slash::SlashModule { #[endpoint] fn upgrade(&self) {} - - fn require_sc_address(&self, address: &ManagedAddress) { - require!( - !address.is_zero() && self.blockchain().is_smart_contract(address), - "Invalid SC address" - ); - } } diff --git a/chain-factory/wasm/Cargo.lock b/chain-factory/wasm/Cargo.lock index 77e68358..122b38a9 100644 --- a/chain-factory/wasm/Cargo.lock +++ b/chain-factory/wasm/Cargo.lock @@ -37,11 +37,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chain-config" +version = "0.0.0" +dependencies = [ + "multiversx-sc", + "multiversx-sc-modules", +] + [[package]] name = "chain-factory" version = "0.0.0" dependencies = [ + "chain-config", "multiversx-sc", + "utils", ] [[package]] @@ -128,6 +138,15 @@ dependencies = [ "syn", ] +[[package]] +name = "multiversx-sc-modules" +version = "0.43.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a02a1c14d05986661eff35beab26f5e72cdc44753b1f415eff64d6c4e4bc98" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "multiversx-sc-wasm-adapter" version = "0.43.5" @@ -212,6 +231,13 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utils" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + [[package]] name = "version_check" version = "0.9.4" diff --git a/common/utils/Cargo.toml b/common/utils/Cargo.toml new file mode 100644 index 00000000..2dddb029 --- /dev/null +++ b/common/utils/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "utils" +version = "0.0.0" +authors = ["Dorin Iancu "] +edition = "2021" + +[lib] +path = "src/lib.rs" + +[dependencies.multiversx-sc] +version = "=0.43.5" +features = ["esdt-token-payment-legacy-decode"] diff --git a/common/utils/src/lib.rs b/common/utils/src/lib.rs new file mode 100644 index 00000000..f76ae703 --- /dev/null +++ b/common/utils/src/lib.rs @@ -0,0 +1,13 @@ +#![no_std] + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait UtilsModule { + fn require_sc_address(&self, address: &ManagedAddress) { + require!( + !address.is_zero() && self.blockchain().is_smart_contract(address), + "Invalid SC address" + ); + } +}