From 5d426aa834e0fac2970f646f9f3631a35c9d998e Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Fri, 20 Sep 2024 17:04:18 +0300 Subject: [PATCH 1/6] adjustUserEnergy functionality --- locked-asset/energy-factory/src/lib.rs | 35 ++++++++ .../tests/energy_factory_setup/mod.rs | 26 +++++- .../tests/simple_lock_energy_test.rs | 79 +++++++++++++++++++ locked-asset/energy-factory/wasm/src/lib.rs | 5 +- 4 files changed, 142 insertions(+), 3 deletions(-) diff --git a/locked-asset/energy-factory/src/lib.rs b/locked-asset/energy-factory/src/lib.rs index f38c2e0e7..9936fdff3 100644 --- a/locked-asset/energy-factory/src/lib.rs +++ b/locked-asset/energy-factory/src/lib.rs @@ -230,4 +230,39 @@ pub trait SimpleLockEnergy: output_tokens } + + /// Adjusts the energy of a user. + /// This function allows the owner to adjust the energy of a user by adding or subtracting from the energy amount and total locked tokens. + /// + /// # Arguments + /// - `user`: The address of the user whose energy is to be adjusted. + /// - `energy_amount`: The amount of energy to add or subtract. + /// - `token_amount`: The amount of tokens to add or subtract. + #[only_owner] + #[endpoint(adjustUserEnergy)] + fn adjust_user_energy( + &self, + user: ManagedAddress, + energy_amount: BigInt, + token_amount: BigInt, + ) { + require!(!self.user_energy(&user).is_empty(), "User energy not found"); + let old_energy = self.get_updated_energy_entry_for_user(&user); + let new_energy_amount = old_energy.get_energy_amount() + energy_amount; + let new_total_locked_tokens = if token_amount >= 0 { + old_energy.get_total_locked_tokens() + &token_amount.magnitude() + } else { + let token_amount_magnitude = token_amount.magnitude(); + require!( + old_energy.get_total_locked_tokens() >= &token_amount_magnitude, + "Insufficient locked tokens" + ); + old_energy.get_total_locked_tokens() - &token_amount_magnitude + }; + + let current_epoch = self.blockchain().get_block_epoch(); + let new_energy = Energy::new(new_energy_amount, current_epoch, new_total_locked_tokens); + + self.set_energy_entry(&user, new_energy); + } } diff --git a/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs b/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs index 7d2c17b79..78ecbb9df 100644 --- a/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs +++ b/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs @@ -10,7 +10,7 @@ use energy_factory::{ use multiversx_sc::{ codec::multi_types::OptionalValue, storage::mappers::StorageTokenWrapper, - types::{Address, EsdtLocalRole, MultiValueEncoded}, + types::{Address, BigInt, EsdtLocalRole, MultiValueEncoded}, }; use multiversx_sc_modules::pause::PauseModule; use multiversx_sc_scenario::{ @@ -272,6 +272,30 @@ where result } + + pub fn get_user_locked_tokens(&mut self, user: &Address) -> num_bigint::BigUint { + let mut result = rust_biguint!(0); + self.b_mock + .execute_query(&self.sc_wrapper, |sc| { + let user_energy = sc.get_updated_energy_entry_for_user(&managed_address!(user)); + result = to_rust_biguint(user_energy.get_total_locked_tokens().clone()); + }) + .assert_ok(); + + result + } + + pub fn adjust_user_energy(&mut self, user: &Address, energy_amount: i64, token_amount: i64) { + self.b_mock + .execute_tx(&self.owner, &self.sc_wrapper, &rust_biguint!(0), |sc| { + sc.adjust_user_energy( + managed_address!(user), + BigInt::from(energy_amount), + BigInt::from(token_amount), + ); + }) + .assert_ok(); + } } pub fn to_rust_biguint( diff --git a/locked-asset/energy-factory/tests/simple_lock_energy_test.rs b/locked-asset/energy-factory/tests/simple_lock_energy_test.rs index 202630958..cdfbba66b 100644 --- a/locked-asset/energy-factory/tests/simple_lock_energy_test.rs +++ b/locked-asset/energy-factory/tests/simple_lock_energy_test.rs @@ -566,3 +566,82 @@ fn extend_lock_period_endpoint_test() { LOCK_OPTIONS[1] * energy_per_epoch.clone() - energy_per_epoch.clone() ); } + +#[test] +fn adjust_user_energy_test() { + let mut setup = SimpleLockEnergySetup::new(energy_factory::contract_obj); + let user = setup.first_user.clone(); + let user_balance = 1_000_000u64; + + // Initial lock to create user energy + setup + .lock(&user, BASE_ASSET_TOKEN_ID, user_balance, LOCK_OPTIONS[0]) + .assert_ok(); + + // Check initial energy + let initial_locked_tokens = rust_biguint!(user_balance); + let initial_energy = initial_locked_tokens.clone() * LOCK_OPTIONS[0]; + assert_eq!(setup.get_user_locked_tokens(&user), initial_locked_tokens); + assert_eq!(setup.get_user_energy(&user), initial_energy); + + // Case 1: Positive energy, positive token amount + let adjustment1_energy = 1_000_000i64; + let adjustment1_tokens = 500_000i64; + setup.adjust_user_energy(&user, adjustment1_energy, adjustment1_tokens); + + let locked_tokens1 = setup.get_user_locked_tokens(&user); + let energy1 = setup.get_user_energy(&user); + assert_eq!( + locked_tokens1, + &initial_locked_tokens + &rust_biguint!(adjustment1_tokens) + ); + assert_eq!( + energy1, + &initial_energy + &rust_biguint!(adjustment1_energy) + ); + + // Case 2: Positive energy, negative token amount + let adjustment2_energy = 800_000i64; + let adjustment2_tokens = -300_000i64; + setup.adjust_user_energy(&user, adjustment2_energy, adjustment2_tokens); + + let locked_tokens2 = setup.get_user_locked_tokens(&user); + let energy2 = setup.get_user_energy(&user); + assert_eq!( + locked_tokens2, + &locked_tokens1 - &rust_biguint!(adjustment2_tokens.unsigned_abs()) + ); + assert_eq!(energy2, &energy1 + &rust_biguint!(adjustment2_energy)); + + // Case 3: Negative energy, positive token amount + let adjustment3_energy = -1_500_000i64; + let adjustment3_tokens = 200_000i64; + setup.adjust_user_energy(&user, adjustment3_energy, adjustment3_tokens); + + let locked_tokens3 = setup.get_user_locked_tokens(&user); + let energy3 = setup.get_user_energy(&user); + assert_eq!( + locked_tokens3, + &locked_tokens2 + &rust_biguint!(adjustment3_tokens) + ); + assert_eq!( + energy3, + &energy2 - &rust_biguint!(adjustment3_energy.unsigned_abs()) + ); + + // Case 4: Negative energy, negative token amount + let adjustment4_energy = -700_000i64; + let adjustment4_tokens = -100_000i64; + setup.adjust_user_energy(&user, adjustment4_energy, adjustment4_tokens); + + let locked_tokens4 = setup.get_user_locked_tokens(&user); + let energy4 = setup.get_user_energy(&user); + assert_eq!( + locked_tokens4, + &locked_tokens3 - &rust_biguint!(adjustment4_tokens.unsigned_abs()) + ); + assert_eq!( + energy4, + &energy3 - &rust_biguint!(adjustment4_energy.unsigned_abs()) + ); +} diff --git a/locked-asset/energy-factory/wasm/src/lib.rs b/locked-asset/energy-factory/wasm/src/lib.rs index fafdc534e..181f50f1a 100644 --- a/locked-asset/energy-factory/wasm/src/lib.rs +++ b/locked-asset/energy-factory/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 33 +// Endpoints: 34 // Async Callback: 1 -// Total number of exported functions: 36 +// Total number of exported functions: 37 #![no_std] @@ -23,6 +23,7 @@ multiversx_sc_wasm_adapter::endpoints! { lockTokens => lock_tokens_endpoint unlockTokens => unlock_tokens_endpoint extendLockPeriod => extend_lock_period + adjustUserEnergy => adjust_user_energy issueLockedToken => issue_locked_token getLockedTokenId => locked_token getBaseAssetTokenId => base_asset_token_id From 46db339b3e19e05121cc6c7286dfe969b42b8934 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Mon, 30 Sep 2024 02:25:15 +0300 Subject: [PATCH 2/6] claimBoostedRewards extra check --- dex/farm-with-locked-rewards/src/lib.rs | 5 +++ .../tests/farm_with_locked_rewards_test.rs | 41 ++++++++++++++++++- dex/farm/src/lib.rs | 5 +++ .../src/claim_only_boosted_staking_rewards.rs | 5 +++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index 972ddbbd7..732a77ac5 100644 --- a/dex/farm-with-locked-rewards/src/lib.rs +++ b/dex/farm-with-locked-rewards/src/lib.rs @@ -226,6 +226,11 @@ pub trait Farm: ); } + require!( + !self.current_claim_progress(&user).is_empty(), + "User energy is not registered!" + ); + 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); 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 6fbeb9cc6..cdf075cf9 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,8 @@ #![allow(deprecated)] use common_structs::FarmTokenAttributes; -use multiversx_sc::codec::Empty; +use farm_with_locked_rewards::Farm; +use multiversx_sc::{codec::Empty, imports::OptionalValue}; use multiversx_sc_scenario::{managed_address, managed_biguint, rust_biguint, DebugApi}; use simple_lock::locked_token::LockedTokenAttributes; @@ -528,3 +529,41 @@ fn claim_boosted_rewards_with_zero_position_test() { None, ); } + +#[test] +fn claim_boosted_rewards_user_energy_not_registered_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 first_user = farm_setup.first_user.clone(); + let farm_in_amount = 100_000_000; + + farm_setup.set_user_energy(&first_user, 1_000, 2, 1); + + // Attempt to claim boosted rewards without entering the farm + farm_setup + .b_mock + .execute_tx( + &first_user, + &farm_setup.farm_wrapper, + &rust_biguint!(0), + |sc| { + sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(&first_user))); + }, + ) + .assert_error(4, "User energy is not registered!"); + + // User enters the farm + farm_setup.enter_farm(&first_user, farm_in_amount); + + // Now the user should be able to claim boosted rewards + // Rewards computation is out of scope + farm_setup.claim_boosted_rewards_for_user(&first_user, &first_user, 0); +} diff --git a/dex/farm/src/lib.rs b/dex/farm/src/lib.rs index aeabcaaa0..7c9c009d6 100644 --- a/dex/farm/src/lib.rs +++ b/dex/farm/src/lib.rs @@ -228,6 +228,11 @@ pub trait Farm: ); } + require!( + !self.current_claim_progress(&user).is_empty(), + "User energy is not registered!" + ); + 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); 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..2d6a40071 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 @@ -41,6 +41,11 @@ pub trait ClaimOnlyBoostedStakingRewardsModule: ); } + require!( + !self.current_claim_progress(&user).is_empty(), + "User energy is not registered!" + ); + let mut storage_cache = StorageCache::new(self); FarmStakingWrapper::::generate_aggregated_rewards(self, &mut storage_cache); From ee2456b0c6300faf9de37d71125ccb570eeb3225 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Mon, 30 Sep 2024 02:55:34 +0300 Subject: [PATCH 3/6] clippy & tests fixes --- dex/farm-with-locked-rewards/src/lib.rs | 2 +- .../tests/farm_with_locked_rewards_test.rs | 20 +++++++++++----- dex/farm/src/lib.rs | 2 +- .../src/claim_only_boosted_staking_rewards.rs | 2 +- .../tests/farm_staking_energy_test.rs | 23 ++++++++++++++----- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index 732a77ac5..a32ee36f3 100644 --- a/dex/farm-with-locked-rewards/src/lib.rs +++ b/dex/farm-with-locked-rewards/src/lib.rs @@ -227,7 +227,7 @@ pub trait Farm: } require!( - !self.current_claim_progress(&user).is_empty(), + !self.current_claim_progress(user).is_empty(), "User energy is not registered!" ); 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 cdf075cf9..733d4191d 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 @@ -504,11 +504,19 @@ fn claim_boosted_rewards_with_zero_position_test() { 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); + farm_setup + .b_mock + .execute_tx( + &temp_user, + &farm_setup.farm_wrapper, + &rust_biguint!(0), + |sc| { + sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(&temp_user))); + }, + ) + .assert_error(4, "User energy is not registered!"); - assert_eq!(second_week_received_reward_amt, 0); - farm_setup.check_farm_rps(150_000_000u64); + farm_setup.check_farm_rps(75_000_000u64); // advance 1 week let boosted_rewards = 2_500; @@ -518,14 +526,14 @@ fn claim_boosted_rewards_with_zero_position_test() { 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) + 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), + &rust_biguint!(boosted_rewards), None, ); } diff --git a/dex/farm/src/lib.rs b/dex/farm/src/lib.rs index 7c9c009d6..36947476b 100644 --- a/dex/farm/src/lib.rs +++ b/dex/farm/src/lib.rs @@ -229,7 +229,7 @@ pub trait Farm: } require!( - !self.current_claim_progress(&user).is_empty(), + !self.current_claim_progress(user).is_empty(), "User energy is not registered!" ); 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 2d6a40071..ccebe0f6a 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,7 @@ pub trait ClaimOnlyBoostedStakingRewardsModule: } require!( - !self.current_claim_progress(&user).is_empty(), + !self.current_claim_progress(user).is_empty(), "User energy is not registered!" ); 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 f22555545..4fae90129 100644 --- a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs @@ -3,6 +3,7 @@ pub mod farm_staking_setup; use config::ConfigModule; use farm_staking::{ + claim_only_boosted_staking_rewards::ClaimOnlyBoostedStakingRewardsModule, claim_stake_farm_rewards::ClaimStakeFarmRewardsModule, stake_farm::StakeFarmModule, token_attributes::{StakingFarmTokenAttributes, UnbondSftAttributes}, @@ -1667,9 +1668,19 @@ fn claim_boosted_rewards_with_zero_position_test() { 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 + .b_mock + .execute_tx( + &second_user, + &fs_setup.farm_wrapper, + &rust_biguint!(0u64), + |sc| { + sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(&second_user))); + }, + ) + .assert_error(4, "User energy is not registered!"); + fs_setup.check_farm_rps(current_farm_rps); // advance 1 week @@ -1679,16 +1690,16 @@ fn claim_boosted_rewards_with_zero_position_test() { fs_setup.claim_boosted_rewards_for_user( &first_user, &first_user, - boosted_rewards_for_week * 2, - &rust_biguint!(boosted_rewards_for_week * 2), + boosted_rewards_for_week, + &rust_biguint!(boosted_rewards_for_week), ); - current_farm_rps += farm_rps_increase; + current_farm_rps += farm_rps_increase * 2; 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), + &rust_biguint!(boosted_rewards_for_week), ); let expected_attributes = StakingFarmTokenAttributes:: { From 9d2ce14577e47b19e756641e67b158a9e69b8fa6 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Mon, 30 Sep 2024 13:26:08 +0300 Subject: [PATCH 4/6] audit fix + updated unit test --- locked-asset/energy-factory/src/lib.rs | 2 +- .../tests/energy_factory_setup/mod.rs | 24 ++++++ .../tests/simple_lock_energy_test.rs | 83 +++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/locked-asset/energy-factory/src/lib.rs b/locked-asset/energy-factory/src/lib.rs index 9936fdff3..c9c398f44 100644 --- a/locked-asset/energy-factory/src/lib.rs +++ b/locked-asset/energy-factory/src/lib.rs @@ -248,7 +248,7 @@ pub trait SimpleLockEnergy: ) { require!(!self.user_energy(&user).is_empty(), "User energy not found"); let old_energy = self.get_updated_energy_entry_for_user(&user); - let new_energy_amount = old_energy.get_energy_amount() + energy_amount; + let new_energy_amount = old_energy.get_energy_amount_raw() + &energy_amount; let new_total_locked_tokens = if token_amount >= 0 { old_energy.get_total_locked_tokens() + &token_amount.magnitude() } else { diff --git a/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs b/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs index 78ecbb9df..cd068a05e 100644 --- a/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs +++ b/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs @@ -19,6 +19,8 @@ use multiversx_sc_scenario::{ whitebox_legacy::{BlockchainStateWrapper, ContractObjWrapper}, DebugApi, }; + +use num_bigint::Sign; use simple_lock::locked_token::LockedTokenModule; use unbond_sc_mock::*; @@ -273,6 +275,18 @@ where result } + pub fn get_user_energy_raw(&mut self, user: &Address) -> num_bigint::BigInt { + let mut result = num_bigint::BigInt::from_biguint(Sign::NoSign, rust_biguint!(0)); + self.b_mock + .execute_query(&self.sc_wrapper, |sc| { + let user_energy = sc.get_updated_energy_entry_for_user(&managed_address!(user)); + result = to_rust_bigint(user_energy.get_energy_amount_raw().clone()); + }) + .assert_ok(); + + result + } + pub fn get_user_locked_tokens(&mut self, user: &Address) -> num_bigint::BigUint { let mut result = rust_biguint!(0); self.b_mock @@ -304,6 +318,16 @@ pub fn to_rust_biguint( num_bigint::BigUint::from_bytes_be(managed_biguint.to_bytes_be().as_slice()) } +pub fn to_rust_bigint( + managed_biguint: multiversx_sc::types::BigInt, +) -> num_bigint::BigInt { + if managed_biguint < 0 { + num_bigint::BigInt::from_biguint(Sign::Minus, to_rust_biguint(managed_biguint.magnitude())) + } else { + num_bigint::BigInt::from_biguint(Sign::Plus, to_rust_biguint(managed_biguint.magnitude())) + } +} + pub fn to_start_of_month(unlock_epoch: u64) -> u64 { unlock_epoch - unlock_epoch % 30 } diff --git a/locked-asset/energy-factory/tests/simple_lock_energy_test.rs b/locked-asset/energy-factory/tests/simple_lock_energy_test.rs index cdfbba66b..530a906cc 100644 --- a/locked-asset/energy-factory/tests/simple_lock_energy_test.rs +++ b/locked-asset/energy-factory/tests/simple_lock_energy_test.rs @@ -7,6 +7,8 @@ use energy_factory::{ }; use energy_factory_setup::*; use multiversx_sc::types::BigUint; +use num_bigint::BigInt; +use num_traits::{FromPrimitive, Zero}; use simple_lock::locked_token::LockedTokenAttributes; use multiversx_sc_scenario::{ @@ -644,4 +646,85 @@ fn adjust_user_energy_test() { energy4, &energy3 - &rust_biguint!(adjustment4_energy.unsigned_abs()) ); + + // Bring energy to negative value + let adjustment5_energy = -500_000_000i64; // Adjust to negative energy + let adjustment5_tokens = 0i64; // Positive token amount + setup.adjust_user_energy(&user, adjustment5_energy, adjustment5_tokens); + + let locked_tokens5 = setup.get_user_locked_tokens(&user); + let energy5 = setup.get_user_energy_raw(&user); + assert_eq!( + locked_tokens5, + &locked_tokens4 + &rust_biguint!(adjustment5_tokens) + ); + assert!(energy5 < BigInt::zero()); // Energy should be negative + + // Replay Case 1 on negative energy + let adjustment6_energy = 500_000i64; + let adjustment6_tokens = 200_000i64; + setup.adjust_user_energy(&user, adjustment6_energy, adjustment6_tokens); + + let locked_tokens6 = setup.get_user_locked_tokens(&user); + let energy6 = setup.get_user_energy_raw(&user); + assert_eq!( + locked_tokens6, + &locked_tokens5 + &rust_biguint!(adjustment6_tokens) + ); + assert_eq!( + energy6, + &energy5 + &BigInt::from_i64(adjustment6_energy).unwrap() + ); + assert!(energy6 < BigInt::zero()); // Energy should remain negative + + // Replay Case 2 on negative energy + let adjustment7_energy = 300_000i64; + let adjustment7_tokens = -100_000i64; + setup.adjust_user_energy(&user, adjustment7_energy, adjustment7_tokens); + + let locked_tokens7 = setup.get_user_locked_tokens(&user); + let energy7 = setup.get_user_energy_raw(&user); + assert_eq!( + locked_tokens7, + &locked_tokens6 - &rust_biguint!(adjustment7_tokens.unsigned_abs()) + ); + assert_eq!( + energy7, + &energy6 + &BigInt::from_i64(adjustment7_energy).unwrap() + ); + assert!(energy7 < BigInt::zero()); // Energy should remain negative + + // Replay Case 3 on negative energy + let adjustment8_energy = -500_000i64; + let adjustment8_tokens = 100_000i64; + setup.adjust_user_energy(&user, adjustment8_energy, adjustment8_tokens); + + let locked_tokens8 = setup.get_user_locked_tokens(&user); + let energy8 = setup.get_user_energy_raw(&user); + assert_eq!( + locked_tokens8, + &locked_tokens7 + &rust_biguint!(adjustment8_tokens) + ); + assert_eq!( + energy8, + &energy7 + &BigInt::from_i64(adjustment8_energy).unwrap() + ); + assert!(energy8 < BigInt::zero()); // Energy should remain negative + + // Replay Case 4 on negative energy + let adjustment9_energy = -300_000i64; + let adjustment9_tokens = -50_000i64; + setup.adjust_user_energy(&user, adjustment9_energy, adjustment9_tokens); + + let locked_tokens9 = setup.get_user_locked_tokens(&user); + let energy9 = setup.get_user_energy_raw(&user); + assert_eq!( + locked_tokens9, + &locked_tokens8 - &rust_biguint!(adjustment9_tokens.unsigned_abs()) + ); + assert_eq!( + energy9, + &energy8 + &BigInt::from_i64(adjustment9_energy).unwrap() + ); + assert!(energy9 < BigInt::zero()); // Energy should remain negative } From 23047c72cc3d71d983977f05ee43f7469e80b0df Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Tue, 1 Oct 2024 12:25:16 +0300 Subject: [PATCH 5/6] totalFarmPosition updated check --- dex/farm-with-locked-rewards/src/lib.rs | 4 ++-- .../tests/farm_with_locked_rewards_test.rs | 4 ++-- dex/farm/src/lib.rs | 4 ++-- .../farm-staking/src/claim_only_boosted_staking_rewards.rs | 4 ++-- farm-staking/farm-staking/tests/farm_staking_energy_test.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/dex/farm-with-locked-rewards/src/lib.rs b/dex/farm-with-locked-rewards/src/lib.rs index a32ee36f3..b25e7667e 100644 --- a/dex/farm-with-locked-rewards/src/lib.rs +++ b/dex/farm-with-locked-rewards/src/lib.rs @@ -227,8 +227,8 @@ pub trait Farm: } require!( - !self.current_claim_progress(user).is_empty(), - "User energy is not registered!" + !self.user_total_farm_position(user).is_empty(), + "User total farm position is empty!" ); let mut storage_cache = StorageCache::new(self); 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 733d4191d..649461f18 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 @@ -514,7 +514,7 @@ fn claim_boosted_rewards_with_zero_position_test() { sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(&temp_user))); }, ) - .assert_error(4, "User energy is not registered!"); + .assert_error(4, "User total farm position is empty!"); farm_setup.check_farm_rps(75_000_000u64); @@ -566,7 +566,7 @@ fn claim_boosted_rewards_user_energy_not_registered_test() { sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(&first_user))); }, ) - .assert_error(4, "User energy is not registered!"); + .assert_error(4, "User total farm position is empty!"); // User enters the farm farm_setup.enter_farm(&first_user, farm_in_amount); diff --git a/dex/farm/src/lib.rs b/dex/farm/src/lib.rs index 36947476b..750ebe78f 100644 --- a/dex/farm/src/lib.rs +++ b/dex/farm/src/lib.rs @@ -229,8 +229,8 @@ pub trait Farm: } require!( - !self.current_claim_progress(user).is_empty(), - "User energy is not registered!" + !self.user_total_farm_position(user).is_empty(), + "User total farm position is empty!" ); let mut storage_cache = StorageCache::new(self); 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 ccebe0f6a..ef01e3b48 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,8 +42,8 @@ pub trait ClaimOnlyBoostedStakingRewardsModule: } require!( - !self.current_claim_progress(user).is_empty(), - "User energy is not registered!" + !self.user_total_farm_position(user).is_empty(), + "User total farm position is empty!" ); let mut storage_cache = StorageCache::new(self); 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 4fae90129..a4046f03e 100644 --- a/farm-staking/farm-staking/tests/farm_staking_energy_test.rs +++ b/farm-staking/farm-staking/tests/farm_staking_energy_test.rs @@ -1679,7 +1679,7 @@ fn claim_boosted_rewards_with_zero_position_test() { sc.claim_boosted_rewards(OptionalValue::Some(managed_address!(&second_user))); }, ) - .assert_error(4, "User energy is not registered!"); + .assert_error(4, "User total farm position is empty!"); fs_setup.check_farm_rps(current_farm_rps); From 4c11d3ae370b8586905d4f5aad81ba0ad2ebb757 Mon Sep 17 00:00:00 2001 From: Sorin Petreasca Date: Wed, 2 Oct 2024 12:29:57 +0300 Subject: [PATCH 6/6] allow adjustUserEnergy to receive an array of users --- locked-asset/energy-factory/src/lib.rs | 46 ++++++++----------- .../tests/energy_factory_setup/mod.rs | 13 ++++-- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/locked-asset/energy-factory/src/lib.rs b/locked-asset/energy-factory/src/lib.rs index c9c398f44..a8cd96be4 100644 --- a/locked-asset/energy-factory/src/lib.rs +++ b/locked-asset/energy-factory/src/lib.rs @@ -231,38 +231,32 @@ pub trait SimpleLockEnergy: output_tokens } - /// Adjusts the energy of a user. - /// This function allows the owner to adjust the energy of a user by adding or subtracting from the energy amount and total locked tokens. - /// - /// # Arguments - /// - `user`: The address of the user whose energy is to be adjusted. - /// - `energy_amount`: The amount of energy to add or subtract. - /// - `token_amount`: The amount of tokens to add or subtract. #[only_owner] #[endpoint(adjustUserEnergy)] fn adjust_user_energy( &self, - user: ManagedAddress, - energy_amount: BigInt, - token_amount: BigInt, + args: MultiValueEncoded>, ) { - require!(!self.user_energy(&user).is_empty(), "User energy not found"); - let old_energy = self.get_updated_energy_entry_for_user(&user); - let new_energy_amount = old_energy.get_energy_amount_raw() + &energy_amount; - let new_total_locked_tokens = if token_amount >= 0 { - old_energy.get_total_locked_tokens() + &token_amount.magnitude() - } else { - let token_amount_magnitude = token_amount.magnitude(); - require!( - old_energy.get_total_locked_tokens() >= &token_amount_magnitude, - "Insufficient locked tokens" - ); - old_energy.get_total_locked_tokens() - &token_amount_magnitude - }; + for arg in args { + let (user, energy_amount, token_amount) = arg.into_tuple(); + require!(!self.user_energy(&user).is_empty(), "User energy not found"); + let old_energy = self.get_updated_energy_entry_for_user(&user); + let new_energy_amount = old_energy.get_energy_amount_raw() + &energy_amount; + let new_total_locked_tokens = if token_amount >= 0 { + old_energy.get_total_locked_tokens() + &token_amount.magnitude() + } else { + let token_amount_magnitude = token_amount.magnitude(); + require!( + old_energy.get_total_locked_tokens() >= &token_amount_magnitude, + "Insufficient locked tokens" + ); + old_energy.get_total_locked_tokens() - &token_amount_magnitude + }; - let current_epoch = self.blockchain().get_block_epoch(); - let new_energy = Energy::new(new_energy_amount, current_epoch, new_total_locked_tokens); + let current_epoch = self.blockchain().get_block_epoch(); + let new_energy = Energy::new(new_energy_amount, current_epoch, new_total_locked_tokens); - self.set_energy_entry(&user, new_energy); + self.set_energy_entry(&user, new_energy); + } } } diff --git a/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs b/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs index cd068a05e..4f3abf678 100644 --- a/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs +++ b/locked-asset/energy-factory/tests/energy_factory_setup/mod.rs @@ -302,11 +302,16 @@ where pub fn adjust_user_energy(&mut self, user: &Address, energy_amount: i64, token_amount: i64) { self.b_mock .execute_tx(&self.owner, &self.sc_wrapper, &rust_biguint!(0), |sc| { - sc.adjust_user_energy( - managed_address!(user), - BigInt::from(energy_amount), - BigInt::from(token_amount), + let mut args = MultiValueEncoded::new(); + args.push( + ( + managed_address!(user), + BigInt::from(energy_amount), + BigInt::from(token_amount), + ) + .into(), ); + sc.adjust_user_energy(args); }) .assert_ok(); }