diff --git a/modules/incentives/src/lib.rs b/modules/incentives/src/lib.rs index d5b7ab4064..b99cd73e50 100644 --- a/modules/incentives/src/lib.rs +++ b/modules/incentives/src/lib.rs @@ -21,34 +21,27 @@ //! ## Overview //! //! Acala platform need support different types of rewards for some other protocol. -//! Each type of reward has a pool with its own reward currency type and reward accumulation -//! mechanism. ORML rewards module records the total shares, total rewards anduser shares of -//! specific pool. Incentives module provides hooks to other protocals to manage shares, accumulates -//! rewards and distributes rewards to users based on their shares. +//! Each Pool has its own multi currencies rewards and reward accumulation +//! mechanism. ORML rewards module records the total shares, total multi currencies rewards anduser +//! shares of specific pool. Incentives module provides hooks to other protocals to manage shares, +//! accumulates rewards and distributes rewards to users based on their shares. //! //! Pool types: -//! 1. LoansIncentive: this is platform‘s reward to users of Honzon protocol, reward currency type -//! is native currency. -//! 2. DexIncentive: this is platform‘s reward to makers of DEX, reward currency type is native -//! currency. -//! 3. HomaIncentive: this is platform‘s reward to users of Homa protocol, reward currency -//! type is native currency. -//! 4. DexSaving: this is Honzon protocol's extra reward to makers of DEX because they participate -//! in the liquidation of unsafe CDP, reward currency type is stable currency. -//! 5. HomaValidatorAllowance: this is third party's allowance to guarantor of Homa protocol, reward -//! currency type is liquid currency. +//! 1. Loans: record the shares and rewards for users of Loans(Honzon protocol). +//! 2. Dex: record the shares and rewards for DEX makers who staking LP token. //! -//! Reward sources: -//! 1. Native currency(ACA/KAR): reward comes from unreleased reservation because the economic -//! mechanism of Acala is not an inflation model. -//! 2. Stable currency(AUSD/KUSD): reward comes from debit pool of CDP treasury. -//! 3. Liquid currency(LDOT/LKSM): reward comes from the transfer of other accounts(Usually are the -//! validators on the relay chain). -//! -//! Reward accumulation: -//! 1. LoansIncentive/DexIncentive/HomaIncentive/DexSaving: the fixed blocks is -//! period(AccumulatePeriod), and on the beginning of each period will accumulate reward. -//! 2. HomaValidatorAllowance: transfer rewards into the vault account. +//! Rewards accumulation: +//! 1. Incentives: periodicly(AccumulatePeriod), accumulate fixed amount according to Incentive. +//! Rewards come from RewardsSource, please transfer enough tokens to RewardsSource before +//! start incentive plan. +//! 2. DexSaving: periodicly(AccumulatePeriod), the reward currency is Stable(KUSD/AUSD), +//! the accumulation amount is the multiplier of DexSavingRewardRates and the stable amount of +//! corresponding liquidity pool. CDPTreasury will issue the stable currency to RewardsSource. + +//! TODO list: +//! 1. Refactor PoolId, decoupling PoolId with reward currency type and reward accumulation +//! mechanism 2. Remove unused +//! 3. Migration #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::unused_unit)] @@ -62,36 +55,26 @@ use sp_runtime::{ traits::{AccountIdConversion, MaybeDisplay, One, UniqueSaturatedInto, Zero}, DispatchResult, FixedPointNumber, RuntimeDebug, }; -use sp_std::{fmt::Debug, vec::Vec}; +use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, prelude::*}; use support::{CDPTreasury, DEXIncentives, DEXManager, EmergencyShutdown, Rate}; +pub mod migrations; mod mock; mod tests; pub mod weights; +pub use migrations::{get_reward_currency_id, PoolIdConvertor, PoolIdV0}; pub use module::*; pub use weights::WeightInfo; /// PoolId for various rewards pools -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] -pub enum PoolId { - /// Rewards pool(NativeCurrencyId) for users who open CDP - LoansIncentive(CurrencyId), - - /// Rewards pool(NativeCurrencyId) for market makers who provide dex - /// liquidity - DexIncentive(CurrencyId), - - /// Rewards pool(NativeCurrencyId) for users who staking by Homa protocol - HomaIncentive, +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] +pub enum PoolId { + /// Rewards and shares pool for users who open CDP(CollateralCurrencyId) + Loans(CurrencyId), - /// Rewards pool(StableCurrencyId) for liquidators who provide dex liquidity - /// to participate automatic liquidation - DexSaving(CurrencyId), - - /// Rewards pool(LiquidCurrencyId) for users who guarantee for validators by - /// Homa protocol - HomaValidatorAllowance(AccountId), + /// Rewards and shares pool for DEX makers who stake LP token(LPCurrencyId) + Dex(CurrencyId), } #[frame_support::pallet] @@ -101,11 +84,18 @@ pub mod module { #[pallet::config] pub trait Config: frame_system::Config - + orml_rewards::Config> + + orml_rewards::Config< + Share = Balance, + Balance = Balance, + PoolIdV0 = PoolIdV0, + PoolId = PoolId, + CurrencyId = CurrencyId, + > { type Event: From> + IsType<::Event>; /// The type of validator account id on relaychain. + /// NOTE: remove it after migration type RelaychainAccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord + Default; /// The period to accumulate rewards @@ -113,6 +103,7 @@ pub mod module { type AccumulatePeriod: Get; /// The reward type for incentive. + /// NOTE: remove it after migration #[pallet::constant] type NativeCurrencyId: Get; @@ -121,12 +112,13 @@ pub mod module { type StableCurrencyId: Get; /// The reward type for homa validator insurance + /// NOTE: remove it after migration #[pallet::constant] type LiquidCurrencyId: Get; /// The source account for native token rewards. #[pallet::constant] - type NativeRewardsSource: Get; + type RewardsSource: Get; /// The origin which may update incentive related params type UpdateOrigin: EnsureOrigin; @@ -165,67 +157,107 @@ pub mod module { #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] - #[pallet::metadata(T::AccountId = "AccountId", PoolId = "PoolId")] + #[pallet::metadata(T::AccountId = "AccountId", PoolId = "PoolId")] pub enum Event { /// Deposit DEX share. \[who, dex_share_type, deposit_amount\] DepositDexShare(T::AccountId, CurrencyId, Balance), /// Withdraw DEX share. \[who, dex_share_type, withdraw_amount\] WithdrawDexShare(T::AccountId, CurrencyId, Balance), /// Claim rewards. \[who, pool_id, reward_currency_id, actual_amount, deduction_amount\] - ClaimRewards( - T::AccountId, - PoolId, - CurrencyId, - Balance, - Balance, - ), - /// Incentive reward amount updated. \[pool_id, reward_amount_per_period\] - IncentiveRewardAmountUpdated(PoolId, Balance), + ClaimRewards(T::AccountId, PoolId, CurrencyId, Balance, Balance), + /// Incentive reward amount updated. \[pool_id, reward_currency_id, + /// reward_amount_per_period\] + IncentiveRewardAmountUpdated(PoolId, CurrencyId, Balance), /// Saving reward rate updated. \[pool_id, reward_rate_per_period\] - SavingRewardRateUpdated(PoolId, Rate), + SavingRewardRateUpdated(PoolId, Rate), /// Payout deduction rate updated. \[pool_id, deduction_rate\] - PayoutDeductionRateUpdated(PoolId, Rate), + ClaimRewardDeductionRateUpdated(PoolId, Rate), } /// Mapping from pool to its fixed reward amount per period. /// - /// IncentiveRewardAmount: map PoolId => Balance + /// IncentiveRewardAmount: map PoolIdV0 => Balance + /// NOTE: will be renamed to `IncentiveRewardAmounts` in new release, remove it after migration #[pallet::storage] #[pallet::getter(fn incentive_reward_amount)] pub type IncentiveRewardAmount = - StorageMap<_, Twox64Concat, PoolId, Balance, ValueQuery>; + StorageMap<_, Twox64Concat, PoolIdV0, Balance, ValueQuery>; /// Mapping from pool to its fixed reward rate per period. /// - /// DexSavingRewardRate: map PoolId => Rate + /// DexSavingRewardRate: map PoolIdV0 => Rate + /// NOTE: will be renamed to `DexSavingRewardRates` in new release, remove it after migration #[pallet::storage] #[pallet::getter(fn dex_saving_reward_rate)] pub type DexSavingRewardRate = - StorageMap<_, Twox64Concat, PoolId, Rate, ValueQuery>; + StorageMap<_, Twox64Concat, PoolIdV0, Rate, ValueQuery>; /// Mapping from pool to its payout deduction rate. /// - /// PayoutDeductionRates: map PoolId => Rate + /// PayoutDeductionRates: map PoolIdV0 => Rate + /// NOTE: will be renamed to `ClaimRewardDeductionRates` in new release, remove it after + /// migration #[pallet::storage] #[pallet::getter(fn payout_deduction_rates)] pub type PayoutDeductionRates = - StorageMap<_, Twox64Concat, PoolId, Rate, ValueQuery>; + StorageMap<_, Twox64Concat, PoolIdV0, Rate, ValueQuery>; /// The pending rewards amount, actual available rewards amount may be deducted /// - /// PendingRewards: double_map PoolId, AccountId => Balance + /// PendingRewards: double_map PoolIdV0, AccountId => Balance + /// NOTE: will be migrate to `PendingMultiRewards` in new release, remove it after migration + /// done #[pallet::storage] #[pallet::getter(fn pending_rewards)] pub type PendingRewards = StorageDoubleMap< _, Twox64Concat, - PoolId, + PoolIdV0, Twox64Concat, T::AccountId, Balance, ValueQuery, >; + /// Mapping from pool to its fixed incentive amounts of multi currencies per period. + /// + /// IncentiveRewardAmounts: double_map Pool, RewardCurrencyId => RewardAmountPerPeriod + /// NOTE: need migrate from old `IncentiveRewardAmount` + #[pallet::storage] + #[pallet::getter(fn incentive_reward_amounts)] + pub type IncentiveRewardAmounts = + StorageDoubleMap<_, Twox64Concat, PoolId, Twox64Concat, CurrencyId, Balance, ValueQuery>; + + /// Mapping from pool to its fixed reward rate per period. + /// + /// DexSavingRewardRates: map Pool => SavingRatePerPeriod + /// NOTE: need migrate from old `DexSavingRewardRate` + #[pallet::storage] + #[pallet::getter(fn dex_saving_reward_rates)] + pub type DexSavingRewardRates = StorageMap<_, Twox64Concat, PoolId, Rate, ValueQuery>; + + /// Mapping from pool to its claim reward deduction rate. + /// + /// ClaimRewardDeductionRates: map Pool => DeductionRate + #[pallet::storage] + #[pallet::getter(fn claim_reward_deduction_rates)] + pub type ClaimRewardDeductionRates = StorageMap<_, Twox64Concat, PoolId, Rate, ValueQuery>; + + /// The pending rewards amount, actual available rewards amount may be deducted + /// + /// PendingMultiRewards: double_map PoolId, AccountId => BTreeMap + #[pallet::storage] + #[pallet::getter(fn pending_multi_rewards)] + pub type PendingMultiRewards = StorageDoubleMap< + _, + Twox64Concat, + PoolId, + Twox64Concat, + T::AccountId, + BTreeMap, + ValueQuery, + >; + #[pallet::pallet] pub struct Pallet(_); @@ -233,91 +265,26 @@ pub mod module { impl Hooks for Pallet { fn on_initialize(now: T::BlockNumber) -> Weight { // accumulate reward periodically - if !T::EmergencyShutdown::is_shutdown() && now % T::AccumulatePeriod::get() == Zero::zero() { + if now % T::AccumulatePeriod::get() == Zero::zero() { let mut count: u32 = 0; - let native_currency_id = T::NativeCurrencyId::get(); - let stable_currency_id = T::StableCurrencyId::get(); + let shutdown = T::EmergencyShutdown::is_shutdown(); - for (pool_id, pool_info) in orml_rewards::Pools::::iter() { + for (pool_id, pool_info) in orml_rewards::PoolInfos::::iter() { if !pool_info.total_shares.is_zero() { match pool_id { - PoolId::LoansIncentive(_) | PoolId::DexIncentive(_) | PoolId::HomaIncentive => { + // do not accumulate incentives for PoolId::Loans after shutdown + PoolId::Loans(_) if !shutdown => { count += 1; - let incentive_reward_amount = Self::incentive_reward_amount(pool_id.clone()); - - if !incentive_reward_amount.is_zero() { - let res = T::Currency::transfer( - native_currency_id, - &T::NativeRewardsSource::get(), - &Self::account_id(), - incentive_reward_amount, - ); - match res { - Ok(_) => { - >::accumulate_reward( - &pool_id, - incentive_reward_amount, - ); - } - Err(e) => { - log::warn!( - target: "incentives", - "transfer: failed to transfer {:?} {:?} from {:?} to {:?}: {:?}. \ - This is unexpected but should be safe", - incentive_reward_amount, native_currency_id, T::NativeRewardsSource::get(), Self::account_id(), e - ); - } - } - } + Self::accumulate_incentives(pool_id); } - - PoolId::DexSaving(lp_currency_id) => { - count += 1; - let dex_saving_reward_rate = Self::dex_saving_reward_rate(pool_id.clone()); - - if !dex_saving_reward_rate.is_zero() { - if let Some((currency_id_a, currency_id_b)) = - lp_currency_id.split_dex_share_currency_id() - { - // accumulate saving reward only for liquidity pool of stable currency id - let dex_saving_reward_base = if currency_id_a == stable_currency_id { - T::DEX::get_liquidity_pool(stable_currency_id, currency_id_b).0 - } else if currency_id_b == stable_currency_id { - T::DEX::get_liquidity_pool(stable_currency_id, currency_id_a).0 - } else { - Zero::zero() - }; - let dex_saving_reward_amount = - dex_saving_reward_rate.saturating_mul_int(dex_saving_reward_base); - - // issue stable coin without backing. - if !dex_saving_reward_amount.is_zero() { - let res = T::CDPTreasury::issue_debit( - &Self::account_id(), - dex_saving_reward_amount, - false, - ); - match res { - Ok(_) => { - >::accumulate_reward( - &pool_id, - dex_saving_reward_amount, - ); - } - Err(e) => { - log::warn!( - target: "incentives", - "issue_debit: failed to issue {:?} unbacked stable to {:?}: {:?}. \ - This is unexpected but should be safe", - dex_saving_reward_amount, Self::account_id(), e - ); - } - } - } - } + PoolId::Dex(lp_currency_id) => { + // do not accumulate dex saving any more after shutdown + if !shutdown { + Self::accumulate_dex_saving(lp_currency_id, pool_id); } + count += 1; + Self::accumulate_incentives(pool_id); } - _ => {} } } @@ -328,10 +295,39 @@ pub mod module { 0 } } + + fn on_runtime_upgrade() -> Weight { + let mut accumulated_weight: Weight = 0; + + // migrate orml-rewards `Pools` to `PoolInfos` + let get_reward_currency = + |old_pool_id: &PoolIdV0| get_reward_currency_id::(old_pool_id.clone()); + accumulated_weight = accumulated_weight.saturating_add( + orml_rewards::migrations::migrate_to_pool_infos::(None, Box::new(get_reward_currency)), + ); + + // migrate `PayoutDeductionRates` to `ClaimRewardDeductionRates` + // migrate `DexSavingRewardRate` to `DexSavingRewardRates` + // migrate `IncentiveRewardAmount` to `IncentiveRewardAmounts` + accumulated_weight = accumulated_weight + .saturating_add(crate::migrations::migrate_to_claim_reward_deduction_rates::(None)); + accumulated_weight = + accumulated_weight.saturating_add(crate::migrations::migrate_to_dex_saving_reward_rates::(None)); + accumulated_weight = + accumulated_weight.saturating_add(crate::migrations::migrate_to_incentive_reward_amounts::(None)); + + accumulated_weight + } } #[pallet::call] impl Pallet { + /// Stake LP token to add shares of Pool::Dex + /// + /// The dispatch origin of this call must be `Signed` by the transactor. + /// + /// - `lp_currency_id`: LP token type + /// - `amount`: amount to stake #[pallet::weight(::WeightInfo::deposit_dex_share())] #[transactional] pub fn deposit_dex_share(origin: OriginFor, lp_currency_id: CurrencyId, amount: Balance) -> DispatchResult { @@ -340,6 +336,12 @@ pub mod module { Ok(()) } + /// Unstake LP token to remove shares of Pool::Dex + /// + /// The dispatch origin of this call must be `Signed` by the transactor. + /// + /// - `lp_currency_id`: LP token type + /// - `amount`: amount to unstake #[pallet::weight(::WeightInfo::withdraw_dex_share())] #[transactional] pub fn withdraw_dex_share(origin: OriginFor, lp_currency_id: CurrencyId, amount: Balance) -> DispatchResult { @@ -348,31 +350,32 @@ pub mod module { Ok(()) } + /// Claim all avalible multi currencies rewards for specific PoolId. + /// + /// The dispatch origin of this call must be `Signed` by the transactor. + /// + /// - `pool_id`: pool type #[pallet::weight(::WeightInfo::claim_rewards())] #[transactional] - pub fn claim_rewards(origin: OriginFor, pool_id: PoolId) -> DispatchResult { + pub fn claim_rewards(origin: OriginFor, pool_id: PoolId) -> DispatchResult { let who = ensure_signed(origin)?; + // orml_rewards will claim rewards for all currencies rewards >::claim_rewards(&who, &pool_id); - let pending_reward: Balance = PendingRewards::::take(&pool_id, &who); - if !pending_reward.is_zero() { - let currency_id = match pool_id { - PoolId::LoansIncentive(_) | PoolId::DexIncentive(_) | PoolId::HomaIncentive => { - T::NativeCurrencyId::get() - } - PoolId::DexSaving(_) => T::StableCurrencyId::get(), - PoolId::HomaValidatorAllowance(_) => T::LiquidCurrencyId::get(), - }; + let pending_multi_rewards: BTreeMap = PendingMultiRewards::::take(&pool_id, &who); + let deduction_rate = Self::claim_reward_deduction_rates(&pool_id); + for (currency_id, pending_reward) in pending_multi_rewards { + if pending_reward.is_zero() { + continue; + } // calculate actual rewards and deduction amount let (actual_amount, deduction_amount) = { - let deduction_amount = Self::payout_deduction_rates(&pool_id) - .saturating_mul_int(pending_reward) - .min(pending_reward); + let deduction_amount = deduction_rate.saturating_mul_int(pending_reward).min(pending_reward); if !deduction_amount.is_zero() { // re-accumulate deduction to rewards pool if deduction amount is not zero - >::accumulate_reward(&pool_id, deduction_amount); + >::accumulate_reward(&pool_id, currency_id, deduction_amount)?; } (pending_reward.saturating_sub(deduction_amount), deduction_amount) }; @@ -383,7 +386,7 @@ pub mod module { T::Currency::transfer(currency_id, &Self::account_id(), &who, actual_amount)?; Self::deposit_event(Event::ClaimRewards( - who, + who.clone(), pool_id, currency_id, actual_amount, @@ -394,91 +397,135 @@ pub mod module { Ok(()) } - #[pallet::weight(::WeightInfo::update_incentive_rewards(updates.len() as u32))] + /// Update incentive reward amount for specific PoolId + /// + /// The dispatch origin of this call must be `UpdateOrigin`. + /// + /// - `updates`: Vec<(PoolId, Vec<(RewardCurrencyId, FixedAmountPerPeriod)>)> + #[pallet::weight(::WeightInfo::update_incentive_rewards( + updates.iter().fold(0, |count, x| count + x.1.len()) as u32 + ))] #[transactional] pub fn update_incentive_rewards( origin: OriginFor, - updates: Vec<(PoolId, Balance)>, + updates: Vec<(PoolId, Vec<(CurrencyId, Balance)>)>, ) -> DispatchResult { T::UpdateOrigin::ensure_origin(origin)?; - for (pool_id, amount) in updates { - match pool_id { - PoolId::DexIncentive(currency_id) => { - ensure!(currency_id.is_dex_share_currency_id(), Error::::InvalidCurrencyId); - } - PoolId::LoansIncentive(_) | PoolId::HomaIncentive => {} - _ => { - return Err(Error::::InvalidPoolId.into()); - } + for (pool_id, update_list) in updates { + if let PoolId::Dex(currency_id) = pool_id { + ensure!(currency_id.is_dex_share_currency_id(), Error::::InvalidPoolId); + } + + for (currency_id, amount) in update_list { + IncentiveRewardAmounts::::mutate_exists(pool_id, currency_id, |maybe_amount| { + let mut v = maybe_amount.unwrap_or_default(); + if amount != v { + v = amount; + Self::deposit_event(Event::IncentiveRewardAmountUpdated(pool_id, currency_id, amount)); + } + + if v.is_zero() { + *maybe_amount = None; + } else { + *maybe_amount = Some(v); + } + }); } - IncentiveRewardAmount::::insert(&pool_id, amount); - Self::deposit_event(Event::IncentiveRewardAmountUpdated(pool_id, amount)); } Ok(()) } + /// Update DEX saving reward rate for specific PoolId + /// + /// The dispatch origin of this call must be `UpdateOrigin`. + /// + /// - `updates`: Vec<(PoolId, Rate)> #[pallet::weight(::WeightInfo::update_dex_saving_rewards(updates.len() as u32))] #[transactional] - pub fn update_dex_saving_rewards( - origin: OriginFor, - updates: Vec<(PoolId, Rate)>, - ) -> DispatchResult { + pub fn update_dex_saving_rewards(origin: OriginFor, updates: Vec<(PoolId, Rate)>) -> DispatchResult { T::UpdateOrigin::ensure_origin(origin)?; for (pool_id, rate) in updates { match pool_id { - PoolId::DexSaving(currency_id) => { - ensure!(currency_id.is_dex_share_currency_id(), Error::::InvalidCurrencyId); + PoolId::Dex(currency_id) if currency_id.is_dex_share_currency_id() => {} + _ => return Err(Error::::InvalidPoolId.into()), + } + ensure!(rate <= Rate::one(), Error::::InvalidRate); + + DexSavingRewardRates::::mutate_exists(&pool_id, |maybe_rate| { + let mut v = maybe_rate.unwrap_or_default(); + if rate != v { + v = rate; + Self::deposit_event(Event::SavingRewardRateUpdated(pool_id, rate)); } - _ => { - return Err(Error::::InvalidPoolId.into()); + + if v.is_zero() { + *maybe_rate = None; + } else { + *maybe_rate = Some(v); } - } - DexSavingRewardRate::::insert(&pool_id, rate); - Self::deposit_event(Event::SavingRewardRateUpdated(pool_id, rate)); + }); } Ok(()) } - #[pallet::weight(::WeightInfo::update_payout_deduction_rates(updates.len() as u32))] + /// Update claim rewards deduction rates for all rewards currencies of specific PoolId + /// + /// The dispatch origin of this call must be `UpdateOrigin`. + /// + /// - `updates`: Vec<(PoolId, DecutionRate>)> + #[pallet::weight(::WeightInfo::update_claim_reward_deduction_rates(updates.len() as u32))] #[transactional] - pub fn update_payout_deduction_rates( + pub fn update_claim_reward_deduction_rates( origin: OriginFor, - updates: Vec<(PoolId, Rate)>, + updates: Vec<(PoolId, Rate)>, ) -> DispatchResult { T::UpdateOrigin::ensure_origin(origin)?; for (pool_id, deduction_rate) in updates { - match pool_id { - PoolId::DexSaving(currency_id) | PoolId::DexIncentive(currency_id) => { - ensure!(currency_id.is_dex_share_currency_id(), Error::::InvalidCurrencyId); - } - _ => {} + if let PoolId::Dex(currency_id) = pool_id { + ensure!(currency_id.is_dex_share_currency_id(), Error::::InvalidPoolId); } ensure!(deduction_rate <= Rate::one(), Error::::InvalidRate); - PayoutDeductionRates::::insert(&pool_id, deduction_rate); - Self::deposit_event(Event::PayoutDeductionRateUpdated(pool_id, deduction_rate)); + ClaimRewardDeductionRates::::mutate_exists(&pool_id, |maybe_rate| { + let mut v = maybe_rate.unwrap_or_default(); + if deduction_rate != v { + v = deduction_rate; + Self::deposit_event(Event::ClaimRewardDeductionRateUpdated(pool_id, deduction_rate)); + } + + if v.is_zero() { + *maybe_rate = None; + } else { + *maybe_rate = Some(v); + } + }); } Ok(()) } - #[pallet::weight(::WeightInfo::add_allowance())] + #[pallet::weight({ + let reads_and_writes: u64 = (count*2).into(); + ::DbWeight::get().reads_writes(reads_and_writes, reads_and_writes) + })] #[transactional] - pub fn add_allowance( - origin: OriginFor, - pool_id: PoolId, - amount: Balance, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - match pool_id { - PoolId::HomaValidatorAllowance(_) => { - T::Currency::transfer(T::LiquidCurrencyId::get(), &who, &Self::account_id(), amount)?; - >::accumulate_reward(&pool_id, amount); - } - _ => { - return Err(Error::::InvalidPoolId.into()); - } - } + pub fn migrate_share_and_withdrawn_reward(origin: OriginFor, count: u32) -> DispatchResult { + let _ = ensure_signed(origin)?; + let get_reward_currency = + |old_pool_id: &PoolIdV0| get_reward_currency_id::(old_pool_id.clone()); + orml_rewards::migrations::migrate_to_shares_and_withdrawn_rewards::( + Some(count as usize), + Box::new(get_reward_currency), + ); + Ok(()) + } + #[pallet::weight({ + let reads_and_writes: u64 = (count*2).into(); + ::DbWeight::get().reads_writes(reads_and_writes, reads_and_writes) + })] + #[transactional] + pub fn migrate_pending_rewards(origin: OriginFor, count: u32) -> DispatchResult { + let _ = ensure_signed(origin)?; + crate::migrations::migrate_to_pending_multi_rewards::(Some(count as usize)); Ok(()) } } @@ -488,6 +535,96 @@ impl Pallet { pub fn account_id() -> T::AccountId { T::PalletId::get().into_account() } + + // accumulate incentive rewards of multi currencies + fn accumulate_incentives(pool_id: PoolId) { + for (reward_currency_id, reward_amount) in IncentiveRewardAmounts::::iter_prefix(pool_id) { + if reward_amount.is_zero() { + continue; + } + + let res = T::Currency::transfer( + reward_currency_id, + &T::RewardsSource::get(), + &Self::account_id(), + reward_amount, + ); + + match res { + Ok(_) => { + let _ = >::accumulate_reward( + &pool_id, + reward_currency_id, + reward_amount, + ) + .map_err(|e| { + log::error!( + target: "incentives", + "accumulate_reward: failed to accumulate reward to non-existen pool {:?}, reward_currency_id {:?}, reward_amount {:?}: {:?}", + pool_id, reward_currency_id, reward_amount, e + ); + }); + } + Err(e) => { + log::warn!( + target: "incentives", + "transfer: failed to transfer {:?} {:?} from {:?} to {:?}: {:?}. \ + This is unexpected but should be safe", + reward_amount, reward_currency_id, T::RewardsSource::get(), Self::account_id(), e + ); + } + } + } + } + + // accumulate DEX saving reward(stable currency) for Dex Pool + fn accumulate_dex_saving(lp_currency_id: CurrencyId, pool_id: PoolId) { + let stable_currency_id = T::StableCurrencyId::get(); + let dex_saving_reward_rate = Self::dex_saving_reward_rates(&pool_id); + + if !dex_saving_reward_rate.is_zero() { + if let Some((currency_id_a, currency_id_b)) = lp_currency_id.split_dex_share_currency_id() { + // accumulate saving reward only for liquidity pool of stable currency id + let dex_saving_reward_base = if currency_id_a == stable_currency_id { + T::DEX::get_liquidity_pool(stable_currency_id, currency_id_b).0 + } else if currency_id_b == stable_currency_id { + T::DEX::get_liquidity_pool(stable_currency_id, currency_id_a).0 + } else { + Zero::zero() + }; + let dex_saving_reward_amount = dex_saving_reward_rate.saturating_mul_int(dex_saving_reward_base); + + // issue stable currency without backing. + if !dex_saving_reward_amount.is_zero() { + let res = T::CDPTreasury::issue_debit(&Self::account_id(), dex_saving_reward_amount, false); + match res { + Ok(_) => { + let _ = >::accumulate_reward( + &pool_id, + stable_currency_id, + dex_saving_reward_amount, + ) + .map_err(|e| { + log::error!( + target: "incentives", + "accumulate_reward: failed to accumulate reward to non-existen pool {:?}, reward_currency {:?}, amount {:?}: {:?}", + pool_id, stable_currency_id, dex_saving_reward_amount, e + ); + }); + } + Err(e) => { + log::warn!( + target: "incentives", + "issue_debit: failed to issue {:?} unbacked stable to {:?}: {:?}. \ + This is unexpected but should be safe", + dex_saving_reward_amount, Self::account_id(), e + ); + } + } + } + } + } + } } impl DEXIncentives for Pallet { @@ -495,12 +632,7 @@ impl DEXIncentives for Pallet { ensure!(lp_currency_id.is_dex_share_currency_id(), Error::::InvalidCurrencyId); T::Currency::transfer(lp_currency_id, who, &Self::account_id(), amount)?; - >::add_share( - who, - &PoolId::DexIncentive(lp_currency_id), - amount.unique_saturated_into(), - ); - >::add_share(who, &PoolId::DexSaving(lp_currency_id), amount); + >::add_share(who, &PoolId::Dex(lp_currency_id), amount.unique_saturated_into()); Self::deposit_event(Event::DepositDexShare(who.clone(), lp_currency_id, amount)); Ok(()) @@ -509,22 +641,12 @@ impl DEXIncentives for Pallet { fn do_withdraw_dex_share(who: &T::AccountId, lp_currency_id: CurrencyId, amount: Balance) -> DispatchResult { ensure!(lp_currency_id.is_dex_share_currency_id(), Error::::InvalidCurrencyId); ensure!( - >::share_and_withdrawn_reward(&PoolId::DexIncentive(lp_currency_id), &who).0 - >= amount && >::share_and_withdrawn_reward( - &PoolId::DexSaving(lp_currency_id), - &who - ) - .0 >= amount, + >::shares_and_withdrawn_rewards(&PoolId::Dex(lp_currency_id), &who).0 >= amount, Error::::NotEnough, ); T::Currency::transfer(lp_currency_id, &Self::account_id(), who, amount)?; - >::remove_share( - who, - &PoolId::DexIncentive(lp_currency_id), - amount.unique_saturated_into(), - ); - >::remove_share(who, &PoolId::DexSaving(lp_currency_id), amount); + >::remove_share(who, &PoolId::Dex(lp_currency_id), amount.unique_saturated_into()); Self::deposit_event(Event::WithdrawDexShare(who.clone(), lp_currency_id, amount)); Ok(()) @@ -535,50 +657,32 @@ pub struct OnUpdateLoan(sp_std::marker::PhantomData); impl Happened<(T::AccountId, CurrencyId, Amount, Balance)> for OnUpdateLoan { fn happened(info: &(T::AccountId, CurrencyId, Amount, Balance)) { let (who, currency_id, adjustment, previous_amount) = info; - let pool_id: PoolId = PoolId::LoansIncentive(*currency_id); - - // Only when a pool has incentive, shares will be updated. - // If the incentive has not been opened before, users did something that should update share after - // opening the incentive, TODO: do Pool::LoansIncentive(KSM) migration - if !Pallet::::incentive_reward_amount(&pool_id).is_zero() { - let adjustment_abs = - sp_std::convert::TryInto::::try_into(adjustment.saturating_abs()).unwrap_or_default(); + let adjustment_abs = + sp_std::convert::TryInto::::try_into(adjustment.saturating_abs()).unwrap_or_default(); - let new_share_amount = if adjustment.is_positive() { - previous_amount.saturating_add(adjustment_abs) - } else { - previous_amount.saturating_sub(adjustment_abs) - }; - - >::set_share(who, &PoolId::LoansIncentive(*currency_id), new_share_amount); - } - } -} - -pub struct OnIncreaseGuarantee(sp_std::marker::PhantomData); -impl Happened<(T::AccountId, T::RelaychainAccountId, Balance)> for OnIncreaseGuarantee { - fn happened(info: &(T::AccountId, T::RelaychainAccountId, Balance)) { - let (who, validator, increment) = info; - >::add_share(who, &PoolId::HomaValidatorAllowance(validator.clone()), *increment); - } -} + let new_share_amount = if adjustment.is_positive() { + previous_amount.saturating_add(adjustment_abs) + } else { + previous_amount.saturating_sub(adjustment_abs) + }; -pub struct OnDecreaseGuarantee(sp_std::marker::PhantomData); -impl Happened<(T::AccountId, T::RelaychainAccountId, Balance)> for OnDecreaseGuarantee { - fn happened(info: &(T::AccountId, T::RelaychainAccountId, Balance)) { - let (who, validator, decrement) = info; - >::remove_share(who, &PoolId::HomaValidatorAllowance(validator.clone()), *decrement); + >::set_share(who, &PoolId::Loans(*currency_id), new_share_amount); } } -impl RewardHandler for Pallet { +impl RewardHandler for Pallet { type Balance = Balance; - type PoolId = PoolId; + type PoolId = PoolId; - fn payout(who: &T::AccountId, pool_id: &Self::PoolId, payout_amount: Self::Balance) { + fn payout(who: &T::AccountId, pool_id: &Self::PoolId, currency_id: CurrencyId, payout_amount: Self::Balance) { if payout_amount.is_zero() { return; } - PendingRewards::::mutate(pool_id, who, |p| *p = p.saturating_add(payout_amount)); + PendingMultiRewards::::mutate(pool_id, who, |rewards| { + rewards + .entry(currency_id) + .and_modify(|current| *current = current.saturating_add(payout_amount)) + .or_insert(payout_amount); + }); } } diff --git a/modules/incentives/src/migrations.rs b/modules/incentives/src/migrations.rs new file mode 100644 index 0000000000..9378e86430 --- /dev/null +++ b/modules/incentives/src/migrations.rs @@ -0,0 +1,504 @@ +// This file is part of Acala. + +// Copyright (C) 2020-2021 Acala Foundation. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use frame_support::log; + +/// PoolId for various rewards pools +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] +pub enum PoolIdV0 { + /// Rewards pool(NativeCurrencyId) for users who open CDP + LoansIncentive(CurrencyId), + + /// Rewards pool(NativeCurrencyId) for market makers who provide dex + /// liquidity + DexIncentive(CurrencyId), + + /// Rewards pool(NativeCurrencyId) for users who staking by Homa protocol + HomaIncentive, + + /// Rewards pool(StableCurrencyId) for liquidators who provide dex liquidity + /// to participate automatic liquidation + DexSaving(CurrencyId), + + /// Rewards pool(LiquidCurrencyId) for users who guarantee for validators by + /// Homa protocol + HomaValidatorAllowance(AccountId), +} + +pub struct PoolIdConvertor(sp_std::marker::PhantomData); +impl sp_runtime::traits::Convert, Option> for PoolIdConvertor { + fn convert(a: PoolIdV0) -> Option { + convert_to_new_pool_id::(a) + } +} + +// migrate storage `PayoutDeductionRates` to `ClaimRewardDeductionRates` +pub fn migrate_to_claim_reward_deduction_rates(maybe_limit: Option) -> Weight { + let mut remove_items = 0; + let mut insert_items = 0; + + for (old_pool_id, rate) in PayoutDeductionRates::::drain().take(maybe_limit.unwrap_or(usize::MAX)) { + remove_items += 1; + if !rate.is_zero() { + if let Some(pool_id) = convert_to_new_pool_id::(old_pool_id) { + ClaimRewardDeductionRates::::insert(pool_id, rate); + insert_items += 1; + } + } + } + + log::info!( + target: "incentives-migration", + "migrate incentives PayoutDeductionRates: migrate {:?} items", + remove_items, + ); + + let total_reads_writes = remove_items + insert_items; + T::DbWeight::get().reads_writes(total_reads_writes, total_reads_writes) +} + +// migrate storage `DexSavingRewardRate` to `DexSavingRewardRates` +pub fn migrate_to_dex_saving_reward_rates(maybe_limit: Option) -> Weight { + let mut remove_items = 0; + let mut insert_items = 0; + + for (old_pool_id, rate) in DexSavingRewardRate::::drain().take(maybe_limit.unwrap_or(usize::MAX)) { + remove_items += 1; + if !rate.is_zero() { + if let PoolIdV0::DexSaving(currency_id) = old_pool_id { + DexSavingRewardRates::::insert(PoolId::Dex(currency_id), rate); + insert_items += 1; + } + } + } + + log::info!( + target: "incentives-migration", + "migrate incentives DexSavingRewardRate: migrate {:?} items", + remove_items, + ); + + let total_reads_writes = remove_items + insert_items; + T::DbWeight::get().reads_writes(total_reads_writes, total_reads_writes) +} + +// migrate storage `IncentiveRewardAmount` to `IncentiveRewardAmounts` +pub fn migrate_to_incentive_reward_amounts(maybe_limit: Option) -> Weight { + let reward_currency_id = T::NativeCurrencyId::get(); + let mut remove_items = 0; + let mut insert_items = 0; + + for (old_pool_id, amount) in IncentiveRewardAmount::::drain().take(maybe_limit.unwrap_or(usize::MAX)) { + remove_items += 1; + if !amount.is_zero() { + if let Some(pool_id) = match old_pool_id { + PoolIdV0::DexIncentive(currency_id) => Some(PoolId::Dex(currency_id)), + PoolIdV0::LoansIncentive(currency_id) => Some(PoolId::Loans(currency_id)), + _ => None, + } { + IncentiveRewardAmounts::::insert(pool_id, reward_currency_id, amount); + insert_items += 1; + } + } + } + + log::info!( + target: "incentives-migration", + "migrate incentives IncentiveRewardAmount: migrate {:?} items", + remove_items, + ); + + let total_reads_writes = remove_items + insert_items; + T::DbWeight::get().reads_writes(total_reads_writes, total_reads_writes) +} + +// migrate storage `PendingRewards` to `PendingMultiRewards` +pub fn migrate_to_pending_multi_rewards(maybe_limit: Option) -> Weight { + let mut remove_items = 0; + let mut insert_items = 0; + + for (old_pool_id, who, reward_amount) in PendingRewards::::drain().take(maybe_limit.unwrap_or(usize::MAX)) { + remove_items += 1; + + if !reward_amount.is_zero() { + if let Some(pool_id) = convert_to_new_pool_id::(old_pool_id.clone()) { + PendingMultiRewards::::mutate(pool_id, who, |multi_rewards| { + multi_rewards + .entry(get_reward_currency_id::(old_pool_id)) + .and_modify(|amount| { + *amount = amount.saturating_add(reward_amount); + }) + .or_insert(reward_amount); + }); + insert_items += 1; + } + } + } + + log::info!( + target: "incentives-migration", + "migrate incentives PendingRewards: migrate {:?} items", + remove_items, + ); + + let total_reads_writes = remove_items + insert_items; + T::DbWeight::get().reads_writes(total_reads_writes, total_reads_writes) +} + +// helper to map PoolIdV0 to PoolId +pub fn convert_to_new_pool_id(old_pool_id: PoolIdV0) -> Option { + match old_pool_id { + PoolIdV0::LoansIncentive(collateral_currency_id) => Some(PoolId::Loans(collateral_currency_id)), + PoolIdV0::DexIncentive(lp_currency_id) | PoolIdV0::DexSaving(lp_currency_id) => { + Some(PoolId::Dex(lp_currency_id)) + } + _ => None, + } +} + +// helper to map PoolIdV0 to reward currency id +pub fn get_reward_currency_id(old_pool_id: PoolIdV0) -> CurrencyId { + match old_pool_id { + PoolIdV0::HomaValidatorAllowance(_) => T::LiquidCurrencyId::get(), + PoolIdV0::DexSaving(_) => T::StableCurrencyId::get(), + _ => T::NativeCurrencyId::get(), + } +} + +#[test] +fn migrate_to_claim_reward_deduction_rates_works() { + use super::mock::*; + + ExtBuilder::default().build().execute_with(|| { + PayoutDeductionRates::::insert(PoolIdV0::DexSaving(DOT_AUSD_LP), Rate::zero()); + PayoutDeductionRates::::insert( + PoolIdV0::DexIncentive(DOT_AUSD_LP), + Rate::saturating_from_rational(30, 100), + ); + PayoutDeductionRates::::insert(PoolIdV0::LoansIncentive(DOT), Rate::saturating_from_rational(20, 100)); + PayoutDeductionRates::::insert(PoolIdV0::HomaIncentive, Rate::saturating_from_rational(10, 100)); + PayoutDeductionRates::::insert( + PoolIdV0::HomaValidatorAllowance(ALICE::get()), + Rate::saturating_from_rational(20, 100), + ); + + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP)), + true + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::DexIncentive(DOT_AUSD_LP)), + true + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::LoansIncentive(DOT)), + true + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::HomaIncentive), + true + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::HomaValidatorAllowance(ALICE::get())), + true + ); + assert_eq!( + ClaimRewardDeductionRates::::contains_key(PoolId::Dex(DOT_AUSD_LP)), + false + ); + assert_eq!( + ClaimRewardDeductionRates::::contains_key(PoolId::Loans(DOT)), + false + ); + + assert_eq!( + migrate_to_claim_reward_deduction_rates::(None), + ::DbWeight::get().reads_writes(5 + 2, 5 + 2) + ); + + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP)), + false + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::DexIncentive(DOT_AUSD_LP)), + false + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::LoansIncentive(DOT)), + false + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::HomaIncentive), + false + ); + assert_eq!( + PayoutDeductionRates::::contains_key(PoolIdV0::HomaValidatorAllowance(ALICE::get())), + false + ); + assert_eq!( + ClaimRewardDeductionRates::::contains_key(PoolId::Dex(DOT_AUSD_LP)), + true + ); + assert_eq!( + ClaimRewardDeductionRates::::contains_key(PoolId::Loans(DOT)), + true + ); + assert_eq!( + IncentivesModule::claim_reward_deduction_rates(PoolId::Dex(DOT_AUSD_LP)), + Rate::saturating_from_rational(30, 100) + ); + assert_eq!( + IncentivesModule::claim_reward_deduction_rates(PoolId::Loans(DOT)), + Rate::saturating_from_rational(20, 100) + ); + }); +} + +#[test] +fn migrate_to_dex_saving_reward_rates_works() { + use super::mock::*; + + ExtBuilder::default().build().execute_with(|| { + DexSavingRewardRate::::insert( + PoolIdV0::DexSaving(DOT_AUSD_LP), + Rate::saturating_from_rational(20, 100), + ); + DexSavingRewardRate::::insert(PoolIdV0::DexSaving(BTC_AUSD_LP), Rate::zero()); + DexSavingRewardRate::::insert( + PoolIdV0::DexIncentive(BTC_AUSD_LP), + Rate::saturating_from_rational(30, 100), + ); + + assert_eq!( + DexSavingRewardRate::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP)), + true + ); + assert_eq!( + DexSavingRewardRate::::contains_key(PoolIdV0::DexSaving(BTC_AUSD_LP)), + true + ); + assert_eq!( + DexSavingRewardRate::::contains_key(PoolIdV0::DexIncentive(BTC_AUSD_LP)), + true + ); + assert_eq!( + DexSavingRewardRates::::contains_key(PoolId::Dex(DOT_AUSD_LP)), + false + ); + assert_eq!( + DexSavingRewardRates::::contains_key(PoolId::Dex(BTC_AUSD_LP)), + false + ); + + assert_eq!( + migrate_to_dex_saving_reward_rates::(None), + ::DbWeight::get().reads_writes(3 + 1, 3 + 1) + ); + + assert_eq!( + DexSavingRewardRate::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP)), + false + ); + assert_eq!( + DexSavingRewardRate::::contains_key(PoolIdV0::DexSaving(BTC_AUSD_LP)), + false + ); + assert_eq!( + DexSavingRewardRate::::contains_key(PoolIdV0::DexIncentive(BTC_AUSD_LP)), + false + ); + assert_eq!( + DexSavingRewardRates::::contains_key(PoolId::Dex(DOT_AUSD_LP)), + true + ); + assert_eq!( + DexSavingRewardRates::::contains_key(PoolId::Dex(BTC_AUSD_LP)), + false + ); + assert_eq!( + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(DOT_AUSD_LP)), + Rate::saturating_from_rational(20, 100) + ); + assert_eq!( + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(BTC_AUSD_LP)), + Rate::zero() + ); + }); +} + +#[test] +fn migrate_to_incentive_reward_amounts_works() { + use super::mock::*; + + ExtBuilder::default().build().execute_with(|| { + IncentiveRewardAmount::::insert(PoolIdV0::DexIncentive(DOT_AUSD_LP), 0); + IncentiveRewardAmount::::insert(PoolIdV0::DexSaving(DOT_AUSD_LP), 100); + IncentiveRewardAmount::::insert(PoolIdV0::LoansIncentive(DOT), 1000); + IncentiveRewardAmount::::insert(PoolIdV0::HomaIncentive, 2000); + + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::DexIncentive(DOT_AUSD_LP)), + true + ); + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP)), + true + ); + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::LoansIncentive(DOT)), + true + ); + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::HomaIncentive), + true + ); + assert_eq!( + IncentiveRewardAmounts::::contains_key(PoolId::Dex(DOT_AUSD_LP), ACA), + false + ); + assert_eq!( + IncentiveRewardAmounts::::contains_key(PoolId::Loans(DOT), ACA), + false + ); + + assert_eq!( + migrate_to_incentive_reward_amounts::(None), + ::DbWeight::get().reads_writes(4 + 1, 4 + 1) + ); + + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::DexIncentive(DOT_AUSD_LP)), + false + ); + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP)), + false + ); + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::LoansIncentive(DOT)), + false + ); + assert_eq!( + IncentiveRewardAmount::::contains_key(PoolIdV0::HomaIncentive), + false + ); + assert_eq!( + IncentiveRewardAmounts::::contains_key(PoolId::Dex(DOT_AUSD_LP), ACA), + false + ); + assert_eq!( + IncentiveRewardAmounts::::contains_key(PoolId::Loans(DOT), ACA), + true + ); + assert_eq!( + IncentivesModule::incentive_reward_amounts(PoolId::Dex(DOT_AUSD_LP), ACA), + 0 + ); + assert_eq!( + IncentivesModule::incentive_reward_amounts(PoolId::Loans(DOT), ACA), + 1000 + ); + }); +} + +#[test] +fn migrate_to_pending_multi_rewards_works() { + use super::mock::*; + + ExtBuilder::default().build().execute_with(|| { + PendingRewards::::insert(PoolIdV0::DexIncentive(DOT_AUSD_LP), ALICE::get(), 100); + PendingRewards::::insert(PoolIdV0::DexSaving(DOT_AUSD_LP), ALICE::get(), 200); + PendingRewards::::insert(PoolIdV0::LoansIncentive(DOT), ALICE::get(), 300); + PendingRewards::::insert(PoolIdV0::HomaIncentive, ALICE::get(), 400); + PendingRewards::::insert(PoolIdV0::HomaValidatorAllowance(BOB::get()), ALICE::get(), 500); + + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::DexIncentive(DOT_AUSD_LP), ALICE::get()), + true + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP), ALICE::get()), + true + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::LoansIncentive(DOT), ALICE::get()), + true + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::HomaIncentive, ALICE::get()), + true + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::HomaValidatorAllowance(BOB::get()), ALICE::get()), + true + ); + assert_eq!( + PendingMultiRewards::::contains_key(PoolId::Dex(DOT_AUSD_LP), ALICE::get()), + false + ); + assert_eq!( + PendingMultiRewards::::contains_key(PoolId::Loans(DOT), ALICE::get()), + false + ); + + assert_eq!( + migrate_to_pending_multi_rewards::(None), + ::DbWeight::get().reads_writes(5 + 3, 5 + 3) + ); + + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::DexIncentive(DOT_AUSD_LP), ALICE::get()), + false + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::DexSaving(DOT_AUSD_LP), ALICE::get()), + false + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::LoansIncentive(DOT), ALICE::get()), + false + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::HomaIncentive, ALICE::get()), + false + ); + assert_eq!( + PendingRewards::::contains_key(PoolIdV0::HomaValidatorAllowance(BOB::get()), ALICE::get()), + false + ); + assert_eq!( + PendingMultiRewards::::contains_key(PoolId::Dex(DOT_AUSD_LP), ALICE::get()), + true + ); + assert_eq!( + PendingMultiRewards::::contains_key(PoolId::Loans(DOT), ALICE::get()), + true + ); + + assert_eq!( + IncentivesModule::pending_multi_rewards(PoolId::Dex(DOT_AUSD_LP), ALICE::get()), + vec![(ACA, 100), (AUSD, 200)].into_iter().collect() + ); + assert_eq!( + IncentivesModule::pending_multi_rewards(PoolId::Loans(DOT), ALICE::get()), + vec![(ACA, 300)].into_iter().collect() + ); + }); +} diff --git a/modules/incentives/src/mock.rs b/modules/incentives/src/mock.rs index a24fbe1495..a3c3e34af1 100644 --- a/modules/incentives/src/mock.rs +++ b/modules/incentives/src/mock.rs @@ -25,6 +25,7 @@ use frame_support::{ construct_runtime, dispatch::{DispatchError, DispatchResult}, ord_parameter_types, parameter_types, + weights::constants::RocksDbWeight, }; use frame_system::EnsureSignedBy; use orml_traits::parameter_type_with_key; @@ -55,8 +56,7 @@ ord_parameter_types! { pub const ALICE: AccountId = AccountId::from([1u8; 32]); pub const BOB: AccountId = AccountId::from([2u8; 32]); pub const VAULT: AccountId = IncentivesModule::account_id(); - pub const UNRELEASED: AccountId = AccountId::from([3u8; 32]); - pub const VALIDATOR: AccountId = AccountId::from([4u8; 32]); + pub const RewardsSource: AccountId = AccountId::from([3u8; 32]); pub const ROOT: AccountId = AccountId32::new([255u8; 32]); } @@ -83,7 +83,7 @@ impl frame_system::Config for Runtime { type AccountData = pallet_balances::AccountData; type OnNewAccount = (); type OnKilledAccount = (); - type DbWeight = (); + type DbWeight = RocksDbWeight; type BaseCallFilter = (); type SystemWeightInfo = (); type SS58Prefix = (); @@ -243,12 +243,14 @@ impl EmergencyShutdown for MockEmergencyShutdown { impl orml_rewards::Config for Runtime { type Share = Balance; type Balance = Balance; - type PoolId = PoolId; + type PoolIdV0 = PoolIdV0; + type PoolIdConvertor = PoolIdConvertor; + type PoolId = PoolId; + type CurrencyId = CurrencyId; type Handler = IncentivesModule; } parameter_types! { - pub NativeRewardsSource: AccountId = UNRELEASED::get(); pub const AccumulatePeriod: BlockNumber = 10; pub const NativeCurrencyId: CurrencyId = ACA; pub const StableCurrencyId: CurrencyId = AUSD; @@ -263,12 +265,12 @@ ord_parameter_types! { impl Config for Runtime { type Event = Event; type RelaychainAccountId = AccountId; - type NativeRewardsSource = NativeRewardsSource; + type RewardsSource = RewardsSource; type AccumulatePeriod = AccumulatePeriod; type NativeCurrencyId = NativeCurrencyId; type StableCurrencyId = StableCurrencyId; type LiquidCurrencyId = LiquidCurrencyId; - type UpdateOrigin = EnsureSignedBy; + type UpdateOrigin = EnsureSignedBy; type CDPTreasury = MockCDPTreasury; type Currency = TokensModule; type DEX = MockDEX; @@ -299,9 +301,7 @@ pub struct ExtBuilder { impl Default for ExtBuilder { fn default() -> Self { - Self { - balances: vec![(UNRELEASED::get(), ACA, 10_000)], - } + Self { balances: vec![] } } } diff --git a/modules/incentives/src/tests.rs b/modules/incentives/src/tests.rs index 674952b369..c85dfe895c 100644 --- a/modules/incentives/src/tests.rs +++ b/modules/incentives/src/tests.rs @@ -37,29 +37,11 @@ fn deposit_dex_share_works() { TokensModule::free_balance(BTC_AUSD_LP, &IncentivesModule::account_id()), 0 ); + assert_eq!(RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), PoolInfo::default(),); + assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), - PoolInfo { - total_shares: 0, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)), - PoolInfo { - total_shares: 0, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - (0, 0) - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexSaving(BTC_AUSD_LP), ALICE::get()), - (0, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + Default::default(), ); assert_ok!(IncentivesModule::deposit_dex_share( @@ -78,28 +60,15 @@ fn deposit_dex_share_works() { 10000 ); assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), PoolInfo { total_shares: 10000, - total_rewards: 0, - total_withdrawn_rewards: 0 + ..Default::default() } ); assert_eq!( - RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)), - PoolInfo { - total_shares: 10000, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - (10000, 0) - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexSaving(BTC_AUSD_LP), ALICE::get()), - (10000, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + (10000, Default::default()) ); }); } @@ -126,28 +95,15 @@ fn withdraw_dex_share_works() { 10000 ); assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), PoolInfo { total_shares: 10000, - total_rewards: 0, - total_withdrawn_rewards: 0 + ..Default::default() } ); assert_eq!( - RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)), - PoolInfo { - total_shares: 10000, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - (10000, 0) - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexSaving(BTC_AUSD_LP), ALICE::get()), - (10000, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + (10000, Default::default()) ); assert_ok!(IncentivesModule::withdraw_dex_share( @@ -166,28 +122,15 @@ fn withdraw_dex_share_works() { 2000 ); assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), PoolInfo { total_shares: 2000, - total_rewards: 0, - total_withdrawn_rewards: 0 + ..Default::default() } ); assert_eq!( - RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)), - PoolInfo { - total_shares: 2000, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - (2000, 0) - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexSaving(BTC_AUSD_LP), ALICE::get()), - (2000, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + (2000, Default::default()) ); }); } @@ -200,62 +143,83 @@ fn update_incentive_rewards_works() { IncentivesModule::update_incentive_rewards(Origin::signed(ALICE::get()), vec![]), BadOrigin ); + assert_noop!( + IncentivesModule::update_incentive_rewards(Origin::signed(ROOT::get()), vec![(PoolId::Dex(DOT), vec![])]), + Error::::InvalidPoolId + ); - assert_eq!(IncentivesModule::incentive_reward_amount(PoolId::HomaIncentive), 0); assert_eq!( - IncentivesModule::incentive_reward_amount(PoolId::DexIncentive(DOT_AUSD_LP)), + IncentivesModule::incentive_reward_amounts(PoolId::Dex(DOT_AUSD_LP), ACA), 0 ); assert_eq!( - IncentivesModule::incentive_reward_amount(PoolId::LoansIncentive(DOT)), + IncentivesModule::incentive_reward_amounts(PoolId::Dex(DOT_AUSD_LP), DOT), 0 ); + assert_eq!(IncentivesModule::incentive_reward_amounts(PoolId::Loans(DOT), ACA), 0); assert_ok!(IncentivesModule::update_incentive_rewards( - Origin::signed(Root::get()), + Origin::signed(ROOT::get()), vec![ - (PoolId::HomaIncentive, 200), - (PoolId::DexIncentive(DOT_AUSD_LP), 1000), - (PoolId::LoansIncentive(DOT), 500), + (PoolId::Dex(DOT_AUSD_LP), vec![(ACA, 1000), (DOT, 100)]), + (PoolId::Loans(DOT), vec![(ACA, 500)]), ], )); System::assert_has_event(Event::IncentivesModule(crate::Event::IncentiveRewardAmountUpdated( - PoolId::HomaIncentive, - 200, + PoolId::Dex(DOT_AUSD_LP), + ACA, + 1000, ))); System::assert_has_event(Event::IncentivesModule(crate::Event::IncentiveRewardAmountUpdated( - PoolId::DexIncentive(DOT_AUSD_LP), - 1000, + PoolId::Dex(DOT_AUSD_LP), + DOT, + 100, ))); System::assert_has_event(Event::IncentivesModule(crate::Event::IncentiveRewardAmountUpdated( - PoolId::LoansIncentive(DOT), + PoolId::Loans(DOT), + ACA, 500, ))); - assert_eq!(IncentivesModule::incentive_reward_amount(PoolId::HomaIncentive), 200); assert_eq!( - IncentivesModule::incentive_reward_amount(PoolId::DexIncentive(DOT_AUSD_LP)), + IncentivesModule::incentive_reward_amounts(PoolId::Dex(DOT_AUSD_LP), ACA), 1000 ); assert_eq!( - IncentivesModule::incentive_reward_amount(PoolId::LoansIncentive(DOT)), - 500 + IncentiveRewardAmounts::::contains_key(PoolId::Dex(DOT_AUSD_LP), DOT), + true ); - - assert_noop!( - IncentivesModule::update_incentive_rewards( - Origin::signed(Root::get()), - vec![(PoolId::DexIncentive(DOT), 800)], - ), - Error::::InvalidCurrencyId + assert_eq!( + IncentivesModule::incentive_reward_amounts(PoolId::Dex(DOT_AUSD_LP), DOT), + 100 ); + assert_eq!(IncentivesModule::incentive_reward_amounts(PoolId::Loans(DOT), ACA), 500); - assert_noop!( - IncentivesModule::update_incentive_rewards( - Origin::signed(Root::get()), - vec![(PoolId::HomaValidatorAllowance(VALIDATOR::get()), 300)], - ), - Error::::InvalidPoolId + assert_ok!(IncentivesModule::update_incentive_rewards( + Origin::signed(ROOT::get()), + vec![ + (PoolId::Dex(DOT_AUSD_LP), vec![(ACA, 200), (DOT, 0)]), + (PoolId::Loans(DOT), vec![(ACA, 500)]), + ], + )); + System::assert_has_event(Event::IncentivesModule(crate::Event::IncentiveRewardAmountUpdated( + PoolId::Dex(DOT_AUSD_LP), + ACA, + 200, + ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::IncentiveRewardAmountUpdated( + PoolId::Dex(DOT_AUSD_LP), + DOT, + 0, + ))); + assert_eq!( + IncentivesModule::incentive_reward_amounts(PoolId::Dex(DOT_AUSD_LP), ACA), + 200 + ); + assert_eq!( + IncentiveRewardAmounts::::contains_key(PoolId::Dex(DOT_AUSD_LP), DOT), + false ); + assert_eq!(IncentivesModule::incentive_reward_amounts(PoolId::Loans(DOT), ACA), 500); }); } @@ -269,113 +233,179 @@ fn update_dex_saving_rewards_works() { ); assert_noop!( IncentivesModule::update_dex_saving_rewards( - Origin::signed(Root::get()), - vec![(PoolId::DexIncentive(DOT_AUSD_LP), Rate::zero())] + Origin::signed(ROOT::get()), + vec![(PoolId::Dex(DOT), Rate::zero())] + ), + Error::::InvalidPoolId + ); + assert_noop!( + IncentivesModule::update_dex_saving_rewards( + Origin::signed(ROOT::get()), + vec![(PoolId::Loans(DOT), Rate::zero())] ), Error::::InvalidPoolId ); assert_noop!( IncentivesModule::update_dex_saving_rewards( - Origin::signed(Root::get()), - vec![(PoolId::DexSaving(DOT), Rate::zero())] + Origin::signed(ROOT::get()), + vec![(PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(101, 100))] ), - Error::::InvalidCurrencyId + Error::::InvalidRate ); assert_eq!( - IncentivesModule::dex_saving_reward_rate(PoolId::DexSaving(DOT_AUSD_LP)), + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(DOT_AUSD_LP)), Rate::zero() ); + assert_eq!( + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(BTC_AUSD_LP)), + Rate::zero() + ); + assert_ok!(IncentivesModule::update_dex_saving_rewards( - Origin::signed(Root::get()), - vec![(PoolId::DexSaving(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100)),] + Origin::signed(ROOT::get()), + vec![ + (PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100)), + (PoolId::Dex(BTC_AUSD_LP), Rate::saturating_from_rational(2, 100)) + ] )); System::assert_has_event(Event::IncentivesModule(crate::Event::SavingRewardRateUpdated( - PoolId::DexSaving(DOT_AUSD_LP), + PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100), ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::SavingRewardRateUpdated( + PoolId::Dex(BTC_AUSD_LP), + Rate::saturating_from_rational(2, 100), + ))); assert_eq!( - IncentivesModule::dex_saving_reward_rate(PoolId::DexSaving(DOT_AUSD_LP)), + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(DOT_AUSD_LP)), Rate::saturating_from_rational(1, 100) ); + assert_eq!( + DexSavingRewardRates::::contains_key(PoolId::Dex(BTC_AUSD_LP)), + true + ); + assert_eq!( + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(BTC_AUSD_LP)), + Rate::saturating_from_rational(2, 100) + ); + + assert_ok!(IncentivesModule::update_dex_saving_rewards( + Origin::signed(ROOT::get()), + vec![ + (PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(5, 100)), + (PoolId::Dex(BTC_AUSD_LP), Rate::zero()) + ] + )); + System::assert_has_event(Event::IncentivesModule(crate::Event::SavingRewardRateUpdated( + PoolId::Dex(DOT_AUSD_LP), + Rate::saturating_from_rational(5, 100), + ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::SavingRewardRateUpdated( + PoolId::Dex(BTC_AUSD_LP), + Rate::zero(), + ))); + assert_eq!( + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(DOT_AUSD_LP)), + Rate::saturating_from_rational(5, 100) + ); + assert_eq!( + DexSavingRewardRates::::contains_key(PoolId::Dex(BTC_AUSD_LP)), + false + ); + assert_eq!( + IncentivesModule::dex_saving_reward_rates(PoolId::Dex(BTC_AUSD_LP)), + Rate::zero() + ); }); } #[test] -fn update_payout_deduction_rates_works() { +fn update_claim_reward_deduction_rates_works() { ExtBuilder::default().build().execute_with(|| { System::set_block_number(1); assert_noop!( - IncentivesModule::update_payout_deduction_rates(Origin::signed(ALICE::get()), vec![]), + IncentivesModule::update_claim_reward_deduction_rates(Origin::signed(ALICE::get()), vec![]), BadOrigin ); assert_noop!( - IncentivesModule::update_payout_deduction_rates( - Origin::signed(Root::get()), - vec![(PoolId::DexIncentive(DOT), Rate::zero())] - ), - Error::::InvalidCurrencyId - ); - assert_noop!( - IncentivesModule::update_payout_deduction_rates( - Origin::signed(Root::get()), - vec![(PoolId::DexSaving(DOT), Rate::zero())] + IncentivesModule::update_claim_reward_deduction_rates( + Origin::signed(ROOT::get()), + vec![(PoolId::Dex(DOT), Rate::zero())] ), - Error::::InvalidCurrencyId + Error::::InvalidPoolId ); assert_noop!( - IncentivesModule::update_payout_deduction_rates( - Origin::signed(Root::get()), - vec![(PoolId::DexSaving(DOT_AUSD_LP), Rate::saturating_from_rational(101, 100)),] + IncentivesModule::update_claim_reward_deduction_rates( + Origin::signed(ROOT::get()), + vec![(PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(101, 100)),] ), Error::::InvalidRate, ); assert_eq!( - IncentivesModule::payout_deduction_rates(PoolId::DexSaving(DOT_AUSD_LP)), + IncentivesModule::claim_reward_deduction_rates(PoolId::Dex(DOT_AUSD_LP)), Rate::zero() ); - assert_ok!(IncentivesModule::update_payout_deduction_rates( - Origin::signed(Root::get()), - vec![(PoolId::DexSaving(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100)),] + assert_eq!( + IncentivesModule::claim_reward_deduction_rates(PoolId::Dex(BTC_AUSD_LP)), + Rate::zero() + ); + + assert_ok!(IncentivesModule::update_claim_reward_deduction_rates( + Origin::signed(ROOT::get()), + vec![ + (PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100)), + (PoolId::Dex(BTC_AUSD_LP), Rate::saturating_from_rational(2, 100)) + ] )); - System::assert_last_event(Event::IncentivesModule(crate::Event::PayoutDeductionRateUpdated( - PoolId::DexSaving(DOT_AUSD_LP), + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewardDeductionRateUpdated( + PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100), ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewardDeductionRateUpdated( + PoolId::Dex(BTC_AUSD_LP), + Rate::saturating_from_rational(2, 100), + ))); assert_eq!( - IncentivesModule::payout_deduction_rates(PoolId::DexSaving(DOT_AUSD_LP)), + IncentivesModule::claim_reward_deduction_rates(PoolId::Dex(DOT_AUSD_LP)), Rate::saturating_from_rational(1, 100) ); - }); -} - -#[test] -fn add_allowance_works() { - ExtBuilder::default().build().execute_with(|| { - assert_noop!( - IncentivesModule::add_allowance(Origin::signed(ALICE::get()), PoolId::HomaIncentive, 200), - Error::::InvalidPoolId + assert_eq!( + ClaimRewardDeductionRates::::contains_key(PoolId::Dex(BTC_AUSD_LP)), + true ); - - assert_ok!(TokensModule::deposit(LDOT, &ALICE::get(), 10000)); - assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 0); - assert_eq!(TokensModule::free_balance(LDOT, &ALICE::get()), 10000); assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())).total_rewards, - 0 + IncentivesModule::claim_reward_deduction_rates(PoolId::Dex(BTC_AUSD_LP)), + Rate::saturating_from_rational(2, 100) ); - assert_ok!(IncentivesModule::add_allowance( - Origin::signed(ALICE::get()), - PoolId::HomaValidatorAllowance(VALIDATOR::get()), - 1000 + assert_ok!(IncentivesModule::update_claim_reward_deduction_rates( + Origin::signed(ROOT::get()), + vec![ + (PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(5, 100)), + (PoolId::Dex(BTC_AUSD_LP), Rate::zero()) + ] )); - assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 1000); - assert_eq!(TokensModule::free_balance(LDOT, &ALICE::get()), 9000); + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewardDeductionRateUpdated( + PoolId::Dex(DOT_AUSD_LP), + Rate::saturating_from_rational(5, 100), + ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewardDeductionRateUpdated( + PoolId::Dex(BTC_AUSD_LP), + Rate::zero(), + ))); assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())).total_rewards, - 1000 + IncentivesModule::claim_reward_deduction_rates(PoolId::Dex(DOT_AUSD_LP)), + Rate::saturating_from_rational(5, 100) + ); + assert_eq!( + ClaimRewardDeductionRates::::contains_key(PoolId::Dex(BTC_AUSD_LP)), + false + ); + assert_eq!( + IncentivesModule::claim_reward_deduction_rates(PoolId::Dex(BTC_AUSD_LP)), + Rate::zero() ); }); } @@ -383,144 +413,80 @@ fn add_allowance_works() { #[test] fn on_update_loan_works() { ExtBuilder::default().build().execute_with(|| { + assert_eq!(RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo::default(),); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), - PoolInfo { - total_shares: 0, - total_rewards: 0, - total_withdrawn_rewards: 0 - } + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()), + Default::default(), ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), ALICE::get()), - (0, 0) - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), BOB::get()), - (0, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), BOB::get()), + Default::default(), ); - // will not update shares when LoansIncentives type pool without incentive OnUpdateLoan::::happened(&(ALICE::get(), BTC, 100, 0)); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 0, - total_rewards: 0, - total_withdrawn_rewards: 0 + total_shares: 100, + ..Default::default() } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), ALICE::get()), - (0, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()), + (100, Default::default()) ); - assert_ok!(IncentivesModule::update_incentive_rewards( - Origin::signed(Root::get()), - vec![(PoolId::LoansIncentive(BTC), 1000),], - )); - // share will be updated even if the adjustment is zero - OnUpdateLoan::::happened(&(ALICE::get(), BTC, 0, 100)); + OnUpdateLoan::::happened(&(ALICE::get(), BTC, 0, 200)); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 100, - total_rewards: 0, - total_withdrawn_rewards: 0 + total_shares: 200, + ..Default::default() } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), ALICE::get()), - (100, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()), + (200, Default::default()) ); OnUpdateLoan::::happened(&(BOB::get(), BTC, 100, 500)); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 700, - total_rewards: 0, - total_withdrawn_rewards: 0 + total_shares: 800, + ..Default::default() } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), BOB::get()), - (600, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), BOB::get()), + (600, Default::default()) ); - OnUpdateLoan::::happened(&(ALICE::get(), BTC, -50, 100)); + OnUpdateLoan::::happened(&(ALICE::get(), BTC, -50, 200)); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 650, - total_rewards: 0, - total_withdrawn_rewards: 0 + total_shares: 750, + ..Default::default() } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), ALICE::get()), - (50, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()), + (150, Default::default()) ); OnUpdateLoan::::happened(&(BOB::get(), BTC, -650, 600)); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), - PoolInfo { - total_shares: 50, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), BOB::get()), - (0, 0) - ); - }); -} - -#[test] -fn guarantee_hooks_works() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 0, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - (0, 0) - ); - - OnIncreaseGuarantee::::happened(&(ALICE::get(), VALIDATOR::get(), 100)); - assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())), - PoolInfo { - total_shares: 100, - total_rewards: 0, - total_withdrawn_rewards: 0 - } - ); - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - (100, 0) - ); - - OnDecreaseGuarantee::::happened(&(ALICE::get(), VALIDATOR::get(), 10)); - assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())), - PoolInfo { - total_shares: 90, - total_rewards: 0, - total_withdrawn_rewards: 0 + total_shares: 150, + ..Default::default() } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - (90, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), BOB::get()), + Default::default(), ); }); } @@ -529,20 +495,20 @@ fn guarantee_hooks_works() { fn payout_works() { ExtBuilder::default().build().execute_with(|| { assert_eq!( - IncentivesModule::pending_rewards(PoolId::LoansIncentive(BTC), ALICE::get()), - 0 + IncentivesModule::pending_multi_rewards(PoolId::Loans(BTC), ALICE::get()), + BTreeMap::default() ); - IncentivesModule::payout(&ALICE::get(), &PoolId::LoansIncentive(BTC), 1000); + IncentivesModule::payout(&ALICE::get(), &PoolId::Loans(BTC), ACA, 1000); assert_eq!( - IncentivesModule::pending_rewards(PoolId::LoansIncentive(BTC), ALICE::get()), - 1000 + IncentivesModule::pending_multi_rewards(PoolId::Loans(BTC), ALICE::get()), + vec![(ACA, 1000)].into_iter().collect() ); - IncentivesModule::payout(&ALICE::get(), &PoolId::LoansIncentive(BTC), 1000); + IncentivesModule::payout(&ALICE::get(), &PoolId::Loans(BTC), ACA, 1000); assert_eq!( - IncentivesModule::pending_rewards(PoolId::LoansIncentive(BTC), ALICE::get()), - 2000 + IncentivesModule::pending_multi_rewards(PoolId::Loans(BTC), ALICE::get()), + vec![(ACA, 2000)].into_iter().collect() ); }); } @@ -554,421 +520,417 @@ fn claim_rewards_works() { assert_ok!(TokensModule::deposit(ACA, &VAULT::get(), 10000)); assert_ok!(TokensModule::deposit(AUSD, &VAULT::get(), 10000)); assert_ok!(TokensModule::deposit(LDOT, &VAULT::get(), 10000)); - assert_ok!(IncentivesModule::update_payout_deduction_rates( - Origin::signed(Root::get()), + assert_ok!(IncentivesModule::update_claim_reward_deduction_rates( + Origin::signed(ROOT::get()), vec![ - ( - PoolId::DexIncentive(BTC_AUSD_LP), - Rate::saturating_from_rational(50, 100) - ), - (PoolId::DexSaving(BTC_AUSD_LP), Rate::saturating_from_rational(20, 100)), - ( - PoolId::HomaValidatorAllowance(VALIDATOR::get()), - Rate::saturating_from_rational(90, 100) - ), + (PoolId::Dex(BTC_AUSD_LP), Rate::saturating_from_rational(50, 100)), + (PoolId::Loans(BTC), Rate::saturating_from_rational(90, 100)), ] )); // alice add shares before accumulate rewards - RewardsModule::add_share(&ALICE::get(), &PoolId::LoansIncentive(BTC), 100); - RewardsModule::add_share(&ALICE::get(), &PoolId::DexIncentive(BTC_AUSD_LP), 100); - RewardsModule::add_share(&ALICE::get(), &PoolId::DexSaving(BTC_AUSD_LP), 100); - RewardsModule::add_share(&ALICE::get(), &PoolId::HomaValidatorAllowance(VALIDATOR::get()), 100); + RewardsModule::add_share(&ALICE::get(), &PoolId::Loans(BTC), 100); + RewardsModule::add_share(&ALICE::get(), &PoolId::Dex(BTC_AUSD_LP), 100); // bob add shares before accumulate rewards - RewardsModule::add_share(&BOB::get(), &PoolId::DexSaving(BTC_AUSD_LP), 100); - RewardsModule::add_share(&BOB::get(), &PoolId::DexIncentive(BTC_AUSD_LP), 100); + RewardsModule::add_share(&BOB::get(), &PoolId::Dex(BTC_AUSD_LP), 100); // accumulate rewards for different pools - RewardsModule::accumulate_reward(&PoolId::LoansIncentive(BTC), 2000); - RewardsModule::accumulate_reward(&PoolId::DexIncentive(BTC_AUSD_LP), 1000); - RewardsModule::accumulate_reward(&PoolId::DexSaving(BTC_AUSD_LP), 2000); - RewardsModule::accumulate_reward(&PoolId::HomaValidatorAllowance(VALIDATOR::get()), 5000); + assert_ok!(RewardsModule::accumulate_reward(&PoolId::Loans(BTC), ACA, 2000)); + assert_ok!(RewardsModule::accumulate_reward(&PoolId::Dex(BTC_AUSD_LP), ACA, 1000)); + assert_ok!(RewardsModule::accumulate_reward(&PoolId::Dex(BTC_AUSD_LP), AUSD, 2000)); // bob add share after accumulate rewards - RewardsModule::add_share(&BOB::get(), &PoolId::LoansIncentive(BTC), 100); + RewardsModule::add_share(&BOB::get(), &PoolId::Loans(BTC), 100); - // alice claim rewards for PoolId::LoansIncentive(BTC) + // accumulate LDOT rewards for PoolId::Loans(BTC) + assert_ok!(RewardsModule::accumulate_reward(&PoolId::Loans(BTC), LDOT, 500)); + + // alice claim rewards for PoolId::Loans(BTC) assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { total_shares: 200, - total_rewards: 4000, - total_withdrawn_rewards: 2000 + rewards: vec![(ACA, (4000, 2000)), (LDOT, (500, 0))].into_iter().collect(), } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), ALICE::get()), - (100, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()), + (100, Default::default()) ); assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 10000); + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 10000); assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 0); + assert_eq!(TokensModule::free_balance(LDOT, &ALICE::get()), 0); assert_ok!(IncentivesModule::claim_rewards( Origin::signed(ALICE::get()), - PoolId::LoansIncentive(BTC) + PoolId::Loans(BTC) )); - System::assert_last_event(Event::IncentivesModule(crate::Event::ClaimRewards( + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewards( ALICE::get(), - PoolId::LoansIncentive(BTC), + PoolId::Loans(BTC), ACA, - 2000, - 0, + 200, + 1800, + ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewards( + ALICE::get(), + PoolId::Loans(BTC), + LDOT, + 25, + 225, ))); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { total_shares: 200, - total_rewards: 4000, - total_withdrawn_rewards: 4000 + rewards: vec![(ACA, (5800, 4000)), (LDOT, (725, 250))].into_iter().collect(), } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), ALICE::get()), - (100, 2000) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), ALICE::get()), + (100, vec![(ACA, 2000), (LDOT, 250)].into_iter().collect()) ); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 8000); - assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 2000); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 9800); + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 9975); + assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 200); + assert_eq!(TokensModule::free_balance(LDOT, &ALICE::get()), 25); - // bob claim rewards for PoolId::LoansIncentive(BTC) + // bob claim rewards for PoolId::Loans(BTC) assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), BOB::get()), - (100, 2000) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), BOB::get()), + (100, vec![(ACA, 2000)].into_iter().collect()) ); assert_eq!(TokensModule::free_balance(ACA, &BOB::get()), 0); assert_ok!(IncentivesModule::claim_rewards( Origin::signed(BOB::get()), - PoolId::LoansIncentive(BTC) + PoolId::Loans(BTC) )); + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewards( + BOB::get(), + PoolId::Loans(BTC), + ACA, + 90, + 810, + ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewards( + BOB::get(), + PoolId::Loans(BTC), + LDOT, + 37, + 325, + ))); assert_eq!( - RewardsModule::pools(PoolId::LoansIncentive(BTC)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { total_shares: 200, - total_rewards: 4000, - total_withdrawn_rewards: 4000 + rewards: vec![(ACA, (6610, 4900)), (LDOT, (1050, 612))].into_iter().collect(), } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::LoansIncentive(BTC), BOB::get()), - (100, 2000) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Loans(BTC), BOB::get()), + (100, vec![(ACA, 2900), (LDOT, 362)].into_iter().collect()) ); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 8000); - assert_eq!(TokensModule::free_balance(ACA, &BOB::get()), 0); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 9710); + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 9938); + assert_eq!(TokensModule::free_balance(ACA, &BOB::get()), 90); + assert_eq!(TokensModule::free_balance(LDOT, &BOB::get()), 37); - // alice remove share for PoolId::DexIncentive(BTC_AUSD_LP) before claim rewards + // alice remove share for PoolId::Dex(BTC_AUSD_LP) before claim rewards, + // rewards will be settled and as pending rewards, will not be deducted. assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), PoolInfo { total_shares: 200, - total_rewards: 1000, - total_withdrawn_rewards: 0 + rewards: vec![(ACA, (1000, 0)), (AUSD, (2000, 0))].into_iter().collect(), } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - (100, 0) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + (100, Default::default()) ); - assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 2000); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 9710); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 10000); + assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 200); + assert_eq!(TokensModule::free_balance(AUSD, &ALICE::get()), 0); assert_eq!( - IncentivesModule::pending_rewards(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - 0 + IncentivesModule::pending_multi_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + BTreeMap::default() ); - RewardsModule::remove_share(&ALICE::get(), &PoolId::DexIncentive(BTC_AUSD_LP), 50); + RewardsModule::remove_share(&ALICE::get(), &PoolId::Dex(BTC_AUSD_LP), 50); assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), PoolInfo { total_shares: 150, - total_rewards: 750, - total_withdrawn_rewards: 250 + rewards: vec![(ACA, (750, 250)), (AUSD, (1500, 500))].into_iter().collect(), } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - (50, 250) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + (50, vec![(ACA, 250), (AUSD, 500)].into_iter().collect()) ); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 8000); - assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 2000); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 9710); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 10000); + assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 200); + assert_eq!(TokensModule::free_balance(AUSD, &ALICE::get()), 0); assert_eq!( - IncentivesModule::pending_rewards(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - 500 + IncentivesModule::pending_multi_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + vec![(ACA, 500), (AUSD, 1000)].into_iter().collect() ); - // bob claim rewards for PoolId::DexIncentive(BTC_AUSD_LP) - assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), BOB::get()), - (100, 0) - ); - assert_eq!(TokensModule::free_balance(ACA, &BOB::get()), 0); - assert_eq!( - IncentivesModule::pending_rewards(PoolId::DexIncentive(BTC_AUSD_LP), BOB::get()), - 0 - ); + // alice claim rewards for PoolId::Dex(BTC_AUSD_LP) assert_ok!(IncentivesModule::claim_rewards( - Origin::signed(BOB::get()), - PoolId::DexIncentive(BTC_AUSD_LP) + Origin::signed(ALICE::get()), + PoolId::Dex(BTC_AUSD_LP) )); - System::assert_last_event(Event::IncentivesModule(crate::Event::ClaimRewards( - BOB::get(), - PoolId::DexIncentive(BTC_AUSD_LP), + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewards( + ALICE::get(), + PoolId::Dex(BTC_AUSD_LP), ACA, 250, - 249, + 250, + ))); + System::assert_has_event(Event::IncentivesModule(crate::Event::ClaimRewards( + ALICE::get(), + PoolId::Dex(BTC_AUSD_LP), + AUSD, + 500, + 500, ))); assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), PoolInfo { total_shares: 150, - total_rewards: 999, - total_withdrawn_rewards: 749 + rewards: vec![(ACA, (1000, 250)), (AUSD, (2000, 500))].into_iter().collect(), } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), BOB::get()), - (100, 499) + RewardsModule::shares_and_withdrawn_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + (50, vec![(ACA, 250), (AUSD, 500)].into_iter().collect()) ); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 7750); - assert_eq!(TokensModule::free_balance(ACA, &BOB::get()), 250); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 9460); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 9500); + assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 450); + assert_eq!(TokensModule::free_balance(AUSD, &ALICE::get()), 500); assert_eq!( - IncentivesModule::pending_rewards(PoolId::DexIncentive(BTC_AUSD_LP), BOB::get()), - 0 + IncentivesModule::pending_multi_rewards(PoolId::Dex(BTC_AUSD_LP), ALICE::get()), + BTreeMap::default() ); + }); +} - // alice claim rewards for PoolId::DexIncentive(BTC_AUSD_LP) - assert_ok!(IncentivesModule::claim_rewards( - Origin::signed(ALICE::get()), - PoolId::DexIncentive(BTC_AUSD_LP) +#[test] +fn on_initialize_should_work() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(TokensModule::deposit(ACA, &RewardsSource::get(), 10000)); + assert_ok!(TokensModule::deposit(AUSD, &RewardsSource::get(), 10000)); + assert_ok!(TokensModule::deposit(LDOT, &RewardsSource::get(), 10000)); + + assert_ok!(IncentivesModule::update_incentive_rewards( + Origin::signed(ROOT::get()), + vec![ + (PoolId::Loans(BTC), vec![(ACA, 1000), (AUSD, 500)]), + (PoolId::Loans(DOT), vec![(ACA, 2000), (LDOT, 50)]), + (PoolId::Dex(BTC_AUSD_LP), vec![(ACA, 100)]), + (PoolId::Dex(DOT_AUSD_LP), vec![(ACA, 200)]), + ], )); - System::assert_last_event(Event::IncentivesModule(crate::Event::ClaimRewards( - ALICE::get(), - PoolId::DexIncentive(BTC_AUSD_LP), - ACA, - 291, - 291, - ))); + assert_ok!(IncentivesModule::update_dex_saving_rewards( + Origin::signed(ROOT::get()), + vec![ + (PoolId::Dex(BTC_AUSD_LP), Rate::saturating_from_rational(1, 100)), + (PoolId::Dex(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100)), + ], + )); + + RewardsModule::add_share(&ALICE::get(), &PoolId::Loans(BTC), 1); + RewardsModule::add_share(&ALICE::get(), &PoolId::Dex(BTC_AUSD_LP), 1); + RewardsModule::add_share(&ALICE::get(), &PoolId::Dex(DOT_AUSD_LP), 1); + + assert_eq!(TokensModule::free_balance(ACA, &RewardsSource::get()), 10000); + assert_eq!(TokensModule::free_balance(AUSD, &RewardsSource::get()), 10000); + assert_eq!(TokensModule::free_balance(LDOT, &RewardsSource::get()), 10000); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 0); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 0); + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 0); assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 150, - total_rewards: 1290, - total_withdrawn_rewards: 831 + total_shares: 1, + ..Default::default() } ); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - (50, 332) + RewardsModule::pool_infos(PoolId::Loans(DOT)), + PoolInfo { + total_shares: 0, + ..Default::default() + } ); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 7459); - assert_eq!(TokensModule::free_balance(ACA, &ALICE::get()), 2291); assert_eq!( - IncentivesModule::pending_rewards(PoolId::DexIncentive(BTC_AUSD_LP), ALICE::get()), - 0 + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), + PoolInfo { + total_shares: 1, + ..Default::default() + } ); - - // alice claim rewards for PoolId::DexSaving(BTC_AUSD_LP) assert_eq!( - RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Dex(DOT_AUSD_LP)), PoolInfo { - total_shares: 200, - total_rewards: 2000, - total_withdrawn_rewards: 0 + total_shares: 1, + ..Default::default() } ); + + // per 10 blocks will accumulate rewards, nothing happened when on_initialize(9) + IncentivesModule::on_initialize(9); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 0); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 0); + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 0); + + IncentivesModule::on_initialize(10); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexSaving(BTC_AUSD_LP), ALICE::get()), - (100, 0) + TokensModule::free_balance(ACA, &RewardsSource::get()), + 10000 - (1000 + 200 + 100) ); - assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 10000); - assert_eq!(TokensModule::free_balance(AUSD, &ALICE::get()), 0); - assert_ok!(IncentivesModule::claim_rewards( - Origin::signed(ALICE::get()), - PoolId::DexSaving(BTC_AUSD_LP) - )); - System::assert_last_event(Event::IncentivesModule(crate::Event::ClaimRewards( - ALICE::get(), - PoolId::DexSaving(BTC_AUSD_LP), - AUSD, - 800, - 200, - ))); + assert_eq!(TokensModule::free_balance(AUSD, &RewardsSource::get()), 10000 - 500); + assert_eq!(TokensModule::free_balance(LDOT, &RewardsSource::get()), 10000); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 1000 + 200 + 100); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 500 + (5 + 4)); // (5 + 4) from debit_issue, 500 from RewardsSource + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 0); + // 1000 ACA and 500 AUSD are incentive reward assert_eq!( - RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 200, - total_rewards: 2200, - total_withdrawn_rewards: 1000 + total_shares: 1, + rewards: vec![(ACA, (1000, 0)), (AUSD, (500, 0))].into_iter().collect(), } ); + // because total_shares of PoolId::Loans(DOT) is zero, will not accumulate rewards assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::DexSaving(BTC_AUSD_LP), ALICE::get()), - (100, 1000) - ); - assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 9200); - assert_eq!(TokensModule::free_balance(AUSD, &ALICE::get()), 800); - - // alice remove all share for PoolId::HomaValidatorAllowance(VALIDATOR::get()) - assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())), + RewardsModule::pool_infos(PoolId::Loans(DOT)), PoolInfo { - total_shares: 100, - total_rewards: 5000, - total_withdrawn_rewards: 0 + total_shares: 0, + ..Default::default() } ); + // 100 ACA is incentive reward, 5 AUSD is dex saving reward assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - (100, 0) + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (100, 0)), (AUSD, (5, 0))].into_iter().collect(), + } ); + // 200 ACA is incentive reward, 4 AUSD is dex saving reward assert_eq!( - IncentivesModule::pending_rewards(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - 0 + RewardsModule::pool_infos(PoolId::Dex(DOT_AUSD_LP)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (200, 0)), (AUSD, (4, 0))].into_iter().collect(), + } ); - RewardsModule::remove_share(&ALICE::get(), &PoolId::HomaValidatorAllowance(VALIDATOR::get()), 100); + + // add share for PoolId::Loans(DOT) + RewardsModule::add_share(&ALICE::get(), &PoolId::Loans(DOT), 1); assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())), + RewardsModule::pool_infos(PoolId::Loans(DOT)), PoolInfo { - total_shares: 0, - total_rewards: 0, - total_withdrawn_rewards: 0 + total_shares: 1, + ..Default::default() } ); + + IncentivesModule::on_initialize(20); assert_eq!( - RewardsModule::share_and_withdrawn_reward(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - (0, 0) + TokensModule::free_balance(ACA, &RewardsSource::get()), + 8700 - (1000 + 2000 + 100 + 200) ); + assert_eq!(TokensModule::free_balance(AUSD, &RewardsSource::get()), 9500 - 500); + assert_eq!(TokensModule::free_balance(LDOT, &RewardsSource::get()), 10000 - 50); assert_eq!( - IncentivesModule::pending_rewards(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - 5000 + TokensModule::free_balance(ACA, &VAULT::get()), + 1300 + (1000 + 2000 + 100 + 200) ); - - // alice claim rewards for PoolId::HomaValidatorAllowance(VALIDATOR::get()) - assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 10000); - assert_eq!(TokensModule::free_balance(LDOT, &ALICE::get()), 0); - assert_ok!(IncentivesModule::claim_rewards( - Origin::signed(ALICE::get()), - PoolId::HomaValidatorAllowance(VALIDATOR::get()) - )); - System::assert_last_event(Event::IncentivesModule(crate::Event::ClaimRewards( - ALICE::get(), - PoolId::HomaValidatorAllowance(VALIDATOR::get()), - LDOT, - 500, - 4500, - ))); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 509 + (500 + 9)); // 9 from debit_issue, 500 from RewardsSource + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 0 + 50); + // 1000 ACA and 500 AUSD are incentive reward assert_eq!( - RewardsModule::pools(PoolId::HomaValidatorAllowance(VALIDATOR::get())), + RewardsModule::pool_infos(PoolId::Loans(BTC)), PoolInfo { - total_shares: 0, - total_rewards: 4500, - total_withdrawn_rewards: 0 + total_shares: 1, + rewards: vec![(ACA, (2000, 0)), (AUSD, (1000, 0))].into_iter().collect(), } ); - assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 9500); - assert_eq!(TokensModule::free_balance(LDOT, &ALICE::get()), 500); + // 2000 ACA and 50 LDOT are incentive reward assert_eq!( - IncentivesModule::pending_rewards(PoolId::HomaValidatorAllowance(VALIDATOR::get()), ALICE::get()), - 0 + RewardsModule::pool_infos(PoolId::Loans(DOT)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (2000, 0)), (LDOT, (50, 0))].into_iter().collect(), + } ); - }); -} - -#[test] -fn on_initialize_should_work() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(IncentivesModule::update_incentive_rewards( - Origin::signed(Root::get()), - vec![ - (PoolId::LoansIncentive(BTC), 1000), - (PoolId::LoansIncentive(DOT), 2000), - (PoolId::DexIncentive(BTC_AUSD_LP), 100), - (PoolId::DexIncentive(DOT_AUSD_LP), 200), - (PoolId::HomaIncentive, 30), - ], - )); - assert_ok!(IncentivesModule::update_dex_saving_rewards( - Origin::signed(Root::get()), - vec![ - (PoolId::DexSaving(BTC_AUSD_LP), Rate::saturating_from_rational(1, 100)), - (PoolId::DexSaving(DOT_AUSD_LP), Rate::saturating_from_rational(1, 100)), - ], - )); - - RewardsModule::add_share(&ALICE::get(), &PoolId::LoansIncentive(BTC), 1); - RewardsModule::add_share(&ALICE::get(), &PoolId::DexIncentive(BTC_AUSD_LP), 1); - RewardsModule::add_share(&ALICE::get(), &PoolId::DexIncentive(DOT_AUSD_LP), 1); - RewardsModule::add_share(&ALICE::get(), &PoolId::DexSaving(BTC_AUSD_LP), 1); - RewardsModule::add_share(&ALICE::get(), &PoolId::DexSaving(DOT_AUSD_LP), 1); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 0); - assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 0); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(BTC)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(DOT)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexIncentive(DOT_AUSD_LP)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::HomaIncentive).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(DOT_AUSD_LP)).total_rewards, 0); - - IncentivesModule::on_initialize(9); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 0); - assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 0); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(BTC)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(DOT)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexIncentive(DOT_AUSD_LP)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::HomaIncentive).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(DOT_AUSD_LP)).total_rewards, 0); - - IncentivesModule::on_initialize(10); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 1300); - assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 9); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(BTC)).total_rewards, 1000); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(DOT)).total_rewards, 0); + // 100 ACA is incentive reward, 5 AUSD is dex saving reward assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)).total_rewards, - 100 + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (200, 0)), (AUSD, (10, 0))].into_iter().collect(), + } ); + // 200 ACA is incentive reward, 4 AUSD is dex saving reward assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(DOT_AUSD_LP)).total_rewards, - 200 + RewardsModule::pool_infos(PoolId::Dex(DOT_AUSD_LP)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (400, 0)), (AUSD, (8, 0))].into_iter().collect(), + } ); - assert_eq!(RewardsModule::pools(PoolId::HomaIncentive).total_rewards, 0); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)).total_rewards, 5); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(DOT_AUSD_LP)).total_rewards, 4); - RewardsModule::add_share(&ALICE::get(), &PoolId::LoansIncentive(DOT), 1); - RewardsModule::add_share(&ALICE::get(), &PoolId::HomaIncentive, 1); - IncentivesModule::on_initialize(20); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 4630); - assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 18); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(BTC)).total_rewards, 2000); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(DOT)).total_rewards, 2000); + mock_shutdown(); + IncentivesModule::on_initialize(30); assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)).total_rewards, - 200 + TokensModule::free_balance(ACA, &RewardsSource::get()), + 5400 - (100 + 200) ); + assert_eq!(TokensModule::free_balance(AUSD, &RewardsSource::get()), 9000); + assert_eq!(TokensModule::free_balance(LDOT, &RewardsSource::get()), 9950); + assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 4600 + (100 + 200)); + assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 1018); + assert_eq!(TokensModule::free_balance(LDOT, &VAULT::get()), 50); + // PoolId::Loans will not accumulate incentive rewards after shutdown assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(DOT_AUSD_LP)).total_rewards, - 400 + RewardsModule::pool_infos(PoolId::Loans(BTC)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (2000, 0)), (AUSD, (1000, 0))].into_iter().collect(), + } ); - assert_eq!(RewardsModule::pools(PoolId::HomaIncentive).total_rewards, 30); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)).total_rewards, 10); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(DOT_AUSD_LP)).total_rewards, 8); - - mock_shutdown(); - IncentivesModule::on_initialize(30); - assert_eq!(TokensModule::free_balance(ACA, &VAULT::get()), 4630); - assert_eq!(TokensModule::free_balance(AUSD, &VAULT::get()), 18); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(BTC)).total_rewards, 2000); - assert_eq!(RewardsModule::pools(PoolId::LoansIncentive(DOT)).total_rewards, 2000); + // PoolId::Loans will not accumulate incentive rewards after shutdown assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(BTC_AUSD_LP)).total_rewards, - 200 + RewardsModule::pool_infos(PoolId::Loans(DOT)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (2000, 0)), (LDOT, (50, 0))].into_iter().collect(), + } + ); + // after shutdown, PoolId::Dex will accumulate incentive rewards, but will not accumulate dex saving + // reward + assert_eq!( + RewardsModule::pool_infos(PoolId::Dex(BTC_AUSD_LP)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (300, 0)), (AUSD, (10, 0))].into_iter().collect(), + } ); + // after shutdown, PoolId::Dex will accumulate incentive rewards, but will not accumulate dex saving + // reward assert_eq!( - RewardsModule::pools(PoolId::DexIncentive(DOT_AUSD_LP)).total_rewards, - 400 + RewardsModule::pool_infos(PoolId::Dex(DOT_AUSD_LP)), + PoolInfo { + total_shares: 1, + rewards: vec![(ACA, (600, 0)), (AUSD, (8, 0))].into_iter().collect(), + } ); - assert_eq!(RewardsModule::pools(PoolId::HomaIncentive).total_rewards, 30); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(BTC_AUSD_LP)).total_rewards, 10); - assert_eq!(RewardsModule::pools(PoolId::DexSaving(DOT_AUSD_LP)).total_rewards, 8); }); } diff --git a/modules/incentives/src/weights.rs b/modules/incentives/src/weights.rs index e74d999959..3813887cbe 100644 --- a/modules/incentives/src/weights.rs +++ b/modules/incentives/src/weights.rs @@ -54,8 +54,7 @@ pub trait WeightInfo { fn claim_rewards() -> Weight; fn update_incentive_rewards(c: u32, ) -> Weight; fn update_dex_saving_rewards(c: u32, ) -> Weight; - fn update_payout_deduction_rates(c: u32, ) -> Weight; - fn add_allowance() -> Weight; + fn update_claim_reward_deduction_rates(c: u32, ) -> Weight; } /// Weights for module_incentives using the Acala node and recommended hardware. @@ -94,16 +93,12 @@ impl WeightInfo for AcalaWeight { .saturating_add((1_829_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn update_payout_deduction_rates(c: u32, ) -> Weight { + fn update_claim_reward_deduction_rates(c: u32, ) -> Weight { (914_000 as Weight) // Standard Error: 21_000 .saturating_add((1_829_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn add_allowance() -> Weight { - (2_000_000 as Weight) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) - } } // For backwards compatibility and tests @@ -141,14 +136,10 @@ impl WeightInfo for () { .saturating_add((1_829_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn update_payout_deduction_rates(c: u32, ) -> Weight { + fn update_claim_reward_deduction_rates(c: u32, ) -> Weight { (914_000 as Weight) // Standard Error: 21_000 .saturating_add((1_829_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn add_allowance() -> Weight { - (2_000_000 as Weight) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) - } } diff --git a/orml b/orml index 59df1dfc1a..1eea735c0a 160000 --- a/orml +++ b/orml @@ -1 +1 @@ -Subproject commit 59df1dfc1a04d781906ee4442bbd410c9ca3ce68 +Subproject commit 1eea735c0a4962bf07afa653ce0720095faca3e2 diff --git a/runtime/acala/src/lib.rs b/runtime/acala/src/lib.rs index bc7fc63639..ae26f3823f 100644 --- a/runtime/acala/src/lib.rs +++ b/runtime/acala/src/lib.rs @@ -1131,7 +1131,10 @@ impl module_evm_manager::Config for Runtime { impl orml_rewards::Config for Runtime { type Share = Balance; type Balance = Balance; - type PoolId = module_incentives::PoolId; + type PoolIdV0 = module_incentives::PoolIdV0; + type PoolIdConvertor = module_incentives::PoolIdConvertor; + type PoolId = module_incentives::PoolId; + type CurrencyId = CurrencyId; type Handler = Incentives; } @@ -1142,7 +1145,7 @@ parameter_types! { impl module_incentives::Config for Runtime { type Event = Event; type RelaychainAccountId = AccountId; - type NativeRewardsSource = UnreleasedNativeVaultAccountId; + type RewardsSource = UnreleasedNativeVaultAccountId; type NativeCurrencyId = GetNativeCurrencyId; type StableCurrencyId = GetStableCurrencyId; type LiquidCurrencyId = GetLiquidCurrencyId; @@ -1234,8 +1237,8 @@ impl module_homa_validator_list::Config for Runtime { type OnSlash = module_staking_pool::OnSlash; type LiquidStakingExchangeRateProvider = LiquidStakingExchangeRateProvider; type WeightInfo = (); - type OnIncreaseGuarantee = module_incentives::OnIncreaseGuarantee; - type OnDecreaseGuarantee = module_incentives::OnDecreaseGuarantee; + type OnIncreaseGuarantee = (); + type OnDecreaseGuarantee = (); type BlockNumberProvider = RelaychainBlockNumberProvider; } diff --git a/runtime/acala/src/weights/module_incentives.rs b/runtime/acala/src/weights/module_incentives.rs index f2d4eb56ed..e75bb348e0 100644 --- a/runtime/acala/src/weights/module_incentives.rs +++ b/runtime/acala/src/weights/module_incentives.rs @@ -79,13 +79,10 @@ impl module_incentives::WeightInfo for WeightInfo { .saturating_add((1_832_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn update_payout_deduction_rates(c: u32) -> Weight { + fn update_claim_reward_deduction_rates(c: u32) -> Weight { (875_000 as Weight) // Standard Error: 21_000 .saturating_add((1_832_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn add_allowance() -> Weight { - (2_000_000 as Weight).saturating_add(T::DbWeight::get().writes(1 as Weight)) - } } diff --git a/runtime/karura/src/lib.rs b/runtime/karura/src/lib.rs index aea66d6e65..1edcb66c29 100644 --- a/runtime/karura/src/lib.rs +++ b/runtime/karura/src/lib.rs @@ -1126,7 +1126,10 @@ impl module_evm_manager::Config for Runtime { impl orml_rewards::Config for Runtime { type Share = Balance; type Balance = Balance; - type PoolId = module_incentives::PoolId; + type PoolIdV0 = module_incentives::PoolIdV0; + type PoolIdConvertor = module_incentives::PoolIdConvertor; + type PoolId = module_incentives::PoolId; + type CurrencyId = CurrencyId; type Handler = Incentives; } @@ -1137,7 +1140,7 @@ parameter_types! { impl module_incentives::Config for Runtime { type Event = Event; type RelaychainAccountId = AccountId; - type NativeRewardsSource = UnreleasedNativeVaultAccountId; + type RewardsSource = UnreleasedNativeVaultAccountId; type NativeCurrencyId = GetNativeCurrencyId; type StableCurrencyId = GetStableCurrencyId; type LiquidCurrencyId = GetLiquidCurrencyId; diff --git a/runtime/karura/src/weights/module_incentives.rs b/runtime/karura/src/weights/module_incentives.rs index 19063a155a..035924b0a8 100644 --- a/runtime/karura/src/weights/module_incentives.rs +++ b/runtime/karura/src/weights/module_incentives.rs @@ -81,15 +81,10 @@ impl module_incentives::WeightInfo for WeightInfo { .saturating_add((19_798_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn update_payout_deduction_rates(c: u32, ) -> Weight { + fn update_claim_reward_deduction_rates(c: u32, ) -> Weight { (1_850_000 as Weight) // Standard Error: 54_000 .saturating_add((19_603_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn add_allowance() -> Weight { - (79_658_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - } } diff --git a/runtime/mandala/src/benchmarking/incentives.rs b/runtime/mandala/src/benchmarking/incentives.rs index 61688d857a..72177d41f6 100644 --- a/runtime/mandala/src/benchmarking/incentives.rs +++ b/runtime/mandala/src/benchmarking/incentives.rs @@ -17,8 +17,8 @@ // along with this program. If not, see . use crate::{ - dollar, AccountId, AccumulatePeriod, CollateralCurrencyIds, Currencies, CurrencyId, GetLiquidCurrencyId, - GetNativeCurrencyId, GetStableCurrencyId, GetStakingCurrencyId, Incentives, Rate, Rewards, Runtime, System, + dollar, AccountId, AccumulatePeriod, CollateralCurrencyIds, Currencies, CurrencyId, GetNativeCurrencyId, + GetStableCurrencyId, GetStakingCurrencyId, Incentives, Rate, Rewards, Runtime, System, }; use super::utils::set_balance; @@ -36,7 +36,6 @@ const SEED: u32 = 0; const NATIVE: CurrencyId = GetNativeCurrencyId::get(); const STAKING: CurrencyId = GetStakingCurrencyId::get(); const STABLECOIN: CurrencyId = GetStableCurrencyId::get(); -const LIQUID: CurrencyId = GetLiquidCurrencyId::get(); runtime_benchmarks! { { Runtime, module_incentives } @@ -48,10 +47,10 @@ runtime_benchmarks! { for i in 0 .. c { let currency_id = currency_ids[i as usize]; - let pool_id = PoolId::LoansIncentive(currency_id); + let pool_id = PoolId::Loans(currency_id); - Incentives::update_incentive_rewards(RawOrigin::Root.into(), vec![(pool_id.clone(), 100 * dollar(NATIVE))])?; - orml_rewards::Pools::::mutate(pool_id, |pool_info| { + Incentives::update_incentive_rewards(RawOrigin::Root.into(), vec![(pool_id.clone(), vec![(NATIVE, 100 * dollar(NATIVE))])])?; + orml_rewards::PoolInfos::::mutate(pool_id, |pool_info| { pool_info.total_shares += 100; }); } @@ -81,12 +80,12 @@ runtime_benchmarks! { claim_rewards { let caller: AccountId = whitelisted_caller(); - let pool_id = PoolId::LoansIncentive(STAKING); + let pool_id = PoolId::Loans(STAKING); let native_currency_id = GetNativeCurrencyId::get(); Rewards::add_share(&caller, &pool_id, 100); Currencies::deposit(native_currency_id, &Incentives::account_id(), 80 * dollar(native_currency_id))?; - Rewards::accumulate_reward(&pool_id, 80 * dollar(native_currency_id)); + Rewards::accumulate_reward(&pool_id, native_currency_id, 80 * dollar(native_currency_id))?; }: _(RawOrigin::Signed(caller), pool_id) update_incentive_rewards { @@ -96,7 +95,7 @@ runtime_benchmarks! { for i in 0 .. c { let currency_id = currency_ids[i as usize]; - updates.push((PoolId::LoansIncentive(currency_id), 100 * dollar(NATIVE))); + updates.push((PoolId::Loans(currency_id), vec![(NATIVE, dollar(NATIVE))])); } }: _(RawOrigin::Root, updates) @@ -115,26 +114,20 @@ runtime_benchmarks! { } _ => return Err("invalid currency id"), }; - updates.push((PoolId::DexSaving(lp_share_currency_id), Rate::default())); + updates.push((PoolId::Dex(lp_share_currency_id), Rate::default())); } }: _(RawOrigin::Root, updates) - update_payout_deduction_rates { + update_claim_reward_deduction_rates { let c in 0 .. CollateralCurrencyIds::get().len().saturating_sub(1) as u32; let currency_ids = CollateralCurrencyIds::get(); let mut updates = vec![]; for i in 0 .. c { let currency_id = currency_ids[i as usize]; - updates.push((PoolId::LoansIncentive(currency_id), Rate::default())); + updates.push((PoolId::Loans(currency_id), Rate::default())); } }: _(RawOrigin::Root, updates) - - add_allowance { - let caller: AccountId = whitelisted_caller(); - set_balance(LIQUID, &caller, 10_000 * dollar(STABLECOIN)); - let pool_id = PoolId::HomaValidatorAllowance(caller.clone()); - }: _(RawOrigin::Signed(caller), pool_id, 1 * dollar(LIQUID)) } #[cfg(test)] diff --git a/runtime/mandala/src/lib.rs b/runtime/mandala/src/lib.rs index ebd5c36307..953b833b98 100644 --- a/runtime/mandala/src/lib.rs +++ b/runtime/mandala/src/lib.rs @@ -1200,7 +1200,10 @@ impl module_evm_manager::Config for Runtime { impl orml_rewards::Config for Runtime { type Share = Balance; type Balance = Balance; - type PoolId = module_incentives::PoolId; + type PoolIdV0 = module_incentives::PoolIdV0; + type PoolIdConvertor = module_incentives::PoolIdConvertor; + type PoolId = module_incentives::PoolId; + type CurrencyId = CurrencyId; type Handler = Incentives; } @@ -1211,7 +1214,7 @@ parameter_types! { impl module_incentives::Config for Runtime { type Event = Event; type RelaychainAccountId = AccountId; - type NativeRewardsSource = UnreleasedNativeVaultAccountId; + type RewardsSource = UnreleasedNativeVaultAccountId; type NativeCurrencyId = GetNativeCurrencyId; type StableCurrencyId = GetStableCurrencyId; type LiquidCurrencyId = GetLiquidCurrencyId; @@ -1338,8 +1341,8 @@ impl module_homa_validator_list::Config for Runtime { type OnSlash = module_staking_pool::OnSlash; type LiquidStakingExchangeRateProvider = LiquidStakingExchangeRateProvider; type WeightInfo = (); - type OnIncreaseGuarantee = module_incentives::OnIncreaseGuarantee; - type OnDecreaseGuarantee = module_incentives::OnDecreaseGuarantee; + type OnIncreaseGuarantee = (); + type OnDecreaseGuarantee = (); type BlockNumberProvider = RelaychainBlockNumberProvider; } diff --git a/runtime/mandala/src/weights/module_incentives.rs b/runtime/mandala/src/weights/module_incentives.rs index 1ca9dbde5a..b9f27c9168 100644 --- a/runtime/mandala/src/weights/module_incentives.rs +++ b/runtime/mandala/src/weights/module_incentives.rs @@ -81,15 +81,10 @@ impl module_incentives::WeightInfo for WeightInfo { .saturating_add((17_620_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn update_payout_deduction_rates(c: u32, ) -> Weight { + fn update_claim_reward_deduction_rates(c: u32, ) -> Weight { (3_692_000 as Weight) // Standard Error: 455_000 .saturating_add((17_687_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(c as Weight))) } - fn add_allowance() -> Weight { - (85_473_000 as Weight) - .saturating_add(T::DbWeight::get().reads(4 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) - } }