From 808e38066789b80baaaa140f74fd841de9276d88 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 11 Dec 2024 10:26:35 +0200 Subject: [PATCH 1/5] impl --- dex/pair/tests/pair_rs_test.rs | 2 + dex/router/src/factory.rs | 30 ++++----- .../src/additional_locked_tokens.rs | 3 + .../fees-collector/src/claim.rs | 2 + .../src/external_sc_interactions/mod.rs | 2 + .../src/external_sc_interactions/pair.rs | 36 +++++++++++ .../src/external_sc_interactions/router.rs | 61 +++++++++++++++++++ .../fees-collector/src/fees_accumulation.rs | 41 +++++++++---- energy-integration/fees-collector/src/lib.rs | 9 +++ .../src/redistribute_rewards.rs | 3 + .../tests/fees_collector_test_setup/mod.rs | 2 + .../fees-collector/wasm/src/lib.rs | 6 +- .../governance-v2/tests/gov_test_setup/mod.rs | 2 + 13 files changed, 169 insertions(+), 30 deletions(-) create mode 100644 energy-integration/fees-collector/src/external_sc_interactions/mod.rs create mode 100644 energy-integration/fees-collector/src/external_sc_interactions/pair.rs create mode 100644 energy-integration/fees-collector/src/external_sc_interactions/router.rs diff --git a/dex/pair/tests/pair_rs_test.rs b/dex/pair/tests/pair_rs_test.rs index 7f43373ff..831be54e7 100644 --- a/dex/pair/tests/pair_rs_test.rs +++ b/dex/pair/tests/pair_rs_test.rs @@ -1600,6 +1600,8 @@ fn fees_collector_pair_test() { sc.init( managed_token_id!(LOCKED_TOKEN_ID), managed_address!(&energy_factory_mock_addr), + managed_address!(&energy_factory_mock_addr), // unused + managed_token_id!(b"RANDTOK-123456"), // unused MultiValueEncoded::new(), ); let _ = sc.known_contracts().insert(managed_address!(&pair_addr)); diff --git a/dex/router/src/factory.rs b/dex/router/src/factory.rs index ff7633a15..9a575bdd3 100644 --- a/dex/router/src/factory.rs +++ b/dex/router/src/factory.rs @@ -132,24 +132,20 @@ pub trait FactoryModule: config::ConfigModule + read_pair_storage::ReadPairStora first_token_id: TokenIdentifier, second_token_id: TokenIdentifier, ) -> ManagedAddress { - let mut address = self - .pair_map() - .get(&PairTokens { - first_token_id: first_token_id.clone(), - second_token_id: second_token_id.clone(), - }) - .unwrap_or_else(ManagedAddress::zero); - - if address.is_zero() { - address = self - .pair_map() - .get(&PairTokens { - first_token_id: second_token_id, - second_token_id: first_token_id, - }) - .unwrap_or_else(ManagedAddress::zero); + let mut opt_address = self.pair_map().get(&PairTokens { + first_token_id: first_token_id.clone(), + second_token_id: second_token_id.clone(), + }); + if opt_address.is_some() { + return unsafe { opt_address.unwrap_unchecked() }; } - address + + opt_address = self.pair_map().get(&PairTokens { + first_token_id: second_token_id, + second_token_id: first_token_id, + }); + + opt_address.unwrap_or_else(ManagedAddress::zero) } fn get_pair_temporary_owner(&self, pair_address: &ManagedAddress) -> Option { diff --git a/energy-integration/fees-collector/src/additional_locked_tokens.rs b/energy-integration/fees-collector/src/additional_locked_tokens.rs index 9303a408f..f1b9e4e12 100644 --- a/energy-integration/fees-collector/src/additional_locked_tokens.rs +++ b/energy-integration/fees-collector/src/additional_locked_tokens.rs @@ -10,6 +10,9 @@ pub trait AdditionalLockedTokensModule: + crate::fees_accumulation::FeesAccumulationModule + crate::events::FeesCollectorEventsModule + week_timekeeping::WeekTimekeepingModule + + crate::external_sc_interactions::router::RouterInteractionsModule + + crate::external_sc_interactions::pair::PairInteractionsModule + + utils::UtilsModule { #[only_owner] #[endpoint(setLockedTokensPerBlock)] diff --git a/energy-integration/fees-collector/src/claim.rs b/energy-integration/fees-collector/src/claim.rs index b0994d08b..2d5291f4c 100644 --- a/energy-integration/fees-collector/src/claim.rs +++ b/energy-integration/fees-collector/src/claim.rs @@ -24,6 +24,8 @@ pub trait ClaimModule: + sc_whitelist_module::SCWhitelistModule + multiversx_sc_modules::only_admin::OnlyAdminModule + crate::redistribute_rewards::RedistributeRewardsModule + + crate::external_sc_interactions::router::RouterInteractionsModule + + crate::external_sc_interactions::pair::PairInteractionsModule { #[endpoint(claimRewards)] fn claim_rewards_endpoint( diff --git a/energy-integration/fees-collector/src/external_sc_interactions/mod.rs b/energy-integration/fees-collector/src/external_sc_interactions/mod.rs new file mode 100644 index 000000000..20d2f674c --- /dev/null +++ b/energy-integration/fees-collector/src/external_sc_interactions/mod.rs @@ -0,0 +1,2 @@ +pub mod pair; +pub mod router; diff --git a/energy-integration/fees-collector/src/external_sc_interactions/pair.rs b/energy-integration/fees-collector/src/external_sc_interactions/pair.rs new file mode 100644 index 000000000..c2c94b46e --- /dev/null +++ b/energy-integration/fees-collector/src/external_sc_interactions/pair.rs @@ -0,0 +1,36 @@ +multiversx_sc::imports!(); + +mod pair_proxy { + multiversx_sc::imports!(); + + #[multiversx_sc::proxy] + pub trait PairProxy { + #[payable("*")] + #[endpoint(swapTokensFixedInput)] + fn swap_tokens_fixed_input( + &self, + token_out: TokenIdentifier, + amount_out_min: BigUint, // TOOD: Must be at least 1 + ) -> EsdtTokenPayment; + } +} + +const TOKEN_OUT_MIN: u32 = 1; + +#[multiversx_sc::module] +pub trait PairInteractionsModule { + fn swap_to_common_token( + &self, + pair_address: ManagedAddress, + input_payment: EsdtTokenPayment, + token_out: TokenIdentifier, + ) -> EsdtTokenPayment { + self.pair_proxy_builder(pair_address) + .swap_tokens_fixed_input(token_out, BigUint::from(TOKEN_OUT_MIN)) + .with_esdt_transfer(input_payment) + .execute_on_dest_context() + } + + #[proxy] + fn pair_proxy_builder(&self, sc_address: ManagedAddress) -> pair_proxy::Proxy; +} diff --git a/energy-integration/fees-collector/src/external_sc_interactions/router.rs b/energy-integration/fees-collector/src/external_sc_interactions/router.rs new file mode 100644 index 000000000..bfe2e5738 --- /dev/null +++ b/energy-integration/fees-collector/src/external_sc_interactions/router.rs @@ -0,0 +1,61 @@ +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, PartialEq)] +pub struct PairTokens { + pub first_token_id: TokenIdentifier, + pub second_token_id: TokenIdentifier, +} + +#[multiversx_sc::module] +pub trait RouterInteractionsModule: crate::config::ConfigModule + utils::UtilsModule { + #[only_owner] + #[endpoint(setRouterAddress)] + fn set_router_address(&self, router_address: ManagedAddress) { + self.require_sc_address(&router_address); + + self.router_address().set(router_address); + } + + #[only_owner] + #[endpoint(setBaseTokenId)] + fn set_base_token_id(&self, base_token_id: TokenIdentifier) { + self.require_valid_token_id(&base_token_id); + + self.base_token_id().set(base_token_id); + } + + // Mimics the "get_pair" logic from router. Way cheaper than doing an external call. + fn get_pair(&self, other_token_id: TokenIdentifier) -> Option { + let router_address = self.router_address().get(); + let base_token_id = self.base_token_id().get(); + let pair_map_mapper = self.pair_map(router_address); + + let opt_address = pair_map_mapper.get(&PairTokens { + first_token_id: other_token_id.clone(), + second_token_id: base_token_id.clone(), + }); + if opt_address.is_some() { + return opt_address; + } + + pair_map_mapper.get(&PairTokens { + first_token_id: base_token_id, + second_token_id: other_token_id, + }) + } + + #[storage_mapper("routerAddress")] + fn router_address(&self) -> SingleValueMapper; + + #[storage_mapper("baseTokenId")] + fn base_token_id(&self) -> SingleValueMapper; + + // router storage + + #[storage_mapper_from_address("pair_map")] + fn pair_map( + &self, + router_address: ManagedAddress, + ) -> MapMapper, ManagedAddress, ManagedAddress>; +} diff --git a/energy-integration/fees-collector/src/fees_accumulation.rs b/energy-integration/fees-collector/src/fees_accumulation.rs index e6eb4ba41..d7cd3d74f 100644 --- a/energy-integration/fees-collector/src/fees_accumulation.rs +++ b/energy-integration/fees-collector/src/fees_accumulation.rs @@ -8,6 +8,9 @@ pub trait FeesAccumulationModule: crate::config::ConfigModule + crate::events::FeesCollectorEventsModule + week_timekeeping::WeekTimekeepingModule + + crate::external_sc_interactions::router::RouterInteractionsModule + + crate::external_sc_interactions::pair::PairInteractionsModule + + utils::UtilsModule { /// Pair SC will deposit the fees through this endpoint /// Deposits for current week are accessible starting next week @@ -20,23 +23,26 @@ pub trait FeesAccumulationModule: "Only known contracts can deposit" ); - let payment = self.call_value().single_esdt(); + let mut payment = self.call_value().single_esdt(); require!( self.known_tokens().contains(&payment.token_identifier), "Invalid payment token" ); - if payment.token_nonce > 0 { - require!( - payment.token_identifier == self.locked_token_id().get(), - "Invalid locked token" - ); + if payment.token_nonce == 0 { + let opt_pair = self.get_pair(payment.token_identifier.clone()); + if let Some(pair_address) = opt_pair { + let base_token_id = self.base_token_id().get(); + payment = self.swap_to_common_token(pair_address, payment, base_token_id.clone()); - self.send().esdt_local_burn( - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ); + // just a sanity check + require!( + payment.token_identifier == base_token_id, + "Wrong token received from pair" + ); + } + } else { + self.burn_locked_token(&payment); } let current_week = self.get_current_week(); @@ -59,6 +65,19 @@ pub trait FeesAccumulationModule: } } + fn burn_locked_token(&self, payment: &EsdtTokenPayment) { + require!( + payment.token_identifier == self.locked_token_id().get(), + "Invalid locked token" + ); + + self.send().esdt_local_burn( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + } + #[view(getAccumulatedFees)] #[storage_mapper("accumulatedFees")] fn accumulated_fees(&self, week: Week, token: &TokenIdentifier) -> SingleValueMapper; diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index 2ee36602c..54e18b30e 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -6,6 +6,7 @@ pub mod additional_locked_tokens; pub mod claim; pub mod config; pub mod events; +pub mod external_sc_interactions; pub mod fees_accumulation; pub mod redistribute_rewards; @@ -29,16 +30,24 @@ pub trait FeesCollector: + multiversx_sc_modules::only_admin::OnlyAdminModule + claim::ClaimModule + redistribute_rewards::RedistributeRewardsModule + + external_sc_interactions::router::RouterInteractionsModule + + external_sc_interactions::pair::PairInteractionsModule { #[init] fn init( &self, locked_token_id: TokenIdentifier, energy_factory_address: ManagedAddress, + router_address: ManagedAddress, + base_token_id: TokenIdentifier, admins: MultiValueEncoded, ) { self.require_valid_token_id(&locked_token_id); self.require_sc_address(&energy_factory_address); + self.require_valid_token_id(&base_token_id); + + self.set_router_address(router_address); + self.set_base_token_id(base_token_id); let current_epoch = self.blockchain().get_block_epoch(); self.first_week_start_epoch().set(current_epoch); diff --git a/energy-integration/fees-collector/src/redistribute_rewards.rs b/energy-integration/fees-collector/src/redistribute_rewards.rs index d3c5d35ce..9ebd6764d 100644 --- a/energy-integration/fees-collector/src/redistribute_rewards.rs +++ b/energy-integration/fees-collector/src/redistribute_rewards.rs @@ -10,6 +10,9 @@ pub trait RedistributeRewardsModule: + crate::events::FeesCollectorEventsModule + week_timekeeping::WeekTimekeepingModule + multiversx_sc_modules::only_admin::OnlyAdminModule + + crate::external_sc_interactions::router::RouterInteractionsModule + + crate::external_sc_interactions::pair::PairInteractionsModule + + utils::UtilsModule { #[only_admin] #[endpoint(redistributeRewards)] diff --git a/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs b/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs index 3bc7d4bca..59db61cdc 100644 --- a/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs +++ b/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs @@ -155,6 +155,8 @@ where sc.init( managed_token_id!(LOCKED_TOKEN_ID), managed_address!(energy_factory_wrapper.address_ref()), + managed_address!(energy_factory_wrapper.address_ref()), // unused + managed_token_id!(b"RANDTOK-123456"), // unused admins, ); diff --git a/energy-integration/fees-collector/wasm/src/lib.rs b/energy-integration/fees-collector/wasm/src/lib.rs index 4aab5f1d3..8a1d75821 100644 --- a/energy-integration/fees-collector/wasm/src/lib.rs +++ b/energy-integration/fees-collector/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 43 +// Endpoints: 45 // Async Callback (empty): 1 -// Total number of exported functions: 46 +// Total number of exported functions: 48 #![no_std] @@ -63,6 +63,8 @@ multiversx_sc_wasm_adapter::endpoints! { claimBoostedRewards => claim_boosted_rewards redistributeRewards => redistribute_rewards getRemainingRewards => remaining_rewards + setRouterAddress => set_router_address + setBaseTokenId => set_base_token_id ) } diff --git a/energy-integration/governance-v2/tests/gov_test_setup/mod.rs b/energy-integration/governance-v2/tests/gov_test_setup/mod.rs index 5cc2d851c..0efcaa37e 100644 --- a/energy-integration/governance-v2/tests/gov_test_setup/mod.rs +++ b/energy-integration/governance-v2/tests/gov_test_setup/mod.rs @@ -112,6 +112,8 @@ where sc.init( managed_token_id!(XMEX_TOKEN_ID), managed_address!(energy_factory_wrapper.address_ref()), + managed_address!(energy_factory_wrapper.address_ref()), // unused + managed_token_id!(b"RANDTOK-123456"), // unused MultiValueEncoded::new(), ); }) From 62df8efa3204f0900116dc2e0c46607e75b6bfcc Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 11 Dec 2024 10:28:01 +0200 Subject: [PATCH 2/5] remove todo --- .../fees-collector/src/external_sc_interactions/pair.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/energy-integration/fees-collector/src/external_sc_interactions/pair.rs b/energy-integration/fees-collector/src/external_sc_interactions/pair.rs index c2c94b46e..4be485ca1 100644 --- a/energy-integration/fees-collector/src/external_sc_interactions/pair.rs +++ b/energy-integration/fees-collector/src/external_sc_interactions/pair.rs @@ -10,7 +10,7 @@ mod pair_proxy { fn swap_tokens_fixed_input( &self, token_out: TokenIdentifier, - amount_out_min: BigUint, // TOOD: Must be at least 1 + amount_out_min: BigUint, ) -> EsdtTokenPayment; } } From 7c3ae25e4d31ac527aaff6b2c88dfda6c4333aa3 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 11 Dec 2024 10:30:33 +0200 Subject: [PATCH 3/5] early exit condition --- .../fees-collector/src/external_sc_interactions/router.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/energy-integration/fees-collector/src/external_sc_interactions/router.rs b/energy-integration/fees-collector/src/external_sc_interactions/router.rs index bfe2e5738..4eee6b3fc 100644 --- a/energy-integration/fees-collector/src/external_sc_interactions/router.rs +++ b/energy-integration/fees-collector/src/external_sc_interactions/router.rs @@ -27,8 +27,12 @@ pub trait RouterInteractionsModule: crate::config::ConfigModule + utils::UtilsMo // Mimics the "get_pair" logic from router. Way cheaper than doing an external call. fn get_pair(&self, other_token_id: TokenIdentifier) -> Option { - let router_address = self.router_address().get(); let base_token_id = self.base_token_id().get(); + if other_token_id == base_token_id { + return None; + } + + let router_address = self.router_address().get(); let pair_map_mapper = self.pair_map(router_address); let opt_address = pair_map_mapper.get(&PairTokens { From 1e583c91aed4433d05634f1d0e89150df4f7ca09 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 11 Dec 2024 10:35:49 +0200 Subject: [PATCH 4/5] de-nesting --- .../fees-collector/src/fees_accumulation.rs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/energy-integration/fees-collector/src/fees_accumulation.rs b/energy-integration/fees-collector/src/fees_accumulation.rs index d7cd3d74f..ccc22303b 100644 --- a/energy-integration/fees-collector/src/fees_accumulation.rs +++ b/energy-integration/fees-collector/src/fees_accumulation.rs @@ -30,17 +30,7 @@ pub trait FeesAccumulationModule: ); if payment.token_nonce == 0 { - let opt_pair = self.get_pair(payment.token_identifier.clone()); - if let Some(pair_address) = opt_pair { - let base_token_id = self.base_token_id().get(); - payment = self.swap_to_common_token(pair_address, payment, base_token_id.clone()); - - // just a sanity check - require!( - payment.token_identifier == base_token_id, - "Wrong token received from pair" - ); - } + self.try_swap_to_base_token(&mut payment); } else { self.burn_locked_token(&payment); } @@ -65,6 +55,24 @@ pub trait FeesAccumulationModule: } } + fn try_swap_to_base_token(&self, payment: &mut EsdtTokenPayment) { + let opt_pair = self.get_pair(payment.token_identifier.clone()); + if opt_pair.is_none() { + return; + } + + let pair_address = unsafe { opt_pair.unwrap_unchecked() }; + let base_token_id = self.base_token_id().get(); + *payment = + self.swap_to_common_token(pair_address, (*payment).clone(), base_token_id.clone()); + + // just a sanity check + require!( + payment.token_identifier == base_token_id, + "Wrong token received from pair" + ); + } + fn burn_locked_token(&self, payment: &EsdtTokenPayment) { require!( payment.token_identifier == self.locked_token_id().get(), From 8497b7024b22ff61322918b789b382cf7104f99e Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 11 Dec 2024 11:01:03 +0200 Subject: [PATCH 5/5] test --- Cargo.lock | 3 +- dex/router/Cargo.toml | 3 ++ dex/router/tests/router_setup/mod.rs | 50 ++++++++--------- dex/router/tests/router_test.rs | 80 +++++++++++++++++++++++++--- 4 files changed, 100 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72759ef35..4bc39b643 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ahash" @@ -1721,6 +1721,7 @@ dependencies = [ name = "router" version = "0.0.0" dependencies = [ + "fees-collector", "locking_module", "multiversx-sc", "multiversx-sc-scenario", diff --git a/dex/router/Cargo.toml b/dex/router/Cargo.toml index 4ecf1aa3c..b92c6201c 100644 --- a/dex/router/Cargo.toml +++ b/dex/router/Cargo.toml @@ -29,3 +29,6 @@ path = "../../locked-asset/simple-lock" [dev-dependencies.multiversx-sc-scenario] version = "=0.53.2" + +[dev-dependencies.fees-collector] +path = "../../energy-integration/fees-collector" diff --git a/dex/router/tests/router_setup/mod.rs b/dex/router/tests/router_setup/mod.rs index 4339d502d..40cab2aa2 100644 --- a/dex/router/tests/router_setup/mod.rs +++ b/dex/router/tests/router_setup/mod.rs @@ -42,7 +42,7 @@ where RouterObjBuilder: 'static + Copy + Fn() -> router::ContractObj, PairObjBuilder: 'static + Copy + Fn() -> pair::ContractObj, { - pub blockchain_wrapper: BlockchainStateWrapper, + pub b_mock: BlockchainStateWrapper, pub owner_address: Address, pub user_address: Address, pub router_wrapper: ContractObjWrapper, RouterObjBuilder>, @@ -57,31 +57,23 @@ where { pub fn new(router_builder: RouterObjBuilder, pair_builder: PairObjBuilder) -> Self { let rust_zero = rust_biguint!(0u64); - let mut blockchain_wrapper = BlockchainStateWrapper::new(); - let owner_addr = blockchain_wrapper.create_user_account(&rust_zero); + let mut b_mock = BlockchainStateWrapper::new(); + let owner_addr = b_mock.create_user_account(&rust_zero); - let router_wrapper = blockchain_wrapper.create_sc_account( + let router_wrapper = b_mock.create_sc_account( &rust_zero, Some(&owner_addr), router_builder, ROUTER_WASM_PATH, ); - let mex_pair_wrapper = blockchain_wrapper.create_sc_account( - &rust_zero, - Some(&owner_addr), - pair_builder, - PAIR_WASM_PATH, - ); + let mex_pair_wrapper = + b_mock.create_sc_account(&rust_zero, Some(&owner_addr), pair_builder, PAIR_WASM_PATH); - let usdc_pair_wrapper = blockchain_wrapper.create_sc_account( - &rust_zero, - Some(&owner_addr), - pair_builder, - PAIR_WASM_PATH, - ); + let usdc_pair_wrapper = + b_mock.create_sc_account(&rust_zero, Some(&owner_addr), pair_builder, PAIR_WASM_PATH); - blockchain_wrapper + b_mock .execute_tx(&owner_addr, &mex_pair_wrapper, &rust_zero, |sc| { let first_token_id = managed_token_id!(WEGLD_TOKEN_ID); let second_token_id = managed_token_id!(MEX_TOKEN_ID); @@ -108,7 +100,7 @@ where }) .assert_ok(); - blockchain_wrapper + b_mock .execute_tx(&owner_addr, &usdc_pair_wrapper, &rust_zero, |sc| { let first_token_id = managed_token_id!(WEGLD_TOKEN_ID); let second_token_id = managed_token_id!(USDC_TOKEN_ID); @@ -135,7 +127,7 @@ where }) .assert_ok(); - blockchain_wrapper + b_mock .execute_tx(&owner_addr, &router_wrapper, &rust_zero, |sc| { sc.init(OptionalValue::None); @@ -157,38 +149,38 @@ where .assert_ok(); let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; - blockchain_wrapper.set_esdt_local_roles( + b_mock.set_esdt_local_roles( mex_pair_wrapper.address_ref(), LPMEX_TOKEN_ID, &lp_token_roles[..], ); let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; - blockchain_wrapper.set_esdt_local_roles( + b_mock.set_esdt_local_roles( usdc_pair_wrapper.address_ref(), LPUSDC_TOKEN_ID, &lp_token_roles[..], ); - let user_addr = blockchain_wrapper.create_user_account(&rust_biguint!(100_000_000)); - blockchain_wrapper.set_esdt_balance( + let user_addr = b_mock.create_user_account(&rust_biguint!(100_000_000)); + b_mock.set_esdt_balance( &user_addr, WEGLD_TOKEN_ID, &rust_biguint!(USER_TOTAL_WEGLD_TOKENS), ); - blockchain_wrapper.set_esdt_balance( + b_mock.set_esdt_balance( &user_addr, MEX_TOKEN_ID, &rust_biguint!(USER_TOTAL_MEX_TOKENS), ); - blockchain_wrapper.set_esdt_balance( + b_mock.set_esdt_balance( &user_addr, USDC_TOKEN_ID, &rust_biguint!(USER_TOTAL_USDC_TOKENS), ); RouterSetup { - blockchain_wrapper, + b_mock, owner_address: owner_addr, user_address: user_addr, router_wrapper, @@ -211,7 +203,7 @@ where }, ]; - self.blockchain_wrapper + self.b_mock .execute_esdt_multi_transfer( &self.user_address, &self.mex_pair_wrapper, @@ -238,7 +230,7 @@ where }, ]; - self.blockchain_wrapper + self.b_mock .execute_esdt_multi_transfer( &self.user_address, &self.usdc_pair_wrapper, @@ -261,7 +253,7 @@ where ) { let payment_amount_big = rust_biguint!(payment_amount); - self.blockchain_wrapper + self.b_mock .execute_esdt_transfer( &self.user_address, &self.router_wrapper, diff --git a/dex/router/tests/router_test.rs b/dex/router/tests/router_test.rs index 6564a508e..357882a21 100644 --- a/dex/router/tests/router_test.rs +++ b/dex/router/tests/router_test.rs @@ -1,6 +1,7 @@ #![allow(deprecated)] mod router_setup; +use fees_collector::{fees_accumulation::FeesAccumulationModule, FeesCollector}; use multiversx_sc::{ codec::multi_types::OptionalValue, storage::mappers::StorageTokenWrapper, @@ -131,17 +132,17 @@ fn test_multi_pair_swap() { router_setup.add_liquidity(); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, WEGLD_TOKEN_ID, &rust_biguint!(5_000_000_000), ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, MEX_TOKEN_ID, &rust_biguint!(5_000_000_000), ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, USDC_TOKEN_ID, &rust_biguint!(5_000_000_000), @@ -164,17 +165,17 @@ fn test_multi_pair_swap() { router_setup.multi_pair_swap(MEX_TOKEN_ID, 100_000, &ops); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, WEGLD_TOKEN_ID, &rust_biguint!(5_000_000_000), //unchanged ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, MEX_TOKEN_ID, &rust_biguint!(4_999_900_000), //spent 100_000 ); - router_setup.blockchain_wrapper.check_esdt_balance( + router_setup.b_mock.check_esdt_balance( &router_setup.user_address, USDC_TOKEN_ID, &rust_biguint!(5_000_082_909), //gained 82_909 @@ -558,3 +559,70 @@ fn user_enable_pair_swaps_fail_test() { }), ); } + +#[test] +fn fees_collector_base_token_feature_test() { + let mut setup = RouterSetup::new(router::contract_obj, pair::contract_obj); + + setup.add_liquidity(); + + let fc_wrapper = setup.b_mock.create_sc_account( + &rust_biguint!(0), + Some(&setup.owner_address), + fees_collector::contract_obj, + "fees collector path", + ); + + let router_address = setup.router_wrapper.address_ref().clone(); + setup + .b_mock + .execute_tx(&setup.owner_address, &fc_wrapper, &rust_biguint!(0), |sc| { + sc.init( + managed_token_id!(b"LOCKED-123456"), // unused + managed_address!(&router_address), // unused + managed_address!(&router_address), + managed_token_id!(WEGLD_TOKEN_ID), + MultiValueEncoded::new(), + ); + + let mut tokens = MultiValueEncoded::new(); + tokens.push(managed_token_id!(WEGLD_TOKEN_ID)); + tokens.push(managed_token_id!(USDC_TOKEN_ID)); + tokens.push(managed_token_id!(CUSTOM_TOKEN_ID)); + + // must use qualified syntax, otherwise, you get complaints of multiple "config" modules + fees_collector::config::ConfigModule::add_known_tokens(&sc, tokens); + + let _ = fees_collector::config::ConfigModule::known_contracts(&sc) + .insert(managed_address!(&setup.owner_address)); + }) + .assert_ok(); + + // try deposit USDC + setup + .b_mock + .set_esdt_balance(&setup.owner_address, USDC_TOKEN_ID, &rust_biguint!(1_000)); + + setup + .b_mock + .execute_esdt_transfer( + &setup.owner_address, + &fc_wrapper, + USDC_TOKEN_ID, + 0, + &rust_biguint!(1_000), + |sc| { + sc.deposit_swap_fees(); + + // check fees were accumulate for WEGLD instead of USDC + assert!(sc + .accumulated_fees(1, &managed_token_id!(USDC_TOKEN_ID)) + .is_empty()); + + assert!(!sc + .accumulated_fees(1, &managed_token_id!(WEGLD_TOKEN_ID)) + .is_empty()); + }, + ) + .assert_ok(); +}