Skip to content

Commit

Permalink
SLP cross chain fee cause lack of vToken reserve (#1649)
Browse files Browse the repository at this point in the history
* refactor: 💡 charge_host_fee_and_tune_vtoken_exchange_rate

* fix: 🐛 delegator value

* style: 💄 format
  • Loading branch information
yooml authored Feb 7, 2025
1 parent eecdeb2 commit c83570b
Show file tree
Hide file tree
Showing 17 changed files with 75 additions and 49 deletions.
2 changes: 1 addition & 1 deletion pallets/slp-v2/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ mod benchmarks {
None
));
#[extrinsic_call]
_(RawOrigin::Root, STAKING_PROTOCOL, delegator, 1000);
_(RawOrigin::Root, STAKING_PROTOCOL, delegator, 1000, 0);
Ok(())
}

Expand Down
24 changes: 16 additions & 8 deletions pallets/slp-v2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,10 @@ pub mod pallet {
protocol_fee_currency_id: CurrencyId,
/// The amount of the fee charged to the protocol
protocol_fee: Balance,
/// Amount of exchange rates updated
amount: Balance,
/// Amount of pool value updated
pool_value: Balance,
/// Amount of delegator value updated
delegator_value: Balance,
},
/// Transfer the staking token to remote chain.
TransferTo {
Expand Down Expand Up @@ -656,7 +658,8 @@ pub mod pallet {
origin: OriginFor<T>,
staking_protocol: StakingProtocol,
delegator: Delegator<T::AccountId>,
amount: Balance,
pool_value: Balance,
delegator_value: Balance,
) -> DispatchResultWithPostInfo {
Self::ensure_governance_or_operator(origin, staking_protocol)?;
let currency_id = staking_protocol.info().currency_id;
Expand All @@ -683,12 +686,16 @@ pub mod pallet {
let pool_token_amount = T::VtokenMinting::get_token_pool(currency_id);
let max_amount = max_update_permill.mul_floor(pool_token_amount);
ensure!(
amount <= max_amount || max_amount == 0,
pool_value <= max_amount || max_amount == 0,
Error::<T>::UpdateTokenExchangeRateAmountTooLarge
);
ensure!(
delegator_value <= max_amount || max_amount == 0,
Error::<T>::UpdateTokenExchangeRateAmountTooLarge
);

// Charge the protocol fee.
let mut protocol_fee = protocol_fee_rate.mul_floor(amount);
let mut protocol_fee = protocol_fee_rate.mul_floor(pool_value);
let protocol_fee_currency_id = T::CurrencyIdConversion::convert_to_vtoken(currency_id)
.map_err(|_| Error::<T>::DerivativeAccountIdFailed)?;
if protocol_fee != 0 {
Expand All @@ -706,15 +713,15 @@ pub mod pallet {
}

// Update the token exchange rate.
T::VtokenMinting::increase_token_pool(currency_id, amount)
T::VtokenMinting::increase_token_pool(currency_id, pool_value)
.map_err(|_| Error::<T>::IncreaseTokenPoolFailed)?;
LedgerByStakingProtocolAndDelegator::<T>::mutate(
staking_protocol,
delegator.clone(),
|ledger| match ledger {
#[cfg(feature = "polkadot")]
Some(Ledger::AstarDappStaking(astar_dapp_staking_ledger)) => {
astar_dapp_staking_ledger.add_lock_amount(amount);
astar_dapp_staking_ledger.add_lock_amount(delegator_value);
Ok(())
}
_ => Err(Error::<T>::LedgerNotFound),
Expand All @@ -731,7 +738,8 @@ pub mod pallet {
delegator,
protocol_fee_currency_id,
protocol_fee,
amount,
pool_value,
delegator_value,
});
Ok(().into())
}
Expand Down
14 changes: 10 additions & 4 deletions pallets/slp-v2/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ fn update_token_exchange_rate_should_work() {
RuntimeOrigin::root(),
staking_protocol,
delegator.clone(),
amount,
amount
));
// The protocol_fee is 888.644046532367789159 VASTR.
Expand All @@ -957,7 +958,8 @@ fn update_token_exchange_rate_should_work() {
delegator: delegator.clone(),
protocol_fee_currency_id: VASTR,
protocol_fee,
amount,
pool_value: amount,
delegator_value: amount,
});
let vtoken_total_issuance = vtoken_total_issuance + protocol_fee;
let token_pool = token_pool + amount;
Expand All @@ -975,6 +977,7 @@ fn update_token_exchange_rate_should_work() {
RuntimeOrigin::root(),
staking_protocol,
delegator.clone(),
amount,
amount
));

Expand All @@ -991,7 +994,8 @@ fn update_token_exchange_rate_should_work() {
delegator: delegator.clone(),
protocol_fee_currency_id: VASTR,
protocol_fee: protocol_fee_1,
amount,
pool_value: amount,
delegator_value: amount,
});
let vtoken_total_issuance = vtoken_total_issuance + protocol_fee_1;
let token_pool = token_pool + amount;
Expand Down Expand Up @@ -1033,7 +1037,8 @@ fn update_token_exchange_rate_limt_error() {
RuntimeOrigin::root(),
staking_protocol,
delegator.clone(),
amount
amount,
0
),
SlpV2Error::<Test>::UpdateIntervalTooShort
);
Expand All @@ -1046,7 +1051,8 @@ fn update_token_exchange_rate_limt_error() {
RuntimeOrigin::root(),
staking_protocol,
delegator.clone(),
amount
amount,
0
),
SlpV2Error::<Test>::UpdateTokenExchangeRateAmountTooLarge
);
Expand Down
13 changes: 5 additions & 8 deletions pallets/slp/src/agents/astar_agent/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,30 +552,27 @@ impl<T: Config>
fn tune_vtoken_exchange_rate(
&self,
who: &Option<MultiLocation>,
token_amount: BalanceOf<T>,
pool_value: BalanceOf<T>,
delegator_value: BalanceOf<T>,
_vtoken_amount: BalanceOf<T>,
currency_id: CurrencyId,
) -> Result<(), Error<T>> {
let who = who.as_ref().ok_or(Error::<T>::DelegatorNotExist)?;

Pallet::<T>::tune_vtoken_exchange_rate_without_update_ledger(
who,
token_amount,
currency_id,
)?;
Pallet::<T>::tune_vtoken_exchange_rate_without_update_ledger(who, pool_value, currency_id)?;

// update delegator ledger
DelegatorLedgers::<T>::mutate(currency_id, who, |old_ledger| -> Result<(), Error<T>> {
if let Some(Ledger::Substrate(ref mut old_sub_ledger)) = old_ledger {
// Increase both the active and total amount.
old_sub_ledger.active = old_sub_ledger
.active
.checked_add(&token_amount)
.checked_add(&delegator_value)
.ok_or(Error::<T>::OverFlow)?;

old_sub_ledger.total = old_sub_ledger
.total
.checked_add(&token_amount)
.checked_add(&delegator_value)
.ok_or(Error::<T>::OverFlow)?;
Ok(())
} else {
Expand Down
9 changes: 5 additions & 4 deletions pallets/slp/src/agents/filecoin_agent/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,8 @@ impl<T: Config>
fn tune_vtoken_exchange_rate(
&self,
who: &Option<MultiLocation>,
token_amount: BalanceOf<T>,
pool_value: BalanceOf<T>,
_delegator_value: BalanceOf<T>,
_vtoken_amount: BalanceOf<T>,
currency_id: CurrencyId,
) -> Result<(), Error<T>> {
Expand All @@ -469,14 +470,14 @@ impl<T: Config>
Error::<T>::DelegatorAlreadyTuned
);

ensure!(!token_amount.is_zero(), Error::<T>::AmountZero);
ensure!(!pool_value.is_zero(), Error::<T>::AmountZero);

// issue the increased interest amount to the entrance account
// Get charged fee value
let (fee_permill, _beneficiary) =
HostingFees::<T>::get(currency_id).ok_or(Error::<T>::InvalidHostingFee)?;
let fee_to_charge = fee_permill.mul_floor(token_amount);
let amount_to_increase = token_amount
let fee_to_charge = fee_permill.mul_floor(pool_value);
let amount_to_increase = pool_value
.checked_sub(&fee_to_charge)
.ok_or(Error::<T>::UnderFlow)?;

Expand Down
7 changes: 4 additions & 3 deletions pallets/slp/src/agents/parachain_staking_agent/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1590,14 +1590,15 @@ impl<T: Config>
fn tune_vtoken_exchange_rate(
&self,
_who: &Option<MultiLocation>,
token_amount: BalanceOf<T>,
pool_value: BalanceOf<T>,
_delegator_value: BalanceOf<T>,
_vtoken_amount: BalanceOf<T>,
currency_id: CurrencyId,
) -> Result<(), Error<T>> {
ensure!(!token_amount.is_zero(), Error::<T>::AmountZero);
ensure!(!pool_value.is_zero(), Error::<T>::AmountZero);

// Tune the vtoken exchange rate.
T::VtokenMinting::increase_token_pool(currency_id, token_amount)
T::VtokenMinting::increase_token_pool(currency_id, pool_value)
.map_err(|_| Error::<T>::IncreaseTokenPoolError)?;

Ok(())
Expand Down
9 changes: 3 additions & 6 deletions pallets/slp/src/agents/phala_agent/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,8 @@ impl<T: Config>
fn tune_vtoken_exchange_rate(
&self,
who: &Option<MultiLocation>,
token_amount: BalanceOf<T>,
pool_value: BalanceOf<T>,
_delegator_value: BalanceOf<T>,
_vtoken_amount: BalanceOf<T>,
currency_id: CurrencyId,
) -> Result<(), Error<T>> {
Expand All @@ -764,11 +765,7 @@ impl<T: Config>
Err(Error::<T>::DelegatorNotExist)?;
}

Pallet::<T>::tune_vtoken_exchange_rate_without_update_ledger(
who,
token_amount,
currency_id,
)?;
Pallet::<T>::tune_vtoken_exchange_rate_without_update_ledger(who, pool_value, currency_id)?;

Ok(())
}
Expand Down
13 changes: 5 additions & 8 deletions pallets/slp/src/agents/polkadot_agent/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,30 +964,27 @@ impl<T: Config>
fn tune_vtoken_exchange_rate(
&self,
who: &Option<MultiLocation>,
token_amount: BalanceOf<T>,
pool_value: BalanceOf<T>,
delegator_value: BalanceOf<T>,
_vtoken_amount: BalanceOf<T>,
currency_id: CurrencyId,
) -> Result<(), Error<T>> {
let who = who.as_ref().ok_or(Error::<T>::DelegatorNotExist)?;

Pallet::<T>::tune_vtoken_exchange_rate_without_update_ledger(
who,
token_amount,
currency_id,
)?;
Pallet::<T>::tune_vtoken_exchange_rate_without_update_ledger(who, pool_value, currency_id)?;

// update delegator ledger
DelegatorLedgers::<T>::mutate(currency_id, who, |old_ledger| -> Result<(), Error<T>> {
if let Some(Ledger::Substrate(ref mut old_sub_ledger)) = old_ledger {
// Increase both the active and total amount.
old_sub_ledger.active = old_sub_ledger
.active
.checked_add(&token_amount)
.checked_add(&delegator_value)
.ok_or(Error::<T>::OverFlow)?;

old_sub_ledger.total = old_sub_ledger
.total
.checked_add(&token_amount)
.checked_add(&delegator_value)
.ok_or(Error::<T>::OverFlow)?;
Ok(())
} else {
Expand Down
1 change: 1 addition & 0 deletions pallets/slp/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ mod benchmarks {
origin as <T as frame_system::Config>::RuntimeOrigin,
KSM,
10u32.into(),
10u32.into(),
Some(DELEGATOR1),
);

Expand Down
22 changes: 16 additions & 6 deletions pallets/slp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1254,14 +1254,16 @@ pub mod pallet {
pub fn charge_host_fee_and_tune_vtoken_exchange_rate(
origin: OriginFor<T>,
currency_id: CurrencyId,
#[pallet::compact] value: BalanceOf<T>,
#[pallet::compact] pool_value: BalanceOf<T>,
#[pallet::compact] delegator_value: BalanceOf<T>,
who: Option<MultiLocation>,
) -> DispatchResult {
// Ensure origin
Self::ensure_authorized(origin, currency_id)?;

// Ensure the value is valid.
ensure!(value > Zero::zero(), Error::<T>::AmountZero);
ensure!(pool_value > Zero::zero(), Error::<T>::AmountZero);
ensure!(delegator_value > Zero::zero(), Error::<T>::AmountZero);

// Ensure the value is valid.
let (limit_num, max_permill) = CurrencyTuneExchangeRateLimit::<T>::get(currency_id)
Expand All @@ -1270,7 +1272,14 @@ pub mod pallet {
let pool_token = T::VtokenMinting::get_token_pool(currency_id);
// Calculate max increase allowed.
let max_to_increase = max_permill.mul_floor(pool_token);
ensure!(value <= max_to_increase, Error::<T>::GreaterThanMaximum);
ensure!(
pool_value <= max_to_increase,
Error::<T>::GreaterThanMaximum
);
ensure!(
delegator_value <= max_to_increase,
Error::<T>::GreaterThanMaximum
);

// Ensure this tune is within limit.
// Get current TimeUnit.
Expand Down Expand Up @@ -1299,7 +1308,7 @@ pub mod pallet {
// Get charged fee value
let (fee_permill, beneficiary) =
HostingFees::<T>::get(currency_id).ok_or(Error::<T>::InvalidHostingFee)?;
let fee_to_charge = fee_permill.mul_floor(value);
let fee_to_charge = fee_permill.mul_floor(pool_value);

// Should first charge fee, and then tune exchange rate. Otherwise, the rate will be
// wrong.
Expand All @@ -1315,7 +1324,8 @@ pub mod pallet {
// Tune the new exchange rate.
staking_agent.tune_vtoken_exchange_rate(
&who,
value,
pool_value,
delegator_value,
// Dummy value for vtoken amount
Zero::zero(),
currency_id,
Expand All @@ -1333,7 +1343,7 @@ pub mod pallet {
});
Pallet::<T>::deposit_event(Event::PoolTokenIncreased {
currency_id,
amount: value,
amount: pool_value,
});
Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions pallets/slp/src/tests/filecoin_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ fn charge_host_fee_and_tune_vtoken_exchange_rate_should_work() {
RuntimeOrigin::signed(ALICE),
FIL,
100,
100,
Some(location)
),
Error::<Runtime>::TuneExchangeRateLimitNotSet
Expand Down Expand Up @@ -480,6 +481,7 @@ fn charge_host_fee_and_tune_vtoken_exchange_rate_should_work() {
RuntimeOrigin::signed(ALICE),
FIL,
100,
100,
Some(location)
));

Expand Down
1 change: 1 addition & 0 deletions pallets/slp/src/tests/kusama_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ fn charge_host_fee_and_tune_vtoken_exchange_rate_works() {
RuntimeOrigin::signed(ALICE),
KSM,
100,
100,
Some(subaccount_0_location)
));

Expand Down
1 change: 1 addition & 0 deletions pallets/slp/src/tests/manta_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,7 @@ fn charge_host_fee_and_tune_vtoken_exchange_rate_works() {
RuntimeOrigin::signed(ALICE),
MANTA,
100,
100,
Some(subaccount_0_location)
));

Expand Down
1 change: 1 addition & 0 deletions pallets/slp/src/tests/moonriver_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,7 @@ fn charge_host_fee_and_tune_vtoken_exchange_rate_works() {
RuntimeOrigin::signed(ALICE),
MOVR,
100,
100,
Some(subaccount_0_location)
));

Expand Down
1 change: 1 addition & 0 deletions pallets/slp/src/tests/parachain_staking_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,7 @@ fn charge_host_fee_and_tune_vtoken_exchange_rate_works() {
RuntimeOrigin::signed(ALICE),
BNC,
1000,
1000,
Some(subaccount_0_location)
));

Expand Down
Loading

0 comments on commit c83570b

Please sign in to comment.