From 5252631cbd328c213137e4f8c14be46d8f2b08bc Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 28 Feb 2024 13:56:16 +0200 Subject: [PATCH] setup test --- common/token-module/src/lib.rs | 4 +- common/tx-batch-module/src/lib.rs | 2 + esdt-safe/src/lib.rs | 36 +- multi-transfer-esdt/src/lib.rs | 50 +-- .../tests/multi_transfer_blackbox_test.rs | 372 ------------------ multisig/src/lib.rs | 6 +- multisig/tests/multisig_rust_test.rs | 10 + multisig/tests/multisig_setup/mod.rs | 331 ++++++++++++++++ 8 files changed, 383 insertions(+), 428 deletions(-) delete mode 100644 multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs diff --git a/common/token-module/src/lib.rs b/common/token-module/src/lib.rs index 51af8595..6e0c3810 100644 --- a/common/token-module/src/lib.rs +++ b/common/token-module/src/lib.rs @@ -170,8 +170,8 @@ pub trait TokenModule: fee_estimator_module::FeeEstimatorModule { #[only_owner] #[endpoint(setAccumulatedBurnedTokens)] - fn set_accumulated_burned_tokens(&self, token_id: &TokenIdentifier, value: BigUint) { - self.accumulated_burned_tokens(token_id).set_if_empty(value); + fn set_accumulated_burned_tokens(&self, token_id: TokenIdentifier, value: BigUint) { + self.accumulated_burned_tokens(&token_id).set_if_empty(value); } // storage diff --git a/common/tx-batch-module/src/lib.rs b/common/tx-batch-module/src/lib.rs index 545a4cca..6be4a5aa 100644 --- a/common/tx-batch-module/src/lib.rs +++ b/common/tx-batch-module/src/lib.rs @@ -10,6 +10,8 @@ use tx_batch_mapper::TxBatchMapper; pub mod batch_status; pub mod tx_batch_mapper; +pub const FIRST_BATCH_ID: u64 = 1; + #[multiversx_sc::module] pub trait TxBatchModule { // endpoints - owner-only diff --git a/esdt-safe/src/lib.rs b/esdt-safe/src/lib.rs index 3adf6ae8..c42bd855 100644 --- a/esdt-safe/src/lib.rs +++ b/esdt-safe/src/lib.rs @@ -9,6 +9,7 @@ use core::convert::TryFrom; use eth_address::*; use fee_estimator_module::GWEI_STRING; use transaction::{transaction_status::TransactionStatus, Transaction}; +use tx_batch_module::FIRST_BATCH_ID; const DEFAULT_MAX_TX_BATCH_SIZE: usize = 10; const DEFAULT_MAX_TX_BATCH_BLOCK_DURATION: u64 = 100; // ~10 minutes @@ -29,17 +30,16 @@ pub trait EsdtSafe: #[init] fn init(&self, fee_estimator_contract_address: ManagedAddress, eth_tx_gas_limit: BigUint) { self.fee_estimator_contract_address() - .set(&fee_estimator_contract_address); - self.eth_tx_gas_limit().set(ð_tx_gas_limit); + .set(fee_estimator_contract_address); + self.eth_tx_gas_limit().set(eth_tx_gas_limit); - self.max_tx_batch_size() - .set_if_empty(DEFAULT_MAX_TX_BATCH_SIZE); + self.max_tx_batch_size().set(DEFAULT_MAX_TX_BATCH_SIZE); self.max_tx_batch_block_duration() - .set_if_empty(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); + .set(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); // batch ID 0 is considered invalid - self.first_batch_id().set_if_empty(1); - self.last_batch_id().set_if_empty(1); + self.first_batch_id().set(FIRST_BATCH_ID); + self.last_batch_id().set(FIRST_BATCH_ID); // set ticker for "GWEI" let gwei_token_id = TokenIdentifier::from(GWEI_STRING); @@ -50,25 +50,7 @@ pub trait EsdtSafe: } #[upgrade] - fn upgrade(&self, fee_estimator_contract_address: ManagedAddress, eth_tx_gas_limit: BigUint) { - self.fee_estimator_contract_address() - .set(&fee_estimator_contract_address); - self.eth_tx_gas_limit().set(ð_tx_gas_limit); - - self.max_tx_batch_size() - .set_if_empty(DEFAULT_MAX_TX_BATCH_SIZE); - self.max_tx_batch_block_duration() - .set_if_empty(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); - - // batch ID 0 is considered invalid - self.first_batch_id().set_if_empty(1); - self.last_batch_id().set_if_empty(1); - - // set ticker for "GWEI" - let gwei_token_id = TokenIdentifier::from(GWEI_STRING); - self.token_ticker(&gwei_token_id) - .set(gwei_token_id.as_managed_buffer()); - + fn upgrade(&self) { self.set_paused(true); } @@ -116,7 +98,7 @@ pub trait EsdtSafe: } } TransactionStatus::Rejected => { - let addr = ManagedAddress::try_from(tx.from).unwrap(); + let addr = unsafe { ManagedAddress::try_from(tx.from).unwrap_unchecked() }; self.mark_refund(&addr, &tx.token_identifier, &tx.amount); } _ => { diff --git a/multi-transfer-esdt/src/lib.rs b/multi-transfer-esdt/src/lib.rs index bb232405..2bb8876d 100644 --- a/multi-transfer-esdt/src/lib.rs +++ b/multi-transfer-esdt/src/lib.rs @@ -4,8 +4,10 @@ multiversx_sc::imports!(); use token_module::ProxyTrait as OtherProxyTrait; use transaction::{ - EthTransaction, EthTransactionPayment, PaymentsVec, Transaction, TxBatchSplitInFields, + call_data::CallData, EthTransaction, EthTransactionPayment, PaymentsVec, Transaction, + TxBatchSplitInFields, }; +use tx_batch_module::FIRST_BATCH_ID; const DEFAULT_MAX_TX_BATCH_SIZE: usize = 10; const DEFAULT_MAX_TX_BATCH_BLOCK_DURATION: u64 = u64::MAX; @@ -18,25 +20,16 @@ pub trait MultiTransferEsdt: { #[init] fn init(&self) { - self.max_tx_batch_size() - .set_if_empty(DEFAULT_MAX_TX_BATCH_SIZE); + self.max_tx_batch_size().set(DEFAULT_MAX_TX_BATCH_SIZE); self.max_tx_batch_block_duration() - .set_if_empty(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); + .set(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); // batch ID 0 is considered invalid - self.first_batch_id().set_if_empty(1); - self.last_batch_id().set_if_empty(1); + self.first_batch_id().set(FIRST_BATCH_ID); + self.last_batch_id().set(FIRST_BATCH_ID); } #[upgrade] - fn upgrade(&self) { - self.max_tx_batch_size() - .set_if_empty(DEFAULT_MAX_TX_BATCH_SIZE); - self.max_tx_batch_block_duration() - .set_if_empty(DEFAULT_MAX_TX_BATCH_BLOCK_DURATION); - // batch ID 0 is considered invalid - self.first_batch_id().set_if_empty(1); - self.last_batch_id().set_if_empty(1); - } + fn upgrade(&self) {} #[only_owner] #[endpoint(batchTransferEsdtToken)] @@ -68,14 +61,7 @@ pub trait MultiTransferEsdt: } else if is_dest_sc { match ð_tx.call_data { Some(call_data) => { - #[allow(clippy::if_same_then_else)] - if call_data.gas_limit < MIN_GAS_LIMIT_FOR_SC_CALL - || call_data.gas_limit > MAX_GAS_LIMIT_FOR_SC_CALL - { - must_refund = true; - } else if call_data.endpoint.len() > u8::MAX as usize { - must_refund = true; - } else if call_data.args.len() > u8::MAX as usize { + if self.must_refund_tx_with_call_data(&call_data) { must_refund = true; } } @@ -107,7 +93,7 @@ pub trait MultiTransferEsdt: // emit event before the actual transfer so we don't have to save the tx_nonces as well self.transfer_performed_event(batch_id, eth_tx.tx_nonce); - valid_tx_list.push(eth_tx.clone()); + valid_tx_list.push(eth_tx); valid_payments_list.push(minted_token); } @@ -191,8 +177,23 @@ pub trait MultiTransferEsdt: self.add_multiple_tx_to_batch(&refund_tx_list); } + // private + fn must_refund_tx_with_call_data(&self, call_data: &CallData) -> bool { + if call_data.gas_limit < MIN_GAS_LIMIT_FOR_SC_CALL + || call_data.gas_limit > MAX_GAS_LIMIT_FOR_SC_CALL + { + return true; + } + + if call_data.endpoint.len() > u8::MAX as usize { + return true; + } + + call_data.args.len() > u8::MAX as usize + } + fn convert_to_refund_tx(&self, eth_tx: EthTransaction) -> Transaction { Transaction { block_nonce: self.blockchain().get_block_nonce(), @@ -285,6 +286,7 @@ pub trait MultiTransferEsdt: } // storage + #[view(getWrappingContractAddress)] #[storage_mapper("wrappingContractAddress")] fn wrapping_contract_address(&self) -> SingleValueMapper; diff --git a/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs b/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs deleted file mode 100644 index 50ec1914..00000000 --- a/multi-transfer-esdt/tests/multi_transfer_blackbox_test.rs +++ /dev/null @@ -1,372 +0,0 @@ -#![allow(unused)] - -use bridge_proxy::{config::ProxyTrait as _, ProxyTrait as _}; -use bridged_tokens_wrapper::ProxyTrait as _; -use esdt_safe::{EsdtSafe, ProxyTrait as _}; -use multi_transfer_esdt::ProxyTrait as _; - -use multiversx_sc::{ - api::{HandleConstraints, ManagedTypeApi}, - codec::{ - multi_types::{MultiValueVec, OptionalValue}, - Empty, - }, - storage::mappers::SingleValue, - types::{ - Address, BigUint, CodeMetadata, ManagedAddress, ManagedBuffer, ManagedByteArray, - ManagedVec, MultiValueEncoded, TokenIdentifier, - }, -}; -use multiversx_sc_modules::pause::ProxyTrait; -use multiversx_sc_scenario::{ - api::{StaticApi, VMHooksApi}, - scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}, - scenario_model::*, - ContractInfo, DebugApi, ScenarioWorld, -}; - -use eth_address::*; -use token_module::ProxyTrait as _; -use transaction::{call_data::CallData, EthTransaction, EthTransactionPayment}; - -const BRIDGE_TOKEN_ID: &[u8] = b"BRIDGE-123456"; -const BRIDGE_TOKEN_ID_EXPR: &str = "str:BRIDGE-123456"; - -const USER_ETHEREUM_ADDRESS: &[u8] = b"0x0102030405060708091011121314151617181920"; - -const GAS_LIMIT: u64 = 100_000_000; - -const MULTI_TRANSFER_PATH_EXPR: &str = "file:output/multi-transfer-esdt.wasm"; -const BRIDGE_PROXY_PATH_EXPR: &str = "file:../bridge-proxy/output/bridge-proxy.wasm"; -const ESDT_SAFE_PATH_EXPR: &str = "file:../esdt-safe/output/esdt-safe.wasm"; -const BRIDGED_TOKENS_WRAPPER_PATH_EXPR: &str = - "file:../bridged-tokens-wrapper/output/bridged-tokens-wrapper.wasm"; -const PRICE_AGGREGATOR_PATH_EXPR: &str = "file:../price-aggregator/price-aggregator.wasm"; - -const MULTI_TRANSFER_ADDRESS_EXPR: &str = "sc:multi_transfer"; -const BRIDGE_PROXY_ADDRESS_EXPR: &str = "sc:bridge_proxy"; -const ESDT_SAFE_ADDRESS_EXPR: &str = "sc:esdt_safe"; -const BRIDGED_TOKENS_WRAPPER_ADDRESS_EXPR: &str = "sc:bridged_tokens_wrapper"; -const PRICE_AGGREGATOR_ADDRESS_EXPR: &str = "sc:price_aggregator"; - -const ORACLE_ADDRESS_EXPR: &str = "address:oracle"; -const OWNER_ADDRESS_EXPR: &str = "address:owner"; - -const ESDT_SAFE_ETH_TX_GAS_LIMIT: u64 = 150_000; - -const BALANCE: &str = "2,000,000"; - -fn world() -> ScenarioWorld { - let mut blockchain = ScenarioWorld::new(); - - blockchain.register_contract( - MULTI_TRANSFER_PATH_EXPR, - multi_transfer_esdt::ContractBuilder, - ); - blockchain.register_contract(BRIDGE_PROXY_PATH_EXPR, bridge_proxy::ContractBuilder); - - blockchain.register_contract(ESDT_SAFE_PATH_EXPR, esdt_safe::ContractBuilder); - - blockchain.register_contract( - BRIDGED_TOKENS_WRAPPER_PATH_EXPR, - bridged_tokens_wrapper::ContractBuilder, - ); - - blockchain -} - -type MultiTransferContract = ContractInfo>; -type BridgeProxyContract = ContractInfo>; -type EsdtSafeContract = ContractInfo>; -type BridgedTokensWrapperContract = ContractInfo>; - -struct MultiTransferTestState { - world: ScenarioWorld, - owner: AddressValue, - user1: AddressValue, - user2: AddressValue, - eth_user: EthAddress, - multi_transfer: MultiTransferContract, - bridge_proxy: BridgeProxyContract, - esdt_safe: EsdtSafeContract, - bridged_tokens_wrapper: BridgedTokensWrapperContract, -} - -impl MultiTransferTestState { - fn setup() -> Self { - let world = world(); - let ic = &world.interpreter_context(); - - let mut state: MultiTransferTestState = MultiTransferTestState { - world, - owner: "address:owner".into(), - user1: "address:user1".into(), - user2: "address:user2".into(), - eth_user: EthAddress { - raw_addr: ManagedByteArray::default(), - }, - multi_transfer: MultiTransferContract::new("sc:multi_transfer"), - bridge_proxy: BridgeProxyContract::new("sc:bridge_proxy"), - esdt_safe: EsdtSafeContract::new("sc:esdt_safe"), - bridged_tokens_wrapper: BridgedTokensWrapperContract::new("sc:bridged_tokens_wrapper"), - }; - - let multi_transfer_code = state.world.code_expression(MULTI_TRANSFER_PATH_EXPR); - let bridge_proxy_code = state.world.code_expression(BRIDGE_PROXY_PATH_EXPR); - let esdt_safe_code = state.world.code_expression(ESDT_SAFE_PATH_EXPR); - let bridged_tokens_wrapper_code = state - .world - .code_expression(BRIDGED_TOKENS_WRAPPER_PATH_EXPR); - - let roles = vec![ - "ESDTRoleLocalMint".to_string(), - "ESDTRoleLocalBurn".to_string(), - ]; - - state.world.set_state_step( - SetStateStep::new() - .put_account( - &state.owner, - Account::new() - .nonce(1) - .balance(BALANCE) - .esdt_balance(BRIDGE_TOKEN_ID_EXPR, BALANCE), - ) - .put_account(&state.user1, Account::new().nonce(1)) - .new_address(&state.owner, 1, MULTI_TRANSFER_ADDRESS_EXPR) - .new_address(&state.owner, 2, BRIDGE_PROXY_ADDRESS_EXPR) - .new_address(&state.owner, 3, ESDT_SAFE_ADDRESS_EXPR) - .put_account( - ESDT_SAFE_ADDRESS_EXPR, - Account::new() - .code(&esdt_safe_code) - .owner(&state.owner) - .esdt_roles(BRIDGE_TOKEN_ID_EXPR, roles) - .esdt_balance(BRIDGE_TOKEN_ID_EXPR, "1_000"), - ) - .new_address(&state.owner, 4, BRIDGED_TOKENS_WRAPPER_ADDRESS_EXPR), - ); - state - } - - fn multi_transfer_deploy(&mut self) -> &mut Self { - self.world.sc_deploy( - ScDeployStep::new() - .from(self.owner.clone()) - .code(self.world.code_expression(MULTI_TRANSFER_PATH_EXPR)) - .call(self.multi_transfer.init()), - ); - - self - } - - fn bridge_proxy_deploy(&mut self) -> &mut Self { - self.world.sc_deploy( - ScDeployStep::new() - .from(self.owner.clone()) - .code(self.world.code_expression(BRIDGE_PROXY_PATH_EXPR)) - .call(self.bridge_proxy.init(self.multi_transfer.to_address())), - ); - - self - } - - fn safe_deploy(&mut self, price_aggregator_contract_address: Address) -> &mut Self { - self.world.sc_call( - ScCallStep::new().from(self.owner.clone()).call( - self.esdt_safe - .upgrade(ManagedAddress::zero(), ESDT_SAFE_ETH_TX_GAS_LIMIT), - ), - ); - - self - } - - fn bridged_tokens_wrapper_deploy(&mut self) -> &mut Self { - self.world.sc_deploy( - ScDeployStep::new() - .from(self.owner.clone()) - .code(self.world.code_expression(BRIDGED_TOKENS_WRAPPER_PATH_EXPR)) - .call(self.bridged_tokens_wrapper.init()), - ); - - self - } - - fn config_multi_transfer(&mut self) { - self.world - .sc_call( - ScCallStep::new() - .from(self.owner.clone()) - .to(&self.multi_transfer) - .call( - self.multi_transfer.set_wrapping_contract_address( - self.bridged_tokens_wrapper.to_address(), - ), - ), - ) - .sc_call( - ScCallStep::new() - .from(self.owner.clone()) - .to(&self.multi_transfer) - .call( - self.multi_transfer - .set_bridge_proxy_contract_address(self.bridge_proxy.to_address()), - ), - ) - .sc_call( - ScCallStep::new() - .from(self.owner.clone()) - .to(&self.multi_transfer) - .call( - self.multi_transfer - .set_esdt_safe_contract_address(self.esdt_safe.to_address()), - ), - ) - .sc_call( - ScCallStep::new() - .from(self.owner.clone()) - .to(&self.esdt_safe) - .call( - self.esdt_safe - .set_multi_transfer_contract_address(self.multi_transfer.to_address()), - ), - ) - .sc_call( - ScCallStep::new() - .from(self.owner.clone()) - .to(&self.esdt_safe) - .call(self.esdt_safe.add_token_to_whitelist( - TokenIdentifier::from_esdt_bytes("BRIDGE-123456"), - "BRIDGE", - true, - BigUint::from(ESDT_SAFE_ETH_TX_GAS_LIMIT), - )), - ) - .sc_call( - ScCallStep::new() - .from(self.owner.clone()) - .to(&self.esdt_safe) - .call(self.esdt_safe.set_accumulated_burned_tokens( - TokenIdentifier::from_esdt_bytes("BRIDGE-123456"), - BigUint::from(1_000u64), - )), - ); - } -} - -#[test] -fn basic_setup_test() { - let mut test: MultiTransferTestState = MultiTransferTestState::setup(); - let bridge_token_id_expr = "str:BRIDGE-123456"; // when specifying the token transfer - - test.multi_transfer_deploy(); - test.bridge_proxy_deploy(); - test.safe_deploy(Address::zero()); - test.bridged_tokens_wrapper_deploy(); - test.config_multi_transfer(); - - test.world.set_state_step(SetStateStep::new().put_account( - &test.owner, - Account::new().esdt_balance(bridge_token_id_expr, 1_000u64), - )); - - let eth_tx = EthTransaction { - from: test.eth_user, - to: ManagedAddress::from_address(&test.user1.value), - token_id: TokenIdentifier::from_esdt_bytes(BRIDGE_TOKEN_ID), - amount: BigUint::from(500u64), - tx_nonce: 1u64, - call_data: Some(CallData { - endpoint: ManagedBuffer::from("data"), - gas_limit: GAS_LIMIT, - args: ManagedVec::new(), - }), - }; - - test.world.check_state_step( - CheckStateStep::new().put_account( - &test.multi_transfer, - CheckAccount::new() - .check_storage("str:bridgeProxyContractAddress", "sc:bridge_proxy") - .check_storage("str:lastBatchId", "0x01") - .check_storage("str:wrappingContractAddress", "sc:bridged_tokens_wrapper") - .check_storage("str:maxTxBatchBlockDuration", "0xffffffffffffffff") - .check_storage("str:maxTxBatchSize", "10") - .check_storage("str:firstBatchId", "0x01") - .check_storage("str:esdtSafeContractAddress", "sc:esdt_safe"), - ), - ); -} - -#[test] -fn basic_transfer_test() { - let mut test: MultiTransferTestState = MultiTransferTestState::setup(); - let token_amount = BigUint::from(500u64); - - test.multi_transfer_deploy(); - test.bridge_proxy_deploy(); - test.safe_deploy(Address::zero()); - test.bridged_tokens_wrapper_deploy(); - test.config_multi_transfer(); - - let eth_tx = EthTransaction { - from: test.eth_user, - to: ManagedAddress::from_address(&test.user1.value), - token_id: TokenIdentifier::from_esdt_bytes(BRIDGE_TOKEN_ID), - amount: token_amount.clone(), - tx_nonce: 1u64, - call_data: Some(CallData { - endpoint: ManagedBuffer::from("data"), - gas_limit: GAS_LIMIT, - args: ManagedVec::new(), - }), - }; - - test.world.check_state_step( - CheckStateStep::new().put_account( - &test.multi_transfer, - CheckAccount::new() - .check_storage("str:bridgeProxyContractAddress", "sc:bridge_proxy") - .check_storage("str:lastBatchId", "0x01") - .check_storage("str:wrappingContractAddress", "sc:bridged_tokens_wrapper") - .check_storage("str:maxTxBatchBlockDuration", "0xffffffffffffffff") - .check_storage("str:maxTxBatchSize", "10") - .check_storage("str:firstBatchId", "0x01") - .check_storage("str:esdtSafeContractAddress", "sc:esdt_safe"), - ), - ); - - let mut transfers = MultiValueEncoded::new(); - transfers.push(eth_tx); - - test.world.sc_call( - ScCallStep::new() - .from(&test.owner) - .to(&test.esdt_safe) - .call(test.esdt_safe.unpause_endpoint()), - ); - - test.world.sc_call( - ScCallStep::new() - .from(&test.owner) - .to(&test.bridged_tokens_wrapper) - .call(test.bridged_tokens_wrapper.unpause_endpoint()), - ); - - test.world.sc_call( - ScCallStep::new() - .from(&test.owner) - .to(&test.multi_transfer) - .call( - test.multi_transfer - .batch_transfer_esdt_token(1u32, transfers), - ), - ); - - test.world - .check_state_step(CheckStateStep::new().put_account( - test.user1, - CheckAccount::new().esdt_balance(BRIDGE_TOKEN_ID_EXPR, token_amount), - )); -} diff --git a/multisig/src/lib.rs b/multisig/src/lib.rs index 39c658ea..d7229b74 100644 --- a/multisig/src/lib.rs +++ b/multisig/src/lib.rs @@ -57,8 +57,7 @@ pub trait Multisig: }); require!(!duplicates, "duplicate board member"); - self.num_board_members() - .update(|nr_board_members| *nr_board_members += board_len); + self.num_board_members().set(board_len); self.change_quorum(quorum); require!( @@ -130,7 +129,8 @@ pub trait Multisig: /// before being allowed to sign actions #[payable("EGLD")] #[endpoint] - fn stake(&self, #[payment] payment: BigUint) { + fn stake(&self) { + let payment = self.call_value().egld_value().clone_value(); let caller = self.blockchain().get_caller(); let caller_role = self.user_role(&caller); require!( diff --git a/multisig/tests/multisig_rust_test.rs b/multisig/tests/multisig_rust_test.rs index e6bbdf5c..81aca5cf 100644 --- a/multisig/tests/multisig_rust_test.rs +++ b/multisig/tests/multisig_rust_test.rs @@ -2,3 +2,13 @@ pub mod multisig_setup; use multisig_setup::*; + +#[test] +fn setup_test() { + let _ = MultisigSetup::new( + multiversx_price_aggregator_sc::contract_obj, + esdt_safe::contract_obj, + multi_transfer_esdt::contract_obj, + multisig::contract_obj, + ); +} diff --git a/multisig/tests/multisig_setup/mod.rs b/multisig/tests/multisig_setup/mod.rs index e69de29b..e42fad99 100644 --- a/multisig/tests/multisig_setup/mod.rs +++ b/multisig/tests/multisig_setup/mod.rs @@ -0,0 +1,331 @@ +use esdt_safe::EsdtSafe; +use multi_transfer_esdt::MultiTransferEsdt; +use multisig::Multisig; +use multiversx_price_aggregator_sc::PriceAggregator; +use multiversx_sc::{ + codec::multi_types::OptionalValue, + types::{Address, EsdtLocalRole, MultiValueEncoded}, +}; +use multiversx_sc_modules::{pause::PauseModule, staking::StakingModule}; +use multiversx_sc_scenario::{ + managed_address, managed_biguint, managed_buffer, managed_egld_token_id, managed_token_id, + rust_biguint, + whitebox_legacy::{BlockchainStateWrapper, ContractObjWrapper}, + DebugApi, +}; +use token_module::TokenModule; +use tx_batch_module::TxBatchModule; + +pub static WEGLD_TOKEN_ID: &[u8] = b"WEGLD-123456"; +pub static ETH_TOKEN_ID: &[u8] = b"ETH-123456"; +pub static GWEI_TOKEN_ID: &[u8] = b"GWEI"; +pub static BRIDGE_TOKEN_ID: &[u8] = b"BRIDGE"; + +pub const ETH_TX_GAS_LIMIT: u64 = 150_000; +pub const STAKE_AMOUNT: u64 = 1_000; + +pub struct MultisigSetup< + PriceAggregatorBuilder, + EsdtSafeBuilder, + MultiTransferBuilder, + MultisigBuilder, +> where + PriceAggregatorBuilder: + 'static + Copy + Fn() -> multiversx_price_aggregator_sc::ContractObj, + EsdtSafeBuilder: 'static + Copy + Fn() -> esdt_safe::ContractObj, + MultiTransferBuilder: 'static + Copy + Fn() -> multi_transfer_esdt::ContractObj, + MultisigBuilder: 'static + Copy + Fn() -> multisig::ContractObj, +{ + pub b_mock: BlockchainStateWrapper, + pub owner_addr: Address, + pub price_agg_wrapper: ContractObjWrapper< + multiversx_price_aggregator_sc::ContractObj, + PriceAggregatorBuilder, + >, + pub esdt_safe_wrapper: ContractObjWrapper, EsdtSafeBuilder>, + pub multi_transfer_wrapper: + ContractObjWrapper, MultiTransferBuilder>, + pub multisig_wrapper: ContractObjWrapper, MultisigBuilder>, +} + +impl + MultisigSetup +where + PriceAggregatorBuilder: + 'static + Copy + Fn() -> multiversx_price_aggregator_sc::ContractObj, + EsdtSafeBuilder: 'static + Copy + Fn() -> esdt_safe::ContractObj, + MultiTransferBuilder: 'static + Copy + Fn() -> multi_transfer_esdt::ContractObj, + MultisigBuilder: 'static + Copy + Fn() -> multisig::ContractObj, +{ + pub fn new( + price_aggregator_builder: PriceAggregatorBuilder, + esdt_safe_builder: EsdtSafeBuilder, + multi_transfer_builder: MultiTransferBuilder, + multisig_builder: MultisigBuilder, + ) -> Self { + let rust_zero = rust_biguint!(0); + let mut b_mock = BlockchainStateWrapper::new(); + let owner_addr = b_mock.create_user_account(&rust_zero); + + let mut oracles = Vec::with_capacity(5); + for _ in 0..5 { + let oracle = b_mock.create_user_account(&rust_biguint!(100)); + oracles.push(oracle); + } + + // Price Aggregator setup + + let price_agg_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(&owner_addr), + price_aggregator_builder, + "price aggregator wasm path", + ); + b_mock + .execute_tx(&owner_addr, &price_agg_wrapper, &rust_zero, |sc| { + let mut oracles_managed = MultiValueEncoded::new(); + for oracle in &oracles { + oracles_managed.push(managed_address!(oracle)); + } + + sc.init( + managed_egld_token_id!(), + managed_biguint!(20), + managed_biguint!(10), + 3, + 3, + oracles_managed, + ); + + sc.set_pair_decimals( + managed_buffer!(GWEI_TOKEN_ID), + managed_buffer!(BRIDGE_TOKEN_ID), + 6, + ); + sc.set_pair_decimals( + managed_buffer!(GWEI_TOKEN_ID), + managed_buffer!(WEGLD_TOKEN_ID), + 6, + ); + + sc.unpause_endpoint(); + }) + .assert_ok(); + + for i in 0..2 { + b_mock + .execute_tx(&oracles[i], &price_agg_wrapper, &rust_biguint!(100), |sc| { + sc.stake(); + }) + .assert_ok(); + } + + for i in 0..2 { + b_mock + .execute_tx(&oracles[i], &price_agg_wrapper, &rust_zero, |sc| { + sc.submit( + managed_buffer!(GWEI_TOKEN_ID), + managed_buffer!(BRIDGE_TOKEN_ID), + 0, + managed_biguint!(10), + 6, + ); + }) + .assert_ok(); + } + + b_mock + .execute_tx(&oracles[0], &price_agg_wrapper, &rust_zero, |sc| { + sc.submit( + managed_buffer!(GWEI_TOKEN_ID), + managed_buffer!(BRIDGE_TOKEN_ID), + 0, + managed_biguint!(1), + 6, + ); + }) + .assert_ok(); + + b_mock + .execute_tx(&oracles[0], &price_agg_wrapper, &rust_zero, |sc| { + sc.submit( + managed_buffer!(GWEI_TOKEN_ID), + managed_buffer!(WEGLD_TOKEN_ID), + 0, + managed_biguint!(10), + 6, + ); + }) + .assert_ok(); + + // Create multisig wrapper first - needed for the other contracts + + let multisig_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(&owner_addr), + multisig_builder, + "multisig wasm path", + ); + + // Esdt Safe setup + + let esdt_safe_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(multisig_wrapper.address_ref()), + esdt_safe_builder, + "esdt safe wasm path", + ); + + let multi_transfer_wrapper = b_mock.create_sc_account( + &rust_zero, + Some(multisig_wrapper.address_ref()), + multi_transfer_builder, + "multi-transfer wasm path", + ); + + b_mock + .execute_tx( + multisig_wrapper.address_ref(), + &esdt_safe_wrapper, + &rust_zero, + |sc| { + sc.init( + managed_address!(price_agg_wrapper.address_ref()), + managed_biguint!(ETH_TX_GAS_LIMIT), + ); + + sc.set_multi_transfer_contract_address(OptionalValue::Some(managed_address!( + multi_transfer_wrapper.address_ref() + ))); + + sc.add_token_to_whitelist( + managed_token_id!(WEGLD_TOKEN_ID), + managed_buffer!(b"WEGLD"), + true, + OptionalValue::Some(managed_biguint!(500_000)), + ); + sc.add_token_to_whitelist( + managed_token_id!(ETH_TOKEN_ID), + managed_buffer!(b"ETH"), + true, + OptionalValue::Some(managed_biguint!(500_000)), + ); + + sc.set_accumulated_burned_tokens( + managed_token_id!(WEGLD_TOKEN_ID), + managed_biguint!(500_000_000_000), + ); + sc.set_accumulated_burned_tokens( + managed_token_id!(ETH_TOKEN_ID), + managed_biguint!(500_000_000_000), + ); + + sc.set_max_tx_batch_block_duration(100); + }, + ) + .assert_ok(); + + b_mock.set_esdt_local_roles( + esdt_safe_wrapper.address_ref(), + WEGLD_TOKEN_ID, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + b_mock.set_esdt_local_roles( + esdt_safe_wrapper.address_ref(), + ETH_TOKEN_ID, + &[EsdtLocalRole::Mint, EsdtLocalRole::Burn], + ); + + // Multi-Transfer setup + + b_mock + .execute_tx( + multisig_wrapper.address_ref(), + &multi_transfer_wrapper, + &rust_zero, + |sc| { + sc.init(); + + sc.set_max_tx_batch_block_duration(3_600); + sc.set_esdt_safe_contract_address(OptionalValue::Some(managed_address!( + esdt_safe_wrapper.address_ref() + ))); + }, + ) + .assert_ok(); + + b_mock.set_esdt_local_roles( + multi_transfer_wrapper.address_ref(), + WEGLD_TOKEN_ID, + &[EsdtLocalRole::Mint], + ); + b_mock.set_esdt_local_roles( + multi_transfer_wrapper.address_ref(), + ETH_TOKEN_ID, + &[EsdtLocalRole::Mint], + ); + + // Multisig setup + + let relayer_1 = b_mock.create_user_account(&rust_zero); + let relayer_2 = b_mock.create_user_account(&rust_zero); + let user = b_mock.create_user_account(&rust_zero); + + b_mock.set_egld_balance(&relayer_1, &rust_biguint!(STAKE_AMOUNT)); + b_mock.set_egld_balance(&relayer_2, &rust_biguint!(STAKE_AMOUNT)); + b_mock.set_esdt_balance(&user, WEGLD_TOKEN_ID, &rust_biguint!(100_000_000_000)); + b_mock.set_esdt_balance(&user, ETH_TOKEN_ID, &rust_biguint!(200_000_000_000)); + + b_mock + .execute_tx(&owner_addr, &multisig_wrapper, &rust_zero, |sc| { + let mut board = MultiValueEncoded::new(); + board.push(managed_address!(&relayer_1)); + board.push(managed_address!(&relayer_2)); + + sc.init( + managed_address!(esdt_safe_wrapper.address_ref()), + managed_address!(multi_transfer_wrapper.address_ref()), + managed_biguint!(STAKE_AMOUNT), + managed_biguint!(500), + 2, + board, + ); + + sc.unpause_endpoint(); + }) + .assert_ok(); + + b_mock + .execute_tx( + &relayer_1, + &multisig_wrapper, + &rust_biguint!(STAKE_AMOUNT), + |sc| { + sc.stake(); + }, + ) + .assert_ok(); + + b_mock + .execute_tx( + &relayer_2, + &multisig_wrapper, + &rust_biguint!(STAKE_AMOUNT), + |sc| { + sc.stake(); + }, + ) + .assert_ok(); + + // Do I need EGLD-ESDT swap? + + Self { + b_mock, + owner_addr, + price_agg_wrapper, + esdt_safe_wrapper, + multi_transfer_wrapper, + multisig_wrapper, + } + } +}