From 102a8f21179eb34c7ef942f542d151516648cf5b Mon Sep 17 00:00:00 2001 From: Cheng JIANG Date: Sat, 16 Apr 2022 00:41:24 +0800 Subject: [PATCH] cleanup liquid staking (#1592) Signed-off-by: Cheng JIANG --- pallets/crowdloans/src/lib.rs | 6 +- pallets/liquid-staking/src/distribution.rs | 67 ++++++++++++---------- pallets/liquid-staking/src/lib.rs | 51 +++++++++------- pallets/traits/src/lib.rs | 6 +- pallets/xcm-helper/src/tests.rs | 2 +- primitives/src/tokens.rs | 5 ++ 6 files changed, 79 insertions(+), 58 deletions(-) diff --git a/pallets/crowdloans/src/lib.rs b/pallets/crowdloans/src/lib.rs index 73870bd4f..0e799deab 100644 --- a/pallets/crowdloans/src/lib.rs +++ b/pallets/crowdloans/src/lib.rs @@ -966,9 +966,7 @@ pub mod pallet { ); 'outer: for kind in [Contributed, Flying, Pending] { - for (who, (amount, referral_code)) in - Self::contribution_iterator(vault.trie_index, kind) - { + for (who, (amount, _)) in Self::contribution_iterator(vault.trie_index, kind) { if refund_count >= T::RemoveKeysLimit::get() { all_refunded = false; break 'outer; @@ -994,7 +992,7 @@ pub mod pallet { &who, &mut vault, amount, - Some(referral_code.clone()), + None, ArithmeticKind::Subtraction, kind, )?; diff --git a/pallets/liquid-staking/src/distribution.rs b/pallets/liquid-staking/src/distribution.rs index 80a4d3ef2..4db36a3d7 100644 --- a/pallets/liquid-staking/src/distribution.rs +++ b/pallets/liquid-staking/src/distribution.rs @@ -7,64 +7,71 @@ use sp_std::vec::Vec; pub struct AverageDistribution; impl DistributionStrategy for AverageDistribution { fn get_bond_distributions( - bonding_amounts: &mut Vec<(DerivativeIndex, Balance)>, + bonded_amounts: Vec<(DerivativeIndex, Balance)>, input: Balance, cap: Balance, min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)> { - let length = TryInto::::try_into(bonding_amounts.len()).unwrap_or_default(); + let length = TryInto::::try_into(bonded_amounts.len()).unwrap_or_default(); if length.is_zero() { return Default::default(); } + let mut distributions: Vec<(DerivativeIndex, Balance)> = vec![]; let amount = input.checked_div(&length).unwrap_or_default(); - for (index, bonded) in bonding_amounts.iter() { - if amount.saturating_add(*bonded) < min_nominator_bond { + for (index, bonded) in bonded_amounts.into_iter() { + if amount.saturating_add(bonded) < min_nominator_bond { + continue; + } + let amount = cap.saturating_sub(bonded).min(amount); + if amount.is_zero() { continue; } - let amount = cap.saturating_sub(*bonded).min(amount); - distributions.push((*index, amount)); + distributions.push((index, amount)); } distributions } fn get_unbond_distributions( - bonding_amounts: &mut Vec<(DerivativeIndex, Balance)>, + bonded_amounts: Vec<(DerivativeIndex, Balance)>, input: Balance, _cap: Balance, min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)> { - let length = TryInto::::try_into(bonding_amounts.len()).unwrap_or_default(); + let length = TryInto::::try_into(bonded_amounts.len()).unwrap_or_default(); if length.is_zero() { return Default::default(); } + let mut distributions: Vec<(DerivativeIndex, Balance)> = vec![]; let amount = input.checked_div(&length).unwrap_or_default(); - for (index, bonded) in bonding_amounts.iter() { + for (index, bonded) in bonded_amounts.into_iter() { if bonded.saturating_sub(amount) < min_nominator_bond { continue; } - distributions.push((*index, amount)); + distributions.push((index, amount)); } distributions } fn get_rebond_distributions( - unbonding_amounts: &mut Vec<(DerivativeIndex, Balance, Balance)>, + unbonding_bonded_amounts: Vec<(DerivativeIndex, Balance, Balance)>, input: Balance, _cap: Balance, _min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)> { - let length = TryInto::::try_into(unbonding_amounts.len()).unwrap_or_default(); + let length = + TryInto::::try_into(unbonding_bonded_amounts.len()).unwrap_or_default(); if length.is_zero() { return Default::default(); } + let mut distributions: Vec<(DerivativeIndex, Balance)> = vec![]; let amount = input.checked_div(&length).unwrap_or_default(); - for (index, _, _) in unbonding_amounts.iter() { - distributions.push((*index, amount)); + for (index, _, _) in unbonding_bonded_amounts.into_iter() { + distributions.push((index, amount)); } distributions @@ -76,33 +83,33 @@ impl DistributionStrategy for MaximizationDistribution { fn get_bond_distributions( - bonding_amounts: &mut Vec<(DerivativeIndex, Balance)>, + mut bonded_amounts: Vec<(DerivativeIndex, Balance)>, input: Balance, cap: Balance, min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)> { - //ascending sequence - bonding_amounts.sort_by(|a, b| a.1.cmp(&b.1)); + // ascending sequence + bonded_amounts.sort_by(|a, b| a.1.cmp(&b.1)); let mut distributions: Vec<(DerivativeIndex, Balance)> = vec![]; let mut remain = input; - for (index, bonded) in bonding_amounts.iter() { + for (index, bonded) in bonded_amounts.into_iter() { if remain.is_zero() { break; } - let amount = cap.saturating_sub(*bonded).min(remain); + let amount = cap.saturating_sub(bonded).min(remain); if amount.is_zero() { // `bonding_amounts` is an ascending sequence // if occurs an item that exceed the cap, the items after this one must all be exceeded break; } - if amount.saturating_add(*bonded) < min_nominator_bond { + if amount.saturating_add(bonded) < min_nominator_bond { continue; } - distributions.push((*index, amount)); + distributions.push((index, amount)); remain = remain.saturating_sub(amount); } @@ -110,18 +117,18 @@ impl DistributionStrategy } fn get_unbond_distributions( - bonding_amounts: &mut Vec<(DerivativeIndex, Balance)>, + mut bonded_amounts: Vec<(DerivativeIndex, Balance)>, input: Balance, _cap: Balance, min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)> { // descending sequence - bonding_amounts.sort_by(|a, b| b.1.cmp(&a.1)); + bonded_amounts.sort_by(|a, b| b.1.cmp(&a.1)); let mut distributions: Vec<(DerivativeIndex, Balance)> = vec![]; let mut remain = input; - for (index, bonded) in bonding_amounts.iter() { + for (index, bonded) in bonded_amounts.into_iter() { if remain.is_zero() { break; } @@ -129,33 +136,33 @@ impl DistributionStrategy if amount.is_zero() { continue; } - distributions.push((*index, amount)); + distributions.push((index, amount)); remain = remain.saturating_sub(amount); } distributions } fn get_rebond_distributions( - unbonding_amounts: &mut Vec<(DerivativeIndex, Balance, Balance)>, + mut unbonding_bonded_amounts: Vec<(DerivativeIndex, Balance, Balance)>, input: Balance, cap: Balance, _min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)> { // descending sequence - unbonding_amounts.sort_by(|a, b| b.1.cmp(&a.1)); + unbonding_bonded_amounts.sort_by(|a, b| b.1.cmp(&a.1)); let mut distributions: Vec<(DerivativeIndex, Balance)> = vec![]; let mut remain = input; - for (index, unlocking, active) in unbonding_amounts.iter() { + for (index, unbonding, bonded) in unbonding_bonded_amounts.into_iter() { if remain.is_zero() { break; } - let amount = remain.min(*unlocking).min(cap.saturating_sub(*active)); + let amount = remain.min(unbonding).min(cap.saturating_sub(bonded)); if amount.is_zero() { continue; } - distributions.push((*index, amount)); + distributions.push((index, amount)); remain = remain.saturating_sub(amount); } diff --git a/pallets/liquid-staking/src/lib.rs b/pallets/liquid-staking/src/lib.rs index 35b81642d..2f6c4858f 100644 --- a/pallets/liquid-staking/src/lib.rs +++ b/pallets/liquid-staking/src/lib.rs @@ -799,12 +799,17 @@ pub mod pallet { Self::do_update_ledger(derivative_index, |ledger| { ensure!( - !Self::is_updated(derivative_index), + !Self::is_updated(derivative_index) + || !XcmRequests::::iter().count().is_zero(), Error::::StakingLedgerLocked ); + // only allow to feed rewards + // slashes should be handled properly offchain ensure!( - ledger.active >= T::MinNominatorBond::get(), - Error::::InsufficientBond + staking_ledger.total > ledger.total + && staking_ledger.active > ledger.active + && staking_ledger.unlocking == ledger.unlocking, + Error::::InvalidStakingLedger ); let key = Self::get_staking_ledger_key(derivative_index); let value = staking_ledger.encode(); @@ -895,10 +900,9 @@ pub mod pallet { /// Get total unclaimed pub fn get_total_unclaimed(staking_currency: AssetIdOf) -> BalanceOf { - let matching_pool = Self::matching_pool(); T::Assets::reducible_balance(staking_currency, &Self::account_id(), false) .saturating_sub(Self::total_reserves()) - .saturating_sub(matching_pool.total_stake_amount.total) + .saturating_sub(Self::matching_pool().total_stake_amount.total) } /// Derivative of parachain's account @@ -919,11 +923,18 @@ pub mod pallet { Self::staking_ledger(&index).map_or(Zero::zero(), |ledger| ledger.active) } - // fn unbonding_of(index: DerivativeIndex) -> BalanceOf { - // Self::staking_ledger(&index).map_or(Zero::zero(), |ledger| { - // ledger.total.saturating_sub(ledger.active) - // }) - // } + fn unbonding_of(index: DerivativeIndex) -> BalanceOf { + let current_era = Self::current_era(); + Self::staking_ledger(&index).map_or(Zero::zero(), |ledger| { + ledger.unlocking.iter().fold(Zero::zero(), |acc, chunk| { + if chunk.era > current_era { + acc.saturating_add(chunk.value) + } else { + acc + } + }) + }) + } fn unbonded_of(index: DerivativeIndex) -> BalanceOf { let current_era = Self::current_era(); @@ -940,7 +951,6 @@ pub mod pallet { fn get_total_unbonding() -> BalanceOf { StakingLedgers::::iter_values().fold(Zero::zero(), |acc, ledger| { - // FIXME: Confirm if it's better to calculate total unlocking amount acc.saturating_add(ledger.total.saturating_sub(ledger.active)) }) } @@ -1275,12 +1285,13 @@ pub mod pallet { if total_amount.is_zero() { return Ok(()); } - let mut amounts: Vec<(DerivativeIndex, BalanceOf)> = T::DerivativeIndexList::get() + + let amounts: Vec<(DerivativeIndex, BalanceOf)> = T::DerivativeIndexList::get() .iter() .map(|&index| (index, Self::bonded_of(index))) .collect(); let distributions = T::DistributionStrategy::get_bond_distributions( - &mut amounts, + amounts, total_amount, Self::staking_ledger_cap(), T::MinNominatorBond::get(), @@ -1298,12 +1309,13 @@ pub mod pallet { if total_amount.is_zero() { return Ok(()); } - let mut amounts: Vec<(DerivativeIndex, BalanceOf)> = T::DerivativeIndexList::get() + + let amounts: Vec<(DerivativeIndex, BalanceOf)> = T::DerivativeIndexList::get() .iter() .map(|&index| (index, Self::bonded_of(index))) .collect(); let distributions = T::DistributionStrategy::get_unbond_distributions( - &mut amounts, + amounts, total_amount, Self::staking_ledger_cap(), T::MinNominatorBond::get(), @@ -1321,13 +1333,14 @@ pub mod pallet { if total_amount.is_zero() { return Ok(()); } - let mut amounts: Vec<(DerivativeIndex, BalanceOf, BalanceOf)> = + + let amounts: Vec<(DerivativeIndex, BalanceOf, BalanceOf)> = T::DerivativeIndexList::get() .iter() - .map(|&index| (index, Self::unbonded_of(index), Self::bonded_of(index))) + .map(|&index| (index, Self::unbonding_of(index), Self::bonded_of(index))) .collect(); let distributions = T::DistributionStrategy::get_rebond_distributions( - &mut amounts, + amounts, total_amount, Self::staking_ledger_cap(), T::MinNominatorBond::get(), @@ -1450,7 +1463,6 @@ pub mod pallet { #[require_transactional] fn do_update_exchange_rate() -> DispatchResult { let matching_ledger = Self::matching_pool(); - //TODO: use ledger.total or ledger.active? let total_bonded = Self::get_total_active_bonded(); let issuance = T::Assets::total_issuance(Self::liquid_currency()?); if issuance.is_zero() { @@ -1556,7 +1568,6 @@ pub mod pallet { derivative_index: DerivativeIndex, amount: BalanceOf, ) -> DispatchResult { - // FIXME: confirm use ledger.active or ledger.total ensure!( Self::bonded_of(derivative_index).saturating_add(amount) <= Self::staking_ledger_cap(), diff --git a/pallets/traits/src/lib.rs b/pallets/traits/src/lib.rs index ae8286cea..4e056104d 100644 --- a/pallets/traits/src/lib.rs +++ b/pallets/traits/src/lib.rs @@ -90,19 +90,19 @@ pub trait ValidationDataProvider { /// Distribute liquidstaking asset to multi-accounts pub trait DistributionStrategy { fn get_bond_distributions( - active_bonded_amount: &mut Vec<(DerivativeIndex, Balance)>, + bonded_amounts: Vec<(DerivativeIndex, Balance)>, input: Balance, cap: Balance, min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)>; fn get_unbond_distributions( - active_bonded_amount: &mut Vec<(DerivativeIndex, Balance)>, + bonded_amounts: Vec<(DerivativeIndex, Balance)>, input: Balance, cap: Balance, min_nominator_bond: Balance, ) -> Vec<(DerivativeIndex, Balance)>; fn get_rebond_distributions( - unlocking_amount: &mut Vec<(DerivativeIndex, Balance, Balance)>, + unbonding_bonded_amounts: Vec<(DerivativeIndex, Balance, Balance)>, input: Balance, cap: Balance, min_nominator_bond: Balance, diff --git a/pallets/xcm-helper/src/tests.rs b/pallets/xcm-helper/src/tests.rs index a3223b9c8..948a1579a 100644 --- a/pallets/xcm-helper/src/tests.rs +++ b/pallets/xcm-helper/src/tests.rs @@ -1,7 +1,7 @@ use super::*; use crate::mock::{Call as TestCall, *}; use frame_support::{assert_noop, assert_ok}; -use pallet_traits::ump::*; + use primitives::tokens::DOT; use sp_runtime::traits::{One, Zero}; diff --git a/primitives/src/tokens.rs b/primitives/src/tokens.rs index 1ba57a8e9..d308c8bc5 100644 --- a/primitives/src/tokens.rs +++ b/primitives/src/tokens.rs @@ -74,15 +74,20 @@ pub const LP_USDT_HKO: CurrencyId = 5000; pub const LP_KSM_USDT: CurrencyId = 5001; pub const LP_KSM_HKO: CurrencyId = 5002; pub const LP_KSM_SKSM: CurrencyId = 5003; +pub const LP_KSM_CKSM_20_27: CurrencyId = 5004; pub const LP_USDT_PARA: CurrencyId = 6000; pub const LP_DOT_USDT: CurrencyId = 6001; pub const LP_DOT_PARA: CurrencyId = 6002; pub const LP_DOT_SDOT: CurrencyId = 6003; +pub const LP_DOT_CDOT_6_13: CurrencyId = 6004; +pub const LP_DOT_CDOT_7_14: CurrencyId = 6005; +pub const LP_PARA_CDOT_6_13: CurrencyId = 6006; // Crowdloan Derivative pub const CKSM_15_22: CurrencyId = 100150022; pub const CKSM_20_27: CurrencyId = 100200027; +pub const CKSM_21_28: CurrencyId = 100210028; pub const CDOT_6_13: CurrencyId = 200060013; pub const CDOT_7_14: CurrencyId = 200070014; pub const CDOT_8_15: CurrencyId = 200080015;