Skip to content

Commit

Permalink
cleanup liquid staking (#1592)
Browse files Browse the repository at this point in the history
Signed-off-by: Cheng JIANG <[email protected]>
  • Loading branch information
GopherJ authored Apr 15, 2022
1 parent 840baed commit 102a8f2
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 58 deletions.
6 changes: 2 additions & 4 deletions pallets/crowdloans/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -994,7 +992,7 @@ pub mod pallet {
&who,
&mut vault,
amount,
Some(referral_code.clone()),
None,
ArithmeticKind::Subtraction,
kind,
)?;
Expand Down
67 changes: 37 additions & 30 deletions pallets/liquid-staking/src/distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,71 @@ use sp_std::vec::Vec;
pub struct AverageDistribution;
impl<Balance: BalanceT + FixedPointOperand> DistributionStrategy<Balance> 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::<Balance>::try_into(bonding_amounts.len()).unwrap_or_default();
let length = TryInto::<Balance>::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::<Balance>::try_into(bonding_amounts.len()).unwrap_or_default();
let length = TryInto::<Balance>::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::<Balance>::try_into(unbonding_amounts.len()).unwrap_or_default();
let length =
TryInto::<Balance>::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
Expand All @@ -76,86 +83,86 @@ impl<Balance: BalanceT + FixedPointOperand> DistributionStrategy<Balance>
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);
}

distributions
}

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;
}
let amount = remain.min(bonded.saturating_sub(min_nominator_bond));
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);
}

Expand Down
51 changes: 31 additions & 20 deletions pallets/liquid-staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<T>::iter().count().is_zero(),
Error::<T>::StakingLedgerLocked
);
// only allow to feed rewards
// slashes should be handled properly offchain
ensure!(
ledger.active >= T::MinNominatorBond::get(),
Error::<T>::InsufficientBond
staking_ledger.total > ledger.total
&& staking_ledger.active > ledger.active
&& staking_ledger.unlocking == ledger.unlocking,
Error::<T>::InvalidStakingLedger
);
let key = Self::get_staking_ledger_key(derivative_index);
let value = staking_ledger.encode();
Expand Down Expand Up @@ -895,10 +900,9 @@ pub mod pallet {

/// Get total unclaimed
pub fn get_total_unclaimed(staking_currency: AssetIdOf<T>) -> BalanceOf<T> {
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
Expand All @@ -919,11 +923,18 @@ pub mod pallet {
Self::staking_ledger(&index).map_or(Zero::zero(), |ledger| ledger.active)
}

// fn unbonding_of(index: DerivativeIndex) -> BalanceOf<T> {
// Self::staking_ledger(&index).map_or(Zero::zero(), |ledger| {
// ledger.total.saturating_sub(ledger.active)
// })
// }
fn unbonding_of(index: DerivativeIndex) -> BalanceOf<T> {
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<T> {
let current_era = Self::current_era();
Expand All @@ -940,7 +951,6 @@ pub mod pallet {

fn get_total_unbonding() -> BalanceOf<T> {
StakingLedgers::<T>::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))
})
}
Expand Down Expand Up @@ -1275,12 +1285,13 @@ pub mod pallet {
if total_amount.is_zero() {
return Ok(());
}
let mut amounts: Vec<(DerivativeIndex, BalanceOf<T>)> = T::DerivativeIndexList::get()

let amounts: Vec<(DerivativeIndex, BalanceOf<T>)> = 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(),
Expand All @@ -1298,12 +1309,13 @@ pub mod pallet {
if total_amount.is_zero() {
return Ok(());
}
let mut amounts: Vec<(DerivativeIndex, BalanceOf<T>)> = T::DerivativeIndexList::get()

let amounts: Vec<(DerivativeIndex, BalanceOf<T>)> = 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(),
Expand All @@ -1321,13 +1333,14 @@ pub mod pallet {
if total_amount.is_zero() {
return Ok(());
}
let mut amounts: Vec<(DerivativeIndex, BalanceOf<T>, BalanceOf<T>)> =

let amounts: Vec<(DerivativeIndex, BalanceOf<T>, BalanceOf<T>)> =
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(),
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -1556,7 +1568,6 @@ pub mod pallet {
derivative_index: DerivativeIndex,
amount: BalanceOf<T>,
) -> DispatchResult {
// FIXME: confirm use ledger.active or ledger.total
ensure!(
Self::bonded_of(derivative_index).saturating_add(amount)
<= Self::staking_ledger_cap(),
Expand Down
6 changes: 3 additions & 3 deletions pallets/traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,19 @@ pub trait ValidationDataProvider {
/// Distribute liquidstaking asset to multi-accounts
pub trait DistributionStrategy<Balance> {
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,
Expand Down
2 changes: 1 addition & 1 deletion pallets/xcm-helper/src/tests.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down
5 changes: 5 additions & 0 deletions primitives/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 102a8f2

Please sign in to comment.