diff --git a/common/modules/sc_whitelist_module/src/sc_whitelist_module.rs b/common/modules/sc_whitelist_module/src/sc_whitelist_module.rs index b04216db2..19de606b0 100644 --- a/common/modules/sc_whitelist_module/src/sc_whitelist_module.rs +++ b/common/modules/sc_whitelist_module/src/sc_whitelist_module.rs @@ -40,6 +40,7 @@ pub trait SCWhitelistModule { match opt_orig_caller { OptionalValue::Some(opt_caller) => { self.require_sc_address_whitelisted(caller); + opt_caller } OptionalValue::None => caller.clone(), diff --git a/dex/pair/tests/pair_rs_test.rs b/dex/pair/tests/pair_rs_test.rs index bd82750d8..7f43373ff 100644 --- a/dex/pair/tests/pair_rs_test.rs +++ b/dex/pair/tests/pair_rs_test.rs @@ -1600,6 +1600,7 @@ fn fees_collector_pair_test() { sc.init( managed_token_id!(LOCKED_TOKEN_ID), managed_address!(&energy_factory_mock_addr), + MultiValueEncoded::new(), ); let _ = sc.known_contracts().insert(managed_address!(&pair_addr)); diff --git a/energy-integration/common-modules/weekly-rewards-splitting/src/base_impl.rs b/energy-integration/common-modules/weekly-rewards-splitting/src/base_impl.rs index de8783686..96de99ce9 100644 --- a/energy-integration/common-modules/weekly-rewards-splitting/src/base_impl.rs +++ b/energy-integration/common-modules/weekly-rewards-splitting/src/base_impl.rs @@ -64,13 +64,15 @@ pub trait WeeklyRewardsSplittingTraitsModule { let total_rewards = self.collect_and_get_rewards_for_week(sc, week); for weekly_reward in &total_rewards { let reward_amount = weekly_reward.amount * energy_amount / total_energy; - if reward_amount > 0 { - user_rewards.push(EsdtTokenPayment::new( - weekly_reward.token_identifier, - 0, - reward_amount, - )); + if reward_amount == 0 { + continue; } + + user_rewards.push(EsdtTokenPayment::new( + weekly_reward.token_identifier, + 0, + reward_amount, + )); } user_rewards diff --git a/energy-integration/common-modules/weekly-rewards-splitting/src/global_info.rs b/energy-integration/common-modules/weekly-rewards-splitting/src/global_info.rs index b05f5aa66..488569bad 100644 --- a/energy-integration/common-modules/weekly-rewards-splitting/src/global_info.rs +++ b/energy-integration/common-modules/weekly-rewards-splitting/src/global_info.rs @@ -1,6 +1,6 @@ multiversx_sc::imports!(); -use common_types::Week; +use common_types::{PaymentsVec, Week}; use energy_query::Energy; use week_timekeeping::EPOCHS_IN_WEEK; @@ -147,10 +147,7 @@ pub trait WeeklyRewardsGlobalInfo: #[view(getTotalRewardsForWeek)] #[storage_mapper("totalRewardsForWeek")] - fn total_rewards_for_week( - &self, - week: Week, - ) -> SingleValueMapper>>; + fn total_rewards_for_week(&self, week: Week) -> SingleValueMapper>; #[view(getTotalEnergyForWeek)] #[storage_mapper("totalEnergyForWeek")] diff --git a/energy-integration/fees-collector/src/additional_locked_tokens.rs b/energy-integration/fees-collector/src/additional_locked_tokens.rs index b74c967f3..9303a408f 100644 --- a/energy-integration/fees-collector/src/additional_locked_tokens.rs +++ b/energy-integration/fees-collector/src/additional_locked_tokens.rs @@ -20,19 +20,18 @@ pub trait AdditionalLockedTokensModule: fn accumulate_additional_locked_tokens(&self) { let last_update_week_mapper = self.last_locked_token_add_week(); - let mut last_update_week = last_update_week_mapper.get(); + let last_update_week = last_update_week_mapper.get(); let current_week = self.get_current_week(); if last_update_week == current_week { return; } - last_update_week = current_week - 1; let blocks_in_week = BLOCKS_IN_WEEK; let amount_per_block = self.locked_tokens_per_block().get(); let new_tokens_amount = amount_per_block * blocks_in_week; let locked_token_id = self.locked_token_id().get(); - self.accumulated_fees(last_update_week, &locked_token_id) + self.accumulated_fees(current_week - 1, &locked_token_id) .update(|fees| *fees += new_tokens_amount); last_update_week_mapper.set(current_week); diff --git a/energy-integration/fees-collector/src/claim.rs b/energy-integration/fees-collector/src/claim.rs new file mode 100644 index 000000000..b0994d08b --- /dev/null +++ b/energy-integration/fees-collector/src/claim.rs @@ -0,0 +1,204 @@ +use core::marker::PhantomData; + +use common_types::{PaymentsVec, Week}; +use weekly_rewards_splitting::base_impl::WeeklyRewardsSplittingTraitsModule; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait ClaimModule: + crate::config::ConfigModule + + crate::events::FeesCollectorEventsModule + + weekly_rewards_splitting::WeeklyRewardsSplittingModule + + weekly_rewards_splitting::events::WeeklyRewardsSplittingEventsModule + + weekly_rewards_splitting::global_info::WeeklyRewardsGlobalInfo + + weekly_rewards_splitting::locked_token_buckets::WeeklyRewardsLockedTokenBucketsModule + + weekly_rewards_splitting::update_claim_progress_energy::UpdateClaimProgressEnergyModule + + crate::fees_accumulation::FeesAccumulationModule + + crate::additional_locked_tokens::AdditionalLockedTokensModule + + locking_module::lock_with_energy_module::LockWithEnergyModule + + energy_query::EnergyQueryModule + + week_timekeeping::WeekTimekeepingModule + + multiversx_sc_modules::pause::PauseModule + + utils::UtilsModule + + sc_whitelist_module::SCWhitelistModule + + multiversx_sc_modules::only_admin::OnlyAdminModule + + crate::redistribute_rewards::RedistributeRewardsModule +{ + #[endpoint(claimRewards)] + fn claim_rewards_endpoint( + &self, + opt_original_caller: OptionalValue, + ) -> PaymentsVec { + self.require_not_paused(); + + let caller = self.blockchain().get_caller(); + let original_caller = self.get_orig_caller_from_opt(&caller, opt_original_caller); + + self.claim_rewards(caller, original_caller) + } + + #[endpoint(claimBoostedRewards)] + fn claim_boosted_rewards( + &self, + opt_original_caller: OptionalValue, + ) -> PaymentsVec { + self.require_not_paused(); + + let original_caller = match opt_original_caller { + OptionalValue::Some(user) => { + require!( + self.allow_external_claim_rewards(&user).get(), + "Cannot claim rewards for this address" + ); + + user + } + OptionalValue::None => self.blockchain().get_caller(), + }; + + self.claim_rewards(original_caller.clone(), original_caller) + } + + fn claim_rewards( + &self, + caller: ManagedAddress, + original_caller: ManagedAddress, + ) -> PaymentsVec { + self.accumulate_additional_locked_tokens(); + + let wrapper = FeesCollectorWrapper::new(); + let mut rewards = self.claim_multi(&wrapper, &original_caller); + if rewards.is_empty() { + return rewards; + } + + let locked_token_id = self.get_locked_token_id(); + let mut i = 0; + let mut len = rewards.len(); + let mut total_locked_token_rewards_amount = BigUint::zero(); + while i < len { + let rew = rewards.get(i); + if rew.token_identifier != locked_token_id { + i += 1; + continue; + } + + total_locked_token_rewards_amount += rew.amount; + len -= 1; + rewards.remove(i); + } + + if !rewards.is_empty() { + self.send().direct_multi(&caller, &rewards); + } + + if total_locked_token_rewards_amount > 0 { + let locked_rewards = self.lock_virtual( + self.get_base_token_id(), + total_locked_token_rewards_amount, + caller, + original_caller, + ); + + rewards.push(locked_rewards); + } + + rewards + } +} + +pub struct FeesCollectorWrapper { + phantom: PhantomData, +} + +impl Default for FeesCollectorWrapper { + fn default() -> Self { + Self::new() + } +} + +impl FeesCollectorWrapper { + pub fn new() -> FeesCollectorWrapper { + FeesCollectorWrapper { + phantom: PhantomData, + } + } +} + +impl WeeklyRewardsSplittingTraitsModule for FeesCollectorWrapper +where + T: ClaimModule, +{ + type WeeklyRewardsSplittingMod = T; + + fn get_user_rewards_for_week( + &self, + sc: &Self::WeeklyRewardsSplittingMod, + week: Week, + energy_amount: &BigUint<::Api>, + total_energy: &BigUint<::Api>, + ) -> PaymentsVec<::Api> { + let mut user_rewards = ManagedVec::new(); + if energy_amount == &0 || total_energy == &0 { + return user_rewards; + } + + let total_rewards = self.collect_and_get_rewards_for_week(sc, week); + let remaining_rewards_mapper = sc.remaining_rewards(week); + let mut remaining_rewards = remaining_rewards_mapper.get(); + for (i, weekly_reward) in total_rewards.iter().enumerate() { + let reward_amount = weekly_reward.amount * energy_amount / total_energy; + if reward_amount == 0 { + continue; + } + + let mut rem_rew_entry = remaining_rewards.get_mut(i); + rem_rew_entry.amount -= &reward_amount; + + user_rewards.push(EsdtTokenPayment::new( + weekly_reward.token_identifier, + 0, + reward_amount, + )); + } + + remaining_rewards_mapper.set(remaining_rewards); + + user_rewards + } + + fn collect_and_get_rewards_for_week( + &self, + sc: &Self::WeeklyRewardsSplittingMod, + week: Week, + ) -> PaymentsVec<::Api> { + let total_rewards_mapper = sc.total_rewards_for_week(week); + if total_rewards_mapper.is_empty() { + let total_rewards = self.collect_rewards_for_week(sc, week); + total_rewards_mapper.set(&total_rewards); + sc.remaining_rewards(week).set(&total_rewards); + + total_rewards + } else { + total_rewards_mapper.get() + } + } + + fn collect_rewards_for_week( + &self, + sc: &Self::WeeklyRewardsSplittingMod, + week: Week, + ) -> PaymentsVec<::Api> { + let mut results = ManagedVec::new(); + let all_tokens = sc.all_tokens().get(); + for token in &all_tokens { + let opt_accumulated_fees = sc.get_and_clear_accumulated_fees(week, &token); + if let Some(accumulated_fees) = opt_accumulated_fees { + results.push(EsdtTokenPayment::new(token, 0, accumulated_fees)); + } + } + + results + } +} diff --git a/energy-integration/fees-collector/src/config.rs b/energy-integration/fees-collector/src/config.rs index 72fa1fc70..0cb2d813b 100644 --- a/energy-integration/fees-collector/src/config.rs +++ b/energy-integration/fees-collector/src/config.rs @@ -11,6 +11,7 @@ pub trait ConfigModule { self.blockchain().is_smart_contract(&sc), "Invalid SC address" ); + let _ = mapper.insert(sc); } } @@ -32,10 +33,12 @@ pub trait ConfigModule { for token in tokens { require!(token.is_valid_esdt_identifier(), "Invalid token ID"); - if !known_tokens_mapper.contains(&token) { - known_tokens_mapper.add(&token); - all_tokens_vec.push(token); + if known_tokens_mapper.contains(&token) { + continue; } + + known_tokens_mapper.add(&token); + all_tokens_vec.push(token); } self.all_tokens().set(&all_tokens_vec); @@ -47,28 +50,29 @@ pub trait ConfigModule { let mut all_tokens_vec = self.all_tokens().get(); let known_tokens_mapper = self.known_tokens(); for token in tokens { - if known_tokens_mapper.contains(&token) { - known_tokens_mapper.remove(&token); + if !known_tokens_mapper.contains(&token) { + continue; + } - unsafe { - let index = all_tokens_vec.find(&token).unwrap_unchecked(); - all_tokens_vec.remove(index); - } + known_tokens_mapper.remove(&token); + unsafe { + let index = all_tokens_vec.find(&token).unwrap_unchecked(); + all_tokens_vec.remove(index); } } self.all_tokens().set(&all_tokens_vec); } - #[view(getLockedTokenId)] - #[storage_mapper("lockedTokenId")] - fn locked_token_id(&self) -> SingleValueMapper; - #[view(getAllTokens)] fn get_all_tokens(&self) -> MultiValueEncoded { self.all_tokens().get().into() } + #[view(getLockedTokenId)] + #[storage_mapper("lockedTokenId")] + fn locked_token_id(&self) -> SingleValueMapper; + #[view(getAllKnownContracts)] #[storage_mapper("knownContracts")] fn known_contracts(&self) -> UnorderedSetMapper; diff --git a/energy-integration/fees-collector/src/events.rs b/energy-integration/fees-collector/src/events.rs index 4962de3e5..7e10ea434 100644 --- a/energy-integration/fees-collector/src/events.rs +++ b/energy-integration/fees-collector/src/events.rs @@ -6,9 +6,9 @@ use common_types::Week; pub trait FeesCollectorEventsModule { fn emit_deposit_swap_fees_event( self, - caller: ManagedAddress, + caller: &ManagedAddress, current_week: Week, - payment: EsdtTokenPayment, + payment: &EsdtTokenPayment, ) { self.deposit_swap_fees_event(caller, current_week, payment); } @@ -16,8 +16,8 @@ pub trait FeesCollectorEventsModule { #[event("deposit_swap_fees_event")] fn deposit_swap_fees_event( &self, - #[indexed] caller: ManagedAddress, + #[indexed] caller: &ManagedAddress, #[indexed] current_week: Week, - #[indexed] payment: EsdtTokenPayment, + #[indexed] payment: &EsdtTokenPayment, ); } diff --git a/energy-integration/fees-collector/src/fees_accumulation.rs b/energy-integration/fees-collector/src/fees_accumulation.rs index f2857407f..e6eb4ba41 100644 --- a/energy-integration/fees-collector/src/fees_accumulation.rs +++ b/energy-integration/fees-collector/src/fees_accumulation.rs @@ -25,23 +25,25 @@ pub trait FeesAccumulationModule: self.known_tokens().contains(&payment.token_identifier), "Invalid payment token" ); - let current_week = self.get_current_week(); if payment.token_nonce > 0 { require!( payment.token_identifier == self.locked_token_id().get(), "Invalid locked token" ); + self.send().esdt_local_burn( &payment.token_identifier, payment.token_nonce, &payment.amount, ); } + + let current_week = self.get_current_week(); self.accumulated_fees(current_week, &payment.token_identifier) .update(|amt| *amt += &payment.amount); - self.emit_deposit_swap_fees_event(caller, current_week, payment); + self.emit_deposit_swap_fees_event(&caller, current_week, &payment); } fn get_and_clear_accumulated_fees( diff --git a/energy-integration/fees-collector/src/lib.rs b/energy-integration/fees-collector/src/lib.rs index e78ed6812..2ee36602c 100644 --- a/energy-integration/fees-collector/src/lib.rs +++ b/energy-integration/fees-collector/src/lib.rs @@ -2,14 +2,12 @@ multiversx_sc::imports!(); -use common_types::{PaymentsVec, Week}; -use core::marker::PhantomData; -use weekly_rewards_splitting::base_impl::WeeklyRewardsSplittingTraitsModule; - pub mod additional_locked_tokens; +pub mod claim; pub mod config; pub mod events; pub mod fees_accumulation; +pub mod redistribute_rewards; #[multiversx_sc::contract] pub trait FeesCollector: @@ -28,145 +26,35 @@ pub trait FeesCollector: + multiversx_sc_modules::pause::PauseModule + utils::UtilsModule + sc_whitelist_module::SCWhitelistModule + + multiversx_sc_modules::only_admin::OnlyAdminModule + + claim::ClaimModule + + redistribute_rewards::RedistributeRewardsModule { #[init] - fn init(&self, locked_token_id: TokenIdentifier, energy_factory_address: ManagedAddress) { - let current_epoch = self.blockchain().get_block_epoch(); - self.first_week_start_epoch().set_if_empty(current_epoch); + fn init( + &self, + locked_token_id: TokenIdentifier, + energy_factory_address: ManagedAddress, + admins: MultiValueEncoded, + ) { self.require_valid_token_id(&locked_token_id); self.require_sc_address(&energy_factory_address); + let current_epoch = self.blockchain().get_block_epoch(); + self.first_week_start_epoch().set(current_epoch); + let mut tokens = MultiValueEncoded::new(); tokens.push(locked_token_id.clone()); self.add_known_tokens(tokens); - self.locked_token_id().set_if_empty(locked_token_id); - self.energy_factory_address().set(&energy_factory_address); - } - - #[upgrade] - fn upgrade(&self) {} - - #[endpoint(claimRewards)] - fn claim_rewards_endpoint( - &self, - opt_original_caller: OptionalValue, - ) -> PaymentsVec { - require!(self.not_paused(), "Cannot claim while paused"); - - let caller = self.blockchain().get_caller(); - let original_caller = self.get_orig_caller_from_opt(&caller, opt_original_caller); - - self.claim_rewards(caller, original_caller) - } - - #[endpoint(claimBoostedRewards)] - fn claim_boosted_rewards( - &self, - opt_original_caller: OptionalValue, - ) -> PaymentsVec { - require!(self.not_paused(), "Cannot claim while paused"); - - let original_caller = match opt_original_caller { - OptionalValue::Some(user) => { - require!( - self.allow_external_claim_rewards(&user).get(), - "Cannot claim rewards for this address" - ); - user - } - OptionalValue::None => self.blockchain().get_caller(), - }; - - self.claim_rewards(original_caller.clone(), original_caller) - } - - fn claim_rewards( - &self, - caller: ManagedAddress, - original_caller: ManagedAddress, - ) -> PaymentsVec { - self.accumulate_additional_locked_tokens(); - - let wrapper = FeesCollectorWrapper::new(); - let mut rewards = self.claim_multi(&wrapper, &original_caller); - if rewards.is_empty() { - return rewards; - } - - let locked_token_id = self.get_locked_token_id(); - let mut i = 0; - let mut len = rewards.len(); - let mut total_locked_token_rewards_amount = BigUint::zero(); - while i < len { - let rew = rewards.get(i); - if rew.token_identifier != locked_token_id { - i += 1; - continue; - } + self.locked_token_id().set(locked_token_id); + self.energy_factory_address().set(energy_factory_address); - total_locked_token_rewards_amount += rew.amount; - len -= 1; - rewards.remove(i); - } - - if !rewards.is_empty() { - self.send().direct_multi(&caller, &rewards); - } - - if total_locked_token_rewards_amount > 0 { - let locked_rewards = self.lock_virtual( - self.get_base_token_id(), - total_locked_token_rewards_amount, - caller, - original_caller, - ); - - rewards.push(locked_rewards); - } - - rewards - } -} - -pub struct FeesCollectorWrapper { - phantom: PhantomData, -} - -impl Default for FeesCollectorWrapper { - fn default() -> Self { - Self::new() - } -} - -impl FeesCollectorWrapper { - pub fn new() -> FeesCollectorWrapper { - FeesCollectorWrapper { - phantom: PhantomData, + for admin in admins { + self.add_admin(admin); } } -} - -impl WeeklyRewardsSplittingTraitsModule for FeesCollectorWrapper -where - T: FeesCollector, -{ - type WeeklyRewardsSplittingMod = T; - fn collect_rewards_for_week( - &self, - sc: &Self::WeeklyRewardsSplittingMod, - week: Week, - ) -> PaymentsVec<::Api> { - let mut results = ManagedVec::new(); - let all_tokens = sc.all_tokens().get(); - for token in &all_tokens { - let opt_accumulated_fees = sc.get_and_clear_accumulated_fees(week, &token); - if let Some(accumulated_fees) = opt_accumulated_fees { - results.push(EsdtTokenPayment::new(token, 0, accumulated_fees)); - } - } - - results - } + #[upgrade] + fn upgrade(&self) {} } diff --git a/energy-integration/fees-collector/src/redistribute_rewards.rs b/energy-integration/fees-collector/src/redistribute_rewards.rs new file mode 100644 index 000000000..d3c5d35ce --- /dev/null +++ b/energy-integration/fees-collector/src/redistribute_rewards.rs @@ -0,0 +1,75 @@ +use common_types::{PaymentsVec, TokenAmountPair, Week}; +use weekly_rewards_splitting::USER_MAX_CLAIM_WEEKS; + +multiversx_sc::imports!(); + +#[multiversx_sc::module] +pub trait RedistributeRewardsModule: + crate::fees_accumulation::FeesAccumulationModule + + crate::config::ConfigModule + + crate::events::FeesCollectorEventsModule + + week_timekeeping::WeekTimekeepingModule + + multiversx_sc_modules::only_admin::OnlyAdminModule +{ + #[only_admin] + #[endpoint(redistributeRewards)] + fn redistribute_rewards(&self, start_week: Week, end_week: Week) { + let collect_rewards_offset = USER_MAX_CLAIM_WEEKS + 1; + let current_week = self.get_current_week(); + require!( + current_week > collect_rewards_offset, + "Current week must be higher than the week offset" + ); + require!(start_week <= end_week, "Invalid week numbers"); + require!( + end_week <= current_week - collect_rewards_offset, + "Invalid end week" + ); + + let all_tokens = self.all_tokens().get(); + let mut all_rewards = ManagedVec::new(); + for token_id in &all_tokens { + all_rewards.push(TokenAmountPair::new(token_id, BigUint::zero())); + } + + for week in start_week..=end_week { + self.accumulate_remaining_rewards_single_week(&mut all_rewards, &all_tokens, week); + } + + for reward_entry in &all_rewards { + if reward_entry.amount == 0 { + continue; + } + + self.accumulated_fees(current_week, &reward_entry.token) + .update(|acc_fees| *acc_fees += reward_entry.amount); + } + } + + fn accumulate_remaining_rewards_single_week( + &self, + all_rewards: &mut ManagedVec>, + all_tokens: &ManagedVec, + week: Week, + ) { + let remaining_rewards = self.remaining_rewards(week).take(); + for rem_rew_entry in &remaining_rewards { + if rem_rew_entry.amount == 0 { + continue; + } + + let opt_index = all_tokens.find(&rem_rew_entry.token_identifier); + if opt_index.is_none() { + continue; + } + + let index = unsafe { opt_index.unwrap_unchecked() }; + let mut rew_entry = all_rewards.get_mut(index); + rew_entry.amount += rem_rew_entry.amount; + } + } + + #[view(getRemainingRewards)] + #[storage_mapper("remainingRewards")] + fn remaining_rewards(&self, week: Week) -> SingleValueMapper>; +} diff --git a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs index 11151d2dc..538c04e3e 100644 --- a/energy-integration/fees-collector/tests/fees_collector_rust_test.rs +++ b/energy-integration/fees-collector/tests/fees_collector_rust_test.rs @@ -5,6 +5,7 @@ mod fees_collector_test_setup; use energy_query::Energy; use fees_collector::additional_locked_tokens::{AdditionalLockedTokensModule, BLOCKS_IN_WEEK}; use fees_collector::fees_accumulation::FeesAccumulationModule; +use fees_collector::redistribute_rewards::RedistributeRewardsModule; use fees_collector_test_setup::*; use multiversx_sc::types::{BigInt, EsdtTokenPayment, ManagedVec}; use multiversx_sc_scenario::{ @@ -1419,3 +1420,196 @@ fn additional_locked_tokens_test() { }) .assert_ok(); } + +#[test] +fn redistribute_rewards_test() { + let rust_zero = rust_biguint!(0); + let mut fc_setup = + FeesCollectorSetup::new(fees_collector::contract_obj, energy_factory::contract_obj); + + let first_user = fc_setup.b_mock.create_user_account(&rust_zero); + let second_user = fc_setup.b_mock.create_user_account(&rust_zero); + let third_user = fc_setup.b_mock.create_user_account(&rust_zero); + + fc_setup.set_energy(&first_user, 50, 3_000); + fc_setup.set_energy(&second_user, 50, 9_000); + fc_setup.set_energy(&third_user, 1, 1); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.claim(&first_user).assert_ok(); + fc_setup.claim(&second_user).assert_ok(); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 2 (inactive week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + fc_setup + .b_mock + .execute_query(&fc_setup.fc_wrapper, |sc| { + let mut expected_total_rewards = ManagedVec::new(); + expected_total_rewards.push(EsdtTokenPayment::new( + managed_token_id!(FIRST_TOKEN_ID), + 0, + managed_biguint!(USER_BALANCE / 10), + )); + expected_total_rewards.push(EsdtTokenPayment::new( + managed_token_id!(SECOND_TOKEN_ID), + 0, + managed_biguint!(USER_BALANCE / 20), + )); + assert_eq!(expected_total_rewards, sc.total_rewards_for_week(1).get()); + }) + .assert_ok(); + + // advance to week 3 (inactive week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 4 (active week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 5 (active week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 6 (active week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 7 (active week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 8 (active week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 9 (active week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // advance to week 10 (active week) + fc_setup.advance_week(); + + fc_setup + .deposit(FIRST_TOKEN_ID, USER_BALANCE / 10) + .assert_ok(); + fc_setup + .deposit(SECOND_TOKEN_ID, USER_BALANCE / 20) + .assert_ok(); + + fc_setup.set_energy(&third_user, 1, 1); + fc_setup.claim(&third_user).assert_ok(); + + // redist rewards + fc_setup + .b_mock + .execute_tx( + &fc_setup.owner_address, + &fc_setup.fc_wrapper, + &rust_zero, + |sc| { + sc.redistribute_rewards(1, 5); + + // Rewards were put in current_week storage (i.e. 10) + + let first_token_balance = sc + .accumulated_fees(10, &managed_token_id!(FIRST_TOKEN_ID)) + .get(); + let second_token_balance = sc + .accumulated_fees(10, &managed_token_id!(SECOND_TOKEN_ID)) + .get(); + + // i.e. 6 weeks worth of rewards minus what the third user claimed + assert_eq!( + first_token_balance, + managed_biguint!(599_952_417_140_485_515u64) + ); + assert_eq!( + second_token_balance, + managed_biguint!(299_976_208_570_242_758) + ); + }, + ) + .assert_ok(); +} diff --git a/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs b/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs index 359c4eeb5..3bc7d4bca 100644 --- a/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs +++ b/energy-integration/fees-collector/tests/fees_collector_test_setup/mod.rs @@ -1,5 +1,6 @@ #![allow(deprecated)] +use claim::ClaimModule; use multiversx_sc::{ codec::multi_types::OptionalValue, storage::mappers::StorageTokenWrapper, @@ -148,9 +149,13 @@ where b_mock .execute_tx(&owner_address, &fc_wrapper, &rust_zero, |sc| { + let mut admins = MultiValueEncoded::new(); + admins.push(managed_address!(&owner_address)); + sc.init( managed_token_id!(LOCKED_TOKEN_ID), managed_address!(energy_factory_wrapper.address_ref()), + admins, ); let _ = sc diff --git a/energy-integration/fees-collector/wasm/src/lib.rs b/energy-integration/fees-collector/wasm/src/lib.rs index 77034bd4a..4aab5f1d3 100644 --- a/energy-integration/fees-collector/wasm/src/lib.rs +++ b/energy-integration/fees-collector/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 37 +// Endpoints: 43 // Async Callback (empty): 1 -// Total number of exported functions: 40 +// Total number of exported functions: 46 #![no_std] @@ -20,14 +20,12 @@ multiversx_sc_wasm_adapter::endpoints! { ( init => init upgrade => upgrade - claimRewards => claim_rewards_endpoint - claimBoostedRewards => claim_boosted_rewards addKnownContracts => add_known_contracts removeKnownContracts => remove_known_contracts addKnownTokens => add_known_tokens removeKnownTokens => remove_known_tokens - getLockedTokenId => locked_token_id getAllTokens => get_all_tokens + getLockedTokenId => locked_token_id getAllKnownContracts => known_contracts getAllowExternalClaimRewards => allow_external_claim_rewards getLastActiveWeekForUser => get_last_active_week_for_user_view @@ -57,6 +55,14 @@ multiversx_sc_wasm_adapter::endpoints! { addSCAddressToWhitelist => add_sc_address_to_whitelist removeSCAddressFromWhitelist => remove_sc_address_from_whitelist isSCAddressWhitelisted => is_sc_address_whitelisted + isAdmin => is_admin + addAdmin => add_admin + removeAdmin => remove_admin + getAdmins => admins + claimRewards => claim_rewards_endpoint + claimBoostedRewards => claim_boosted_rewards + redistributeRewards => redistribute_rewards + getRemainingRewards => remaining_rewards ) } diff --git a/energy-integration/governance-v2/tests/gov_test_setup/mod.rs b/energy-integration/governance-v2/tests/gov_test_setup/mod.rs index c1d448442..5cc2d851c 100644 --- a/energy-integration/governance-v2/tests/gov_test_setup/mod.rs +++ b/energy-integration/governance-v2/tests/gov_test_setup/mod.rs @@ -2,7 +2,7 @@ use energy_factory_mock::EnergyFactoryMock; use energy_query::Energy; -use fees_collector::FeesCollector; +use fees_collector::{claim::ClaimModule, FeesCollector}; use governance_v2::{ configurable::ConfigurablePropertiesModule, proposal_storage::{ProposalStorageModule, VoteType}, @@ -112,6 +112,7 @@ where sc.init( managed_token_id!(XMEX_TOKEN_ID), managed_address!(energy_factory_wrapper.address_ref()), + MultiValueEncoded::new(), ); }) .assert_ok();