diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index 91144b387..972ddbbd7 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("*")] @@ -237,7 +226,14 @@ 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); + + 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, @@ -270,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-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..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 @@ -24,6 +24,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; @@ -422,4 +423,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..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 @@ -1,6 +1,7 @@ #![allow(deprecated)] use common_structs::FarmTokenAttributes; +use multiversx_sc::codec::Empty; use multiversx_sc_scenario::{managed_address, managed_biguint, rust_biguint, DebugApi}; use simple_lock::locked_token::LockedTokenAttributes; @@ -335,3 +336,195 @@ 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 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/dex/farm/src/lib.rs b/dex/farm/src/lib.rs index 08d447830..aeabcaaa0 100644 --- a/dex/farm/src/lib.rs +++ b/dex/farm/src/lib.rs @@ -228,10 +228,16 @@ 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); 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 @@ -261,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/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/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( diff --git a/farm-staking/farm-staking/src/unbond_farm.rs b/farm-staking/farm-staking/src/unbond_farm.rs index 7e85a2a2c..0e661616e 100644 --- a/farm-staking/farm-staking/src/unbond_farm.rs +++ b/farm-staking/farm-staking/src/unbond_farm.rs @@ -16,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 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..f22555545 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,282 @@ 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 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), + ); +} 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..a27b2d0d0 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, @@ -554,6 +578,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| {