From 2ca12e41de740c578476d2b8ebe9b0cfa1287012 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Thu, 1 Aug 2024 13:18:56 +0300 Subject: [PATCH 01/12] farm supply for week fix. incl claimBoosted aggr --- dex/farm-with-locked-rewards/src/lib.rs | 6 ++ dex/farm/src/lib.rs | 5 ++ dex/farm/tests/total_farm_position_test.rs | 58 +++++++++++++++++++ .../src/claim_only_boosted_staking_rewards.rs | 8 +++ .../src/claim_stake_farm_rewards.rs | 4 +- 5 files changed, 79 insertions(+), 2 deletions(-) diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index 91144b387..84d7dc7f4 100644 --- a/dex/farm-with-locked-rewards/src/lib.rs +++ b/dex/farm-with-locked-rewards/src/lib.rs @@ -237,7 +237,13 @@ pub trait Farm: ); } + let mut storage_cache = StorageCache::new(self); + NoMintWrapper::::generate_aggregated_rewards(self, &mut storage_cache); + let boosted_rewards = self.claim_only_boosted_payment(user); + + self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); + self.send_to_lock_contract_non_zero( self.reward_token_id().get(), boosted_rewards, diff --git a/dex/farm/src/lib.rs b/dex/farm/src/lib.rs index 08d447830..211b05e02 100644 --- a/dex/farm/src/lib.rs +++ b/dex/farm/src/lib.rs @@ -228,10 +228,15 @@ pub trait Farm: ); } + let mut storage_cache = StorageCache::new(self); + Wrapper::::generate_aggregated_rewards(self, &mut storage_cache); + let boosted_rewards = self.claim_only_boosted_payment(user); let boosted_rewards_payment = EsdtTokenPayment::new(self.reward_token_id().get(), 0, boosted_rewards); + self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); + self.send_payment_non_zero(user, &boosted_rewards_payment); boosted_rewards_payment diff --git a/dex/farm/tests/total_farm_position_test.rs b/dex/farm/tests/total_farm_position_test.rs index b7ca1be7b..e0819d411 100644 --- a/dex/farm/tests/total_farm_position_test.rs +++ b/dex/farm/tests/total_farm_position_test.rs @@ -1193,3 +1193,61 @@ fn total_farm_position_through_simple_lock_test() { &rust_biguint!(first_received_reward_amt), ); } + +#[test] +fn claim_only_boosted_rewards_per_week_test() { + DebugApi::dummy(); + let mut farm_setup = MultiUserFarmSetup::new( + farm::contract_obj, + energy_factory_mock::contract_obj, + energy_update::contract_obj, + ); + + farm_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + farm_setup.set_boosted_yields_factors(); + farm_setup.b_mock.set_block_epoch(2); + + let temp_user = farm_setup.third_user.clone(); + + // first user enter farm + let farm_in_amount = 100_000_000; + let first_user = farm_setup.first_user.clone(); + farm_setup.set_user_energy(&first_user, 1_000, 2, 1); + farm_setup.enter_farm(&first_user, farm_in_amount); + + farm_setup.check_farm_token_supply(farm_in_amount); + + farm_setup.b_mock.set_block_nonce(10); + farm_setup.b_mock.set_block_epoch(6); + farm_setup.set_user_energy(&first_user, 1_000, 6, 1); + farm_setup.set_user_energy(&temp_user, 1, 6, 1); + farm_setup.enter_farm(&temp_user, 1); + farm_setup.exit_farm(&temp_user, 2, 1); + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 13, 1); + farm_setup.b_mock.set_block_nonce(20); + farm_setup.b_mock.set_block_epoch(13); + + let boosted_rewards = 2_500; + let second_week_received_reward_amt = + farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user); + + assert_eq!(second_week_received_reward_amt, boosted_rewards); + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 15, 1); + farm_setup.b_mock.set_block_nonce(30); + farm_setup.b_mock.set_block_epoch(15); + let third_week_received_reward_amt = + farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user); + + // Should be equal to half base generated rewards + full boosted generated rewards + assert_eq!(third_week_received_reward_amt, boosted_rewards); + + farm_setup.b_mock.check_esdt_balance( + &first_user, + REWARD_TOKEN_ID, + &rust_biguint!(boosted_rewards * 2), + ); +} diff --git a/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs b/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs index a1843a1f6..79d433dfe 100644 --- a/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs +++ b/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs @@ -1,3 +1,6 @@ +use contexts::storage_cache::StorageCache; +use farm_base_impl::base_traits_impl::FarmContract; + use crate::base_impl_wrapper::FarmStakingWrapper; multiversx_sc::imports!(); @@ -38,10 +41,15 @@ pub trait ClaimOnlyBoostedStakingRewardsModule: ); } + let mut storage_cache = StorageCache::new(self); + FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); + let boosted_rewards = self.claim_only_boosted_payment(user); let boosted_rewards_payment = EsdtTokenPayment::new(self.reward_token_id().get(), 0, boosted_rewards); + self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); + self.send_payment_non_zero(user, &boosted_rewards_payment); boosted_rewards_payment diff --git a/farm-staking/farm-staking/src/claim_stake_farm_rewards.rs b/farm-staking/farm-staking/src/claim_stake_farm_rewards.rs index 14aa23da7..e2ba49fe4 100644 --- a/farm-staking/farm-staking/src/claim_stake_farm_rewards.rs +++ b/farm-staking/farm-staking/src/claim_stake_farm_rewards.rs @@ -82,10 +82,10 @@ pub trait ClaimStakeFarmRewardsModule: virtual_farm_token.payment.amount = new_amount.clone(); virtual_farm_token.attributes.current_farm_amount = new_amount; - - self.set_farm_supply_for_current_week(&claim_result.storage_cache.farm_token_supply); } + self.set_farm_supply_for_current_week(&claim_result.storage_cache.farm_token_supply); + self.update_energy_and_progress(&original_caller); let new_farm_token_nonce = self.send().esdt_nft_create_compact( From f668405802716a1995882d3fffbf39d175fd24b6 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Thu, 1 Aug 2024 13:52:54 +0300 Subject: [PATCH 02/12] farm supply on claim fix for farm with locked rew --- dex/farm-with-locked-rewards/src/lib.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index 84d7dc7f4..e03cb80fe 100644 --- a/dex/farm-with-locked-rewards/src/lib.rs +++ b/dex/farm-with-locked-rewards/src/lib.rs @@ -127,30 +127,19 @@ pub trait Farm: self.migrate_old_farm_positions(&orig_caller); - let payments = self.call_value().all_esdt_transfers().clone_value(); - let base_claim_rewards_result = - self.claim_rewards_base::>(orig_caller.clone(), payments); - let output_farm_token_payment = base_claim_rewards_result.new_farm_token.payment.clone(); - self.send_payment_non_zero(&caller, &output_farm_token_payment); + let claim_rewards_result = self.claim_rewards::>(orig_caller.clone()); - let rewards_payment = base_claim_rewards_result.rewards; + self.send_payment_non_zero(&caller, &claim_rewards_result.new_farm_token); + + let rewards_payment = claim_rewards_result.rewards; let locked_rewards_payment = self.send_to_lock_contract_non_zero( rewards_payment.token_identifier, rewards_payment.amount, caller, - orig_caller.clone(), - ); - - self.emit_claim_rewards_event::<_, FarmTokenAttributes>( - &orig_caller, - base_claim_rewards_result.context, - base_claim_rewards_result.new_farm_token, - locked_rewards_payment.clone(), - base_claim_rewards_result.created_with_merge, - base_claim_rewards_result.storage_cache, + orig_caller, ); - (output_farm_token_payment, locked_rewards_payment).into() + (claim_rewards_result.new_farm_token, locked_rewards_payment).into() } #[payable("*")] From a907b89b64f9efdeebebb8a5144c9a9b5fc4cd0e Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 11:34:22 +0300 Subject: [PATCH 03/12] add rewards aggregation in merge endpoints --- dex/farm-with-locked-rewards/src/lib.rs | 2 ++ dex/farm/src/base_functions.rs | 7 +++++++ dex/farm/src/lib.rs | 2 ++ .../src/claim_only_boosted_staking_rewards.rs | 1 + farm-staking/farm-staking/src/custom_rewards.rs | 4 ++++ farm-staking/farm-staking/src/lib.rs | 8 ++++++++ farm-staking/farm-staking/src/unbond_farm.rs | 8 ++++++-- 7 files changed, 30 insertions(+), 2 deletions(-) diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index e03cb80fe..972ddbbd7 100644 --- a/dex/farm-with-locked-rewards/src/lib.rs +++ b/dex/farm-with-locked-rewards/src/lib.rs @@ -227,6 +227,7 @@ pub trait Farm: } let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); NoMintWrapper::::generate_aggregated_rewards(self, &mut storage_cache); let boosted_rewards = self.claim_only_boosted_payment(user); @@ -265,6 +266,7 @@ pub trait Farm: require!(percentage <= MAX_PERCENT, "Invalid percentage"); let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); NoMintWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.boosted_yields_rewards_percentage().set(percentage); diff --git a/dex/farm/src/base_functions.rs b/dex/farm/src/base_functions.rs index d6455a2b7..dad01984e 100644 --- a/dex/farm/src/base_functions.rs +++ b/dex/farm/src/base_functions.rs @@ -192,6 +192,13 @@ pub trait BaseFunctionsModule: FC::check_and_update_user_farm_position(self, orig_caller, &payments); + let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); + + FC::generate_aggregated_rewards(self, &mut storage_cache); + + self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); + self.merge_from_payments_and_burn(payments, &token_mapper) } diff --git a/dex/farm/src/lib.rs b/dex/farm/src/lib.rs index 211b05e02..aeabcaaa0 100644 --- a/dex/farm/src/lib.rs +++ b/dex/farm/src/lib.rs @@ -229,6 +229,7 @@ pub trait Farm: } let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); Wrapper::::generate_aggregated_rewards(self, &mut storage_cache); let boosted_rewards = self.claim_only_boosted_payment(user); @@ -266,6 +267,7 @@ pub trait Farm: require!(percentage <= MAX_PERCENT, "Invalid percentage"); let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); Wrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.boosted_yields_rewards_percentage().set(percentage); diff --git a/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs b/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs index 79d433dfe..4969f3ddb 100644 --- a/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs +++ b/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs @@ -42,6 +42,7 @@ pub trait ClaimOnlyBoostedStakingRewardsModule: } let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); let boosted_rewards = self.claim_only_boosted_payment(user); diff --git a/farm-staking/farm-staking/src/custom_rewards.rs b/farm-staking/farm-staking/src/custom_rewards.rs index 4d07dd5a4..024b8c5e2 100644 --- a/farm-staking/farm-staking/src/custom_rewards.rs +++ b/farm-staking/farm-staking/src/custom_rewards.rs @@ -51,6 +51,7 @@ pub trait CustomRewardsModule: self.require_caller_has_admin_permissions(); let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); let reward_capacity_mapper = self.reward_capacity(); @@ -80,6 +81,7 @@ pub trait CustomRewardsModule: self.require_caller_has_admin_permissions(); let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.produce_rewards_enabled().set(false); } @@ -90,6 +92,7 @@ pub trait CustomRewardsModule: require!(per_block_amount != 0, "Amount cannot be zero"); let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.per_block_reward_amount().set(&per_block_amount); } @@ -100,6 +103,7 @@ pub trait CustomRewardsModule: require!(max_apr != 0, "Max APR cannot be zero"); let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.max_annual_percentage_rewards().set(&max_apr); } diff --git a/farm-staking/farm-staking/src/lib.rs b/farm-staking/farm-staking/src/lib.rs index f783c7831..9cf4b1228 100644 --- a/farm-staking/farm-staking/src/lib.rs +++ b/farm-staking/farm-staking/src/lib.rs @@ -144,6 +144,13 @@ pub trait FarmStaking: FC::check_and_update_user_farm_position(self, orig_caller, &payments); + let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); + + FC::generate_aggregated_rewards(self, &mut storage_cache); + + self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); + self.merge_from_payments_and_burn(payments, &token_mapper) } @@ -153,6 +160,7 @@ pub trait FarmStaking: require!(percentage <= MAX_PERCENT, "Invalid percentage"); let mut storage_cache = StorageCache::new(self); + self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.boosted_yields_rewards_percentage().set(percentage); diff --git a/farm-staking/farm-staking/src/unbond_farm.rs b/farm-staking/farm-staking/src/unbond_farm.rs index 7e85a2a2c..ec2044897 100644 --- a/farm-staking/farm-staking/src/unbond_farm.rs +++ b/farm-staking/farm-staking/src/unbond_farm.rs @@ -1,8 +1,9 @@ multiversx_sc::imports!(); use contexts::storage_cache::StorageCache; +use farm_base_impl::base_traits_impl::FarmContract; -use crate::token_attributes::UnbondSftAttributes; +use crate::{base_impl_wrapper::FarmStakingWrapper, token_attributes::UnbondSftAttributes}; #[multiversx_sc::module] pub trait UnbondFarmModule: @@ -32,7 +33,7 @@ pub trait UnbondFarmModule: #[payable("*")] #[endpoint(unbondFarm)] fn unbond_farm(&self) -> EsdtTokenPayment { - let storage_cache = StorageCache::new(self); + let mut storage_cache = StorageCache::new(self); self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); let farm_token_mapper = self.farm_token(); @@ -48,6 +49,9 @@ pub trait UnbondFarmModule: "Unbond period not over" ); + FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); + self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); + farm_token_mapper.nft_burn(payment.token_nonce, &payment.amount); let caller = self.blockchain().get_caller(); From 3464f856e0ef3cbf573ed71e1848b00fc5245f15 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 12:02:57 +0300 Subject: [PATCH 04/12] remove validation checks from farm staking SC --- .../farm-staking/src/claim_only_boosted_staking_rewards.rs | 1 - farm-staking/farm-staking/src/custom_rewards.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs b/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs index 4969f3ddb..79d433dfe 100644 --- a/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs +++ b/farm-staking/farm-staking/src/claim_only_boosted_staking_rewards.rs @@ -42,7 +42,6 @@ pub trait ClaimOnlyBoostedStakingRewardsModule: } let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); let boosted_rewards = self.claim_only_boosted_payment(user); diff --git a/farm-staking/farm-staking/src/custom_rewards.rs b/farm-staking/farm-staking/src/custom_rewards.rs index 024b8c5e2..4d07dd5a4 100644 --- a/farm-staking/farm-staking/src/custom_rewards.rs +++ b/farm-staking/farm-staking/src/custom_rewards.rs @@ -51,7 +51,6 @@ pub trait CustomRewardsModule: self.require_caller_has_admin_permissions(); let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); let reward_capacity_mapper = self.reward_capacity(); @@ -81,7 +80,6 @@ pub trait CustomRewardsModule: self.require_caller_has_admin_permissions(); let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.produce_rewards_enabled().set(false); } @@ -92,7 +90,6 @@ pub trait CustomRewardsModule: require!(per_block_amount != 0, "Amount cannot be zero"); let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.per_block_reward_amount().set(&per_block_amount); } @@ -103,7 +100,6 @@ pub trait CustomRewardsModule: require!(max_apr != 0, "Max APR cannot be zero"); let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.max_annual_percentage_rewards().set(&max_apr); } From 88dd12bb4fe8184729545f95e4659602dc067819 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 14:10:50 +0300 Subject: [PATCH 05/12] farm with locked rewards unit tests --- .../farm_with_locked_rewards_setup/mod.rs | 87 +++++++ .../tests/farm_with_locked_rewards_test.rs | 233 ++++++++++++++++++ dex/farm/tests/total_farm_position_test.rs | 58 ----- 3 files changed, 320 insertions(+), 58 deletions(-) diff --git a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs index 7125f474b..98c8837ee 100644 --- a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs +++ b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs @@ -8,6 +8,7 @@ use multiversx_sc::{ types::{Address, BigInt, EsdtLocalRole, MultiValueEncoded}, }; use multiversx_sc_scenario::{ + imports::TxTokenTransfer, managed_address, managed_biguint, managed_token_id, rust_biguint, whitebox_legacy::{BlockchainStateWrapper, ContractObjWrapper}, DebugApi, @@ -24,6 +25,7 @@ use farm_with_locked_rewards::Farm; use locking_module::lock_with_energy_module::LockWithEnergyModule; use multiversx_sc_modules::pause::PauseModule; use pausable::{PausableModule, State}; +use rewards::RewardsModule; use sc_whitelist_module::SCWhitelistModule; use simple_lock::locked_token::LockedTokenModule; use week_timekeeping::Epoch; @@ -48,6 +50,11 @@ pub const EPOCHS_IN_YEAR: u64 = 360; pub static LOCK_OPTIONS: &[u64] = &[EPOCHS_IN_YEAR, 2 * EPOCHS_IN_YEAR, 4 * EPOCHS_IN_YEAR]; pub static PENALTY_PERCENTAGES: &[u64] = &[4_000, 6_000, 8_000]; +pub struct NonceAmountPair { + pub nonce: u64, + pub amount: u64, +} + pub struct RawFarmTokenAttributes { pub reward_per_share_bytes: Vec, pub entering_epoch: Epoch, @@ -408,6 +415,37 @@ where result } + pub fn merge_farm_tokens(&mut self, user: &Address, farm_tokens: Vec) { + self.last_farm_token_nonce += 1; + let mut expected_farm_token_amount = 0; + let mut payments = Vec::new(); + for farm_token in farm_tokens { + expected_farm_token_amount += farm_token.amount; + payments.push(TxTokenTransfer { + token_identifier: FARM_TOKEN_ID.to_vec(), + nonce: farm_token.nonce, + value: rust_biguint!(farm_token.amount), + }); + } + + self.b_mock + .execute_esdt_multi_transfer(user, &self.farm_wrapper, &payments, |sc| { + let (out_farm_token, _boosted_rewards) = sc + .merge_farm_tokens_endpoint(OptionalValue::None) + .into_tuple(); + assert_eq!( + out_farm_token.token_identifier, + managed_token_id!(FARM_TOKEN_ID) + ); + assert_eq!(out_farm_token.token_nonce, self.last_farm_token_nonce); + assert_eq!( + out_farm_token.amount, + managed_biguint!(expected_farm_token_amount) + ); + }) + .assert_ok(); + } + pub fn exit_farm(&mut self, user: &Address, farm_token_nonce: u64, exit_farm_amount: u64) { self.b_mock .execute_esdt_transfer( @@ -422,4 +460,53 @@ where ) .assert_ok(); } + + pub fn claim_boosted_rewards_for_user( + &mut self, + owner: &Address, + broker: &Address, + locked_reward_nonce: u64, + ) -> u64 { + self.last_farm_token_nonce += 1; + + let mut result = 0; + self.b_mock + .execute_tx(broker, &self.farm_wrapper, &rust_biguint!(0), |sc| { + let reward_payment = + sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(owner))); + assert_eq!( + reward_payment.token_identifier, + managed_token_id!(LOCKED_REWARD_TOKEN_ID) + ); + assert_eq!(reward_payment.token_nonce, locked_reward_nonce); + + result = reward_payment.amount.to_u64().unwrap(); + }) + .assert_ok(); + + result + } + + pub fn check_farm_token_supply(&mut self, expected_farm_token_supply: u64) { + let b_mock = &mut self.b_mock; + b_mock + .execute_query(&self.farm_wrapper, |sc| { + let actual_farm_supply = sc.farm_token_supply().get(); + assert_eq!( + managed_biguint!(expected_farm_token_supply), + actual_farm_supply + ); + }) + .assert_ok(); + } + + pub fn check_farm_rps(&mut self, expected_amount: u64) { + let b_mock = &mut self.b_mock; + b_mock + .execute_query(&self.farm_wrapper, |sc| { + let current_rps = sc.reward_per_share().get(); + assert_eq!(managed_biguint!(expected_amount), current_rps); + }) + .assert_ok(); + } } diff --git a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs index 8a9fb8793..4668665a4 100644 --- a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs +++ b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs @@ -1,6 +1,8 @@ #![allow(deprecated)] use common_structs::FarmTokenAttributes; +use farm_with_locked_rewards_setup::NonceAmountPair; +use multiversx_sc::codec::Empty; use multiversx_sc_scenario::{managed_address, managed_biguint, rust_biguint, DebugApi}; use simple_lock::locked_token::LockedTokenAttributes; @@ -335,3 +337,234 @@ fn total_farm_position_claim_with_locked_rewards_test() { None, ); } + +#[test] +fn claim_only_boosted_rewards_per_week_test() { + DebugApi::dummy(); + let mut farm_setup = FarmSetup::new( + farm_with_locked_rewards::contract_obj, + energy_factory::contract_obj, + ); + + farm_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + farm_setup.set_boosted_yields_factors(); + farm_setup.b_mock.set_block_epoch(2); + + let temp_user = farm_setup.third_user.clone(); + + // first user enter farm + let farm_in_amount = 100_000_000; + let first_user = farm_setup.first_user.clone(); + farm_setup.set_user_energy(&first_user, 1_000, 2, 1); + farm_setup.enter_farm(&first_user, farm_in_amount); + + farm_setup.check_farm_token_supply(farm_in_amount); + farm_setup.check_farm_rps(0u64); + + farm_setup.b_mock.set_block_nonce(10); + farm_setup.b_mock.set_block_epoch(6); + farm_setup.set_user_energy(&first_user, 1_000, 6, 1); + farm_setup.set_user_energy(&temp_user, 1, 6, 1); + farm_setup.enter_farm(&temp_user, 1); + farm_setup.exit_farm(&temp_user, 2, 1); + + farm_setup.check_farm_rps(75_000_000u64); + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 13, 1); + farm_setup.b_mock.set_block_nonce(20); + farm_setup.b_mock.set_block_epoch(13); + + let boosted_rewards = 2_500; + let second_week_received_reward_amt = + farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user, 1); + + assert_eq!(second_week_received_reward_amt, boosted_rewards); + farm_setup.check_farm_rps(150_000_000u64); + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 15, 1); + farm_setup.b_mock.set_block_nonce(30); + farm_setup.b_mock.set_block_epoch(15); + let third_week_received_reward_amt = + farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user, 1); + + assert_eq!(third_week_received_reward_amt, boosted_rewards); + farm_setup.check_farm_rps(225_000_000u64); + + farm_setup.b_mock.check_nft_balance::( + &first_user, + LOCKED_REWARD_TOKEN_ID, + 1, + &rust_biguint!(boosted_rewards * 2), + None, + ); +} + +#[test] +fn claim_rewards_per_week_test() { + DebugApi::dummy(); + let mut farm_setup = FarmSetup::new( + farm_with_locked_rewards::contract_obj, + energy_factory::contract_obj, + ); + + farm_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + farm_setup.set_boosted_yields_factors(); + farm_setup.b_mock.set_block_epoch(2); + + let temp_user = farm_setup.third_user.clone(); + + // first user enter farm + let farm_in_amount = 100_000_000; + let first_user = farm_setup.first_user.clone(); + farm_setup.set_user_energy(&first_user, 1_000, 2, 1); + farm_setup.enter_farm(&first_user, farm_in_amount); + + farm_setup.check_farm_token_supply(farm_in_amount); + farm_setup.check_farm_rps(0u64); + + farm_setup.b_mock.set_block_nonce(10); + farm_setup.b_mock.set_block_epoch(6); + farm_setup.set_user_energy(&first_user, 1_000, 6, 1); + farm_setup.set_user_energy(&temp_user, 1, 6, 1); + farm_setup.enter_farm(&temp_user, 1); + farm_setup.exit_farm(&temp_user, 2, 1); + + farm_setup.check_farm_rps(75_000_000u64); + let base_rewards_per_week = 7_500; + let boosted_rewards_per_week = 2_500; + let total_rewards_per_week = base_rewards_per_week + boosted_rewards_per_week; + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 13, 1); + farm_setup.b_mock.set_block_nonce(20); + farm_setup.b_mock.set_block_epoch(13); + + let second_week_received_reward_amt = farm_setup.claim_rewards(&first_user, 1, farm_in_amount); + + assert_eq!( + second_week_received_reward_amt, + total_rewards_per_week + base_rewards_per_week + ); + farm_setup.check_farm_rps(150_000_000u64); + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 15, 1); + farm_setup.b_mock.set_block_nonce(30); + farm_setup.b_mock.set_block_epoch(15); + let third_week_received_reward_amt = farm_setup.claim_rewards(&first_user, 3, farm_in_amount); + + assert_eq!(third_week_received_reward_amt, total_rewards_per_week); + farm_setup.check_farm_rps(225_000_000u64); + + farm_setup.b_mock.check_nft_balance::( + &first_user, + LOCKED_REWARD_TOKEN_ID, + 1, + &rust_biguint!(total_rewards_per_week * 2 + base_rewards_per_week), + None, + ); +} + +#[test] +fn merge_farm_position_per_week_test() { + DebugApi::dummy(); + let mut farm_setup = FarmSetup::new( + farm_with_locked_rewards::contract_obj, + energy_factory::contract_obj, + ); + + farm_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + farm_setup.set_boosted_yields_factors(); + farm_setup.b_mock.set_block_epoch(2); + + let temp_user = farm_setup.third_user.clone(); + + // first user enter farm + let farm_in_amount = 10_000_000; + let first_user = farm_setup.first_user.clone(); + farm_setup.set_user_energy(&first_user, 1_000, 2, 1); + + // User creates 3 different positions + farm_setup.enter_farm(&first_user, farm_in_amount); + farm_setup.enter_farm(&first_user, farm_in_amount); + farm_setup.enter_farm(&first_user, farm_in_amount); + + farm_setup.check_farm_token_supply(farm_in_amount * 3); + farm_setup.check_farm_rps(0u64); + + farm_setup.b_mock.set_block_nonce(10); + farm_setup.b_mock.set_block_epoch(6); + farm_setup.set_user_energy(&first_user, 1_000, 6, 1); + farm_setup.set_user_energy(&temp_user, 1, 6, 1); + farm_setup.enter_farm(&temp_user, 1); + farm_setup.exit_farm(&temp_user, 4, 1); + + farm_setup.check_farm_rps(250_000_000u64); + let boosted_rewards_per_week = 2_500; + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 13, 1); + farm_setup.b_mock.set_block_nonce(20); + farm_setup.b_mock.set_block_epoch(13); + + let mut payments = vec![ + NonceAmountPair { + nonce: 1, + amount: farm_in_amount, + }, + NonceAmountPair { + nonce: 2, + amount: farm_in_amount, + }, + ]; + + farm_setup.merge_farm_tokens(&first_user, payments); + + farm_setup.check_farm_token_supply(farm_in_amount * 3); + farm_setup.check_farm_rps(500_000_000u64); + farm_setup.b_mock.check_nft_balance::( + &first_user, + LOCKED_REWARD_TOKEN_ID, + 1, + &rust_biguint!(boosted_rewards_per_week), + None, + ); + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 15, 1); + farm_setup.b_mock.set_block_nonce(30); + farm_setup.b_mock.set_block_epoch(15); + + payments = vec![ + NonceAmountPair { + nonce: 3, + amount: farm_in_amount, + }, + NonceAmountPair { + nonce: 5, + amount: farm_in_amount * 2, + }, + ]; + + farm_setup.merge_farm_tokens(&first_user, payments); + + farm_setup.check_farm_token_supply(farm_in_amount * 3); + farm_setup.check_farm_rps(750_000_000u64); + + farm_setup.b_mock.check_nft_balance::( + &first_user, + FARM_TOKEN_ID, + 6, + &rust_biguint!(farm_in_amount * 3), + None, + ); + farm_setup.b_mock.check_nft_balance::( + &first_user, + LOCKED_REWARD_TOKEN_ID, + 1, + &rust_biguint!(boosted_rewards_per_week * 2), + None, + ); +} diff --git a/dex/farm/tests/total_farm_position_test.rs b/dex/farm/tests/total_farm_position_test.rs index e0819d411..b7ca1be7b 100644 --- a/dex/farm/tests/total_farm_position_test.rs +++ b/dex/farm/tests/total_farm_position_test.rs @@ -1193,61 +1193,3 @@ fn total_farm_position_through_simple_lock_test() { &rust_biguint!(first_received_reward_amt), ); } - -#[test] -fn claim_only_boosted_rewards_per_week_test() { - DebugApi::dummy(); - let mut farm_setup = MultiUserFarmSetup::new( - farm::contract_obj, - energy_factory_mock::contract_obj, - energy_update::contract_obj, - ); - - farm_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); - farm_setup.set_boosted_yields_factors(); - farm_setup.b_mock.set_block_epoch(2); - - let temp_user = farm_setup.third_user.clone(); - - // first user enter farm - let farm_in_amount = 100_000_000; - let first_user = farm_setup.first_user.clone(); - farm_setup.set_user_energy(&first_user, 1_000, 2, 1); - farm_setup.enter_farm(&first_user, farm_in_amount); - - farm_setup.check_farm_token_supply(farm_in_amount); - - farm_setup.b_mock.set_block_nonce(10); - farm_setup.b_mock.set_block_epoch(6); - farm_setup.set_user_energy(&first_user, 1_000, 6, 1); - farm_setup.set_user_energy(&temp_user, 1, 6, 1); - farm_setup.enter_farm(&temp_user, 1); - farm_setup.exit_farm(&temp_user, 2, 1); - - // advance 1 week - farm_setup.set_user_energy(&first_user, 1_000, 13, 1); - farm_setup.b_mock.set_block_nonce(20); - farm_setup.b_mock.set_block_epoch(13); - - let boosted_rewards = 2_500; - let second_week_received_reward_amt = - farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user); - - assert_eq!(second_week_received_reward_amt, boosted_rewards); - - // advance 1 week - farm_setup.set_user_energy(&first_user, 1_000, 15, 1); - farm_setup.b_mock.set_block_nonce(30); - farm_setup.b_mock.set_block_epoch(15); - let third_week_received_reward_amt = - farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user); - - // Should be equal to half base generated rewards + full boosted generated rewards - assert_eq!(third_week_received_reward_amt, boosted_rewards); - - farm_setup.b_mock.check_esdt_balance( - &first_user, - REWARD_TOKEN_ID, - &rust_biguint!(boosted_rewards * 2), - ); -} From 602b696735ab9ce1bda52049113e2bced3c94efe Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 16:54:34 +0300 Subject: [PATCH 06/12] farm staking unit tests --- .../tests/farm_staking_energy_test.rs | 303 ++++++++++++++++++ .../tests/farm_staking_setup/mod.rs | 67 ++++ 2 files changed, 370 insertions(+) diff --git a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs index 1274be166..e71f0db34 100644 --- a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs @@ -1427,3 +1427,306 @@ fn boosted_rewards_config_change_test() { && first_user_total_rewards == third_user_total_rewards ); } + +#[test] +fn claim_only_boosted_rewards_per_week_test() { + DebugApi::dummy(); + let mut fs_setup = + FarmStakingSetup::new(farm_staking::contract_obj, energy_factory::contract_obj); + + fs_setup.set_boosted_yields_factors(); + fs_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + + let first_user = fs_setup.user_address.clone(); + let farm_in_amount = 100_000_000; + + fs_setup.set_user_energy(&first_user, 10_000, 0, 10); + fs_setup.stake_farm(&first_user, farm_in_amount, &[], 1, 0, 0); + + fs_setup.check_farm_token_supply(farm_in_amount); + fs_setup.check_farm_rps(0u64); + + fs_setup.b_mock.set_block_nonce(100); + fs_setup.b_mock.set_block_epoch(6); + fs_setup.set_user_energy(&first_user, 1_000, 6, 1); + + // Reset user balance + fs_setup + .b_mock + .set_esdt_balance(&first_user, FARMING_TOKEN_ID, &rust_biguint!(0)); + + // random user tx to collect rewards + let rand_user = fs_setup.b_mock.create_user_account(&rust_biguint!(0)); + fs_setup.b_mock.set_esdt_balance( + &rand_user, + FARMING_TOKEN_ID, + &rust_biguint!(USER_TOTAL_RIDE_TOKENS), + ); + + fs_setup.set_user_energy(&rand_user, 1, 6, 1); + fs_setup.stake_farm(&rand_user, 10, &[], 2, 3_000_000u64, 0); + fs_setup.unstake_farm_no_checks(&rand_user, 10, 2); + + let farm_rps_increase = 3_000_000u64; + let mut current_farm_rps = 0; + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 13, 1); + fs_setup.b_mock.set_block_nonce(200); + fs_setup.b_mock.set_block_epoch(13); + + let boosted_rewards_for_week = 100; + fs_setup.claim_boosted_rewards_for_user( + &first_user, + &first_user, + boosted_rewards_for_week, + &rust_biguint!(boosted_rewards_for_week), + ); + + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 15, 1); + fs_setup.b_mock.set_block_nonce(300); + fs_setup.b_mock.set_block_epoch(15); + fs_setup.claim_boosted_rewards_for_user( + &first_user, + &first_user, + boosted_rewards_for_week, + &rust_biguint!(boosted_rewards_for_week * 2), + ); + + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + fs_setup.b_mock.check_esdt_balance( + &first_user, + REWARD_TOKEN_ID, + &rust_biguint!(boosted_rewards_for_week * 2), + ); + + let expected_attributes = StakingFarmTokenAttributes:: { + reward_per_share: managed_biguint!(0), + compounded_reward: managed_biguint!(0), + current_farm_amount: managed_biguint!(farm_in_amount), + original_owner: managed_address!(&first_user), + }; + + fs_setup.b_mock.check_nft_balance( + &first_user, + FARM_TOKEN_ID, + 1, + &rust_biguint!(farm_in_amount), + Some(&expected_attributes), + ); +} + +#[test] +fn claim_rewards_per_week_test() { + DebugApi::dummy(); + let mut fs_setup = + FarmStakingSetup::new(farm_staking::contract_obj, energy_factory::contract_obj); + + fs_setup.set_boosted_yields_factors(); + fs_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + + let first_user = fs_setup.user_address.clone(); + let farm_in_amount = 100_000_000; + + fs_setup.set_user_energy(&first_user, 10_000, 0, 10); + fs_setup.stake_farm(&first_user, farm_in_amount, &[], 1, 0, 0); + + fs_setup.check_farm_token_supply(farm_in_amount); + fs_setup.check_farm_rps(0u64); + + fs_setup.b_mock.set_block_nonce(100); + fs_setup.b_mock.set_block_epoch(6); + fs_setup.set_user_energy(&first_user, 1_000, 6, 1); + + // Reset user balance + fs_setup + .b_mock + .set_esdt_balance(&first_user, FARMING_TOKEN_ID, &rust_biguint!(0)); + + // random user tx to collect rewards + let rand_user = fs_setup.b_mock.create_user_account(&rust_biguint!(0)); + fs_setup.b_mock.set_esdt_balance( + &rand_user, + FARMING_TOKEN_ID, + &rust_biguint!(USER_TOTAL_RIDE_TOKENS), + ); + + fs_setup.set_user_energy(&rand_user, 1, 6, 1); + fs_setup.stake_farm(&rand_user, 10, &[], 2, 3_000_000u64, 0); + fs_setup.unstake_farm_no_checks(&rand_user, 10, 2); + + let farm_rps_increase = 3_000_000u64; + let mut current_farm_rps = 0; + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 13, 1); + fs_setup.b_mock.set_block_nonce(200); + fs_setup.b_mock.set_block_epoch(13); + + let base_rewards_for_week = 300; + let boosted_rewards_for_week = 100; + + current_farm_rps += farm_rps_increase; + let mut user_rewards_balance = base_rewards_for_week * 2 + boosted_rewards_for_week; + fs_setup.claim_rewards( + &first_user, + farm_in_amount, + 1, + base_rewards_for_week * 2 + boosted_rewards_for_week, + &rust_biguint!(user_rewards_balance), + &rust_biguint!(user_rewards_balance), // user balance has bet set to 0 at the start + 4, + current_farm_rps, + ); + + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 15, 1); + fs_setup.b_mock.set_block_nonce(300); + fs_setup.b_mock.set_block_epoch(15); + + current_farm_rps += farm_rps_increase; + user_rewards_balance += base_rewards_for_week + boosted_rewards_for_week; + fs_setup.claim_rewards( + &first_user, + farm_in_amount, + 4, + base_rewards_for_week + boosted_rewards_for_week, + &rust_biguint!(user_rewards_balance), + &rust_biguint!(user_rewards_balance), + 5, + current_farm_rps, + ); + + fs_setup.check_farm_rps(current_farm_rps); + + fs_setup.b_mock.check_esdt_balance( + &first_user, + REWARD_TOKEN_ID, + &rust_biguint!(user_rewards_balance), + ); +} + +#[test] +fn merge_farm_position_per_week_test() { + DebugApi::dummy(); + let mut fs_setup = + FarmStakingSetup::new(farm_staking::contract_obj, energy_factory::contract_obj); + + fs_setup.set_boosted_yields_factors(); + fs_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + + let first_user = fs_setup.user_address.clone(); + let farm_in_amount = 100_000_000; + + fs_setup.set_user_energy(&first_user, 10_000, 0, 10); + fs_setup.stake_farm(&first_user, farm_in_amount, &[], 1, 0, 0); + fs_setup.stake_farm(&first_user, farm_in_amount, &[], 2, 0, 0); + fs_setup.stake_farm(&first_user, farm_in_amount, &[], 3, 0, 0); + + fs_setup.check_farm_token_supply(farm_in_amount * 3); + fs_setup.check_farm_rps(0u64); + + fs_setup.b_mock.set_block_nonce(100); + fs_setup.b_mock.set_block_epoch(6); + fs_setup.set_user_energy(&first_user, 1_000, 6, 1); + + // Reset user balance + fs_setup + .b_mock + .set_esdt_balance(&first_user, FARMING_TOKEN_ID, &rust_biguint!(0)); + + // random user tx to collect rewards + let rand_user = fs_setup.b_mock.create_user_account(&rust_biguint!(0)); + fs_setup.b_mock.set_esdt_balance( + &rand_user, + FARMING_TOKEN_ID, + &rust_biguint!(USER_TOTAL_RIDE_TOKENS), + ); + + fs_setup.set_user_energy(&rand_user, 1, 6, 1); + fs_setup.stake_farm(&rand_user, 10, &[], 4, 3_500_000u64, 0); + fs_setup.unstake_farm_no_checks(&rand_user, 10, 4); + + let farm_rps_increase = 3_500_000u64; + let mut current_farm_rps = 0; + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 13, 1); + fs_setup.b_mock.set_block_nonce(200); + fs_setup.b_mock.set_block_epoch(13); + + let boosted_rewards_for_week = 350u64; + + current_farm_rps += farm_rps_increase; + let mut user_rewards_balance = boosted_rewards_for_week; + + let mut payments = vec![ + NonceAmountPair { + nonce: 1, + amount: farm_in_amount, + }, + NonceAmountPair { + nonce: 2, + amount: farm_in_amount, + }, + ]; + fs_setup.merge_farm_tokens(&first_user, payments, 6); + + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 15, 1); + fs_setup.b_mock.set_block_nonce(300); + fs_setup.b_mock.set_block_epoch(15); + + current_farm_rps += farm_rps_increase; + user_rewards_balance += boosted_rewards_for_week; + + payments = vec![ + NonceAmountPair { + nonce: 3, + amount: farm_in_amount, + }, + NonceAmountPair { + nonce: 6, + amount: farm_in_amount * 2, + }, + ]; + fs_setup.merge_farm_tokens(&first_user, payments, 7); + + fs_setup.check_farm_rps(current_farm_rps); + + fs_setup.b_mock.check_esdt_balance( + &first_user, + REWARD_TOKEN_ID, + &rust_biguint!(user_rewards_balance), + ); + + let expected_attributes = StakingFarmTokenAttributes:: { + reward_per_share: managed_biguint!(0), + compounded_reward: managed_biguint!(0), + current_farm_amount: managed_biguint!(farm_in_amount * 3), + original_owner: managed_address!(&first_user), + }; + + fs_setup.b_mock.check_nft_balance( + &first_user, + FARM_TOKEN_ID, + 7, + &rust_biguint!(farm_in_amount * 3), + Some(&expected_attributes), + ); +} diff --git a/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs b/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs index 90513e2d6..45151e926 100644 --- a/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs +++ b/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs @@ -25,6 +25,7 @@ use farm_staking::unstake_farm::UnstakeFarmModule; use farm_staking::*; use farm_token::FarmTokenModule; use pausable::{PausableModule, State}; +use rewards::RewardsModule; pub static REWARD_TOKEN_ID: &[u8] = b"RIDE-abcdef"; // reward token ID pub static FARMING_TOKEN_ID: &[u8] = b"RIDE-abcdef"; // farming token ID @@ -46,6 +47,11 @@ pub const MIN_FARM_AMOUNT_FOR_BOOSTED_YIELDS: u64 = 1; pub const WITHDRAW_AMOUNT_TOO_HIGH: &str = "Withdraw amount is higher than the remaining uncollected rewards!"; +pub struct NonceAmountPair { + pub nonce: u64, + pub amount: u64, +} + pub struct FarmStakingSetup where FarmObjBuilder: 'static + Copy + Fn() -> farm_staking::ContractObj, @@ -509,6 +515,24 @@ where ); } + pub fn unstake_farm_no_checks( + &mut self, + user: &Address, + farm_token_amount: u64, + farm_token_nonce: u64, + ) { + let _ = self.b_mock.execute_esdt_transfer( + user, + &self.farm_wrapper, + FARM_TOKEN_ID, + farm_token_nonce, + &rust_biguint!(farm_token_amount), + |sc| { + sc.unstake_farm(OptionalValue::None); + }, + ); + } + pub fn unbond_farm( &mut self, farm_token_nonce: u64, @@ -542,6 +566,40 @@ where ); } + pub fn merge_farm_tokens( + &mut self, + user: &Address, + farm_tokens: Vec, + expected_farm_token_nonce: u64, + ) { + let mut expected_farm_token_amount = 0; + let mut payments = Vec::new(); + for farm_token in farm_tokens { + expected_farm_token_amount += farm_token.amount; + payments.push(TxTokenTransfer { + token_identifier: FARM_TOKEN_ID.to_vec(), + nonce: farm_token.nonce, + value: rust_biguint!(farm_token.amount), + }); + } + + self.b_mock + .execute_esdt_multi_transfer(user, &self.farm_wrapper, &payments, |sc| { + let (out_farm_token, _boosted_rewards) = + sc.merge_farm_tokens_endpoint().into_tuple(); + assert_eq!( + out_farm_token.token_identifier, + managed_token_id!(FARM_TOKEN_ID) + ); + assert_eq!(out_farm_token.token_nonce, expected_farm_token_nonce); + assert_eq!( + out_farm_token.amount, + managed_biguint!(expected_farm_token_amount) + ); + }) + .assert_ok(); + } + pub fn check_farm_token_supply(&mut self, expected_farm_token_supply: u64) { self.b_mock .execute_query(&self.farm_wrapper, |sc| { @@ -554,6 +612,15 @@ where .assert_ok(); } + pub fn check_farm_rps(&mut self, expected_amount: u64) { + self.b_mock + .execute_query(&self.farm_wrapper, |sc| { + let current_rps = sc.reward_per_share().get(); + assert_eq!(managed_biguint!(expected_amount), current_rps); + }) + .assert_ok(); + } + pub fn check_rewards_capacity(&mut self, expected_farm_token_supply: u64) { self.b_mock .execute_query(&self.farm_wrapper, |sc| { From b147571ad81bca791d612fd6247af4c54edb1640 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 18:01:55 +0300 Subject: [PATCH 07/12] farm staking unbond fix + unit test --- farm-staking/farm-staking/src/unbond_farm.rs | 2 + .../tests/farm_staking_energy_test.rs | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/farm-staking/farm-staking/src/unbond_farm.rs b/farm-staking/farm-staking/src/unbond_farm.rs index ec2044897..de296e4c3 100644 --- a/farm-staking/farm-staking/src/unbond_farm.rs +++ b/farm-staking/farm-staking/src/unbond_farm.rs @@ -49,6 +49,8 @@ pub trait UnbondFarmModule: "Unbond period not over" ); + let current_week = self.get_current_week(); + self.perform_weekly_update(current_week); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); diff --git a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs index e71f0db34..dee471634 100644 --- a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs @@ -1730,3 +1730,95 @@ fn merge_farm_position_per_week_test() { Some(&expected_attributes), ); } + +#[test] +fn unbond_farm_position_per_week_test() { + DebugApi::dummy(); + let mut fs_setup = + FarmStakingSetup::new(farm_staking::contract_obj, energy_factory::contract_obj); + + fs_setup.set_boosted_yields_factors(); + fs_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + + let first_user = fs_setup.user_address.clone(); + let farm_in_amount = 100_000_000; + + fs_setup.set_user_energy(&first_user, 10_000, 0, 10); + fs_setup.stake_farm(&first_user, farm_in_amount, &[], 1, 0, 0); + fs_setup.check_farm_token_supply(farm_in_amount); + + fs_setup.unstake_farm_no_checks(&first_user, farm_in_amount / 2, 1); + fs_setup.check_farm_token_supply(farm_in_amount / 2); + + fs_setup.check_farm_rps(0u64); + + fs_setup.b_mock.set_block_nonce(100); + fs_setup.b_mock.set_block_epoch(6); + fs_setup.set_user_energy(&first_user, 1_000, 6, 1); + + // Reset user balance + fs_setup + .b_mock + .set_esdt_balance(&first_user, FARMING_TOKEN_ID, &rust_biguint!(0)); + + let mut current_farm_rps = 0; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 13, 1); + fs_setup.b_mock.set_block_nonce(200); + fs_setup.b_mock.set_block_epoch(13); + + fs_setup.unbond_farm( + 2, + farm_in_amount / 2, + farm_in_amount / 2, + farm_in_amount / 2, + ); + + let mut user_balance = farm_in_amount / 2; + fs_setup + .b_mock + .check_esdt_balance(&first_user, REWARD_TOKEN_ID, &rust_biguint!(user_balance)); + + let farm_rps_increase = 6_000_000u64; + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 15, 1); + fs_setup.b_mock.set_block_nonce(300); + fs_setup.b_mock.set_block_epoch(15); + + let boosted_rewards_for_week = 100; + user_balance += boosted_rewards_for_week; + fs_setup.claim_boosted_rewards_for_user( + &first_user, + &first_user, + boosted_rewards_for_week, + &rust_biguint!(user_balance), + ); + + // User should have the following balance: unstake_amount + boosted_rewards_week_2 + fs_setup + .b_mock + .check_esdt_balance(&first_user, REWARD_TOKEN_ID, &rust_biguint!(user_balance)); + + current_farm_rps += farm_rps_increase / 2; //user existed with half position + fs_setup.check_farm_rps(current_farm_rps); + + let expected_attributes = StakingFarmTokenAttributes:: { + reward_per_share: managed_biguint!(0), + compounded_reward: managed_biguint!(0), + current_farm_amount: managed_biguint!(farm_in_amount), + original_owner: managed_address!(&first_user), + }; + + fs_setup.b_mock.check_nft_balance( + &first_user, + FARM_TOKEN_ID, + 1, + &rust_biguint!(farm_in_amount / 2), + Some(&expected_attributes), + ); +} From a28f0a4381bdaf82ae58c3c759a2ff09e39c7bdb Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 18:12:39 +0300 Subject: [PATCH 08/12] revert farm staking unbond changes --- farm-staking/farm-staking/src/unbond_farm.rs | 11 +-- .../tests/farm_staking_energy_test.rs | 92 ------------------- 2 files changed, 2 insertions(+), 101 deletions(-) diff --git a/farm-staking/farm-staking/src/unbond_farm.rs b/farm-staking/farm-staking/src/unbond_farm.rs index de296e4c3..0e661616e 100644 --- a/farm-staking/farm-staking/src/unbond_farm.rs +++ b/farm-staking/farm-staking/src/unbond_farm.rs @@ -1,9 +1,8 @@ multiversx_sc::imports!(); use contexts::storage_cache::StorageCache; -use farm_base_impl::base_traits_impl::FarmContract; -use crate::{base_impl_wrapper::FarmStakingWrapper, token_attributes::UnbondSftAttributes}; +use crate::token_attributes::UnbondSftAttributes; #[multiversx_sc::module] pub trait UnbondFarmModule: @@ -17,7 +16,6 @@ pub trait UnbondFarmModule: + pausable::PausableModule + permissions_module::PermissionsModule + multiversx_sc_modules::default_issue_callbacks::DefaultIssueCallbacksModule - + farm_base_impl::base_farm_init::BaseFarmInitModule + farm_base_impl::base_farm_validation::BaseFarmValidationModule + utils::UtilsModule + farm_boosted_yields::FarmBoostedYieldsModule @@ -33,7 +31,7 @@ pub trait UnbondFarmModule: #[payable("*")] #[endpoint(unbondFarm)] fn unbond_farm(&self) -> EsdtTokenPayment { - let mut storage_cache = StorageCache::new(self); + let storage_cache = StorageCache::new(self); self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); let farm_token_mapper = self.farm_token(); @@ -49,11 +47,6 @@ pub trait UnbondFarmModule: "Unbond period not over" ); - let current_week = self.get_current_week(); - self.perform_weekly_update(current_week); - FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); - self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); - farm_token_mapper.nft_burn(payment.token_nonce, &payment.amount); let caller = self.blockchain().get_caller(); diff --git a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs index dee471634..e71f0db34 100644 --- a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs @@ -1730,95 +1730,3 @@ fn merge_farm_position_per_week_test() { Some(&expected_attributes), ); } - -#[test] -fn unbond_farm_position_per_week_test() { - DebugApi::dummy(); - let mut fs_setup = - FarmStakingSetup::new(farm_staking::contract_obj, energy_factory::contract_obj); - - fs_setup.set_boosted_yields_factors(); - fs_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); - - let first_user = fs_setup.user_address.clone(); - let farm_in_amount = 100_000_000; - - fs_setup.set_user_energy(&first_user, 10_000, 0, 10); - fs_setup.stake_farm(&first_user, farm_in_amount, &[], 1, 0, 0); - fs_setup.check_farm_token_supply(farm_in_amount); - - fs_setup.unstake_farm_no_checks(&first_user, farm_in_amount / 2, 1); - fs_setup.check_farm_token_supply(farm_in_amount / 2); - - fs_setup.check_farm_rps(0u64); - - fs_setup.b_mock.set_block_nonce(100); - fs_setup.b_mock.set_block_epoch(6); - fs_setup.set_user_energy(&first_user, 1_000, 6, 1); - - // Reset user balance - fs_setup - .b_mock - .set_esdt_balance(&first_user, FARMING_TOKEN_ID, &rust_biguint!(0)); - - let mut current_farm_rps = 0; - fs_setup.check_farm_rps(current_farm_rps); - - // advance 1 week - fs_setup.set_user_energy(&first_user, 1_000, 13, 1); - fs_setup.b_mock.set_block_nonce(200); - fs_setup.b_mock.set_block_epoch(13); - - fs_setup.unbond_farm( - 2, - farm_in_amount / 2, - farm_in_amount / 2, - farm_in_amount / 2, - ); - - let mut user_balance = farm_in_amount / 2; - fs_setup - .b_mock - .check_esdt_balance(&first_user, REWARD_TOKEN_ID, &rust_biguint!(user_balance)); - - let farm_rps_increase = 6_000_000u64; - current_farm_rps += farm_rps_increase; - fs_setup.check_farm_rps(current_farm_rps); - - // advance 1 week - fs_setup.set_user_energy(&first_user, 1_000, 15, 1); - fs_setup.b_mock.set_block_nonce(300); - fs_setup.b_mock.set_block_epoch(15); - - let boosted_rewards_for_week = 100; - user_balance += boosted_rewards_for_week; - fs_setup.claim_boosted_rewards_for_user( - &first_user, - &first_user, - boosted_rewards_for_week, - &rust_biguint!(user_balance), - ); - - // User should have the following balance: unstake_amount + boosted_rewards_week_2 - fs_setup - .b_mock - .check_esdt_balance(&first_user, REWARD_TOKEN_ID, &rust_biguint!(user_balance)); - - current_farm_rps += farm_rps_increase / 2; //user existed with half position - fs_setup.check_farm_rps(current_farm_rps); - - let expected_attributes = StakingFarmTokenAttributes:: { - reward_per_share: managed_biguint!(0), - compounded_reward: managed_biguint!(0), - current_farm_amount: managed_biguint!(farm_in_amount), - original_owner: managed_address!(&first_user), - }; - - fs_setup.b_mock.check_nft_balance( - &first_user, - FARM_TOKEN_ID, - 1, - &rust_biguint!(farm_in_amount / 2), - Some(&expected_attributes), - ); -} From ba5aec93b500be7c3b03ce6dbc4e41b1625bb428 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 18:32:56 +0300 Subject: [PATCH 09/12] remove supply fix for merge endpoints --- .../farm_with_locked_rewards_setup/mod.rs | 37 ------ .../tests/farm_with_locked_rewards_test.rs | 103 ---------------- farm-staking/farm-staking/src/lib.rs | 8 -- .../tests/farm_staking_energy_test.rs | 114 ------------------ 4 files changed, 262 deletions(-) diff --git a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs index 98c8837ee..5f6015658 100644 --- a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs +++ b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_setup/mod.rs @@ -8,7 +8,6 @@ use multiversx_sc::{ types::{Address, BigInt, EsdtLocalRole, MultiValueEncoded}, }; use multiversx_sc_scenario::{ - imports::TxTokenTransfer, managed_address, managed_biguint, managed_token_id, rust_biguint, whitebox_legacy::{BlockchainStateWrapper, ContractObjWrapper}, DebugApi, @@ -50,11 +49,6 @@ pub const EPOCHS_IN_YEAR: u64 = 360; pub static LOCK_OPTIONS: &[u64] = &[EPOCHS_IN_YEAR, 2 * EPOCHS_IN_YEAR, 4 * EPOCHS_IN_YEAR]; pub static PENALTY_PERCENTAGES: &[u64] = &[4_000, 6_000, 8_000]; -pub struct NonceAmountPair { - pub nonce: u64, - pub amount: u64, -} - pub struct RawFarmTokenAttributes { pub reward_per_share_bytes: Vec, pub entering_epoch: Epoch, @@ -415,37 +409,6 @@ where result } - pub fn merge_farm_tokens(&mut self, user: &Address, farm_tokens: Vec) { - self.last_farm_token_nonce += 1; - let mut expected_farm_token_amount = 0; - let mut payments = Vec::new(); - for farm_token in farm_tokens { - expected_farm_token_amount += farm_token.amount; - payments.push(TxTokenTransfer { - token_identifier: FARM_TOKEN_ID.to_vec(), - nonce: farm_token.nonce, - value: rust_biguint!(farm_token.amount), - }); - } - - self.b_mock - .execute_esdt_multi_transfer(user, &self.farm_wrapper, &payments, |sc| { - let (out_farm_token, _boosted_rewards) = sc - .merge_farm_tokens_endpoint(OptionalValue::None) - .into_tuple(); - assert_eq!( - out_farm_token.token_identifier, - managed_token_id!(FARM_TOKEN_ID) - ); - assert_eq!(out_farm_token.token_nonce, self.last_farm_token_nonce); - assert_eq!( - out_farm_token.amount, - managed_biguint!(expected_farm_token_amount) - ); - }) - .assert_ok(); - } - pub fn exit_farm(&mut self, user: &Address, farm_token_nonce: u64, exit_farm_amount: u64) { self.b_mock .execute_esdt_transfer( diff --git a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs index 4668665a4..d313c3b6b 100644 --- a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs +++ b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs @@ -1,7 +1,6 @@ #![allow(deprecated)] use common_structs::FarmTokenAttributes; -use farm_with_locked_rewards_setup::NonceAmountPair; use multiversx_sc::codec::Empty; use multiversx_sc_scenario::{managed_address, managed_biguint, rust_biguint, DebugApi}; use simple_lock::locked_token::LockedTokenAttributes; @@ -466,105 +465,3 @@ fn claim_rewards_per_week_test() { None, ); } - -#[test] -fn merge_farm_position_per_week_test() { - DebugApi::dummy(); - let mut farm_setup = FarmSetup::new( - farm_with_locked_rewards::contract_obj, - energy_factory::contract_obj, - ); - - farm_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); - farm_setup.set_boosted_yields_factors(); - farm_setup.b_mock.set_block_epoch(2); - - let temp_user = farm_setup.third_user.clone(); - - // first user enter farm - let farm_in_amount = 10_000_000; - let first_user = farm_setup.first_user.clone(); - farm_setup.set_user_energy(&first_user, 1_000, 2, 1); - - // User creates 3 different positions - farm_setup.enter_farm(&first_user, farm_in_amount); - farm_setup.enter_farm(&first_user, farm_in_amount); - farm_setup.enter_farm(&first_user, farm_in_amount); - - farm_setup.check_farm_token_supply(farm_in_amount * 3); - farm_setup.check_farm_rps(0u64); - - farm_setup.b_mock.set_block_nonce(10); - farm_setup.b_mock.set_block_epoch(6); - farm_setup.set_user_energy(&first_user, 1_000, 6, 1); - farm_setup.set_user_energy(&temp_user, 1, 6, 1); - farm_setup.enter_farm(&temp_user, 1); - farm_setup.exit_farm(&temp_user, 4, 1); - - farm_setup.check_farm_rps(250_000_000u64); - let boosted_rewards_per_week = 2_500; - - // advance 1 week - farm_setup.set_user_energy(&first_user, 1_000, 13, 1); - farm_setup.b_mock.set_block_nonce(20); - farm_setup.b_mock.set_block_epoch(13); - - let mut payments = vec![ - NonceAmountPair { - nonce: 1, - amount: farm_in_amount, - }, - NonceAmountPair { - nonce: 2, - amount: farm_in_amount, - }, - ]; - - farm_setup.merge_farm_tokens(&first_user, payments); - - farm_setup.check_farm_token_supply(farm_in_amount * 3); - farm_setup.check_farm_rps(500_000_000u64); - farm_setup.b_mock.check_nft_balance::( - &first_user, - LOCKED_REWARD_TOKEN_ID, - 1, - &rust_biguint!(boosted_rewards_per_week), - None, - ); - - // advance 1 week - farm_setup.set_user_energy(&first_user, 1_000, 15, 1); - farm_setup.b_mock.set_block_nonce(30); - farm_setup.b_mock.set_block_epoch(15); - - payments = vec![ - NonceAmountPair { - nonce: 3, - amount: farm_in_amount, - }, - NonceAmountPair { - nonce: 5, - amount: farm_in_amount * 2, - }, - ]; - - farm_setup.merge_farm_tokens(&first_user, payments); - - farm_setup.check_farm_token_supply(farm_in_amount * 3); - farm_setup.check_farm_rps(750_000_000u64); - - farm_setup.b_mock.check_nft_balance::( - &first_user, - FARM_TOKEN_ID, - 6, - &rust_biguint!(farm_in_amount * 3), - None, - ); - farm_setup.b_mock.check_nft_balance::( - &first_user, - LOCKED_REWARD_TOKEN_ID, - 1, - &rust_biguint!(boosted_rewards_per_week * 2), - None, - ); -} diff --git a/farm-staking/farm-staking/src/lib.rs b/farm-staking/farm-staking/src/lib.rs index 9cf4b1228..f783c7831 100644 --- a/farm-staking/farm-staking/src/lib.rs +++ b/farm-staking/farm-staking/src/lib.rs @@ -144,13 +144,6 @@ pub trait FarmStaking: FC::check_and_update_user_farm_position(self, orig_caller, &payments); - let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); - - FC::generate_aggregated_rewards(self, &mut storage_cache); - - self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); - self.merge_from_payments_and_burn(payments, &token_mapper) } @@ -160,7 +153,6 @@ pub trait FarmStaking: require!(percentage <= MAX_PERCENT, "Invalid percentage"); let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); self.boosted_yields_rewards_percentage().set(percentage); diff --git a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs index e71f0db34..050a4e968 100644 --- a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs @@ -1616,117 +1616,3 @@ fn claim_rewards_per_week_test() { &rust_biguint!(user_rewards_balance), ); } - -#[test] -fn merge_farm_position_per_week_test() { - DebugApi::dummy(); - let mut fs_setup = - FarmStakingSetup::new(farm_staking::contract_obj, energy_factory::contract_obj); - - fs_setup.set_boosted_yields_factors(); - fs_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); - - let first_user = fs_setup.user_address.clone(); - let farm_in_amount = 100_000_000; - - fs_setup.set_user_energy(&first_user, 10_000, 0, 10); - fs_setup.stake_farm(&first_user, farm_in_amount, &[], 1, 0, 0); - fs_setup.stake_farm(&first_user, farm_in_amount, &[], 2, 0, 0); - fs_setup.stake_farm(&first_user, farm_in_amount, &[], 3, 0, 0); - - fs_setup.check_farm_token_supply(farm_in_amount * 3); - fs_setup.check_farm_rps(0u64); - - fs_setup.b_mock.set_block_nonce(100); - fs_setup.b_mock.set_block_epoch(6); - fs_setup.set_user_energy(&first_user, 1_000, 6, 1); - - // Reset user balance - fs_setup - .b_mock - .set_esdt_balance(&first_user, FARMING_TOKEN_ID, &rust_biguint!(0)); - - // random user tx to collect rewards - let rand_user = fs_setup.b_mock.create_user_account(&rust_biguint!(0)); - fs_setup.b_mock.set_esdt_balance( - &rand_user, - FARMING_TOKEN_ID, - &rust_biguint!(USER_TOTAL_RIDE_TOKENS), - ); - - fs_setup.set_user_energy(&rand_user, 1, 6, 1); - fs_setup.stake_farm(&rand_user, 10, &[], 4, 3_500_000u64, 0); - fs_setup.unstake_farm_no_checks(&rand_user, 10, 4); - - let farm_rps_increase = 3_500_000u64; - let mut current_farm_rps = 0; - current_farm_rps += farm_rps_increase; - fs_setup.check_farm_rps(current_farm_rps); - - // advance 1 week - fs_setup.set_user_energy(&first_user, 1_000, 13, 1); - fs_setup.b_mock.set_block_nonce(200); - fs_setup.b_mock.set_block_epoch(13); - - let boosted_rewards_for_week = 350u64; - - current_farm_rps += farm_rps_increase; - let mut user_rewards_balance = boosted_rewards_for_week; - - let mut payments = vec![ - NonceAmountPair { - nonce: 1, - amount: farm_in_amount, - }, - NonceAmountPair { - nonce: 2, - amount: farm_in_amount, - }, - ]; - fs_setup.merge_farm_tokens(&first_user, payments, 6); - - fs_setup.check_farm_rps(current_farm_rps); - - // advance 1 week - fs_setup.set_user_energy(&first_user, 1_000, 15, 1); - fs_setup.b_mock.set_block_nonce(300); - fs_setup.b_mock.set_block_epoch(15); - - current_farm_rps += farm_rps_increase; - user_rewards_balance += boosted_rewards_for_week; - - payments = vec![ - NonceAmountPair { - nonce: 3, - amount: farm_in_amount, - }, - NonceAmountPair { - nonce: 6, - amount: farm_in_amount * 2, - }, - ]; - fs_setup.merge_farm_tokens(&first_user, payments, 7); - - fs_setup.check_farm_rps(current_farm_rps); - - fs_setup.b_mock.check_esdt_balance( - &first_user, - REWARD_TOKEN_ID, - &rust_biguint!(user_rewards_balance), - ); - - let expected_attributes = StakingFarmTokenAttributes:: { - reward_per_share: managed_biguint!(0), - compounded_reward: managed_biguint!(0), - current_farm_amount: managed_biguint!(farm_in_amount * 3), - original_owner: managed_address!(&first_user), - }; - - fs_setup.b_mock.check_nft_balance( - &first_user, - FARM_TOKEN_ID, - 7, - &rust_biguint!(farm_in_amount * 3), - Some(&expected_attributes), - ); -} From c957df6c74648ca49c06b3f7ba3d40ebef5b0bf2 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 22:23:47 +0300 Subject: [PATCH 10/12] remove rewards aggregation from merge farm --- dex/farm/src/base_functions.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dex/farm/src/base_functions.rs b/dex/farm/src/base_functions.rs index dad01984e..d6455a2b7 100644 --- a/dex/farm/src/base_functions.rs +++ b/dex/farm/src/base_functions.rs @@ -192,13 +192,6 @@ pub trait BaseFunctionsModule: FC::check_and_update_user_farm_position(self, orig_caller, &payments); - let mut storage_cache = StorageCache::new(self); - self.validate_contract_state(storage_cache.contract_state, &storage_cache.farm_token_id); - - FC::generate_aggregated_rewards(self, &mut storage_cache); - - self.set_farm_supply_for_current_week(&storage_cache.farm_token_supply); - self.merge_from_payments_and_burn(payments, &token_mapper) } From 6c0d6b6542d433cfb12a20a691e648da117da794 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 22:27:24 +0300 Subject: [PATCH 11/12] farm staking unit tests cleanup --- .../tests/farm_staking_setup/mod.rs | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs b/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs index 45151e926..a27b2d0d0 100644 --- a/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs +++ b/farm-staking/farm-staking/tests/farm_staking_setup/mod.rs @@ -566,40 +566,6 @@ where ); } - pub fn merge_farm_tokens( - &mut self, - user: &Address, - farm_tokens: Vec, - expected_farm_token_nonce: u64, - ) { - let mut expected_farm_token_amount = 0; - let mut payments = Vec::new(); - for farm_token in farm_tokens { - expected_farm_token_amount += farm_token.amount; - payments.push(TxTokenTransfer { - token_identifier: FARM_TOKEN_ID.to_vec(), - nonce: farm_token.nonce, - value: rust_biguint!(farm_token.amount), - }); - } - - self.b_mock - .execute_esdt_multi_transfer(user, &self.farm_wrapper, &payments, |sc| { - let (out_farm_token, _boosted_rewards) = - sc.merge_farm_tokens_endpoint().into_tuple(); - assert_eq!( - out_farm_token.token_identifier, - managed_token_id!(FARM_TOKEN_ID) - ); - assert_eq!(out_farm_token.token_nonce, expected_farm_token_nonce); - assert_eq!( - out_farm_token.amount, - managed_biguint!(expected_farm_token_amount) - ); - }) - .assert_ok(); - } - pub fn check_farm_token_supply(&mut self, expected_farm_token_supply: u64) { self.b_mock .execute_query(&self.farm_wrapper, |sc| { From f5d259305957026045faf2679a3c697444f66d3b Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 2 Aug 2024 23:16:25 +0300 Subject: [PATCH 12/12] zero position claim farm staking farm supply fix --- .../tests/farm_with_locked_rewards_test.rs | 63 +++++++++++++ .../farm-staking/src/base_impl_wrapper.rs | 7 +- .../tests/farm_staking_energy_test.rs | 90 +++++++++++++++++++ 3 files changed, 154 insertions(+), 6 deletions(-) diff --git a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs index d313c3b6b..6fbeb9cc6 100644 --- a/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs +++ b/dex/farm-with-locked-rewards/tests/farm_with_locked_rewards_test.rs @@ -465,3 +465,66 @@ fn claim_rewards_per_week_test() { None, ); } + +#[test] +fn claim_boosted_rewards_with_zero_position_test() { + DebugApi::dummy(); + let mut farm_setup = FarmSetup::new( + farm_with_locked_rewards::contract_obj, + energy_factory::contract_obj, + ); + + farm_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + farm_setup.set_boosted_yields_factors(); + farm_setup.b_mock.set_block_epoch(2); + + let temp_user = farm_setup.third_user.clone(); + + // first user enter farm + let farm_in_amount = 100_000_000; + let first_user = farm_setup.first_user.clone(); + farm_setup.set_user_energy(&first_user, 1_000, 2, 1); + farm_setup.enter_farm(&first_user, farm_in_amount); + + farm_setup.check_farm_token_supply(farm_in_amount); + farm_setup.check_farm_rps(0u64); + + farm_setup.b_mock.set_block_nonce(10); + farm_setup.b_mock.set_block_epoch(6); + farm_setup.set_user_energy(&first_user, 1_000, 6, 1); + farm_setup.set_user_energy(&temp_user, 1, 6, 1); + farm_setup.enter_farm(&temp_user, 1); + farm_setup.exit_farm(&temp_user, 2, 1); + + farm_setup.check_farm_rps(75_000_000u64); + + // advance 1 week + farm_setup.set_user_energy(&first_user, 1_000, 13, 1); + farm_setup.b_mock.set_block_nonce(20); + farm_setup.b_mock.set_block_epoch(13); + + let second_week_received_reward_amt = + farm_setup.claim_boosted_rewards_for_user(&temp_user, &temp_user, 0); + + assert_eq!(second_week_received_reward_amt, 0); + farm_setup.check_farm_rps(150_000_000u64); + + // advance 1 week + let boosted_rewards = 2_500; + farm_setup.set_user_energy(&first_user, 1_000, 15, 1); + farm_setup.b_mock.set_block_nonce(30); + farm_setup.b_mock.set_block_epoch(15); + let third_week_received_reward_amt = + farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user, 1); + + assert_eq!(third_week_received_reward_amt, boosted_rewards * 2); // user receives rewards for weeks 1 and 2) + farm_setup.check_farm_rps(225_000_000u64); + + farm_setup.b_mock.check_nft_balance::( + &first_user, + LOCKED_REWARD_TOKEN_ID, + 1, + &rust_biguint!(boosted_rewards * 2), + None, + ); +} diff --git a/farm-staking/farm-staking/src/base_impl_wrapper.rs b/farm-staking/farm-staking/src/base_impl_wrapper.rs index f2208cfde..21d98f5bc 100644 --- a/farm-staking/farm-staking/src/base_impl_wrapper.rs +++ b/farm-staking/farm-staking/src/base_impl_wrapper.rs @@ -63,13 +63,8 @@ where caller: &ManagedAddress<<::FarmSc as ContractBase>::Api>, ) -> BigUint<<::FarmSc as ContractBase>::Api> { let user_total_farm_position = sc.user_total_farm_position(caller).get(); - let mut boosted_rewards = BigUint::zero(); - if user_total_farm_position > 0 { - boosted_rewards = sc.claim_boosted_yields_rewards(caller, user_total_farm_position); - } - - boosted_rewards + sc.claim_boosted_yields_rewards(caller, user_total_farm_position) } } diff --git a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs index 050a4e968..f22555545 100644 --- a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs @@ -1616,3 +1616,93 @@ fn claim_rewards_per_week_test() { &rust_biguint!(user_rewards_balance), ); } + +#[test] +fn claim_boosted_rewards_with_zero_position_test() { + DebugApi::dummy(); + let mut fs_setup = + FarmStakingSetup::new(farm_staking::contract_obj, energy_factory::contract_obj); + + fs_setup.set_boosted_yields_factors(); + fs_setup.set_boosted_yields_rewards_percentage(BOOSTED_YIELDS_PERCENTAGE); + + let first_user = fs_setup.user_address.clone(); + let farm_in_amount = 100_000_000; + + fs_setup.set_user_energy(&first_user, 10_000, 0, 10); + fs_setup.stake_farm(&first_user, farm_in_amount, &[], 1, 0, 0); + + fs_setup.check_farm_token_supply(farm_in_amount); + fs_setup.check_farm_rps(0u64); + + fs_setup.b_mock.set_block_nonce(100); + fs_setup.b_mock.set_block_epoch(6); + fs_setup.set_user_energy(&first_user, 1_000, 6, 1); + + // Reset user balance + fs_setup + .b_mock + .set_esdt_balance(&first_user, FARMING_TOKEN_ID, &rust_biguint!(0)); + + // tx to collect rewards + let second_user = fs_setup.b_mock.create_user_account(&rust_biguint!(0)); + fs_setup.b_mock.set_esdt_balance( + &second_user, + FARMING_TOKEN_ID, + &rust_biguint!(USER_TOTAL_RIDE_TOKENS), + ); + + fs_setup.set_user_energy(&second_user, 1, 6, 1); + fs_setup.stake_farm(&second_user, 10, &[], 2, 3_000_000u64, 0); + fs_setup.unstake_farm_no_checks(&second_user, 10, 2); + + let farm_rps_increase = 3_000_000u64; + let mut current_farm_rps = 0; + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 13, 1); + fs_setup.b_mock.set_block_nonce(200); + fs_setup.b_mock.set_block_epoch(13); + + let boosted_rewards_for_week = 100; + fs_setup.claim_boosted_rewards_for_user(&second_user, &second_user, 0, &rust_biguint!(0)); + + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + + // advance 1 week + fs_setup.set_user_energy(&first_user, 1_000, 15, 1); + fs_setup.b_mock.set_block_nonce(300); + fs_setup.b_mock.set_block_epoch(15); + fs_setup.claim_boosted_rewards_for_user( + &first_user, + &first_user, + boosted_rewards_for_week * 2, + &rust_biguint!(boosted_rewards_for_week * 2), + ); + + current_farm_rps += farm_rps_increase; + fs_setup.check_farm_rps(current_farm_rps); + fs_setup.b_mock.check_esdt_balance( + &first_user, + REWARD_TOKEN_ID, + &rust_biguint!(boosted_rewards_for_week * 2), + ); + + let expected_attributes = StakingFarmTokenAttributes:: { + reward_per_share: managed_biguint!(0), + compounded_reward: managed_biguint!(0), + current_farm_amount: managed_biguint!(farm_in_amount), + original_owner: managed_address!(&first_user), + }; + + fs_setup.b_mock.check_nft_balance( + &first_user, + FARM_TOKEN_ID, + 1, + &rust_biguint!(farm_in_amount), + Some(&expected_attributes), + ); +}