From 808e38066789b80baaaa140f74fd841de9276d88 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 11 Dec 2024 10:26:35 +0200 Subject: [PATCH 01/23] 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 02/23] 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 03/23] 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 04/23] 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 05/23] 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(); +} From 17b1f17872a8cf26be52673f54400e09008fc3d4 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Fri, 28 Feb 2025 13:32:29 +0200 Subject: [PATCH 06/23] even more changes fees collector --- .../src/additional_locked_tokens.rs | 5 +- .../fees-collector/src/claim.rs | 1 - .../fees-collector/src/config.rs | 72 +------ .../src/external_sc_interactions/mod.rs | 1 - .../src/external_sc_interactions/pair.rs | 36 ---- .../src/external_sc_interactions/router.rs | 175 ++++++++++++++---- .../fees-collector/src/fees_accumulation.rs | 99 +++++----- energy-integration/fees-collector/src/lib.rs | 29 ++- .../src/redistribute_rewards.rs | 2 +- .../fees-collector/wasm/src/lib.rs | 13 +- 10 files changed, 217 insertions(+), 216 deletions(-) delete mode 100644 energy-integration/fees-collector/src/external_sc_interactions/pair.rs diff --git a/energy-integration/fees-collector/src/additional_locked_tokens.rs b/energy-integration/fees-collector/src/additional_locked_tokens.rs index f1b9e4e12..ec07ad765 100644 --- a/energy-integration/fees-collector/src/additional_locked_tokens.rs +++ b/energy-integration/fees-collector/src/additional_locked_tokens.rs @@ -11,8 +11,9 @@ pub trait AdditionalLockedTokensModule: + crate::events::FeesCollectorEventsModule + week_timekeeping::WeekTimekeepingModule + crate::external_sc_interactions::router::RouterInteractionsModule - + crate::external_sc_interactions::pair::PairInteractionsModule + + energy_query::EnergyQueryModule + utils::UtilsModule + + multiversx_sc_modules::only_admin::OnlyAdminModule { #[only_owner] #[endpoint(setLockedTokensPerBlock)] @@ -33,7 +34,7 @@ pub trait AdditionalLockedTokensModule: let amount_per_block = self.locked_tokens_per_block().get(); let new_tokens_amount = amount_per_block * blocks_in_week; - let locked_token_id = self.locked_token_id().get(); + let locked_token_id = self.get_locked_token_id(); self.accumulated_fees(current_week - 1, &locked_token_id) .update(|fees| *fees += new_tokens_amount); diff --git a/energy-integration/fees-collector/src/claim.rs b/energy-integration/fees-collector/src/claim.rs index 2d5291f4c..47ad55a81 100644 --- a/energy-integration/fees-collector/src/claim.rs +++ b/energy-integration/fees-collector/src/claim.rs @@ -25,7 +25,6 @@ pub trait ClaimModule: + 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/config.rs b/energy-integration/fees-collector/src/config.rs index 0cb2d813b..724728b1b 100644 --- a/energy-integration/fees-collector/src/config.rs +++ b/energy-integration/fees-collector/src/config.rs @@ -2,66 +2,16 @@ multiversx_sc::imports!(); #[multiversx_sc::module] pub trait ConfigModule { - #[only_owner] - #[endpoint(addKnownContracts)] - fn add_known_contracts(&self, contracts: MultiValueEncoded) { - let mut mapper = self.known_contracts(); - for sc in contracts { - require!( - self.blockchain().is_smart_contract(&sc), - "Invalid SC address" - ); - - let _ = mapper.insert(sc); - } - } - - #[only_owner] - #[endpoint(removeKnownContracts)] - fn remove_known_contracts(&self, contracts: MultiValueEncoded) { - let mut mapper = self.known_contracts(); - for sc in contracts { - let _ = mapper.swap_remove(&sc); - } - } - - #[only_owner] - #[endpoint(addKnownTokens)] - fn add_known_tokens(&self, tokens: MultiValueEncoded) { - let mut all_tokens_vec = self.all_tokens().get(); + fn add_known_token(&self, token_id: &TokenIdentifier) { let known_tokens_mapper = self.known_tokens(); - for token in tokens { - require!(token.is_valid_esdt_identifier(), "Invalid token ID"); - - if known_tokens_mapper.contains(&token) { - continue; - } - - known_tokens_mapper.add(&token); - all_tokens_vec.push(token); + if known_tokens_mapper.contains(&token_id) { + return; } - self.all_tokens().set(&all_tokens_vec); - } - - #[only_owner] - #[endpoint(removeKnownTokens)] - fn remove_known_tokens(&self, tokens: MultiValueEncoded) { - let mut all_tokens_vec = self.all_tokens().get(); - let known_tokens_mapper = self.known_tokens(); - for token in tokens { - if !known_tokens_mapper.contains(&token) { - continue; - } - - known_tokens_mapper.remove(&token); - unsafe { - let index = all_tokens_vec.find(&token).unwrap_unchecked(); - all_tokens_vec.remove(index); - } - } - - self.all_tokens().set(&all_tokens_vec); + known_tokens_mapper.add(&token_id); + self.all_tokens().update(|all_tokens| { + all_tokens.push(token_id.clone()); + }); } #[view(getAllTokens)] @@ -69,14 +19,6 @@ pub trait ConfigModule { self.all_tokens().get().into() } - #[view(getLockedTokenId)] - #[storage_mapper("lockedTokenId")] - fn locked_token_id(&self) -> SingleValueMapper; - - #[view(getAllKnownContracts)] - #[storage_mapper("knownContracts")] - fn known_contracts(&self) -> UnorderedSetMapper; - #[storage_mapper("knownTokens")] fn known_tokens(&self) -> WhitelistMapper; diff --git a/energy-integration/fees-collector/src/external_sc_interactions/mod.rs b/energy-integration/fees-collector/src/external_sc_interactions/mod.rs index 20d2f674c..fcddb5c62 100644 --- a/energy-integration/fees-collector/src/external_sc_interactions/mod.rs +++ b/energy-integration/fees-collector/src/external_sc_interactions/mod.rs @@ -1,2 +1 @@ -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 deleted file mode 100644 index 4be485ca1..000000000 --- a/energy-integration/fees-collector/src/external_sc_interactions/pair.rs +++ /dev/null @@ -1,36 +0,0 @@ -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, - ) -> 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 index 4eee6b3fc..fca912ee9 100644 --- a/energy-integration/fees-collector/src/external_sc_interactions/router.rs +++ b/energy-integration/fees-collector/src/external_sc_interactions/router.rs @@ -1,14 +1,50 @@ +use common_types::{PaymentsVec, Week}; +use router_proxy::FunctionName; + 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, +mod router_proxy { + use common_types::PaymentsVec; + + multiversx_sc::imports!(); + + pub type FunctionName = ManagedBuffer; + pub type SwapOperationType = + MultiValue4, FunctionName, TokenIdentifier, BigUint>; + + #[multiversx_sc::proxy] + pub trait RouterProxy { + #[payable("*")] + #[endpoint(multiPairSwap)] + fn multi_pair_swap( + &self, + swap_operations: MultiValueEncoded>, + ) -> PaymentsVec; + } +} + +#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone)] +pub struct SwapOperation { + pub pair_address: ManagedAddress, + pub function_name: FunctionName, + pub input_token_id: TokenIdentifier, + pub min_amount_out: BigUint, } +pub type SwapOperationArgs = MultiValueEncoded>>; +pub type SingleSwapOperationArg = ManagedVec>; + #[multiversx_sc::module] -pub trait RouterInteractionsModule: crate::config::ConfigModule + utils::UtilsModule { +pub trait RouterInteractionsModule: + crate::fees_accumulation::FeesAccumulationModule + + crate::config::ConfigModule + + crate::events::FeesCollectorEventsModule + + week_timekeeping::WeekTimekeepingModule + + energy_query::EnergyQueryModule + + utils::UtilsModule + + multiversx_sc_modules::only_admin::OnlyAdminModule +{ #[only_owner] #[endpoint(setRouterAddress)] fn set_router_address(&self, router_address: ManagedAddress) { @@ -17,49 +53,112 @@ pub trait RouterInteractionsModule: crate::config::ConfigModule + utils::UtilsMo 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); + /// Swaps tokens to the base token (i.e. MEX). + /// + /// The first token must be a known token to the fees collector, and the very last token must be MEX. + /// + /// The fees collector uses the given pair paths through the router contract. + #[only_admin] + #[endpoint(swapTokenToBaseToken)] + fn swap_token_to_base_token(&self, swap_operations: SwapOperationArgs) { + let current_week = self.get_current_week(); + let router_address = self.router_address().get(); + let base_token_id = self.get_base_token_id(); + let mut total_base_tokens = BigUint::zero(); + for swap_op in swap_operations { + let payment = self.check_args_and_get_first_token_payment( + current_week, + &base_token_id, + swap_op.clone(), + ); + if payment.amount == 0 { + continue; + } - self.base_token_id().set(base_token_id); - } + let mut received_tokens = + self.call_swap_through_router(router_address.clone(), payment, swap_op); + require!( + received_tokens.token_identifier == base_token_id, + "Invalid tokens received from router" + ); - // Mimics the "get_pair" logic from router. Way cheaper than doing an external call. - fn get_pair(&self, other_token_id: TokenIdentifier) -> Option { - let base_token_id = self.base_token_id().get(); - if other_token_id == base_token_id { - return None; - } + self.burn_base_token(&mut received_tokens); - let router_address = self.router_address().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; + total_base_tokens += received_tokens.amount; } - pair_map_mapper.get(&PairTokens { - first_token_id: base_token_id, - second_token_id: other_token_id, - }) + self.accumulated_fees(current_week, &base_token_id) + .update(|acc_fees| *acc_fees += total_base_tokens); } - #[storage_mapper("routerAddress")] - fn router_address(&self) -> SingleValueMapper; + fn check_args_and_get_first_token_payment( + &self, + current_week: Week, + base_token_id: &TokenIdentifier, + swap_operation: SingleSwapOperationArg, + ) -> EsdtTokenPayment { + let mut iter = swap_operation.into_iter(); + let opt_first_item = iter.next(); + require!(opt_first_item.is_some(), "No arguments provided"); + + let first_item = unsafe { opt_first_item.unwrap_unchecked() }; + let last_item = match iter.last() { + Some(item) => item, + None => first_item.clone(), + }; + + require!( + self.known_tokens().contains(&first_item.input_token_id), + "Invalid first token" + ); - #[storage_mapper("baseTokenId")] - fn base_token_id(&self) -> SingleValueMapper; + require!( + &last_item.input_token_id == base_token_id, + "Invalid last token" + ); - // router storage + let token_amount = self + .accumulated_fees(current_week, &first_item.input_token_id) + .take(); - #[storage_mapper_from_address("pair_map")] - fn pair_map( + EsdtTokenPayment::new(first_item.input_token_id, 0, token_amount) + } + + fn call_swap_through_router( &self, router_address: ManagedAddress, - ) -> MapMapper, ManagedAddress, ManagedAddress>; + payment: EsdtTokenPayment, + swap_operation: SingleSwapOperationArg, + ) -> EsdtTokenPayment { + let mut args = MultiValueEncoded::new(); + for swap_op in &swap_operation { + args.push( + ( + swap_op.pair_address, + swap_op.function_name, + swap_op.input_token_id, + swap_op.min_amount_out, + ) + .into(), + ) + } + + let output_payments: PaymentsVec = self + .router_proxy(router_address) + .multi_pair_swap(args) + .esdt(payment) + .execute_on_dest_context(); + require!( + !output_payments.is_empty(), + "No payments received from router" + ); + + unsafe { output_payments.iter().last().unwrap_unchecked() } + } + + #[storage_mapper("routerAddress")] + fn router_address(&self) -> SingleValueMapper; + + #[proxy] + fn router_proxy(&self, sc_address: ManagedAddress) -> router_proxy::Proxy; } diff --git a/energy-integration/fees-collector/src/fees_accumulation.rs b/energy-integration/fees-collector/src/fees_accumulation.rs index ccc22303b..b4e5b86ed 100644 --- a/energy-integration/fees-collector/src/fees_accumulation.rs +++ b/energy-integration/fees-collector/src/fees_accumulation.rs @@ -1,6 +1,7 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); +use energy_factory::lock_options::MAX_PENALTY_PERCENTAGE; use week_timekeeping::Week; #[multiversx_sc::module] @@ -8,40 +9,70 @@ pub trait FeesAccumulationModule: crate::config::ConfigModule + crate::events::FeesCollectorEventsModule + week_timekeeping::WeekTimekeepingModule - + crate::external_sc_interactions::router::RouterInteractionsModule - + crate::external_sc_interactions::pair::PairInteractionsModule + + energy_query::EnergyQueryModule + utils::UtilsModule { - /// Pair SC will deposit the fees through this endpoint + /// Base token burn percent is between 0 (0%) and 10_000 (100%) + #[only_owner] + #[endpoint(setBaseTokenBurnPercent)] + fn set_base_token_burn_percent(&self, burn_percent: u64) { + require!(burn_percent <= MAX_PENALTY_PERCENTAGE, "Invalid percent"); + + self.base_token_burn_percent().set(burn_percent); + } + + /// Anyone can deposit tokens through this endpoint /// Deposits for current week are accessible starting next week #[payable("*")] #[endpoint(depositSwapFees)] fn deposit_swap_fees(&self) { - let caller = self.blockchain().get_caller(); - require!( - self.known_contracts().contains(&caller), - "Only known contracts can deposit" - ); - let mut payment = self.call_value().single_esdt(); - require!( - self.known_tokens().contains(&payment.token_identifier), - "Invalid payment token" - ); + self.add_known_token(&payment.token_identifier); - if payment.token_nonce == 0 { - self.try_swap_to_base_token(&mut payment); - } else { - self.burn_locked_token(&payment); + if payment.token_nonce != 0 { + self.try_burn_locked_token(&payment); + } + + let base_token_id = self.get_base_token_id(); + if payment.token_identifier == base_token_id { + self.burn_base_token(&mut payment); } let current_week = self.get_current_week(); self.accumulated_fees(current_week, &payment.token_identifier) .update(|amt| *amt += &payment.amount); + let caller = self.blockchain().get_caller(); self.emit_deposit_swap_fees_event(&caller, current_week, &payment); } + fn try_burn_locked_token(&self, payment: &EsdtTokenPayment) { + let locked_token_id = self.get_locked_token_id(); + require!( + payment.token_identifier == locked_token_id, + "Only locked token accepted as SFT/NFT/MetaESDT" + ); + + self.send().esdt_local_burn( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ); + } + + fn burn_base_token(&self, payment: &mut EsdtTokenPayment) { + let burn_percent = self.base_token_burn_percent().get(); + if burn_percent == 0 { + return; + } + + let burn_amount = &payment.amount * burn_percent / MAX_PENALTY_PERCENTAGE; + self.send() + .esdt_local_burn(&payment.token_identifier, 0, &burn_amount); + + payment.amount -= burn_amount; + } + fn get_and_clear_accumulated_fees( &self, week: Week, @@ -55,38 +86,10 @@ 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(), - "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; + + #[storage_mapper("baseTokenBurnPercent")] + fn base_token_burn_percent(&self) -> SingleValueMapper; } diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index 54e18b30e..99c708fc7 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] +use multiversx_sc::storage::StorageKey; + multiversx_sc::imports!(); pub mod additional_locked_tokens; @@ -31,33 +33,25 @@ pub trait FeesCollector: + claim::ClaimModule + redistribute_rewards::RedistributeRewardsModule + external_sc_interactions::router::RouterInteractionsModule - + external_sc_interactions::pair::PairInteractionsModule { + /// Base token burn percent is between 0 (0%) and 10_000 (100%) #[init] fn init( &self, - locked_token_id: TokenIdentifier, energy_factory_address: ManagedAddress, router_address: ManagedAddress, - base_token_id: TokenIdentifier, + base_token_burn_percent: u64, 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_energy_factory_address(energy_factory_address); self.set_router_address(router_address); - self.set_base_token_id(base_token_id); + self.set_base_token_burn_percent(base_token_burn_percent); let current_epoch = self.blockchain().get_block_epoch(); self.first_week_start_epoch().set(current_epoch); - let mut tokens = MultiValueEncoded::new(); - tokens.push(locked_token_id.clone()); - self.add_known_tokens(tokens); - - self.locked_token_id().set(locked_token_id); - self.energy_factory_address().set(energy_factory_address); + let locked_token_id = self.get_locked_token_id(); + self.add_known_token(&locked_token_id); for admin in admins { self.add_admin(admin); @@ -65,5 +59,10 @@ pub trait FeesCollector: } #[upgrade] - fn upgrade(&self) {} + fn upgrade(&self) { + let mut mapper = UnorderedSetMapper::::new(StorageKey::new( + b"knownContracts", + )); + mapper.clear(); + } } diff --git a/energy-integration/fees-collector/src/redistribute_rewards.rs b/energy-integration/fees-collector/src/redistribute_rewards.rs index 9ebd6764d..05c0da1f5 100644 --- a/energy-integration/fees-collector/src/redistribute_rewards.rs +++ b/energy-integration/fees-collector/src/redistribute_rewards.rs @@ -11,7 +11,7 @@ pub trait RedistributeRewardsModule: + week_timekeeping::WeekTimekeepingModule + multiversx_sc_modules::only_admin::OnlyAdminModule + crate::external_sc_interactions::router::RouterInteractionsModule - + crate::external_sc_interactions::pair::PairInteractionsModule + + energy_query::EnergyQueryModule + utils::UtilsModule { #[only_admin] diff --git a/energy-integration/fees-collector/wasm/src/lib.rs b/energy-integration/fees-collector/wasm/src/lib.rs index 8a1d75821..3168bdc88 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: 45 +// Endpoints: 40 // Async Callback (empty): 1 -// Total number of exported functions: 48 +// Total number of exported functions: 43 #![no_std] @@ -20,13 +20,7 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - addKnownContracts => add_known_contracts - removeKnownContracts => remove_known_contracts - addKnownTokens => add_known_tokens - removeKnownTokens => remove_known_tokens getAllTokens => get_all_tokens - getLockedTokenId => locked_token_id - getAllKnownContracts => known_contracts getAllowExternalClaimRewards => allow_external_claim_rewards getLastActiveWeekForUser => get_last_active_week_for_user_view getUserEnergyForWeek => get_user_energy_for_week_view @@ -36,6 +30,7 @@ multiversx_sc_wasm_adapter::endpoints! { getTotalLockedTokensForWeek => total_locked_tokens_for_week updateEnergyForUser => update_energy_for_user getCurrentClaimProgress => current_claim_progress + setBaseTokenBurnPercent => set_base_token_burn_percent depositSwapFees => deposit_swap_fees getAccumulatedFees => accumulated_fees setLockedTokensPerBlock => set_locked_tokens_per_block @@ -64,7 +59,7 @@ multiversx_sc_wasm_adapter::endpoints! { redistributeRewards => redistribute_rewards getRemainingRewards => remaining_rewards setRouterAddress => set_router_address - setBaseTokenId => set_base_token_id + swapTokenToBaseToken => swap_token_to_base_token ) } From 545fbb405394f031f63b151c7ecbae633bbf4b44 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Fri, 28 Feb 2025 13:35:25 +0200 Subject: [PATCH 07/23] small fix --- energy-integration/fees-collector/src/fees_accumulation.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/energy-integration/fees-collector/src/fees_accumulation.rs b/energy-integration/fees-collector/src/fees_accumulation.rs index b4e5b86ed..9b76f5865 100644 --- a/energy-integration/fees-collector/src/fees_accumulation.rs +++ b/energy-integration/fees-collector/src/fees_accumulation.rs @@ -67,6 +67,10 @@ pub trait FeesAccumulationModule: } let burn_amount = &payment.amount * burn_percent / MAX_PENALTY_PERCENTAGE; + if burn_amount == 0 { + return; + } + self.send() .esdt_local_burn(&payment.token_identifier, 0, &burn_amount); From 21392967b1e6e5c41693333276915e2018509517 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Thu, 20 Mar 2025 11:39:04 +0200 Subject: [PATCH 08/23] fixes --- Cargo.lock | 5 +- dex/router/Cargo.toml | 3 - dex/router/tests/router_test.rs | 69 +---- .../energy-factory-mock/src/lib.rs | 3 + energy-integration/fees-collector/Cargo.toml | 12 + .../fees-collector/src/claim.rs | 17 +- .../fees-collector/src/config.rs | 25 +- .../src/external_sc_interactions/router.rs | 36 +-- .../fees-collector/src/fees_accumulation.rs | 31 ++- energy-integration/fees-collector/src/lib.rs | 46 +++- .../src/redistribute_rewards.rs | 20 +- .../tests/fees_collector_rust_test.rs | 178 +++++++++--- .../tests/fees_collector_test_setup/mod.rs | 38 +-- .../fees-collector/tests/router_setup/mod.rs | 259 ++++++++++++++++++ .../fees-collector/wasm/Cargo.lock | 3 +- .../fees-collector/wasm/src/lib.rs | 2 +- .../governance-v2/tests/gov_test_setup/mod.rs | 11 +- 17 files changed, 547 insertions(+), 211 deletions(-) create mode 100644 energy-integration/fees-collector/tests/router_setup/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 4bc39b643..3ad0aabab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -832,6 +832,7 @@ version = "0.0.0" dependencies = [ "common-types", "common_errors", + "common_structs", "energy-factory", "energy-query", "locking_module", @@ -839,6 +840,9 @@ dependencies = [ "multiversx-sc-modules", "multiversx-sc-scenario", "num-bigint", + "pair", + "pausable", + "router", "sc_whitelist_module", "simple-lock", "utils", @@ -1721,7 +1725,6 @@ 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 b92c6201c..4ecf1aa3c 100644 --- a/dex/router/Cargo.toml +++ b/dex/router/Cargo.toml @@ -29,6 +29,3 @@ 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_test.rs b/dex/router/tests/router_test.rs index 357882a21..cbc09f09b 100644 --- a/dex/router/tests/router_test.rs +++ b/dex/router/tests/router_test.rs @@ -1,7 +1,7 @@ #![allow(deprecated)] mod router_setup; -use fees_collector::{fees_accumulation::FeesAccumulationModule, FeesCollector}; + use multiversx_sc::{ codec::multi_types::OptionalValue, storage::mappers::StorageTokenWrapper, @@ -559,70 +559,3 @@ 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(); -} diff --git a/energy-integration/energy-factory-mock/src/lib.rs b/energy-integration/energy-factory-mock/src/lib.rs index d3354e67e..a2c0c5862 100644 --- a/energy-integration/energy-factory-mock/src/lib.rs +++ b/energy-integration/energy-factory-mock/src/lib.rs @@ -55,6 +55,9 @@ pub trait EnergyFactoryMock { #[storage_mapper("userEnergy")] fn user_energy(&self, user: &ManagedAddress) -> SingleValueMapper>; + #[storage_mapper("baseAssetTokenId")] + fn base_asset_token_id(&self) -> SingleValueMapper; + #[storage_mapper("lockedTokenId")] fn locked_token(&self) -> NonFungibleTokenMapper; } diff --git a/energy-integration/fees-collector/Cargo.toml b/energy-integration/fees-collector/Cargo.toml index df169e2c7..92f169c38 100644 --- a/energy-integration/fees-collector/Cargo.toml +++ b/energy-integration/fees-collector/Cargo.toml @@ -42,6 +42,9 @@ path = "../../common/modules/sc_whitelist_module" [dependencies.common-types] path = "../common-types" +[dependencies.common_structs] +path = "../../common/common_structs" + [dependencies.common_errors] path = "../../common/common_errors" @@ -53,3 +56,12 @@ version = "=0.53.2" [dev-dependencies.sc_whitelist_module] path = "../../common/modules/sc_whitelist_module" + +[dev-dependencies.router] +path = "../../dex/router" + +[dev-dependencies.pair] +path = "../../dex/pair" + +[dev-dependencies.pausable] +path = "../../common/modules/pausable" diff --git a/energy-integration/fees-collector/src/claim.rs b/energy-integration/fees-collector/src/claim.rs index 47ad55a81..30e28906d 100644 --- a/energy-integration/fees-collector/src/claim.rs +++ b/energy-integration/fees-collector/src/claim.rs @@ -192,12 +192,17 @@ where week: Week, ) -> PaymentsVec<::Api> { let mut results = ManagedVec::new(); - let all_tokens = sc.all_tokens().get(); - for token in &all_tokens { - let opt_accumulated_fees = sc.get_and_clear_accumulated_fees(week, &token); - if let Some(accumulated_fees) = opt_accumulated_fees { - results.push(EsdtTokenPayment::new(token, 0, accumulated_fees)); - } + + let base_token_id = sc.get_base_token_id(); + let opt_acc_base_token = sc.get_and_clear_accumulated_fees(week, &base_token_id); + if let Some(accumulated_fees) = opt_acc_base_token { + results.push(EsdtTokenPayment::new(base_token_id, 0, accumulated_fees)); + } + + let locked_token_id = sc.get_locked_token_id(); + let opt_acc_locked_token = sc.get_and_clear_accumulated_fees(week, &locked_token_id); + if let Some(accumulated_fees) = opt_acc_locked_token { + results.push(EsdtTokenPayment::new(locked_token_id, 0, accumulated_fees)); } results diff --git a/energy-integration/fees-collector/src/config.rs b/energy-integration/fees-collector/src/config.rs index 724728b1b..84b3a67dc 100644 --- a/energy-integration/fees-collector/src/config.rs +++ b/energy-integration/fees-collector/src/config.rs @@ -2,28 +2,17 @@ multiversx_sc::imports!(); #[multiversx_sc::module] pub trait ConfigModule { - fn add_known_token(&self, token_id: &TokenIdentifier) { - let known_tokens_mapper = self.known_tokens(); - if known_tokens_mapper.contains(&token_id) { - return; - } - - known_tokens_mapper.add(&token_id); - self.all_tokens().update(|all_tokens| { - all_tokens.push(token_id.clone()); - }); + #[inline(always)] + fn add_known_token(&self, token_id: TokenIdentifier) { + let _ = self.all_known_tokens().insert(token_id); } #[view(getAllTokens)] - fn get_all_tokens(&self) -> MultiValueEncoded { - self.all_tokens().get().into() - } - - #[storage_mapper("knownTokens")] - fn known_tokens(&self) -> WhitelistMapper; + #[storage_mapper("allKnownTokens")] + fn all_known_tokens(&self) -> UnorderedSetMapper; - #[storage_mapper("allTokens")] - fn all_tokens(&self) -> SingleValueMapper>; + #[storage_mapper("allAccTokens")] + fn all_accumulated_tokens(&self, token_id: &TokenIdentifier) -> SingleValueMapper; // Update for this storage disabled for this version of the exchange #[view(getAllowExternalClaimRewards)] 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 fca912ee9..613fc6b07 100644 --- a/energy-integration/fees-collector/src/external_sc_interactions/router.rs +++ b/energy-integration/fees-collector/src/external_sc_interactions/router.rs @@ -1,4 +1,4 @@ -use common_types::{PaymentsVec, Week}; +use common_types::PaymentsVec; use router_proxy::FunctionName; multiversx_sc::imports!(); @@ -55,22 +55,17 @@ pub trait RouterInteractionsModule: /// Swaps tokens to the base token (i.e. MEX). /// - /// The first token must be a known token to the fees collector, and the very last token must be MEX. + /// The first token must be a known token to the fees collector, and the very last token received must be MEX. /// /// The fees collector uses the given pair paths through the router contract. #[only_admin] #[endpoint(swapTokenToBaseToken)] fn swap_token_to_base_token(&self, swap_operations: SwapOperationArgs) { - let current_week = self.get_current_week(); let router_address = self.router_address().get(); let base_token_id = self.get_base_token_id(); let mut total_base_tokens = BigUint::zero(); for swap_op in swap_operations { - let payment = self.check_args_and_get_first_token_payment( - current_week, - &base_token_id, - swap_op.clone(), - ); + let payment = self.check_args_and_get_first_token_payment(swap_op.clone()); if payment.amount == 0 { continue; } @@ -82,19 +77,18 @@ pub trait RouterInteractionsModule: "Invalid tokens received from router" ); - self.burn_base_token(&mut received_tokens); + self.burn_part_of_base_token(&mut received_tokens); total_base_tokens += received_tokens.amount; } + let current_week = self.get_current_week(); self.accumulated_fees(current_week, &base_token_id) .update(|acc_fees| *acc_fees += total_base_tokens); } fn check_args_and_get_first_token_payment( &self, - current_week: Week, - base_token_id: &TokenIdentifier, swap_operation: SingleSwapOperationArg, ) -> EsdtTokenPayment { let mut iter = swap_operation.into_iter(); @@ -102,24 +96,22 @@ pub trait RouterInteractionsModule: require!(opt_first_item.is_some(), "No arguments provided"); let first_item = unsafe { opt_first_item.unwrap_unchecked() }; - let last_item = match iter.last() { - Some(item) => item, - None => first_item.clone(), - }; - + let base_token_id = self.get_base_token_id(); + let locked_token_id = self.get_locked_token_id(); require!( - self.known_tokens().contains(&first_item.input_token_id), - "Invalid first token" + first_item.input_token_id != base_token_id + && first_item.input_token_id != locked_token_id, + "May not swap base token or locked token" ); - require!( - &last_item.input_token_id == base_token_id, - "Invalid last token" + self.all_known_tokens().contains(&first_item.input_token_id), + "Unknown first token" ); let token_amount = self - .accumulated_fees(current_week, &first_item.input_token_id) + .all_accumulated_tokens(&first_item.input_token_id) .take(); + require!(token_amount > 0, "No tokens for given week"); EsdtTokenPayment::new(first_item.input_token_id, 0, token_amount) } diff --git a/energy-integration/fees-collector/src/fees_accumulation.rs b/energy-integration/fees-collector/src/fees_accumulation.rs index 9b76f5865..1b29f496c 100644 --- a/energy-integration/fees-collector/src/fees_accumulation.rs +++ b/energy-integration/fees-collector/src/fees_accumulation.rs @@ -1,6 +1,7 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); +use common_structs::Percent; use energy_factory::lock_options::MAX_PENALTY_PERCENTAGE; use week_timekeeping::Week; @@ -15,32 +16,38 @@ pub trait FeesAccumulationModule: /// Base token burn percent is between 0 (0%) and 10_000 (100%) #[only_owner] #[endpoint(setBaseTokenBurnPercent)] - fn set_base_token_burn_percent(&self, burn_percent: u64) { + fn set_base_token_burn_percent(&self, burn_percent: Percent) { require!(burn_percent <= MAX_PENALTY_PERCENTAGE, "Invalid percent"); self.base_token_burn_percent().set(burn_percent); } /// Anyone can deposit tokens through this endpoint + /// /// Deposits for current week are accessible starting next week #[payable("*")] #[endpoint(depositSwapFees)] fn deposit_swap_fees(&self) { let mut payment = self.call_value().single_esdt(); - self.add_known_token(&payment.token_identifier); + self.add_known_token(payment.token_identifier.clone()); + + let current_week = self.get_current_week(); + let base_token_id = self.get_base_token_id(); if payment.token_nonce != 0 { self.try_burn_locked_token(&payment); - } - let base_token_id = self.get_base_token_id(); - if payment.token_identifier == base_token_id { - self.burn_base_token(&mut payment); - } + self.accumulated_fees(current_week, &payment.token_identifier) + .update(|amt| *amt += &payment.amount); + } else if payment.token_identifier == base_token_id { + self.burn_part_of_base_token(&mut payment); - let current_week = self.get_current_week(); - self.accumulated_fees(current_week, &payment.token_identifier) - .update(|amt| *amt += &payment.amount); + self.accumulated_fees(current_week, &payment.token_identifier) + .update(|amt| *amt += &payment.amount); + } else { + self.all_accumulated_tokens(&payment.token_identifier) + .update(|acc_tokens| *acc_tokens += &payment.amount); + } let caller = self.blockchain().get_caller(); self.emit_deposit_swap_fees_event(&caller, current_week, &payment); @@ -60,7 +67,7 @@ pub trait FeesAccumulationModule: ); } - fn burn_base_token(&self, payment: &mut EsdtTokenPayment) { + fn burn_part_of_base_token(&self, payment: &mut EsdtTokenPayment) { let burn_percent = self.base_token_burn_percent().get(); if burn_percent == 0 { return; @@ -95,5 +102,5 @@ pub trait FeesAccumulationModule: fn accumulated_fees(&self, week: Week, token: &TokenIdentifier) -> SingleValueMapper; #[storage_mapper("baseTokenBurnPercent")] - fn base_token_burn_percent(&self) -> SingleValueMapper; + fn base_token_burn_percent(&self) -> SingleValueMapper; } diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index 99c708fc7..05e4ed37b 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] +use common_structs::Percent; use multiversx_sc::storage::StorageKey; multiversx_sc::imports!(); @@ -40,7 +41,7 @@ pub trait FeesCollector: &self, energy_factory_address: ManagedAddress, router_address: ManagedAddress, - base_token_burn_percent: u64, + base_token_burn_percent: Percent, admins: MultiValueEncoded, ) { self.set_energy_factory_address(energy_factory_address); @@ -51,18 +52,51 @@ pub trait FeesCollector: self.first_week_start_epoch().set(current_epoch); let locked_token_id = self.get_locked_token_id(); - self.add_known_token(&locked_token_id); + self.add_known_token(locked_token_id); for admin in admins { self.add_admin(admin); } } + // Do not ever use these keys again! + // + // The whole upgrade logic can be removed after one release and upgrade on mainnet #[upgrade] fn upgrade(&self) { - let mut mapper = UnorderedSetMapper::::new(StorageKey::new( - b"knownContracts", - )); - mapper.clear(); + let all_tokens_mapper = SingleValueMapper::>::new( + StorageKey::new(b"allTokens"), + ); + let all_tokens = all_tokens_mapper.take(); + if all_tokens.is_empty() { + return; + } + + let mut known_contracts_mapper = UnorderedSetMapper::::new( + StorageKey::new(b"knownContracts"), + ); + known_contracts_mapper.clear(); + + let known_tokens_mapper = + WhitelistMapper::::new(StorageKey::new(b"knownTokens")); + + let base_token_id = self.get_base_token_id(); + let locked_token_id = self.get_locked_token_id(); + let current_week = self.get_current_week(); + for token_id in &all_tokens { + known_tokens_mapper.remove(&token_id); + + if token_id == base_token_id || token_id == locked_token_id { + continue; + } + + let acc_fees_current_week = self.accumulated_fees(current_week, &token_id).take(); + if acc_fees_current_week == 0 { + continue; + } + + self.all_accumulated_tokens(&token_id) + .set(acc_fees_current_week); + } } } diff --git a/energy-integration/fees-collector/src/redistribute_rewards.rs b/energy-integration/fees-collector/src/redistribute_rewards.rs index 05c0da1f5..01ad15262 100644 --- a/energy-integration/fees-collector/src/redistribute_rewards.rs +++ b/energy-integration/fees-collector/src/redistribute_rewards.rs @@ -29,11 +29,19 @@ pub trait RedistributeRewardsModule: "Invalid end week" ); - let all_tokens = self.all_tokens().get(); + let base_token_id = self.get_base_token_id(); + let locked_token_id = self.get_locked_token_id(); + let mut all_rewards = ManagedVec::new(); - for token_id in &all_tokens { - all_rewards.push(TokenAmountPair::new(token_id, BigUint::zero())); - } + all_rewards.push(TokenAmountPair::new(base_token_id.clone(), BigUint::zero())); + all_rewards.push(TokenAmountPair::new( + locked_token_id.clone(), + BigUint::zero(), + )); + + let mut all_tokens = ManagedVec::new(); + all_tokens.push(base_token_id); + all_tokens.push(locked_token_id); for week in start_week..=end_week { self.accumulate_remaining_rewards_single_week(&mut all_rewards, &all_tokens, week); @@ -62,9 +70,7 @@ pub trait RedistributeRewardsModule: } let opt_index = all_tokens.find(&rem_rew_entry.token_identifier); - if opt_index.is_none() { - continue; - } + require!(opt_index.is_some(), "Invalid setup"); let index = unsafe { opt_index.unwrap_unchecked() }; let mut rew_entry = all_rewards.get_mut(index); diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index 538c04e3e..020f24fef 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -1,9 +1,11 @@ #![allow(deprecated)] mod fees_collector_test_setup; +mod router_setup; use energy_query::Energy; use fees_collector::additional_locked_tokens::{AdditionalLockedTokensModule, BLOCKS_IN_WEEK}; +use fees_collector::external_sc_interactions::router::RouterInteractionsModule; use fees_collector::fees_accumulation::FeesAccumulationModule; use fees_collector::redistribute_rewards::RedistributeRewardsModule; use fees_collector_test_setup::*; @@ -12,6 +14,7 @@ use multiversx_sc_scenario::{ managed_address, managed_biguint, managed_token_id, managed_token_id_wrapped, rust_biguint, DebugApi, }; +use router_setup::{RouterSetup, USDC_TOKEN_ID}; use simple_lock::locked_token::LockedTokenAttributes; use weekly_rewards_splitting::locked_token_buckets::LockedTokensBucket; use weekly_rewards_splitting::update_claim_progress_energy::UpdateClaimProgressEnergyModule; @@ -36,8 +39,8 @@ fn claim_first_week_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 3_000); @@ -53,14 +56,17 @@ fn claim_first_week_test() { fc_setup .b_mock + .borrow_mut() .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_zero); fc_setup .b_mock + .borrow_mut() .check_esdt_balance(&second_user, FIRST_TOKEN_ID, &rust_zero); let current_epoch = fc_setup.current_epoch; fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!( sc.accumulated_fees(1, &managed_token_id!(FIRST_TOKEN_ID)) @@ -113,10 +119,12 @@ fn claim_first_week_test() { // state remains unchanged fc_setup .b_mock + .borrow_mut() .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_zero); fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!( sc.accumulated_fees(1, &managed_token_id!(FIRST_TOKEN_ID)) @@ -170,8 +178,8 @@ fn claim_after_dex_inactive_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 50, 3_000); fc_setup.set_energy(&second_user, 50, 9_000); @@ -211,12 +219,12 @@ fn claim_after_dex_inactive_test() { let first_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 3_000u32 / 12_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, FIRST_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, SECOND_TOKEN_ID, &first_user_expected_second_token_amt, @@ -227,12 +235,12 @@ fn claim_after_dex_inactive_test() { let second_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 9_000u32 / 12_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, FIRST_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, SECOND_TOKEN_ID, &second_user_expected_second_token_amt, @@ -241,6 +249,7 @@ fn claim_after_dex_inactive_test() { let current_epoch = fc_setup.current_epoch; fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { // for 4 weeks inactive => global update // total -= 4 * 300 => 12_000 - 300 => 11_700 @@ -278,8 +287,8 @@ fn claim_second_week_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 9_000); @@ -304,6 +313,7 @@ fn claim_second_week_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( @@ -324,12 +334,12 @@ fn claim_second_week_test() { let first_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 1_000u32 / 10_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, FIRST_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, SECOND_TOKEN_ID, &first_user_expected_second_token_amt, @@ -338,6 +348,7 @@ fn claim_second_week_test() { let current_epoch = fc_setup.current_epoch; fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { // fees were cleared and accumulated in the total_rewards mapper assert_eq!( @@ -398,12 +409,12 @@ fn claim_second_week_test() { fc_setup.claim(&first_user).assert_ok(); // no rewards were given, and state remains intact - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, FIRST_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, SECOND_TOKEN_ID, &first_user_expected_second_token_amt, @@ -411,6 +422,7 @@ fn claim_second_week_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( @@ -454,12 +466,12 @@ fn claim_second_week_test() { let second_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 9_000u32 / 10_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, FIRST_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, SECOND_TOKEN_ID, &second_user_expected_second_token_amt, @@ -472,8 +484,8 @@ fn claim_for_other_user_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 9_000); @@ -509,6 +521,7 @@ fn claim_for_other_user_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( @@ -529,12 +542,12 @@ fn claim_for_other_user_test() { let first_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 1_000u32 / 10_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, FIRST_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, SECOND_TOKEN_ID, &first_user_expected_second_token_amt, @@ -543,6 +556,7 @@ fn claim_for_other_user_test() { let current_epoch = fc_setup.current_epoch; fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { // fees were cleared and accumulated in the total_rewards mapper assert_eq!( @@ -606,8 +620,8 @@ fn claim_inactive_week_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 50, 3_000); fc_setup.set_energy(&second_user, 50, 9_000); @@ -640,12 +654,12 @@ fn claim_inactive_week_test() { let first_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 3_000u32 / 12_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, FIRST_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, SECOND_TOKEN_ID, &first_user_expected_second_token_amt, @@ -654,6 +668,7 @@ fn claim_inactive_week_test() { let current_epoch = fc_setup.current_epoch; fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { // 12_000 - 700 + 350 - 3_000 + 2_650 // = 11_300 + 350 - 350 @@ -691,12 +706,12 @@ fn claim_inactive_week_test() { / 12_000u32 + rust_biguint!(USER_BALANCE / 2) * 8_650u32 / 11_300u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, FIRST_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, SECOND_TOKEN_ID, &second_user_expected_second_token_amt, @@ -709,8 +724,8 @@ fn locked_token_buckets_shifting_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 50, 3_000); fc_setup.set_energy(&second_user, 50, 9_000); @@ -726,6 +741,7 @@ fn locked_token_buckets_shifting_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!(sc.first_bucket_id().get(), 0); assert_eq!( @@ -794,6 +810,7 @@ fn locked_token_buckets_shifting_test() { // check internal storage after shift fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { // 6 weeks have passed, so we must shift 6 times (first bucket ID was 0 initially) assert_eq!(sc.first_bucket_id().get(), 6); @@ -842,6 +859,7 @@ fn locked_token_buckets_shifting_test() { fc_setup.claim(&second_user).assert_ok(); fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!(sc.first_bucket_id().get(), 6); assert_eq!( @@ -902,8 +920,8 @@ fn multi_bucket_shift_consistency_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 1_000, 7_000); fc_setup.set_energy(&second_user, 100, 2_100); @@ -919,6 +937,7 @@ fn multi_bucket_shift_consistency_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!(sc.first_bucket_id().get(), 0); assert_eq!( @@ -952,6 +971,7 @@ fn multi_bucket_shift_consistency_test() { // check internal storage after shift fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { sc.perform_weekly_update(3); @@ -970,7 +990,7 @@ fn multi_bucket_shift_consistency_test() { #[test] fn surplus_energy_test() { let rust_zero = rust_biguint!(0); - let mut fc_setup = + let fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); // first user, 7_500 energy, 1_000 tokens (7 epochs, 1 week) @@ -984,6 +1004,7 @@ fn surplus_energy_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1086,8 +1107,8 @@ fn claim_locked_rewards_with_energy_update_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 9_000); @@ -1115,6 +1136,7 @@ fn claim_locked_rewards_with_energy_update_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( @@ -1142,17 +1164,17 @@ fn claim_locked_rewards_with_energy_update_test() { let first_user_expected_locked_token_amt = rust_biguint!(USER_BALANCE / 100) * 1_000u32 / 10_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, FIRST_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, SECOND_TOKEN_ID, &first_user_expected_second_token_amt, ); - fc_setup.b_mock.check_nft_balance( + fc_setup.b_mock.borrow_mut().check_nft_balance( &first_user, LOCKED_TOKEN_ID, 1, @@ -1167,6 +1189,7 @@ fn claim_locked_rewards_with_energy_update_test() { let current_epoch = fc_setup.current_epoch; fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { // fees were cleared and accumulated in the total_rewards mapper assert_eq!( @@ -1237,17 +1260,17 @@ fn claim_locked_rewards_with_energy_update_test() { fc_setup.claim(&first_user).assert_ok(); // no rewards were given, and state remains intact - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, FIRST_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, SECOND_TOKEN_ID, &first_user_expected_second_token_amt, ); - fc_setup.b_mock.check_nft_balance( + fc_setup.b_mock.borrow_mut().check_nft_balance( &first_user, LOCKED_TOKEN_ID, 1, @@ -1261,6 +1284,7 @@ fn claim_locked_rewards_with_energy_update_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( @@ -1319,12 +1343,12 @@ fn claim_locked_rewards_with_energy_update_test() { let second_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 9_000u32 / 10_000u32; - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, FIRST_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( + fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, SECOND_TOKEN_ID, &second_user_expected_second_token_amt, @@ -1341,6 +1365,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1354,6 +1379,7 @@ fn additional_locked_tokens_test() { // nothing accumulated yet, as locked_tokens_per_block was 0 fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!(sc.last_locked_token_add_week().get(), 2); assert_eq!(sc.locked_tokens_per_block().get(), 1_000u64); @@ -1369,6 +1395,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1381,6 +1408,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!(sc.last_locked_token_add_week().get(), 2); assert_eq!(sc.locked_tokens_per_block().get(), 1_000u64); @@ -1397,6 +1425,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1409,6 +1438,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!(sc.last_locked_token_add_week().get(), 3); assert_eq!(sc.locked_tokens_per_block().get(), 1_000u64); @@ -1427,9 +1457,9 @@ fn redistribute_rewards_test() { let mut fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); - let first_user = fc_setup.b_mock.create_user_account(&rust_zero); - let second_user = fc_setup.b_mock.create_user_account(&rust_zero); - let third_user = fc_setup.b_mock.create_user_account(&rust_zero); + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let third_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); fc_setup.set_energy(&first_user, 50, 3_000); fc_setup.set_energy(&second_user, 50, 9_000); @@ -1461,6 +1491,7 @@ fn redistribute_rewards_test() { fc_setup .b_mock + .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( @@ -1584,6 +1615,7 @@ fn redistribute_rewards_test() { // redist rewards fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1613,3 +1645,61 @@ fn redistribute_rewards_test() { ) .assert_ok(); } + +#[test] +fn fees_collector_base_token_feature_test() { + let fc_setup = + FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); + let mut router_setup = RouterSetup::new( + fc_setup.b_mock.clone(), + router::contract_obj, + pair::contract_obj, + ); + + router_setup.add_liquidity(); + + let router_address = router_setup.router_wrapper.address_ref().clone(); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + sc.set_router_address(managed_address!(&router_address)); + }, + ) + .assert_ok(); + + // try deposit USDC + router_setup.b_mock.borrow_mut().set_esdt_balance( + &router_setup.owner_address, + USDC_TOKEN_ID, + &rust_biguint!(1_000), + ); + + router_setup + .b_mock + .borrow_mut() + .execute_esdt_transfer( + &fc_setup.owner_address, + &fc_setup.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!(BASE_ASSET_TOKEN_ID)) + .is_empty()); + }, + ) + .assert_ok(); +} 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 59db61cdc..c4544de2a 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 @@ -1,5 +1,7 @@ #![allow(deprecated)] +use std::{cell::RefCell, rc::Rc}; + use claim::ClaimModule; use multiversx_sc::{ codec::multi_types::OptionalValue, @@ -23,6 +25,7 @@ use week_timekeeping::{Week, WeekTimekeepingModule, EPOCHS_IN_WEEK}; pub const INIT_EPOCH: u64 = 5; pub const EPOCHS_IN_YEAR: u64 = 360; pub const USER_BALANCE: u64 = 1_000_000_000_000_000_000; +pub const BASE_TOKEN_BURN_PERCENT: u64 = 0; // 0% pub static LOCK_OPTIONS: &[u64] = &[EPOCHS_IN_YEAR, 2 * EPOCHS_IN_YEAR, 4 * EPOCHS_IN_YEAR]; pub static FIRST_TOKEN_ID: &[u8] = b"FIRST-123456"; @@ -37,7 +40,7 @@ where FeesCollectorObjBuilder: 'static + Copy + Fn() -> fees_collector::ContractObj, EnergyFactoryObjBuilder: 'static + Copy + Fn() -> energy_factory::ContractObj, { - pub b_mock: BlockchainStateWrapper, + pub b_mock: Rc>, pub owner_address: Address, pub depositor_address: Address, pub fc_wrapper: @@ -147,30 +150,19 @@ where }) .assert_ok(); + let energy_factory_address = energy_factory_wrapper.address_ref().clone(); b_mock .execute_tx(&owner_address, &fc_wrapper, &rust_zero, |sc| { let mut admins = MultiValueEncoded::new(); admins.push(managed_address!(&owner_address)); sc.init( - managed_token_id!(LOCKED_TOKEN_ID), - managed_address!(energy_factory_wrapper.address_ref()), + managed_address!(&energy_factory_address), managed_address!(energy_factory_wrapper.address_ref()), // unused - managed_token_id!(b"RANDTOK-123456"), // unused + BASE_TOKEN_BURN_PERCENT, admins, ); - let _ = sc - .known_contracts() - .insert(managed_address!(&depositor_address)); - - let mut tokens = MultiValueEncoded::new(); - tokens.push(managed_token_id!(FIRST_TOKEN_ID)); - tokens.push(managed_token_id!(SECOND_TOKEN_ID)); - tokens.push(managed_token_id!(LOCKED_TOKEN_ID)); - - sc.add_known_tokens(tokens); - sc.set_energy_factory_address(managed_address!( energy_factory_wrapper.address_ref() )); @@ -179,8 +171,11 @@ where }) .assert_ok(); + let b_mock_ref = RefCell::new(b_mock); + let b_mock_rc = Rc::new(b_mock_ref); + FeesCollectorSetup { - b_mock, + b_mock: b_mock_rc, owner_address, depositor_address, fc_wrapper, @@ -191,12 +186,13 @@ where pub fn advance_week(&mut self) { self.current_epoch += EPOCHS_IN_WEEK; - self.b_mock.set_block_epoch(self.current_epoch); + self.b_mock.borrow_mut().set_block_epoch(self.current_epoch); } pub fn get_current_week(&mut self) -> Week { let mut result = 0; self.b_mock + .borrow_mut() .execute_query(&self.fc_wrapper, |sc| result = sc.get_current_week()) .assert_ok(); @@ -204,7 +200,7 @@ where } pub fn deposit(&mut self, token: &[u8], amount: u64) -> TxResult { - self.b_mock.execute_esdt_transfer( + self.b_mock.borrow_mut().execute_esdt_transfer( &self.depositor_address, &self.fc_wrapper, token, @@ -217,7 +213,7 @@ where } pub fn deposit_locked_tokens(&mut self, token: &[u8], nonce: u64, amount: u64) -> TxResult { - self.b_mock.execute_esdt_transfer( + self.b_mock.borrow_mut().execute_esdt_transfer( &self.depositor_address, &self.fc_wrapper, token, @@ -231,6 +227,7 @@ where pub fn claim(&mut self, user: &Address) -> TxResult { self.b_mock + .borrow_mut() .execute_tx(user, &self.fc_wrapper, &rust_biguint!(0), |sc| { let _ = sc.claim_rewards_endpoint(OptionalValue::None); }) @@ -238,6 +235,7 @@ where pub fn claim_for_user(&mut self, owner: &Address, broker: &Address) -> TxResult { self.b_mock + .borrow_mut() .execute_tx(broker, &self.fc_wrapper, &rust_biguint!(0), |sc| { let _ = sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(owner))); }) @@ -245,6 +243,7 @@ where pub fn allow_external_claim_rewards(&mut self, user: &Address) -> TxResult { self.b_mock + .borrow_mut() .execute_tx(user, &self.fc_wrapper, &rust_biguint!(0), |sc| { sc.allow_external_claim_rewards(&managed_address!(user)) .set(true); @@ -254,6 +253,7 @@ where pub fn set_energy(&mut self, user: &Address, total_locked_tokens: u64, energy_amount: u64) { let current_epoch = self.current_epoch; self.b_mock + .borrow_mut() .execute_tx( user, &self.energy_factory_wrapper, diff --git a/energy-integration/fees-collector/tests/router_setup/mod.rs b/energy-integration/fees-collector/tests/router_setup/mod.rs new file mode 100644 index 000000000..760a791a9 --- /dev/null +++ b/energy-integration/fees-collector/tests/router_setup/mod.rs @@ -0,0 +1,259 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use multiversx_sc::codec::multi_types::OptionalValue; +use multiversx_sc::types::{Address, EsdtLocalRole, ManagedAddress, MultiValueEncoded}; +use multiversx_sc_scenario::whitebox_legacy::TxTokenTransfer; +use multiversx_sc_scenario::{ + managed_address, managed_biguint, managed_token_id, rust_biguint, whitebox_legacy::*, DebugApi, +}; + +pub const PAIR_WASM_PATH: &str = "pair/output/pair.wasm"; +pub const ROUTER_WASM_PATH: &str = "router/output/router.wasm"; +pub const MEX_TOKEN_ID: &[u8] = b"MEX-abcdef"; +pub const WEGLD_TOKEN_ID: &[u8] = b"WEGLD-abcdef"; +pub const USDC_TOKEN_ID: &[u8] = b"USDC-abcdef"; +pub const LPMEX_TOKEN_ID: &[u8] = b"LPMEX-abcdef"; +pub const LPUSDC_TOKEN_ID: &[u8] = b"LPUSDC-abcdef"; + +pub const USER_TOTAL_MEX_TOKENS: u64 = 5_001_001_000; +pub const USER_TOTAL_WEGLD_TOKENS: u64 = 5_002_002_000; +pub const USER_TOTAL_USDC_TOKENS: u64 = 5_001_001_000; + +pub const ADD_LIQUIDITY_TOKENS: u64 = 1_001_000; + +use pair::config::ConfigModule as PairConfigModule; +use pair::pair_actions::add_liq::AddLiquidityModule; +use pair::*; +use pausable::{PausableModule, State}; +use router::config::ConfigModule; +use router::factory::*; +use router::*; + +#[allow(dead_code)] +pub struct RouterSetup +where + RouterObjBuilder: 'static + Copy + Fn() -> router::ContractObj, + PairObjBuilder: 'static + Copy + Fn() -> pair::ContractObj, +{ + pub b_mock: Rc>, + pub owner_address: Address, + pub user_address: Address, + pub router_wrapper: ContractObjWrapper, RouterObjBuilder>, + pub mex_pair_wrapper: ContractObjWrapper, PairObjBuilder>, + pub usdc_pair_wrapper: ContractObjWrapper, PairObjBuilder>, +} + +impl RouterSetup +where + RouterObjBuilder: 'static + Copy + Fn() -> router::ContractObj, + PairObjBuilder: 'static + Copy + Fn() -> pair::ContractObj, +{ + pub fn new( + b_mock: Rc>, + router_builder: RouterObjBuilder, + pair_builder: PairObjBuilder, + ) -> Self { + let rust_zero = rust_biguint!(0u64); + let owner_addr = b_mock.borrow_mut().create_user_account(&rust_zero); + + let router_wrapper = b_mock.borrow_mut().create_sc_account( + &rust_zero, + Some(&owner_addr), + router_builder, + ROUTER_WASM_PATH, + ); + + let mex_pair_wrapper = b_mock.borrow_mut().create_sc_account( + &rust_zero, + Some(&owner_addr), + pair_builder, + PAIR_WASM_PATH, + ); + + let usdc_pair_wrapper = b_mock.borrow_mut().create_sc_account( + &rust_zero, + Some(&owner_addr), + pair_builder, + PAIR_WASM_PATH, + ); + + b_mock + .borrow_mut() + .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); + let router_address = managed_address!(&owner_addr); + let router_owner_address = managed_address!(&owner_addr); + let total_fee_percent = 300u64; + let special_fee_percent = 50u64; + + sc.init( + first_token_id, + second_token_id, + router_address, + router_owner_address, + total_fee_percent, + special_fee_percent, + ManagedAddress::::zero(), + MultiValueEncoded::>::new(), + ); + + let lp_token_id = managed_token_id!(LPMEX_TOKEN_ID); + sc.lp_token_identifier().set(&lp_token_id); + + sc.state().set(State::Active); + }) + .assert_ok(); + + b_mock + .borrow_mut() + .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); + let router_address = managed_address!(&owner_addr); + let router_owner_address = managed_address!(&owner_addr); + let total_fee_percent = 300u64; + let special_fee_percent = 50u64; + + sc.init( + first_token_id, + second_token_id, + router_address, + router_owner_address, + total_fee_percent, + special_fee_percent, + ManagedAddress::::zero(), + MultiValueEncoded::>::new(), + ); + + let lp_token_id = managed_token_id!(LPUSDC_TOKEN_ID); + sc.lp_token_identifier().set(&lp_token_id); + + sc.state().set(State::Active); + }) + .assert_ok(); + + b_mock + .borrow_mut() + .execute_tx(&owner_addr, &router_wrapper, &rust_zero, |sc| { + sc.init(OptionalValue::None); + + sc.pair_map().insert( + PairTokens { + first_token_id: managed_token_id!(WEGLD_TOKEN_ID), + second_token_id: managed_token_id!(MEX_TOKEN_ID), + }, + managed_address!(mex_pair_wrapper.address_ref()), + ); + sc.pair_map().insert( + PairTokens { + first_token_id: managed_token_id!(WEGLD_TOKEN_ID), + second_token_id: managed_token_id!(USDC_TOKEN_ID), + }, + managed_address!(usdc_pair_wrapper.address_ref()), + ); + }) + .assert_ok(); + + let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; + b_mock.borrow_mut().set_esdt_local_roles( + mex_pair_wrapper.address_ref(), + LPMEX_TOKEN_ID, + &lp_token_roles[..], + ); + + let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; + b_mock.borrow_mut().set_esdt_local_roles( + usdc_pair_wrapper.address_ref(), + LPUSDC_TOKEN_ID, + &lp_token_roles[..], + ); + + let user_addr = b_mock + .borrow_mut() + .create_user_account(&rust_biguint!(100_000_000)); + b_mock.borrow_mut().set_esdt_balance( + &user_addr, + WEGLD_TOKEN_ID, + &rust_biguint!(USER_TOTAL_WEGLD_TOKENS), + ); + b_mock.borrow_mut().set_esdt_balance( + &user_addr, + MEX_TOKEN_ID, + &rust_biguint!(USER_TOTAL_MEX_TOKENS), + ); + b_mock.borrow_mut().set_esdt_balance( + &user_addr, + USDC_TOKEN_ID, + &rust_biguint!(USER_TOTAL_USDC_TOKENS), + ); + + RouterSetup { + b_mock, + owner_address: owner_addr, + user_address: user_addr, + router_wrapper, + mex_pair_wrapper, + usdc_pair_wrapper, + } + } + + pub fn add_liquidity(&mut self) { + let payments = vec![ + TxTokenTransfer { + token_identifier: WEGLD_TOKEN_ID.to_vec(), + nonce: 0, + value: rust_biguint!(ADD_LIQUIDITY_TOKENS), + }, + TxTokenTransfer { + token_identifier: MEX_TOKEN_ID.to_vec(), + nonce: 0, + value: rust_biguint!(ADD_LIQUIDITY_TOKENS), + }, + ]; + + self.b_mock + .borrow_mut() + .execute_esdt_multi_transfer( + &self.user_address, + &self.mex_pair_wrapper, + &payments, + |sc| { + sc.add_liquidity( + managed_biguint!(ADD_LIQUIDITY_TOKENS), + managed_biguint!(ADD_LIQUIDITY_TOKENS), + ); + }, + ) + .assert_ok(); + + let payments = vec![ + TxTokenTransfer { + token_identifier: WEGLD_TOKEN_ID.to_vec(), + nonce: 0, + value: rust_biguint!(ADD_LIQUIDITY_TOKENS), + }, + TxTokenTransfer { + token_identifier: USDC_TOKEN_ID.to_vec(), + nonce: 0, + value: rust_biguint!(ADD_LIQUIDITY_TOKENS), + }, + ]; + + self.b_mock + .borrow_mut() + .execute_esdt_multi_transfer( + &self.user_address, + &self.usdc_pair_wrapper, + &payments, + |sc| { + sc.add_liquidity( + managed_biguint!(ADD_LIQUIDITY_TOKENS), + managed_biguint!(ADD_LIQUIDITY_TOKENS), + ); + }, + ) + .assert_ok(); + } +} diff --git a/energy-integration/fees-collector/wasm/Cargo.lock b/energy-integration/fees-collector/wasm/Cargo.lock index d962ee257..5b24c9b1a 100644 --- a/energy-integration/fees-collector/wasm/Cargo.lock +++ b/energy-integration/fees-collector/wasm/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 = "arrayvec" @@ -81,6 +81,7 @@ version = "0.0.0" dependencies = [ "common-types", "common_errors", + "common_structs", "energy-factory", "energy-query", "locking_module", diff --git a/energy-integration/fees-collector/wasm/src/lib.rs b/energy-integration/fees-collector/wasm/src/lib.rs index 3168bdc88..e07d9f870 100644 --- a/energy-integration/fees-collector/wasm/src/lib.rs +++ b/energy-integration/fees-collector/wasm/src/lib.rs @@ -20,7 +20,7 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - getAllTokens => get_all_tokens + getAllTokens => all_known_tokens getAllowExternalClaimRewards => allow_external_claim_rewards getLastActiveWeekForUser => get_last_active_week_for_user_view getUserEnergyForWeek => get_user_energy_for_week_view 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 0efcaa37e..06867c2b5 100644 --- a/energy-integration/governance-v2/tests/gov_test_setup/mod.rs +++ b/energy-integration/governance-v2/tests/gov_test_setup/mod.rs @@ -10,6 +10,7 @@ use governance_v2::{ }; use multiversx_sc::{ codec::multi_types::OptionalValue, + imports::StorageTokenWrapper, types::{Address, BigInt, EsdtLocalRole, ManagedVec, MultiValueEncoded}, }; use multiversx_sc_scenario::{ @@ -72,7 +73,7 @@ where // init fees collector let fees_collector_wrapper = b_mock.create_sc_account( &rust_biguint!(0), - None, + Some(&owner), fees_collector::contract_obj, "fees collector path", ); @@ -104,16 +105,20 @@ where 0, managed_biguint!(0), )); + + sc.base_asset_token_id() + .set(managed_token_id!(MEX_TOKEN_ID)); + sc.locked_token() + .set_token_id(managed_token_id!(XMEX_TOKEN_ID)); }) .assert_ok(); b_mock .execute_tx(&owner, &fees_collector_wrapper, &rust_biguint!(0), |sc| { 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 + 0, MultiValueEncoded::new(), ); }) From fe26aece9c2339b9c66c29adc872d901e11370c7 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Thu, 20 Mar 2025 11:51:52 +0200 Subject: [PATCH 09/23] more test fixes --- Cargo.lock | 1 + dex/pair/Cargo.toml | 3 ++ dex/pair/tests/pair_rs_test.rs | 44 +++++++++++++------- energy-integration/fees-collector/src/lib.rs | 4 +- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ad0aabab..22ed33aa1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1379,6 +1379,7 @@ version = "0.0.0" dependencies = [ "common_errors", "common_structs", + "energy-factory-mock", "fees-collector", "itertools 0.10.5", "multiversx-sc", diff --git a/dex/pair/Cargo.toml b/dex/pair/Cargo.toml index 7f913c316..865c88bf6 100644 --- a/dex/pair/Cargo.toml +++ b/dex/pair/Cargo.toml @@ -45,3 +45,6 @@ num-bigint = "0.4.2" [dev-dependencies.multiversx-sc-scenario] version = "=0.53.2" + +[dev-dependencies.energy-factory-mock] +path = "../../energy-integration/energy-factory-mock" diff --git a/dex/pair/tests/pair_rs_test.rs b/dex/pair/tests/pair_rs_test.rs index 831be54e7..67a3883fc 100644 --- a/dex/pair/tests/pair_rs_test.rs +++ b/dex/pair/tests/pair_rs_test.rs @@ -1,9 +1,8 @@ #![allow(deprecated)] mod pair_setup; -use fees_collector::{ - config::ConfigModule, fees_accumulation::FeesAccumulationModule, FeesCollector, -}; +use energy_factory_mock::EnergyFactoryMock; +use fees_collector::{config::ConfigModule, FeesCollector}; use multiversx_sc::codec::{self, TopDecode}; use multiversx_sc::{ api::ManagedTypeApi, @@ -1583,13 +1582,34 @@ fn fees_collector_pair_test() { let mut pair_setup = PairSetup::new(pair::contract_obj); let fees_collector_wrapper = pair_setup.b_mock.create_sc_account( &rust_biguint!(0), - None, + Some(&pair_setup.owner_address), fees_collector::contract_obj, "fees collector path", ); - let pair_addr = pair_setup.pair_wrapper.address_ref().clone(); - let energy_factory_mock_addr = pair_setup.pair_wrapper.address_ref().clone(); + let energy_factory_mock_wrapper = pair_setup.b_mock.create_sc_account( + &rust_biguint!(0), + Some(&pair_setup.owner_address), + energy_factory_mock::contract_obj, + "energy factory mock", + ); + pair_setup + .b_mock + .execute_tx( + &pair_setup.owner_address, + &energy_factory_mock_wrapper, + &rust_biguint!(0), + |sc| { + sc.init(); + sc.base_asset_token_id() + .set(managed_token_id!(MEX_TOKEN_ID)); + sc.locked_token() + .set_token_id(managed_token_id!(LOCKED_TOKEN_ID)); + }, + ) + .assert_ok(); + + let energy_factory_mock_addr = energy_factory_mock_wrapper.address_ref().clone(); pair_setup .b_mock .execute_tx( @@ -1598,19 +1618,11 @@ fn fees_collector_pair_test() { &rust_biguint!(0), |sc| { 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 + 0, MultiValueEncoded::new(), ); - let _ = sc.known_contracts().insert(managed_address!(&pair_addr)); - - let mut tokens = MultiValueEncoded::new(); - tokens.push(managed_token_id!(WEGLD_TOKEN_ID)); - tokens.push(managed_token_id!(MEX_TOKEN_ID)); - - sc.add_known_tokens(tokens); }, ) .assert_ok(); @@ -1646,7 +1658,7 @@ fn fees_collector_pair_test() { .b_mock .execute_query(&fees_collector_wrapper, |sc| { assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(WEGLD_TOKEN_ID)) + sc.all_accumulated_tokens(&managed_token_id!(WEGLD_TOKEN_ID)) .get(), managed_biguint!(25) ); diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index 05e4ed37b..aa612b9a3 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -90,11 +90,13 @@ pub trait FeesCollector: continue; } - let acc_fees_current_week = self.accumulated_fees(current_week, &token_id).take(); + let acc_fees_mapper = self.accumulated_fees(current_week, &token_id); + let acc_fees_current_week = acc_fees_mapper.get(); if acc_fees_current_week == 0 { continue; } + acc_fees_mapper.clear(); self.all_accumulated_tokens(&token_id) .set(acc_fees_current_week); } From 199199676b18e843f24d981a10b40b07429f5e19 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Fri, 21 Mar 2025 09:23:55 +0200 Subject: [PATCH 10/23] fix tests --- .../fees-collector/src/claim.rs | 12 +- .../src/redistribute_rewards.rs | 4 +- .../tests/fees_collector_rust_test.rs | 294 +++--------------- .../tests/fees_collector_test_setup/mod.rs | 9 +- .../fees-collector/tests/router_setup/mod.rs | 29 +- 5 files changed, 81 insertions(+), 267 deletions(-) diff --git a/energy-integration/fees-collector/src/claim.rs b/energy-integration/fees-collector/src/claim.rs index 30e28906d..0f16d2dae 100644 --- a/energy-integration/fees-collector/src/claim.rs +++ b/energy-integration/fees-collector/src/claim.rs @@ -193,18 +193,18 @@ where ) -> PaymentsVec<::Api> { let mut results = ManagedVec::new(); - let base_token_id = sc.get_base_token_id(); - let opt_acc_base_token = sc.get_and_clear_accumulated_fees(week, &base_token_id); - if let Some(accumulated_fees) = opt_acc_base_token { - results.push(EsdtTokenPayment::new(base_token_id, 0, accumulated_fees)); - } - let locked_token_id = sc.get_locked_token_id(); let opt_acc_locked_token = sc.get_and_clear_accumulated_fees(week, &locked_token_id); if let Some(accumulated_fees) = opt_acc_locked_token { results.push(EsdtTokenPayment::new(locked_token_id, 0, accumulated_fees)); } + let base_token_id = sc.get_base_token_id(); + let opt_acc_base_token = sc.get_and_clear_accumulated_fees(week, &base_token_id); + if let Some(accumulated_fees) = opt_acc_base_token { + results.push(EsdtTokenPayment::new(base_token_id, 0, accumulated_fees)); + } + results } } diff --git a/energy-integration/fees-collector/src/redistribute_rewards.rs b/energy-integration/fees-collector/src/redistribute_rewards.rs index 01ad15262..613d50a3b 100644 --- a/energy-integration/fees-collector/src/redistribute_rewards.rs +++ b/energy-integration/fees-collector/src/redistribute_rewards.rs @@ -33,15 +33,15 @@ pub trait RedistributeRewardsModule: let locked_token_id = self.get_locked_token_id(); let mut all_rewards = ManagedVec::new(); - all_rewards.push(TokenAmountPair::new(base_token_id.clone(), BigUint::zero())); all_rewards.push(TokenAmountPair::new( locked_token_id.clone(), BigUint::zero(), )); + all_rewards.push(TokenAmountPair::new(base_token_id.clone(), BigUint::zero())); let mut all_tokens = ManagedVec::new(); - all_tokens.push(base_token_id); all_tokens.push(locked_token_id); + all_tokens.push(base_token_id); for week in start_week..=end_week { self.accumulate_remaining_rewards_single_week(&mut all_rewards, &all_tokens, week); diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index 020f24fef..ef259d0a6 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -45,9 +45,8 @@ fn claim_first_week_test() { fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 3_000); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // user claim first week - users only get registered for week 2, without receiving rewards @@ -57,11 +56,11 @@ fn claim_first_week_test() { fc_setup .b_mock .borrow_mut() - .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_zero); + .check_esdt_balance(&first_user, BASE_ASSET_TOKEN_ID, &rust_zero); fc_setup .b_mock .borrow_mut() - .check_esdt_balance(&second_user, FIRST_TOKEN_ID, &rust_zero); + .check_esdt_balance(&second_user, BASE_ASSET_TOKEN_ID, &rust_zero); let current_epoch = fc_setup.current_epoch; fc_setup @@ -69,15 +68,10 @@ fn claim_first_week_test() { .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(FIRST_TOKEN_ID)) + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .get(), USER_BALANCE ); - assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(SECOND_TOKEN_ID)) - .get(), - USER_BALANCE / 2 - ); let first_user_energy = Energy::new( BigInt::from(managed_biguint!(1_000)), @@ -120,22 +114,17 @@ fn claim_first_week_test() { fc_setup .b_mock .borrow_mut() - .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_zero); + .check_esdt_balance(&first_user, BASE_ASSET_TOKEN_ID, &rust_zero); fc_setup .b_mock .borrow_mut() .execute_query(&fc_setup.fc_wrapper, |sc| { assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(FIRST_TOKEN_ID)) + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .get(), USER_BALANCE ); - assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(SECOND_TOKEN_ID)) - .get(), - USER_BALANCE / 2 - ); let first_user_energy = Energy::new( BigInt::from(managed_biguint!(1_000)), @@ -184,9 +173,8 @@ fn claim_after_dex_inactive_test() { fc_setup.set_energy(&first_user, 50, 3_000); fc_setup.set_energy(&second_user, 50, 9_000); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // user claim first week @@ -203,9 +191,8 @@ fn claim_after_dex_inactive_test() { fc_setup.advance_week(); // deposit rewards week 4 - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // decrease user energy @@ -216,35 +203,21 @@ fn claim_after_dex_inactive_test() { fc_setup.claim(&second_user).assert_ok(); let first_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 3_000u32 / 12_000u32; - let first_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 3_000u32 / 12_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); // energy week 4 for second user will be 9_000 - 7 * 3 * 50 = 9_000 - 1_050 = 7_950 let second_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 9_000u32 / 12_000u32; - let second_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 9_000u32 / 12_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); let current_epoch = fc_setup.current_epoch; fc_setup @@ -293,9 +266,8 @@ fn claim_second_week_test() { fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 9_000); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // user claim first week - users only get registered for week 2, without receiving rewards @@ -317,33 +289,21 @@ fn claim_second_week_test() { .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(expected_total_rewards, sc.total_rewards_for_week(1).get()); }) .assert_ok(); let first_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 1_000u32 / 10_000u32; - let first_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 1_000u32 / 10_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); let current_epoch = fc_setup.current_epoch; fc_setup @@ -352,27 +312,17 @@ fn claim_second_week_test() { .execute_query(&fc_setup.fc_wrapper, |sc| { // fees were cleared and accumulated in the total_rewards mapper assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(FIRST_TOKEN_ID)) - .get(), - managed_biguint!(0) - ); - assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(SECOND_TOKEN_ID)) + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .get(), managed_biguint!(0) ); let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(sc.total_rewards_for_week(1).get(), expected_total_rewards); // first user's new energy is added to week 2 @@ -411,14 +361,9 @@ fn claim_second_week_test() { // no rewards were given, and state remains intact fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); fc_setup .b_mock @@ -426,15 +371,10 @@ fn claim_second_week_test() { .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(sc.total_rewards_for_week(1).get(), expected_total_rewards); // first user's new energy is added to week 2 @@ -463,19 +403,12 @@ fn claim_second_week_test() { fc_setup.claim(&second_user).assert_ok(); let second_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 9_000u32 / 10_000u32; - let second_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 9_000u32 / 10_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); } #[test] @@ -490,9 +423,8 @@ fn claim_for_other_user_test() { fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 9_000); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // user claim first week - user only get registered for week 2, without receiving rewards @@ -525,33 +457,21 @@ fn claim_for_other_user_test() { .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(expected_total_rewards, sc.total_rewards_for_week(1).get()); }) .assert_ok(); let first_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 1_000u32 / 10_000u32; - let first_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 1_000u32 / 10_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); let current_epoch = fc_setup.current_epoch; fc_setup @@ -560,27 +480,17 @@ fn claim_for_other_user_test() { .execute_query(&fc_setup.fc_wrapper, |sc| { // fees were cleared and accumulated in the total_rewards mapper assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(FIRST_TOKEN_ID)) - .get(), - managed_biguint!(0) - ); - assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(SECOND_TOKEN_ID)) + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .get(), managed_biguint!(0) ); let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(sc.total_rewards_for_week(1).get(), expected_total_rewards); // first user's new energy is added to week 2 @@ -626,9 +536,8 @@ fn claim_inactive_week_test() { fc_setup.set_energy(&first_user, 50, 3_000); fc_setup.set_energy(&second_user, 50, 9_000); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // user claim first week - users only get registered for week 2, without receiving rewards @@ -639,9 +548,8 @@ fn claim_inactive_week_test() { fc_setup.advance_week(); // deposit rewards week 2 - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // decrease user energy @@ -651,19 +559,12 @@ fn claim_inactive_week_test() { fc_setup.claim(&first_user).assert_ok(); let first_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 3_000u32 / 12_000u32; - let first_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 3_000u32 / 12_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); let current_epoch = fc_setup.current_epoch; fc_setup @@ -702,20 +603,12 @@ fn claim_inactive_week_test() { // energy week 2 for second user will be 9_000 - 7 * 50 = 9_000 - 350 = 8_650 let second_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 9_000u32 / 12_000u32 + rust_biguint!(USER_BALANCE) * 8_650u32 / 11_300u32; - let second_user_expected_second_token_amt = rust_biguint!(USER_BALANCE / 2) * 9_000u32 - / 12_000u32 - + rust_biguint!(USER_BALANCE / 2) * 8_650u32 / 11_300u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); } #[test] @@ -730,9 +623,8 @@ fn locked_token_buckets_shifting_test() { fc_setup.set_energy(&first_user, 50, 3_000); fc_setup.set_energy(&second_user, 50, 9_000); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // user claim first week - users only get registered for week 2, without receiving rewards @@ -784,9 +676,8 @@ fn locked_token_buckets_shifting_test() { fc_setup.advance_week(); // deposit rewards week 2 - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // advance 5 weeks @@ -926,9 +817,8 @@ fn multi_bucket_shift_consistency_test() { fc_setup.set_energy(&first_user, 1_000, 7_000); fc_setup.set_energy(&second_user, 100, 2_100); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); // user claim first week - users only get registered for week 2, without receiving rewards @@ -1113,12 +1003,11 @@ fn claim_locked_rewards_with_energy_update_test() { fc_setup.set_energy(&first_user, 500, 1_000); fc_setup.set_energy(&second_user, 500, 9_000); - fc_setup.deposit(FIRST_TOKEN_ID, USER_BALANCE).assert_ok(); fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 2) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE) .assert_ok(); fc_setup - .deposit_locked_tokens(LOCKED_TOKEN_ID, 1, USER_BALANCE / 100) + .deposit_locked_tokens(1, USER_BALANCE / 100) .assert_ok(); // user claim first week - users only get registered for week 2, without receiving rewards @@ -1145,35 +1034,23 @@ fn claim_locked_rewards_with_energy_update_test() { managed_biguint!(USER_BALANCE / 100), )); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(expected_total_rewards, sc.total_rewards_for_week(1).get()); }) .assert_ok(); let first_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 1_000u32 / 10_000u32; - let first_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 1_000u32 / 10_000u32; let first_user_expected_locked_token_amt = rust_biguint!(USER_BALANCE / 100) * 1_000u32 / 10_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); fc_setup.b_mock.borrow_mut().check_nft_balance( &first_user, LOCKED_TOKEN_ID, @@ -1193,12 +1070,7 @@ fn claim_locked_rewards_with_energy_update_test() { .execute_query(&fc_setup.fc_wrapper, |sc| { // fees were cleared and accumulated in the total_rewards mapper assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(FIRST_TOKEN_ID)) - .get(), - managed_biguint!(0) - ); - assert_eq!( - sc.accumulated_fees(1, &managed_token_id!(SECOND_TOKEN_ID)) + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .get(), managed_biguint!(0) ); @@ -1215,15 +1087,10 @@ fn claim_locked_rewards_with_energy_update_test() { managed_biguint!(USER_BALANCE / 100), )); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(sc.total_rewards_for_week(1).get(), expected_total_rewards); // first user's new energy is added to week 2 @@ -1262,14 +1129,9 @@ fn claim_locked_rewards_with_energy_update_test() { // no rewards were given, and state remains intact fc_setup.b_mock.borrow_mut().check_esdt_balance( &first_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); fc_setup.b_mock.borrow_mut().check_nft_balance( &first_user, LOCKED_TOKEN_ID, @@ -1293,15 +1155,10 @@ fn claim_locked_rewards_with_energy_update_test() { managed_biguint!(USER_BALANCE / 100), )); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 2), - )); assert_eq!(sc.total_rewards_for_week(1).get(), expected_total_rewards); // first user's new energy is added to week 2 @@ -1340,19 +1197,12 @@ fn claim_locked_rewards_with_energy_update_test() { fc_setup.claim(&second_user).assert_ok(); let second_user_expected_first_token_amt = rust_biguint!(USER_BALANCE) * 9_000u32 / 10_000u32; - let second_user_expected_second_token_amt = - rust_biguint!(USER_BALANCE / 2) * 9_000u32 / 10_000u32; fc_setup.b_mock.borrow_mut().check_esdt_balance( &second_user, - FIRST_TOKEN_ID, + BASE_ASSET_TOKEN_ID, &second_user_expected_first_token_amt, ); - fc_setup.b_mock.borrow_mut().check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); } #[test] @@ -1466,10 +1316,7 @@ fn redistribute_rewards_test() { fc_setup.set_energy(&third_user, 1, 1); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.claim(&first_user).assert_ok(); @@ -1480,10 +1327,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1495,15 +1339,10 @@ fn redistribute_rewards_test() { .execute_query(&fc_setup.fc_wrapper, |sc| { let mut expected_total_rewards = ManagedVec::new(); expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(FIRST_TOKEN_ID), + managed_token_id!(BASE_ASSET_TOKEN_ID), 0, managed_biguint!(USER_BALANCE / 10), )); - expected_total_rewards.push(EsdtTokenPayment::new( - managed_token_id!(SECOND_TOKEN_ID), - 0, - managed_biguint!(USER_BALANCE / 20), - )); assert_eq!(expected_total_rewards, sc.total_rewards_for_week(1).get()); }) .assert_ok(); @@ -1512,10 +1351,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1525,10 +1361,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1538,10 +1371,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1551,10 +1381,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1564,10 +1391,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1577,10 +1401,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1590,10 +1411,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1603,10 +1421,7 @@ fn redistribute_rewards_test() { fc_setup.advance_week(); fc_setup - .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) - .assert_ok(); - fc_setup - .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .deposit(BASE_ASSET_TOKEN_ID, USER_BALANCE / 10) .assert_ok(); fc_setup.set_energy(&third_user, 1, 1); @@ -1626,10 +1441,7 @@ fn redistribute_rewards_test() { // Rewards were put in current_week storage (i.e. 10) let first_token_balance = sc - .accumulated_fees(10, &managed_token_id!(FIRST_TOKEN_ID)) - .get(); - let second_token_balance = sc - .accumulated_fees(10, &managed_token_id!(SECOND_TOKEN_ID)) + .accumulated_fees(10, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .get(); // i.e. 6 weeks worth of rewards minus what the third user claimed @@ -1637,10 +1449,6 @@ fn redistribute_rewards_test() { first_token_balance, managed_biguint!(599_952_417_140_485_515u64) ); - assert_eq!( - second_token_balance, - managed_biguint!(299_976_208_570_242_758) - ); }, ) .assert_ok(); 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 c4544de2a..735940932 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 @@ -111,6 +111,11 @@ where SECOND_TOKEN_ID, &rust_biguint!(USER_BALANCE * 2), ); + b_mock.set_esdt_balance( + &depositor_address, + BASE_ASSET_TOKEN_ID, + &rust_biguint!(USER_BALANCE * 2), + ); DebugApi::dummy(); @@ -212,11 +217,11 @@ where ) } - pub fn deposit_locked_tokens(&mut self, token: &[u8], nonce: u64, amount: u64) -> TxResult { + pub fn deposit_locked_tokens(&mut self, nonce: u64, amount: u64) -> TxResult { self.b_mock.borrow_mut().execute_esdt_transfer( &self.depositor_address, &self.fc_wrapper, - token, + LOCKED_TOKEN_ID, nonce, &rust_biguint!(amount), |sc| { diff --git a/energy-integration/fees-collector/tests/router_setup/mod.rs b/energy-integration/fees-collector/tests/router_setup/mod.rs index 760a791a9..c33ab2c6f 100644 --- a/energy-integration/fees-collector/tests/router_setup/mod.rs +++ b/energy-integration/fees-collector/tests/router_setup/mod.rs @@ -40,8 +40,8 @@ where pub owner_address: Address, pub user_address: Address, pub router_wrapper: ContractObjWrapper, RouterObjBuilder>, - pub mex_pair_wrapper: ContractObjWrapper, PairObjBuilder>, - pub usdc_pair_wrapper: ContractObjWrapper, PairObjBuilder>, + pub wegld_mex_pair_wrapper: ContractObjWrapper, PairObjBuilder>, + pub wegld_usdc_pair_wrapper: ContractObjWrapper, PairObjBuilder>, } impl RouterSetup @@ -64,14 +64,14 @@ where ROUTER_WASM_PATH, ); - let mex_pair_wrapper = b_mock.borrow_mut().create_sc_account( + let wegld_mex_pair_wrapper = b_mock.borrow_mut().create_sc_account( &rust_zero, Some(&owner_addr), pair_builder, PAIR_WASM_PATH, ); - let usdc_pair_wrapper = b_mock.borrow_mut().create_sc_account( + let wegld_usdc_pair_wrapper = b_mock.borrow_mut().create_sc_account( &rust_zero, Some(&owner_addr), pair_builder, @@ -80,7 +80,7 @@ where b_mock .borrow_mut() - .execute_tx(&owner_addr, &mex_pair_wrapper, &rust_zero, |sc| { + .execute_tx(&owner_addr, &wegld_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); let router_address = managed_address!(&owner_addr); @@ -108,7 +108,7 @@ where b_mock .borrow_mut() - .execute_tx(&owner_addr, &usdc_pair_wrapper, &rust_zero, |sc| { + .execute_tx(&owner_addr, &wegld_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); let router_address = managed_address!(&owner_addr); @@ -144,28 +144,28 @@ where first_token_id: managed_token_id!(WEGLD_TOKEN_ID), second_token_id: managed_token_id!(MEX_TOKEN_ID), }, - managed_address!(mex_pair_wrapper.address_ref()), + managed_address!(wegld_mex_pair_wrapper.address_ref()), ); sc.pair_map().insert( PairTokens { first_token_id: managed_token_id!(WEGLD_TOKEN_ID), second_token_id: managed_token_id!(USDC_TOKEN_ID), }, - managed_address!(usdc_pair_wrapper.address_ref()), + managed_address!(wegld_usdc_pair_wrapper.address_ref()), ); }) .assert_ok(); let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; b_mock.borrow_mut().set_esdt_local_roles( - mex_pair_wrapper.address_ref(), + wegld_mex_pair_wrapper.address_ref(), LPMEX_TOKEN_ID, &lp_token_roles[..], ); let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; b_mock.borrow_mut().set_esdt_local_roles( - usdc_pair_wrapper.address_ref(), + wegld_usdc_pair_wrapper.address_ref(), LPUSDC_TOKEN_ID, &lp_token_roles[..], ); @@ -194,11 +194,12 @@ where owner_address: owner_addr, user_address: user_addr, router_wrapper, - mex_pair_wrapper, - usdc_pair_wrapper, + wegld_mex_pair_wrapper, + wegld_usdc_pair_wrapper, } } + // TODO: Maybe change token amounts pub fn add_liquidity(&mut self) { let payments = vec![ TxTokenTransfer { @@ -217,7 +218,7 @@ where .borrow_mut() .execute_esdt_multi_transfer( &self.user_address, - &self.mex_pair_wrapper, + &self.wegld_mex_pair_wrapper, &payments, |sc| { sc.add_liquidity( @@ -245,7 +246,7 @@ where .borrow_mut() .execute_esdt_multi_transfer( &self.user_address, - &self.usdc_pair_wrapper, + &self.wegld_usdc_pair_wrapper, &payments, |sc| { sc.add_liquidity( From c4658cb2527f19f31d3cf9b245737b00b585b618 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Fri, 21 Mar 2025 10:38:04 +0200 Subject: [PATCH 11/23] more fixes --- .../src/external_sc_interactions/router.rs | 101 +++++++----------- .../tests/fees_collector_rust_test.rs | 67 +++++++++--- .../tests/fees_collector_test_setup/mod.rs | 2 + .../fees-collector/tests/router_setup/mod.rs | 8 +- 4 files changed, 96 insertions(+), 82 deletions(-) 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 613fc6b07..eb52b0e48 100644 --- a/energy-integration/fees-collector/src/external_sc_interactions/router.rs +++ b/energy-integration/fees-collector/src/external_sc_interactions/router.rs @@ -1,5 +1,5 @@ use common_types::PaymentsVec; -use router_proxy::FunctionName; +use router_proxy::SwapOperationType; multiversx_sc::imports!(); multiversx_sc::derive_imports!(); @@ -24,17 +24,6 @@ mod router_proxy { } } -#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, ManagedVecItem, Clone)] -pub struct SwapOperation { - pub pair_address: ManagedAddress, - pub function_name: FunctionName, - pub input_token_id: TokenIdentifier, - pub min_amount_out: BigUint, -} - -pub type SwapOperationArgs = MultiValueEncoded>>; -pub type SingleSwapOperationArg = ManagedVec>; - #[multiversx_sc::module] pub trait RouterInteractionsModule: crate::fees_accumulation::FeesAccumulationModule @@ -55,89 +44,73 @@ pub trait RouterInteractionsModule: /// Swaps tokens to the base token (i.e. MEX). /// - /// The first token must be a known token to the fees collector, and the very last token received must be MEX. + /// `token_to_send` must be a known token to the fees collector, and the very last token received must be MEX. /// /// The fees collector uses the given pair paths through the router contract. + /// + /// `swap_operations` are pairs of (pair address, pair function name, token wanted, min amount out) + /// + /// "pair function name" can only be "swapTokensFixedInput" or "swapTokensFixedOutput" + /// + /// "min amount out" is a minimum of 1 #[only_admin] #[endpoint(swapTokenToBaseToken)] - fn swap_token_to_base_token(&self, swap_operations: SwapOperationArgs) { - let router_address = self.router_address().get(); - let base_token_id = self.get_base_token_id(); - let mut total_base_tokens = BigUint::zero(); - for swap_op in swap_operations { - let payment = self.check_args_and_get_first_token_payment(swap_op.clone()); - if payment.amount == 0 { - continue; - } + fn swap_token_to_base_token( + &self, + token_to_send: TokenIdentifier, + swap_operations: MultiValueEncoded>, + ) { + self.check_swap_through_router_args(&token_to_send, &swap_operations); - let mut received_tokens = - self.call_swap_through_router(router_address.clone(), payment, swap_op); - require!( - received_tokens.token_identifier == base_token_id, - "Invalid tokens received from router" - ); + let token_amount = self.all_accumulated_tokens(&token_to_send).take(); + require!(token_amount > 0, "No tokens"); - self.burn_part_of_base_token(&mut received_tokens); + let router_address = self.router_address().get(); + let swap_payment = EsdtTokenPayment::new(token_to_send, 0, token_amount); + let mut received_tokens = + self.call_swap_through_router(router_address.clone(), swap_payment, swap_operations); + + let base_token_id = self.get_base_token_id(); + require!( + received_tokens.token_identifier == base_token_id, + "Invalid tokens received from router" + ); - total_base_tokens += received_tokens.amount; - } + self.burn_part_of_base_token(&mut received_tokens); let current_week = self.get_current_week(); self.accumulated_fees(current_week, &base_token_id) - .update(|acc_fees| *acc_fees += total_base_tokens); + .update(|acc_fees| *acc_fees += received_tokens.amount); } - fn check_args_and_get_first_token_payment( + fn check_swap_through_router_args( &self, - swap_operation: SingleSwapOperationArg, - ) -> EsdtTokenPayment { - let mut iter = swap_operation.into_iter(); - let opt_first_item = iter.next(); - require!(opt_first_item.is_some(), "No arguments provided"); + token_to_send: &TokenIdentifier, + swap_operation: &MultiValueEncoded>, + ) { + require!(!swap_operation.is_empty(), "No arguments provided"); - let first_item = unsafe { opt_first_item.unwrap_unchecked() }; let base_token_id = self.get_base_token_id(); let locked_token_id = self.get_locked_token_id(); require!( - first_item.input_token_id != base_token_id - && first_item.input_token_id != locked_token_id, + token_to_send != &base_token_id && token_to_send != &locked_token_id, "May not swap base token or locked token" ); require!( - self.all_known_tokens().contains(&first_item.input_token_id), + self.all_known_tokens().contains(&token_to_send), "Unknown first token" ); - - let token_amount = self - .all_accumulated_tokens(&first_item.input_token_id) - .take(); - require!(token_amount > 0, "No tokens for given week"); - - EsdtTokenPayment::new(first_item.input_token_id, 0, token_amount) } fn call_swap_through_router( &self, router_address: ManagedAddress, payment: EsdtTokenPayment, - swap_operation: SingleSwapOperationArg, + swap_operations: MultiValueEncoded>, ) -> EsdtTokenPayment { - let mut args = MultiValueEncoded::new(); - for swap_op in &swap_operation { - args.push( - ( - swap_op.pair_address, - swap_op.function_name, - swap_op.input_token_id, - swap_op.min_amount_out, - ) - .into(), - ) - } - let output_payments: PaymentsVec = self .router_proxy(router_address) - .multi_pair_swap(args) + .multi_pair_swap(swap_operations) .esdt(payment) .execute_on_dest_context(); require!( diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index ef259d0a6..11437e609 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -5,16 +5,17 @@ mod router_setup; use energy_query::Energy; use fees_collector::additional_locked_tokens::{AdditionalLockedTokensModule, BLOCKS_IN_WEEK}; +use fees_collector::config::ConfigModule; use fees_collector::external_sc_interactions::router::RouterInteractionsModule; use fees_collector::fees_accumulation::FeesAccumulationModule; use fees_collector::redistribute_rewards::RedistributeRewardsModule; use fees_collector_test_setup::*; -use multiversx_sc::types::{BigInt, EsdtTokenPayment, ManagedVec}; +use multiversx_sc::types::{BigInt, EsdtTokenPayment, ManagedVec, MultiValueEncoded}; use multiversx_sc_scenario::{ - managed_address, managed_biguint, managed_token_id, managed_token_id_wrapped, rust_biguint, - DebugApi, + managed_address, managed_biguint, managed_buffer, managed_token_id, managed_token_id_wrapped, + rust_biguint, DebugApi, }; -use router_setup::{RouterSetup, USDC_TOKEN_ID}; +use router_setup::{RouterSetup, WEGLD_TOKEN_ID}; use simple_lock::locked_token::LockedTokenAttributes; use weekly_rewards_splitting::locked_token_buckets::LockedTokensBucket; use weekly_rewards_splitting::update_claim_progress_energy::UpdateClaimProgressEnergyModule; @@ -1455,7 +1456,7 @@ fn redistribute_rewards_test() { } #[test] -fn fees_collector_base_token_feature_test() { +fn fees_collector_single_swap_test() { let fc_setup = FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); let mut router_setup = RouterSetup::new( @@ -1480,33 +1481,69 @@ fn fees_collector_base_token_feature_test() { ) .assert_ok(); - // try deposit USDC - router_setup.b_mock.borrow_mut().set_esdt_balance( - &router_setup.owner_address, - USDC_TOKEN_ID, + // try deposit WEGLD + fc_setup.b_mock.borrow_mut().set_esdt_balance( + &fc_setup.owner_address, + WEGLD_TOKEN_ID, &rust_biguint!(1_000), ); - router_setup + fc_setup .b_mock .borrow_mut() .execute_esdt_transfer( &fc_setup.owner_address, &fc_setup.fc_wrapper, - USDC_TOKEN_ID, + WEGLD_TOKEN_ID, 0, &rust_biguint!(1_000), |sc| { sc.deposit_swap_fees(); - // check fees were accumulate for WEGLD instead of USDC + assert_eq!( + sc.all_accumulated_tokens(&managed_token_id!(WEGLD_TOKEN_ID)) + .get(), + 1_000 + ); assert!(sc - .accumulated_fees(1, &managed_token_id!(USDC_TOKEN_ID)) + .accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .is_empty()); + }, + ) + .assert_ok(); - assert!(!sc - .accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + // swap WEGLD to MEX + let wegld_mex_pair_addr = router_setup.wegld_mex_pair_wrapper.address_ref().clone(); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + let mut swap_operations = MultiValueEncoded::new(); + swap_operations.push( + ( + managed_address!(&wegld_mex_pair_addr), + managed_buffer!(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME), + managed_token_id!(BASE_ASSET_TOKEN_ID), + managed_biguint!(1), + ) + .into(), + ); + sc.swap_token_to_base_token(managed_token_id!(WEGLD_TOKEN_ID), swap_operations); + + assert!(sc + .all_accumulated_tokens(&managed_token_id!(WEGLD_TOKEN_ID)) .is_empty()); + + // About 1/5, which is the ratio of the pair + assert_eq!( + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .get(), + 199 + ); }, ) .assert_ok(); 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 735940932..ecddc0fcc 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 @@ -35,6 +35,8 @@ pub static LOCKED_TOKEN_ID: &[u8] = b"LOCKED-123456"; pub static LEGACY_LOCKED_TOKEN_ID: &[u8] = b"LEGACY-123456"; pub static PENALTY_PERCENTAGES: &[u64] = &[4_000, 6_000, 8_000]; +pub static SWAP_TOKENS_FIXED_INPUT_FUNC_NAME: &[u8] = b"swapTokensFixedInput"; + pub struct FeesCollectorSetup where FeesCollectorObjBuilder: 'static + Copy + Fn() -> fees_collector::ContractObj, diff --git a/energy-integration/fees-collector/tests/router_setup/mod.rs b/energy-integration/fees-collector/tests/router_setup/mod.rs index c33ab2c6f..cd2532b4d 100644 --- a/energy-integration/fees-collector/tests/router_setup/mod.rs +++ b/energy-integration/fees-collector/tests/router_setup/mod.rs @@ -10,7 +10,7 @@ use multiversx_sc_scenario::{ pub const PAIR_WASM_PATH: &str = "pair/output/pair.wasm"; pub const ROUTER_WASM_PATH: &str = "router/output/router.wasm"; -pub const MEX_TOKEN_ID: &[u8] = b"MEX-abcdef"; +pub const MEX_TOKEN_ID: &[u8] = BASE_ASSET_TOKEN_ID; pub const WEGLD_TOKEN_ID: &[u8] = b"WEGLD-abcdef"; pub const USDC_TOKEN_ID: &[u8] = b"USDC-abcdef"; pub const LPMEX_TOKEN_ID: &[u8] = b"LPMEX-abcdef"; @@ -30,6 +30,8 @@ use router::config::ConfigModule; use router::factory::*; use router::*; +use crate::fees_collector_test_setup::BASE_ASSET_TOKEN_ID; + #[allow(dead_code)] pub struct RouterSetup where @@ -205,7 +207,7 @@ where TxTokenTransfer { token_identifier: WEGLD_TOKEN_ID.to_vec(), nonce: 0, - value: rust_biguint!(ADD_LIQUIDITY_TOKENS), + value: rust_biguint!(ADD_LIQUIDITY_TOKENS * 5), }, TxTokenTransfer { token_identifier: MEX_TOKEN_ID.to_vec(), @@ -233,7 +235,7 @@ where TxTokenTransfer { token_identifier: WEGLD_TOKEN_ID.to_vec(), nonce: 0, - value: rust_biguint!(ADD_LIQUIDITY_TOKENS), + value: rust_biguint!(ADD_LIQUIDITY_TOKENS * 3), }, TxTokenTransfer { token_identifier: USDC_TOKEN_ID.to_vec(), From 3a905bebf01fd2bb04b192b4708291262a1d877c Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Fri, 21 Mar 2025 10:46:07 +0200 Subject: [PATCH 12/23] new test + fixes --- .../tests/fees_collector_rust_test.rs | 107 +++++++++++++++++- .../fees-collector/tests/router_setup/mod.rs | 14 +-- 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index 11437e609..79fe15925 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -15,7 +15,7 @@ use multiversx_sc_scenario::{ managed_address, managed_biguint, managed_buffer, managed_token_id, managed_token_id_wrapped, rust_biguint, DebugApi, }; -use router_setup::{RouterSetup, WEGLD_TOKEN_ID}; +use router_setup::{RouterSetup, USDC_TOKEN_ID, WEGLD_TOKEN_ID}; use simple_lock::locked_token::LockedTokenAttributes; use weekly_rewards_splitting::locked_token_buckets::LockedTokensBucket; use weekly_rewards_splitting::update_claim_progress_energy::UpdateClaimProgressEnergyModule; @@ -1548,3 +1548,108 @@ fn fees_collector_single_swap_test() { ) .assert_ok(); } + +#[test] +fn fees_collector_multiple_swap_test() { + let fc_setup = + FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); + let mut router_setup = RouterSetup::new( + fc_setup.b_mock.clone(), + router::contract_obj, + pair::contract_obj, + ); + + router_setup.add_liquidity(); + + let router_address = router_setup.router_wrapper.address_ref().clone(); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + sc.set_router_address(managed_address!(&router_address)); + }, + ) + .assert_ok(); + + // try deposit USDC + fc_setup.b_mock.borrow_mut().set_esdt_balance( + &fc_setup.owner_address, + USDC_TOKEN_ID, + &rust_biguint!(1_000), + ); + + fc_setup + .b_mock + .borrow_mut() + .execute_esdt_transfer( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + USDC_TOKEN_ID, + 0, + &rust_biguint!(1_000), + |sc| { + sc.deposit_swap_fees(); + + assert_eq!( + sc.all_accumulated_tokens(&managed_token_id!(USDC_TOKEN_ID)) + .get(), + 1_000 + ); + assert!(sc + .accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .is_empty()); + }, + ) + .assert_ok(); + + // swap USDC to WEGLD to MEX + let wegld_mex_pair_addr = router_setup.wegld_mex_pair_wrapper.address_ref().clone(); + let wegld_usdc_pair_addr = router_setup.wegld_usdc_pair_wrapper.address_ref().clone(); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + let mut swap_operations = MultiValueEncoded::new(); + swap_operations.push( + ( + managed_address!(&wegld_usdc_pair_addr), + managed_buffer!(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME), + managed_token_id!(WEGLD_TOKEN_ID), + managed_biguint!(1), + ) + .into(), + ); + swap_operations.push( + ( + managed_address!(&wegld_mex_pair_addr), + managed_buffer!(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME), + managed_token_id!(BASE_ASSET_TOKEN_ID), + managed_biguint!(1), + ) + .into(), + ); + sc.swap_token_to_base_token(managed_token_id!(USDC_TOKEN_ID), swap_operations); + + assert!(sc + .all_accumulated_tokens(&managed_token_id!(USDC_TOKEN_ID)) + .is_empty()); + + // About 1/5, which is the ratio of the first pair, then multiplied by 3, which is the ratio of the second pair + // i.e. ~ 1000 / 5 * 3 + assert_eq!( + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .get(), + 595 + ); + }, + ) + .assert_ok(); +} diff --git a/energy-integration/fees-collector/tests/router_setup/mod.rs b/energy-integration/fees-collector/tests/router_setup/mod.rs index cd2532b4d..09187078b 100644 --- a/energy-integration/fees-collector/tests/router_setup/mod.rs +++ b/energy-integration/fees-collector/tests/router_setup/mod.rs @@ -8,13 +8,13 @@ use multiversx_sc_scenario::{ managed_address, managed_biguint, managed_token_id, rust_biguint, whitebox_legacy::*, DebugApi, }; -pub const PAIR_WASM_PATH: &str = "pair/output/pair.wasm"; -pub const ROUTER_WASM_PATH: &str = "router/output/router.wasm"; -pub const MEX_TOKEN_ID: &[u8] = BASE_ASSET_TOKEN_ID; -pub const WEGLD_TOKEN_ID: &[u8] = b"WEGLD-abcdef"; -pub const USDC_TOKEN_ID: &[u8] = b"USDC-abcdef"; -pub const LPMEX_TOKEN_ID: &[u8] = b"LPMEX-abcdef"; -pub const LPUSDC_TOKEN_ID: &[u8] = b"LPUSDC-abcdef"; +pub static PAIR_WASM_PATH: &str = "pair/output/pair.wasm"; +pub static ROUTER_WASM_PATH: &str = "router/output/router.wasm"; +pub static MEX_TOKEN_ID: &[u8] = BASE_ASSET_TOKEN_ID; +pub static WEGLD_TOKEN_ID: &[u8] = b"WEGLD-abcdef"; +pub static USDC_TOKEN_ID: &[u8] = b"USDC-abcdef"; +pub static LPMEX_TOKEN_ID: &[u8] = b"LPMEX-abcdef"; +pub static LPUSDC_TOKEN_ID: &[u8] = b"LPUSDC-abcdef"; pub const USER_TOTAL_MEX_TOKENS: u64 = 5_001_001_000; pub const USER_TOTAL_WEGLD_TOKENS: u64 = 5_002_002_000; From d922d895d5c3c2adfeed16a04719f1f93c539dea Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 24 Mar 2025 10:28:38 +0200 Subject: [PATCH 13/23] update img tag --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3bb9fa310..2292a533e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,5 +11,5 @@ jobs: build: uses: multiversx/mx-sc-actions/.github/workflows/reproducible-build.yml@v3.3.1 with: - image_tag: v7.0.0 + image_tag: v9.0.0 attach_to_existing_release: true From 812838d294fd3ec6698832318d17bee3e156b489 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 24 Mar 2025 10:30:43 +0200 Subject: [PATCH 14/23] evil clippy --- .../fees-collector/src/external_sc_interactions/router.rs | 2 +- 1 file changed, 1 insertion(+), 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 eb52b0e48..d4ab27023 100644 --- a/energy-integration/fees-collector/src/external_sc_interactions/router.rs +++ b/energy-integration/fees-collector/src/external_sc_interactions/router.rs @@ -97,7 +97,7 @@ pub trait RouterInteractionsModule: "May not swap base token or locked token" ); require!( - self.all_known_tokens().contains(&token_to_send), + self.all_known_tokens().contains(token_to_send), "Unknown first token" ); } From 502d4c10639dbbf1713cdfdffd6e5410c86761bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 24 Mar 2025 10:40:01 +0200 Subject: [PATCH 15/23] Attempt to fix workflows. --- .github/workflows/actions.yml | 5 +++-- .github/workflows/release.yml | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index c166a6cfb..2940c2ae7 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -20,9 +20,10 @@ permissions: jobs: contracts: name: Contracts - uses: multiversx/mx-sc-actions/.github/workflows/contracts.yml@v3.3.1 + uses: multiversx/mx-sc-actions/.github/workflows/contracts.yml@v4.2.2 with: - rust-toolchain: nightly-2024-05-22 + rust-toolchain: stable coverage-args: --ignore-filename-regex='/.cargo/git' --output ./coverage.md secrets: token: ${{ secrets.GITHUB_TOKEN }} + \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2292a533e..f1da7c150 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,8 @@ permissions: jobs: build: - uses: multiversx/mx-sc-actions/.github/workflows/reproducible-build.yml@v3.3.1 + uses: multiversx/mx-sc-actions/.github/workflows/reproducible-build.yml@v4.2.2 with: image_tag: v9.0.0 attach_to_existing_release: true + \ No newline at end of file From 6c7d971e34942422dc2a34199e87590cd2f6c542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 24 Mar 2025 10:55:08 +0200 Subject: [PATCH 16/23] Trial and error: interactors. --- .github/workflows/actions.yml | 2 +- .github/workflows/release.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 2940c2ae7..4866f0588 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -24,6 +24,6 @@ jobs: with: rust-toolchain: stable coverage-args: --ignore-filename-regex='/.cargo/git' --output ./coverage.md + enable-interactor-tests: true secrets: token: ${{ secrets.GITHUB_TOKEN }} - \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f1da7c150..5c4ff587b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,4 +13,3 @@ jobs: with: image_tag: v9.0.0 attach_to_existing_release: true - \ No newline at end of file From 51ac623f5e67905290a9e97fa5ed27761d9a8ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 24 Mar 2025 11:09:05 +0200 Subject: [PATCH 17/23] Disable interactor tests. --- .github/workflows/actions.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 4866f0588..fd870762f 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -24,6 +24,5 @@ jobs: with: rust-toolchain: stable coverage-args: --ignore-filename-regex='/.cargo/git' --output ./coverage.md - enable-interactor-tests: true secrets: token: ${{ secrets.GITHUB_TOKEN }} From 4c44469d2ac596b393afd6d24659b404a17af4ca Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 24 Mar 2025 12:15:29 +0200 Subject: [PATCH 18/23] upgrade changes + fixes for tests --- energy-integration/fees-collector/src/lib.rs | 96 ++++++++++++++++++- .../tests/fees_collector_rust_test.rs | 91 +++++++++++++++++- 2 files changed, 181 insertions(+), 6 deletions(-) diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index aa612b9a3..a860a248a 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -1,7 +1,9 @@ #![no_std] use common_structs::Percent; +use common_types::{PaymentsVec, Week}; use multiversx_sc::storage::StorageKey; +use weekly_rewards_splitting::USER_MAX_CLAIM_WEEKS; multiversx_sc::imports!(); @@ -77,16 +79,37 @@ pub trait FeesCollector: ); known_contracts_mapper.clear(); - let known_tokens_mapper = - WhitelistMapper::::new(StorageKey::new(b"knownTokens")); - let base_token_id = self.get_base_token_id(); let locked_token_id = self.get_locked_token_id(); let current_week = self.get_current_week(); - for token_id in &all_tokens { + self.move_fees_current_week_after_upgrade( + &base_token_id, + &locked_token_id, + &all_tokens, + current_week, + ); + self.move_fees_previous_weeks_after_upgrade( + &base_token_id, + &locked_token_id, + &all_tokens, + current_week, + ); + } + + fn move_fees_current_week_after_upgrade( + &self, + base_token_id: &TokenIdentifier, + locked_token_id: &TokenIdentifier, + all_tokens: &ManagedVec, + current_week: Week, + ) { + let known_tokens_mapper = + WhitelistMapper::::new(StorageKey::new(b"knownTokens")); + + for token_id in all_tokens { known_tokens_mapper.remove(&token_id); - if token_id == base_token_id || token_id == locked_token_id { + if &token_id == base_token_id || &token_id == locked_token_id { continue; } @@ -101,4 +124,67 @@ pub trait FeesCollector: .set(acc_fees_current_week); } } + + fn move_fees_previous_weeks_after_upgrade( + &self, + base_token_id: &TokenIdentifier, + locked_token_id: &TokenIdentifier, + all_tokens: &ManagedVec, + current_week: Week, + ) { + let sc_address = self.blockchain().get_sc_address(); + for token_id in all_tokens { + if &token_id == base_token_id && &token_id == locked_token_id { + continue; + } + + let balance = self + .blockchain() + .get_esdt_balance(&sc_address, &token_id, 0); + if balance == 0 { + continue; + } + + self.all_accumulated_tokens(&token_id) + .update(|token_balance| *token_balance += balance); + } + + for week in (current_week - USER_MAX_CLAIM_WEEKS)..current_week { + let remaining_rewards_mapper = self.remaining_rewards(week); + let remaining_rewards = remaining_rewards_mapper.get(); + let opt_remaining_rewards_base_token = + self.find_token_in_payments_vec(base_token_id, &remaining_rewards); + let opt_remaining_rewards_locked_token = + self.find_token_in_payments_vec(locked_token_id, &remaining_rewards); + + let mut new_remaining_rewards = PaymentsVec::new(); + if let Some(remaining_rewards_base_token) = opt_remaining_rewards_base_token { + new_remaining_rewards.push(remaining_rewards_base_token); + } + if let Some(remaining_rewards_locked_token) = opt_remaining_rewards_locked_token { + new_remaining_rewards.push(remaining_rewards_locked_token); + } + + remaining_rewards_mapper.set(new_remaining_rewards); + } + } + + fn find_token_in_payments_vec( + &self, + token_id: &TokenIdentifier, + vec: &PaymentsVec, + ) -> Option { + for payment in vec { + if token_id == &payment.token_identifier { + return Some(payment); + } + } + + None + } + + // only needed for testing the upgrade functionality + + #[storage_mapper("allTokens")] + fn all_tokens(&self) -> SingleValueMapper>; } diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index 79fe15925..3a64cc81a 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -1450,6 +1450,38 @@ fn redistribute_rewards_test() { first_token_balance, managed_biguint!(599_952_417_140_485_515u64) ); + + assert!(sc.remaining_rewards(1).is_empty()); + assert!(sc.remaining_rewards(2).is_empty()); + assert!(sc.remaining_rewards(3).is_empty()); + assert!(sc.remaining_rewards(4).is_empty()); + assert!(sc.remaining_rewards(5).is_empty()); + }, + ) + .assert_ok(); + + // try redistribute rewards again - same balances in storage + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_zero, + |sc| { + sc.redistribute_rewards(1, 5); + + // Rewards were put in current_week storage (i.e. 10) + + let first_token_balance = sc + .accumulated_fees(10, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .get(); + + // i.e. 6 weeks worth of rewards minus what the third user claimed + assert_eq!( + first_token_balance, + managed_biguint!(599_952_417_140_485_515u64) + ); }, ) .assert_ok(); @@ -1606,9 +1638,66 @@ fn fees_collector_multiple_swap_test() { ) .assert_ok(); - // swap USDC to WEGLD to MEX + // try swap unknown token let wegld_mex_pair_addr = router_setup.wegld_mex_pair_wrapper.address_ref().clone(); let wegld_usdc_pair_addr = router_setup.wegld_usdc_pair_wrapper.address_ref().clone(); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + let mut swap_operations = MultiValueEncoded::new(); + swap_operations.push( + ( + managed_address!(&wegld_usdc_pair_addr), + managed_buffer!(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME), + managed_token_id!(WEGLD_TOKEN_ID), + managed_biguint!(1), + ) + .into(), + ); + swap_operations.push( + ( + managed_address!(&wegld_mex_pair_addr), + managed_buffer!(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME), + managed_token_id!(BASE_ASSET_TOKEN_ID), + managed_biguint!(1), + ) + .into(), + ); + sc.swap_token_to_base_token(managed_token_id!("RAND-123456"), swap_operations); + }, + ) + .assert_user_error("Unknown first token"); + + // try swap last token not MEX + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + let mut swap_operations = MultiValueEncoded::new(); + swap_operations.push( + ( + managed_address!(&wegld_usdc_pair_addr), + managed_buffer!(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME), + managed_token_id!(WEGLD_TOKEN_ID), + managed_biguint!(1), + ) + .into(), + ); + sc.swap_token_to_base_token(managed_token_id!(USDC_TOKEN_ID), swap_operations); + }, + ) + .assert_user_error("Invalid tokens received from router"); + + // swap USDC to WEGLD to MEX fc_setup .b_mock .borrow_mut() From ba650a102a3db330f117586e562fa789393680c3 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Mon, 24 Mar 2025 12:17:55 +0200 Subject: [PATCH 19/23] evil clippy --- energy-integration/fees-collector/src/lib.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index a860a248a..517d9f6e0 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -169,18 +169,14 @@ pub trait FeesCollector: } } + #[inline] fn find_token_in_payments_vec( &self, token_id: &TokenIdentifier, vec: &PaymentsVec, ) -> Option { - for payment in vec { - if token_id == &payment.token_identifier { - return Some(payment); - } - } - - None + vec.into_iter() + .find(|payment| token_id == &payment.token_identifier) } // only needed for testing the upgrade functionality From 458c8a67bb39c53486767a2665b8683bb93b3261 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Tue, 25 Mar 2025 13:07:11 +0200 Subject: [PATCH 20/23] upgrade fixes + test --- energy-integration/fees-collector/src/lib.rs | 92 ++++--- .../tests/fees_collector_rust_test.rs | 238 ++++++++++++++++++ 2 files changed, 293 insertions(+), 37 deletions(-) diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index 517d9f6e0..5fda395e8 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -1,9 +1,12 @@ #![no_std] +use claim::FeesCollectorWrapper; use common_structs::Percent; use common_types::{PaymentsVec, Week}; use multiversx_sc::storage::StorageKey; -use weekly_rewards_splitting::USER_MAX_CLAIM_WEEKS; +use weekly_rewards_splitting::{ + base_impl::WeeklyRewardsSplittingTraitsModule, USER_MAX_CLAIM_WEEKS, +}; multiversx_sc::imports!(); @@ -82,7 +85,7 @@ pub trait FeesCollector: let base_token_id = self.get_base_token_id(); let locked_token_id = self.get_locked_token_id(); let current_week = self.get_current_week(); - self.move_fees_current_week_after_upgrade( + self.clear_fees_current_week_after_upgrade( &base_token_id, &locked_token_id, &all_tokens, @@ -96,32 +99,28 @@ pub trait FeesCollector: ); } - fn move_fees_current_week_after_upgrade( + fn clear_fees_current_week_after_upgrade( &self, base_token_id: &TokenIdentifier, locked_token_id: &TokenIdentifier, all_tokens: &ManagedVec, current_week: Week, ) { + // In case the upgrade action is the very first action in the week + self.accumulate_additional_locked_tokens(); + + let wrapper = FeesCollectorWrapper::new(); + let _ = wrapper.collect_and_get_rewards_for_week(self, current_week - 1); + let known_tokens_mapper = WhitelistMapper::::new(StorageKey::new(b"knownTokens")); for token_id in all_tokens { known_tokens_mapper.remove(&token_id); - if &token_id == base_token_id || &token_id == locked_token_id { - continue; + if &token_id != base_token_id && &token_id != locked_token_id { + self.accumulated_fees(current_week, &token_id).clear(); } - - let acc_fees_mapper = self.accumulated_fees(current_week, &token_id); - let acc_fees_current_week = acc_fees_mapper.get(); - if acc_fees_current_week == 0 { - continue; - } - - acc_fees_mapper.clear(); - self.all_accumulated_tokens(&token_id) - .set(acc_fees_current_week); } } @@ -134,39 +133,58 @@ pub trait FeesCollector: ) { let sc_address = self.blockchain().get_sc_address(); for token_id in all_tokens { - if &token_id == base_token_id && &token_id == locked_token_id { + if &token_id == base_token_id || &token_id == locked_token_id { continue; } let balance = self .blockchain() .get_esdt_balance(&sc_address, &token_id, 0); - if balance == 0 { - continue; + if balance > 0 { + self.all_accumulated_tokens(&token_id).set(balance); } - - self.all_accumulated_tokens(&token_id) - .update(|token_balance| *token_balance += balance); } - for week in (current_week - USER_MAX_CLAIM_WEEKS)..current_week { - let remaining_rewards_mapper = self.remaining_rewards(week); - let remaining_rewards = remaining_rewards_mapper.get(); - let opt_remaining_rewards_base_token = - self.find_token_in_payments_vec(base_token_id, &remaining_rewards); - let opt_remaining_rewards_locked_token = - self.find_token_in_payments_vec(locked_token_id, &remaining_rewards); - - let mut new_remaining_rewards = PaymentsVec::new(); - if let Some(remaining_rewards_base_token) = opt_remaining_rewards_base_token { - new_remaining_rewards.push(remaining_rewards_base_token); - } - if let Some(remaining_rewards_locked_token) = opt_remaining_rewards_locked_token { - new_remaining_rewards.push(remaining_rewards_locked_token); - } + let first_week = if current_week > USER_MAX_CLAIM_WEEKS { + current_week - USER_MAX_CLAIM_WEEKS + } else { + 1 + }; + + for week in first_week..current_week { + self.set_rewards_after_upgrade( + base_token_id, + locked_token_id, + &self.total_rewards_for_week(week), + ); + self.set_rewards_after_upgrade( + base_token_id, + locked_token_id, + &self.remaining_rewards(week), + ); + } + } - remaining_rewards_mapper.set(new_remaining_rewards); + fn set_rewards_after_upgrade( + &self, + base_token_id: &TokenIdentifier, + locked_token_id: &TokenIdentifier, + mapper: &SingleValueMapper>, + ) { + let prev_rewards = mapper.get(); + let opt_rewards_base_token = self.find_token_in_payments_vec(base_token_id, &prev_rewards); + let opt_rewards_locked_token = + self.find_token_in_payments_vec(locked_token_id, &prev_rewards); + + let mut new_rewards = PaymentsVec::new(); + if let Some(remaining_rewards_base_token) = opt_rewards_base_token { + new_rewards.push(remaining_rewards_base_token); } + if let Some(remaining_rewards_locked_token) = opt_rewards_locked_token { + new_rewards.push(remaining_rewards_locked_token); + } + + mapper.set(new_rewards); } #[inline] diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index 3a64cc81a..b95fd26b4 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -9,6 +9,7 @@ use fees_collector::config::ConfigModule; use fees_collector::external_sc_interactions::router::RouterInteractionsModule; use fees_collector::fees_accumulation::FeesAccumulationModule; use fees_collector::redistribute_rewards::RedistributeRewardsModule; +use fees_collector::FeesCollector; use fees_collector_test_setup::*; use multiversx_sc::types::{BigInt, EsdtTokenPayment, ManagedVec, MultiValueEncoded}; use multiversx_sc_scenario::{ @@ -1742,3 +1743,240 @@ fn fees_collector_multiple_swap_test() { ) .assert_ok(); } + +// TODO: Remove after upgrade logic is removed +#[test] +fn test_upgrade_fees_collector() { + let rust_zero = rust_biguint!(0); + let mut fc_setup = + FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_zero, + |sc| { + let mut all_tokens_vec = ManagedVec::new(); + all_tokens_vec.push(managed_token_id!(LOCKED_TOKEN_ID)); + all_tokens_vec.push(managed_token_id!(BASE_ASSET_TOKEN_ID)); + all_tokens_vec.push(managed_token_id!(FIRST_TOKEN_ID)); + all_tokens_vec.push(managed_token_id!(SECOND_TOKEN_ID)); + + sc.all_tokens().set(all_tokens_vec); + }, + ) + .assert_ok(); + + let first_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.borrow_mut().create_user_account(&rust_zero); + + fc_setup.set_energy(&first_user, 50, 3_000); + fc_setup.set_energy(&second_user, 50, 9_000); + + fc_setup.deposit(FIRST_TOKEN_ID, 1_000).assert_ok(); + fc_setup.deposit(SECOND_TOKEN_ID, 2_000).assert_ok(); + fc_setup.deposit(BASE_ASSET_TOKEN_ID, 3_000).assert_ok(); + + // user claim first week + fc_setup.claim(&first_user).assert_ok(); + fc_setup.claim(&second_user).assert_ok(); + + // advance week + fc_setup.advance_week(); + + fc_setup.set_energy(&first_user, 50, 3_000); + fc_setup.set_energy(&second_user, 50, 9_000); + + // simulate previous logic of storing all tokens in rewards + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_zero, + |sc| { + sc.all_accumulated_tokens(&managed_token_id!(FIRST_TOKEN_ID)) + .clear(); + sc.all_accumulated_tokens(&managed_token_id!(SECOND_TOKEN_ID)) + .clear(); + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .clear(); + + let mut total_rewards = ManagedVec::new(); + total_rewards.push(EsdtTokenPayment::new( + managed_token_id!(FIRST_TOKEN_ID), + 0, + managed_biguint!(1_000), + )); + total_rewards.push(EsdtTokenPayment::new( + managed_token_id!(SECOND_TOKEN_ID), + 0, + managed_biguint!(2_000), + )); + total_rewards.push(EsdtTokenPayment::new( + managed_token_id!(BASE_ASSET_TOKEN_ID), + 0, + managed_biguint!(3_000), + )); + sc.total_rewards_for_week(1).set(&total_rewards); + sc.remaining_rewards(1).set(total_rewards); + }, + ) + .assert_ok(); + + // first user claims for first week + fc_setup.claim(&first_user).assert_ok(); + + fc_setup + .b_mock + .borrow() + .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_biguint!(250)); + fc_setup + .b_mock + .borrow() + .check_esdt_balance(&first_user, SECOND_TOKEN_ID, &rust_biguint!(500)); + fc_setup.b_mock.borrow().check_esdt_balance( + &first_user, + BASE_ASSET_TOKEN_ID, + &rust_biguint!(750), + ); + + fc_setup.deposit(FIRST_TOKEN_ID, 5_000).assert_ok(); + fc_setup.deposit(BASE_ASSET_TOKEN_ID, 10_000).assert_ok(); + + // simulate previous logic of storing all tokens in rewards + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_zero, + |sc| { + sc.all_accumulated_tokens(&managed_token_id!(FIRST_TOKEN_ID)) + .clear(); + sc.accumulated_fees(2, &managed_token_id!(FIRST_TOKEN_ID)) + .set(managed_biguint!(5_000)); + }, + ) + .assert_ok(); + + // test upgrade + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_zero, + |sc| { + sc.upgrade(); + + assert!(sc.all_tokens().is_empty()); + assert!(sc + .accumulated_fees(2, &managed_token_id!(FIRST_TOKEN_ID)) + .is_empty()); + assert_eq!( + sc.all_accumulated_tokens(&managed_token_id!(FIRST_TOKEN_ID)) + .get(), + 1_000 - 250 + 5_000 + ); + assert_eq!( + sc.all_accumulated_tokens(&managed_token_id!(SECOND_TOKEN_ID)) + .get(), + 2_000 - 500 + ); + + assert!(sc + .all_accumulated_tokens(&managed_token_id!(BASE_ASSET_TOKEN_ID)) + .is_empty()); + assert!(sc + .accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .is_empty()); + assert_eq!( + sc.accumulated_fees(2, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .get(), + 10_000 + ); + + let expected_fees_first_week = ManagedVec::from_single_item(EsdtTokenPayment::new( + managed_token_id!(BASE_ASSET_TOKEN_ID), + 0, + managed_biguint!(3_000 - 750), + )); + assert_eq!(sc.remaining_rewards(1).get(), expected_fees_first_week); + }, + ) + .assert_ok(); + + // advance week + fc_setup.advance_week(); + + fc_setup.set_energy(&first_user, 50, 3_000); + fc_setup.set_energy(&second_user, 50, 9_000); + + // first user claim third week + fc_setup.claim(&first_user).assert_ok(); + + // first user only received base asset token + fc_setup + .b_mock + .borrow() + .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_biguint!(250)); + fc_setup + .b_mock + .borrow() + .check_esdt_balance(&first_user, SECOND_TOKEN_ID, &rust_biguint!(500)); + fc_setup.b_mock.borrow().check_esdt_balance( + &first_user, + BASE_ASSET_TOKEN_ID, + &rust_biguint!(750 + 2_575), // original balance, + ~1/4 of the new rewards + ); + + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_zero, + |sc| { + let expected_fees_first_week = ManagedVec::from_single_item(EsdtTokenPayment::new( + managed_token_id!(BASE_ASSET_TOKEN_ID), + 0, + managed_biguint!(3_000 - 750), + )); + assert_eq!(sc.remaining_rewards(1).get(), expected_fees_first_week); + + let expected_fees_second_week = + ManagedVec::from_single_item(EsdtTokenPayment::new( + managed_token_id!(BASE_ASSET_TOKEN_ID), + 0, + managed_biguint!(10_000 - 2_575), + )); + assert_eq!(sc.remaining_rewards(2).get(), expected_fees_second_week); + }, + ) + .assert_ok(); + + // second user claim + fc_setup.claim(&second_user).assert_ok(); + + // second user received only base token rewards + fc_setup + .b_mock + .borrow() + .check_esdt_balance(&second_user, FIRST_TOKEN_ID, &rust_zero); + fc_setup + .b_mock + .borrow() + .check_esdt_balance(&second_user, SECOND_TOKEN_ID, &rust_zero); + fc_setup.b_mock.borrow().check_esdt_balance( + &second_user, + BASE_ASSET_TOKEN_ID, + &rust_biguint!(9_674), // ~ 3/4 * 3_000 + 3/4 * 10_000 = ~9_750 + ); +} From aad0205a4580c7299c5d9a3a8300a8066eaa20cf Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 26 Mar 2025 10:57:46 +0200 Subject: [PATCH 21/23] test burn fees percent --- energy-integration/fees-collector/src/lib.rs | 4 +- .../tests/fees_collector_rust_test.rs | 92 +++++++++++++++++++ .../tests/fees_collector_test_setup/mod.rs | 20 ++++ 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index 5fda395e8..0d00debd3 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -64,9 +64,9 @@ pub trait FeesCollector: } } - // Do not ever use these keys again! + // Do not use these storage keys until upgrade: "allTokens", "knownContracts" and "knownTokens" // - // The whole upgrade logic can be removed after one release and upgrade on mainnet + // The whole upgrade logic (and the relevant test) can be removed after one release and upgrade on mainnet #[upgrade] fn upgrade(&self) { let all_tokens_mapper = SingleValueMapper::>::new( diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index b95fd26b4..18b0fefee 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -1744,6 +1744,98 @@ fn fees_collector_multiple_swap_test() { .assert_ok(); } +#[test] +fn test_burn_percentage_base_token_logic() { + let mut fc_setup = + FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); + let mut router_setup = RouterSetup::new( + fc_setup.b_mock.clone(), + router::contract_obj, + pair::contract_obj, + ); + + router_setup.add_liquidity(); + + let router_address = router_setup.router_wrapper.address_ref().clone(); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + sc.set_router_address(managed_address!(&router_address)); + }, + ) + .assert_ok(); + + fc_setup.set_burn_percent(2_500); // 25% + + // deposit WEGLD + fc_setup.b_mock.borrow_mut().set_esdt_balance( + &fc_setup.depositor_address, + WEGLD_TOKEN_ID, + &rust_biguint!(1_000), + ); + fc_setup.deposit(WEGLD_TOKEN_ID, 1_000).assert_ok(); + + let wegld_mex_pair_addr = router_setup.wegld_mex_pair_wrapper.address_ref().clone(); + fc_setup + .b_mock + .borrow_mut() + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_biguint!(0), + |sc| { + let mut swap_operations = MultiValueEncoded::new(); + swap_operations.push( + ( + managed_address!(&wegld_mex_pair_addr), + managed_buffer!(SWAP_TOKENS_FIXED_INPUT_FUNC_NAME), + managed_token_id!(BASE_ASSET_TOKEN_ID), + managed_biguint!(1), + ) + .into(), + ); + sc.swap_token_to_base_token(managed_token_id!(WEGLD_TOKEN_ID), swap_operations); + + assert!(sc + .all_accumulated_tokens(&managed_token_id!(WEGLD_TOKEN_ID)) + .is_empty()); + + // About 1/5, which is the ratio of the pair + assert_eq!( + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .get(), + 199 - 199 / 4 // 25% get burned + ); + }, + ) + .assert_ok(); + + // user deposit mex + fc_setup.b_mock.borrow_mut().set_esdt_balance( + &fc_setup.depositor_address, + BASE_ASSET_TOKEN_ID, + &rust_biguint!(1_000), + ); + fc_setup.deposit(BASE_ASSET_TOKEN_ID, 1_000).assert_ok(); + + fc_setup + .b_mock + .borrow_mut() + .execute_query(&fc_setup.fc_wrapper, |sc| { + assert_eq!( + sc.accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .get(), + 199 - 199 / 4 + 1_000 - 1_000 / 4 // previous balance + new one with 25% burned + ); + }) + .assert_ok(); +} + // TODO: Remove after upgrade logic is removed #[test] fn test_upgrade_fees_collector() { 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 ecddc0fcc..a32ac9fb5 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 @@ -3,6 +3,7 @@ use std::{cell::RefCell, rc::Rc}; use claim::ClaimModule; +use common_structs::Percent; use multiversx_sc::{ codec::multi_types::OptionalValue, storage::mappers::StorageTokenWrapper, @@ -102,6 +103,11 @@ where LOCKED_TOKEN_ID, &[EsdtLocalRole::NftBurn], ); + b_mock.set_esdt_local_roles( + fc_wrapper.address_ref(), + BASE_ASSET_TOKEN_ID, + &[EsdtLocalRole::Burn], + ); b_mock.set_esdt_balance( &depositor_address, @@ -275,4 +281,18 @@ where ) .assert_ok(); } + + pub fn set_burn_percent(&mut self, burn_percent: Percent) { + self.b_mock + .borrow_mut() + .execute_tx( + &self.owner_address, + &self.fc_wrapper, + &rust_biguint!(0), + |sc| { + sc.set_base_token_burn_percent(burn_percent); + }, + ) + .assert_ok(); + } } From 4d900d870a08ab149e21937af883361ce2bfa87e Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Wed, 26 Mar 2025 11:00:45 +0200 Subject: [PATCH 22/23] rename --- energy-integration/fees-collector/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index 0d00debd3..aec968934 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -177,11 +177,11 @@ pub trait FeesCollector: self.find_token_in_payments_vec(locked_token_id, &prev_rewards); let mut new_rewards = PaymentsVec::new(); - if let Some(remaining_rewards_base_token) = opt_rewards_base_token { - new_rewards.push(remaining_rewards_base_token); + if let Some(rewards_base_token) = opt_rewards_base_token { + new_rewards.push(rewards_base_token); } - if let Some(remaining_rewards_locked_token) = opt_rewards_locked_token { - new_rewards.push(remaining_rewards_locked_token); + if let Some(rewards_locked_token) = opt_rewards_locked_token { + new_rewards.push(rewards_locked_token); } mapper.set(new_rewards); From 2b6ae52c0fa52bdf31ac1b60ab2ca58b81db5a37 Mon Sep 17 00:00:00 2001 From: Dorin Marian Iancu Date: Thu, 27 Mar 2025 10:28:10 +0200 Subject: [PATCH 23/23] safety measure for rewards redistribution --- energy-integration/fees-collector/src/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index aec968934..4eabe66d3 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -4,6 +4,7 @@ use claim::FeesCollectorWrapper; use common_structs::Percent; use common_types::{PaymentsVec, Week}; use multiversx_sc::storage::StorageKey; +use week_timekeeping::FIRST_WEEK; use weekly_rewards_splitting::{ base_impl::WeeklyRewardsSplittingTraitsModule, USER_MAX_CLAIM_WEEKS, }; @@ -97,6 +98,7 @@ pub trait FeesCollector: &all_tokens, current_week, ); + self.clear_older_undist_rewards(current_week); } fn clear_fees_current_week_after_upgrade( @@ -197,6 +199,19 @@ pub trait FeesCollector: .find(|payment| token_id == &payment.token_identifier) } + // This makes sure we don't accidentally redistribute rewards again + fn clear_older_undist_rewards(&self, current_week: Week) { + if current_week <= USER_MAX_CLAIM_WEEKS { + return; + } + + let end_week = current_week - USER_MAX_CLAIM_WEEKS; + for week in FIRST_WEEK..end_week { + self.total_rewards_for_week(week).clear(); + self.remaining_rewards(week).clear(); + } + } + // only needed for testing the upgrade functionality #[storage_mapper("allTokens")]