diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index c166a6cfb..fd870762f 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -20,9 +20,9 @@ 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 }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3bb9fa310..5c4ff587b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ 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: v7.0.0 + image_tag: v9.0.0 attach_to_existing_release: true diff --git a/Cargo.lock b/Cargo.lock index 72759ef35..22ed33aa1 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" @@ -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", @@ -1375,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 7f43373ff..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,17 +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 + 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(); @@ -1644,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/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/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..cbc09f09b 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 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 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/additional_locked_tokens.rs b/energy-integration/fees-collector/src/additional_locked_tokens.rs index 9303a408f..ec07ad765 100644 --- a/energy-integration/fees-collector/src/additional_locked_tokens.rs +++ b/energy-integration/fees-collector/src/additional_locked_tokens.rs @@ -10,6 +10,10 @@ pub trait AdditionalLockedTokensModule: + crate::fees_accumulation::FeesAccumulationModule + crate::events::FeesCollectorEventsModule + week_timekeeping::WeekTimekeepingModule + + crate::external_sc_interactions::router::RouterInteractionsModule + + energy_query::EnergyQueryModule + + utils::UtilsModule + + multiversx_sc_modules::only_admin::OnlyAdminModule { #[only_owner] #[endpoint(setLockedTokensPerBlock)] @@ -30,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 b0994d08b..0f16d2dae 100644 --- a/energy-integration/fees-collector/src/claim.rs +++ b/energy-integration/fees-collector/src/claim.rs @@ -24,6 +24,7 @@ pub trait ClaimModule: + sc_whitelist_module::SCWhitelistModule + multiversx_sc_modules::only_admin::OnlyAdminModule + crate::redistribute_rewards::RedistributeRewardsModule + + crate::external_sc_interactions::router::RouterInteractionsModule { #[endpoint(claimRewards)] fn claim_rewards_endpoint( @@ -191,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 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/config.rs b/energy-integration/fees-collector/src/config.rs index 0cb2d813b..84b3a67dc 100644 --- a/energy-integration/fees-collector/src/config.rs +++ b/energy-integration/fees-collector/src/config.rs @@ -2,86 +2,17 @@ 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(); - 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); - } - - 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); + #[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() - } - - #[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; + #[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/mod.rs b/energy-integration/fees-collector/src/external_sc_interactions/mod.rs new file mode 100644 index 000000000..fcddb5c62 --- /dev/null +++ b/energy-integration/fees-collector/src/external_sc_interactions/mod.rs @@ -0,0 +1 @@ +pub mod router; 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..d4ab27023 --- /dev/null +++ b/energy-integration/fees-collector/src/external_sc_interactions/router.rs @@ -0,0 +1,129 @@ +use common_types::PaymentsVec; +use router_proxy::SwapOperationType; + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); + +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; + } +} + +#[multiversx_sc::module] +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) { + self.require_sc_address(&router_address); + + self.router_address().set(router_address); + } + + /// Swaps tokens to the base token (i.e. 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, + token_to_send: TokenIdentifier, + swap_operations: MultiValueEncoded>, + ) { + self.check_swap_through_router_args(&token_to_send, &swap_operations); + + let token_amount = self.all_accumulated_tokens(&token_to_send).take(); + require!(token_amount > 0, "No 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" + ); + + 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 += received_tokens.amount); + } + + fn check_swap_through_router_args( + &self, + token_to_send: &TokenIdentifier, + swap_operation: &MultiValueEncoded>, + ) { + require!(!swap_operation.is_empty(), "No arguments provided"); + + let base_token_id = self.get_base_token_id(); + let locked_token_id = self.get_locked_token_id(); + require!( + 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(token_to_send), + "Unknown first token" + ); + } + + fn call_swap_through_router( + &self, + router_address: ManagedAddress, + payment: EsdtTokenPayment, + swap_operations: MultiValueEncoded>, + ) -> EsdtTokenPayment { + let output_payments: PaymentsVec = self + .router_proxy(router_address) + .multi_pair_swap(swap_operations) + .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 e6eb4ba41..1b29f496c 100644 --- a/energy-integration/fees-collector/src/fees_accumulation.rs +++ b/energy-integration/fees-collector/src/fees_accumulation.rs @@ -1,6 +1,8 @@ multiversx_sc::imports!(); multiversx_sc::derive_imports!(); +use common_structs::Percent; +use energy_factory::lock_options::MAX_PENALTY_PERCENTAGE; use week_timekeeping::Week; #[multiversx_sc::module] @@ -8,42 +10,78 @@ pub trait FeesAccumulationModule: crate::config::ConfigModule + crate::events::FeesCollectorEventsModule + week_timekeeping::WeekTimekeepingModule + + 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: 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.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); + + 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); + + 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); + } + + fn try_burn_locked_token(&self, payment: &EsdtTokenPayment) { + let locked_token_id = self.get_locked_token_id(); require!( - self.known_contracts().contains(&caller), - "Only known contracts can deposit" + payment.token_identifier == locked_token_id, + "Only locked token accepted as SFT/NFT/MetaESDT" ); - let payment = self.call_value().single_esdt(); - require!( - self.known_tokens().contains(&payment.token_identifier), - "Invalid payment token" + self.send().esdt_local_burn( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, ); + } - if payment.token_nonce > 0 { - 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, - ); + fn burn_part_of_base_token(&self, payment: &mut EsdtTokenPayment) { + let burn_percent = self.base_token_burn_percent().get(); + if burn_percent == 0 { + return; } - let current_week = self.get_current_week(); - self.accumulated_fees(current_week, &payment.token_identifier) - .update(|amt| *amt += &payment.amount); + let burn_amount = &payment.amount * burn_percent / MAX_PENALTY_PERCENTAGE; + if burn_amount == 0 { + return; + } - self.emit_deposit_swap_fees_event(&caller, current_week, &payment); + self.send() + .esdt_local_burn(&payment.token_identifier, 0, &burn_amount); + + payment.amount -= burn_amount; } fn get_and_clear_accumulated_fees( @@ -62,4 +100,7 @@ pub trait FeesAccumulationModule: #[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 2ee36602c..4eabe66d3 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -1,11 +1,21 @@ #![no_std] +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, +}; + multiversx_sc::imports!(); 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,32 +39,181 @@ pub trait FeesCollector: + multiversx_sc_modules::only_admin::OnlyAdminModule + claim::ClaimModule + redistribute_rewards::RedistributeRewardsModule + + external_sc_interactions::router::RouterInteractionsModule { + /// 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_burn_percent: Percent, admins: MultiValueEncoded, ) { - self.require_valid_token_id(&locked_token_id); - self.require_sc_address(&energy_factory_address); + self.set_energy_factory_address(energy_factory_address); + self.set_router_address(router_address); + 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); } } + // Do not use these storage keys until upgrade: "allTokens", "knownContracts" and "knownTokens" + // + // The whole upgrade logic (and the relevant test) can be removed after one release and upgrade on mainnet #[upgrade] - fn upgrade(&self) {} + fn upgrade(&self) { + 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 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.clear_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, + ); + self.clear_older_undist_rewards(current_week); + } + + 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 { + self.accumulated_fees(current_week, &token_id).clear(); + } + } + } + + 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 { + self.all_accumulated_tokens(&token_id).set(balance); + } + } + + 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), + ); + } + } + + 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(rewards_base_token) = opt_rewards_base_token { + new_rewards.push(rewards_base_token); + } + if let Some(rewards_locked_token) = opt_rewards_locked_token { + new_rewards.push(rewards_locked_token); + } + + mapper.set(new_rewards); + } + + #[inline] + fn find_token_in_payments_vec( + &self, + token_id: &TokenIdentifier, + vec: &PaymentsVec, + ) -> Option { + vec.into_iter() + .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")] + fn all_tokens(&self) -> SingleValueMapper>; } diff --git a/energy-integration/fees-collector/src/redistribute_rewards.rs b/energy-integration/fees-collector/src/redistribute_rewards.rs index d3c5d35ce..613d50a3b 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 + + energy_query::EnergyQueryModule + + utils::UtilsModule { #[only_admin] #[endpoint(redistributeRewards)] @@ -26,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( + 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(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); @@ -59,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..18b0fefee 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -1,17 +1,22 @@ #![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::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}; +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, 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; @@ -36,15 +41,14 @@ 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); - 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 @@ -53,25 +57,23 @@ fn claim_first_week_test() { fc_setup .b_mock - .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_zero); + .borrow_mut() + .check_esdt_balance(&first_user, BASE_ASSET_TOKEN_ID, &rust_zero); fc_setup .b_mock - .check_esdt_balance(&second_user, FIRST_TOKEN_ID, &rust_zero); + .borrow_mut() + .check_esdt_balance(&second_user, BASE_ASSET_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)) + 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)), @@ -113,21 +115,18 @@ fn claim_first_week_test() { // state remains unchanged fc_setup .b_mock - .check_esdt_balance(&first_user, FIRST_TOKEN_ID, &rust_zero); + .borrow_mut() + .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)), @@ -170,15 +169,14 @@ 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); - 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 @@ -195,9 +193,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 @@ -208,39 +205,26 @@ 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.check_esdt_balance( + 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.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.check_esdt_balance( + 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.check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); 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,15 +262,14 @@ 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); - 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 @@ -304,64 +287,44 @@ 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( - 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.check_esdt_balance( + 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.check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); 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!( - 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 @@ -398,31 +361,22 @@ 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, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); 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( - 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 @@ -451,19 +405,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.check_esdt_balance( + 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.check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); } #[test] @@ -472,15 +419,14 @@ 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); - 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 @@ -509,64 +455,44 @@ 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( - 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.check_esdt_balance( + 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.check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); 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!( - 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 @@ -606,15 +532,14 @@ 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); - 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 @@ -625,9 +550,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 @@ -637,23 +561,17 @@ 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.check_esdt_balance( + 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.check_esdt_balance( - &first_user, - SECOND_TOKEN_ID, - &first_user_expected_second_token_amt, - ); 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 @@ -687,20 +605,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.check_esdt_balance( + 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.check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); } #[test] @@ -709,15 +619,14 @@ 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); - 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 @@ -726,6 +635,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!( @@ -768,9 +678,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 @@ -794,6 +703,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 +752,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,15 +813,14 @@ 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); - 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 @@ -919,6 +829,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 +863,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 +882,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 +896,7 @@ fn surplus_energy_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1086,18 +999,17 @@ 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); - 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 @@ -1115,6 +1027,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( @@ -1123,36 +1036,24 @@ 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.check_esdt_balance( + 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.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,15 +1068,11 @@ 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!( - 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) ); @@ -1192,15 +1089,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 @@ -1237,17 +1129,12 @@ 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, + BASE_ASSET_TOKEN_ID, &first_user_expected_first_token_amt, ); - fc_setup.b_mock.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 +1148,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( @@ -1269,15 +1157,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 @@ -1316,19 +1199,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.check_esdt_balance( + 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.check_esdt_balance( - &second_user, - SECOND_TOKEN_ID, - &second_user_expected_second_token_amt, - ); } #[test] @@ -1341,6 +1217,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1354,6 +1231,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 +1247,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1381,6 +1260,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 +1277,7 @@ fn additional_locked_tokens_test() { fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1409,6 +1290,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,19 +1309,16 @@ 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); 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(); @@ -1450,10 +1329,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); @@ -1461,18 +1337,14 @@ 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( - 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(); @@ -1481,10 +1353,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); @@ -1494,10 +1363,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); @@ -1507,10 +1373,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); @@ -1520,10 +1383,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); @@ -1533,10 +1393,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); @@ -1546,10 +1403,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); @@ -1559,10 +1413,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); @@ -1572,10 +1423,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); @@ -1584,6 +1432,7 @@ fn redistribute_rewards_test() { // redist rewards fc_setup .b_mock + .borrow_mut() .execute_tx( &fc_setup.owner_address, &fc_setup.fc_wrapper, @@ -1594,10 +1443,39 @@ 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)) + .accumulated_fees(10, &managed_token_id!(BASE_ASSET_TOKEN_ID)) .get(); - let second_token_balance = sc - .accumulated_fees(10, &managed_token_id!(SECOND_TOKEN_ID)) + + // 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!(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 @@ -1605,11 +1483,592 @@ fn redistribute_rewards_test() { first_token_balance, managed_biguint!(599_952_417_140_485_515u64) ); + }, + ) + .assert_ok(); +} + +#[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( + 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 WEGLD + fc_setup.b_mock.borrow_mut().set_esdt_balance( + &fc_setup.owner_address, + WEGLD_TOKEN_ID, + &rust_biguint!(1_000), + ); + + fc_setup + .b_mock + .borrow_mut() + .execute_esdt_transfer( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + WEGLD_TOKEN_ID, + 0, + &rust_biguint!(1_000), + |sc| { + sc.deposit_swap_fees(); + + assert_eq!( + sc.all_accumulated_tokens(&managed_token_id!(WEGLD_TOKEN_ID)) + .get(), + 1_000 + ); + assert!(sc + .accumulated_fees(1, &managed_token_id!(BASE_ASSET_TOKEN_ID)) + .is_empty()); + }, + ) + .assert_ok(); + + // 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(); +} + +#[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(); + + // 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() + .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(); +} + +#[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() { + 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!( - second_token_balance, - managed_biguint!(299_976_208_570_242_758) + 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 + ); } 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..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 @@ -1,6 +1,9 @@ #![allow(deprecated)] +use std::{cell::RefCell, rc::Rc}; + use claim::ClaimModule; +use common_structs::Percent; use multiversx_sc::{ codec::multi_types::OptionalValue, storage::mappers::StorageTokenWrapper, @@ -23,6 +26,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"; @@ -32,12 +36,14 @@ 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, 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: @@ -97,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, @@ -108,6 +119,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(); @@ -147,28 +163,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 + 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() )); @@ -177,8 +184,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, @@ -189,12 +199,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(); @@ -202,7 +213,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, @@ -214,11 +225,11 @@ where ) } - pub fn deposit_locked_tokens(&mut self, token: &[u8], nonce: u64, amount: u64) -> TxResult { - self.b_mock.execute_esdt_transfer( + 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| { @@ -229,6 +240,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); }) @@ -236,6 +248,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))); }) @@ -243,6 +256,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); @@ -252,6 +266,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, @@ -266,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(); + } } 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..09187078b --- /dev/null +++ b/energy-integration/fees-collector/tests/router_setup/mod.rs @@ -0,0 +1,262 @@ +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 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; +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::*; + +use crate::fees_collector_test_setup::BASE_ASSET_TOKEN_ID; + +#[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 wegld_mex_pair_wrapper: ContractObjWrapper, PairObjBuilder>, + pub wegld_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 wegld_mex_pair_wrapper = b_mock.borrow_mut().create_sc_account( + &rust_zero, + Some(&owner_addr), + pair_builder, + PAIR_WASM_PATH, + ); + + let wegld_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, &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); + 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, &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); + 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!(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!(wegld_usdc_pair_wrapper.address_ref()), + ); + }) + .assert_ok(); + + let lp_token_roles = [EsdtLocalRole::Mint, EsdtLocalRole::Burn]; + b_mock.borrow_mut().set_esdt_local_roles( + 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( + wegld_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, + wegld_mex_pair_wrapper, + wegld_usdc_pair_wrapper, + } + } + + // TODO: Maybe change token amounts + 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 * 5), + }, + 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.wegld_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 * 3), + }, + 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.wegld_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 4aab5f1d3..e07d9f870 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: 40 // Async Callback (empty): 1 -// Total number of exported functions: 46 +// 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 + getAllTokens => all_known_tokens 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 @@ -63,6 +58,8 @@ multiversx_sc_wasm_adapter::endpoints! { claimBoostedRewards => claim_boosted_rewards redistributeRewards => redistribute_rewards getRemainingRewards => remaining_rewards + setRouterAddress => set_router_address + swapTokenToBaseToken => swap_token_to_base_token ) } 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..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,14 +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 + 0, MultiValueEncoded::new(), ); })