Skip to content

Commit

Permalink
Merge pull request #887 from interlay/fix/fees
Browse files Browse the repository at this point in the history
test: fee pool testing
  • Loading branch information
gregdhill authored Feb 2, 2023
2 parents 5aa0943 + 81e6a17 commit 6b32be2
Show file tree
Hide file tree
Showing 5 changed files with 585 additions and 181 deletions.
3 changes: 3 additions & 0 deletions standalone/runtime/tests/mock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ pub fn iter_all_currencies() -> impl Iterator<Item = CurrencyId> {
impl UserData {
pub fn get(id: [u8; 32]) -> Self {
let account_id = account_of(id);
Self::from_account(account_id)
}
pub fn from_account(account_id: AccountId) -> Self {
let mut hash_map = BTreeMap::new();

for currency_id in iter_all_currencies() {
Expand Down
21 changes: 20 additions & 1 deletion standalone/runtime/tests/mock/redeem_testing_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ pub const VAULT: [u8; 32] = BOB;
pub const VAULT2: [u8; 32] = CAROL;
pub const USER_BTC_ADDRESS: BtcAddress = BtcAddress::P2PKH(H160([2u8; 20]));

pub trait RedeemRequestTestExt {
fn amount_without_fee_as_collateral(&self, currency_id: CurrencyId) -> Amount<Runtime>;
}
impl RedeemRequestTestExt for RedeemRequest<AccountId, BlockNumber, Balance, CurrencyId> {
fn amount_without_fee_as_collateral(&self, currency_id: CurrencyId) -> Amount<Runtime> {
let amount_without_fee = self.amount_btc() + self.transfer_fee_btc();
amount_without_fee.convert_to(currency_id).unwrap()
}
}

pub struct ExecuteRedeemBuilder {
redeem_id: H256,
redeem: RedeemRequest<AccountId32, BlockNumber, Balance, CurrencyId>,
Expand Down Expand Up @@ -80,11 +90,20 @@ pub fn setup_cancelable_redeem(user: [u8; 32], vault: &VaultId, issued_tokens: A

// expire request without transferring btc
mine_blocks((RedeemPallet::redeem_period() + 99) / 100 + 1);
SecurityPallet::set_active_block_number(RedeemPallet::redeem_period() + 1 + 1);
SecurityPallet::set_active_block_number(
SecurityPallet::active_block_number() + RedeemPallet::redeem_period() + 1 + 1,
);

redeem_id
}

pub fn expire_bans() {
mine_blocks((RedeemPallet::redeem_period() + 99) / 100 + 1);
SecurityPallet::set_active_block_number(
SecurityPallet::active_block_number() + VaultRegistryPallet::punishment_delay() + 1 + 1,
);
}

pub fn set_redeem_state(
vault_to_be_redeemed: Amount<Runtime>,
user_to_redeem: Amount<Runtime>,
Expand Down
125 changes: 99 additions & 26 deletions standalone/runtime/tests/mock/reward_testing_utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::*;
use primitives::TruncateFixedPointToInt;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};

pub type StakeId = (VaultId, AccountId);

Expand All @@ -10,7 +10,7 @@ pub struct IdealRewardPool {
secure_threshold: BTreeMap<VaultId, FixedU128>,
accept_new_issues: BTreeMap<VaultId, bool>,
commission: BTreeMap<VaultId, FixedU128>,
collateral: BTreeMap<StakeId, u128>,
collateral: BTreeMap<StakeId, FixedU128>,
rewards: BTreeMap<AccountId, (FixedU128, FixedU128)>,
}

Expand All @@ -36,27 +36,33 @@ impl IdealRewardPool {
pub fn deposit_nominator_collateral(&mut self, account: &StakeId, amount: u128) -> &mut Self {
log::debug!("deposit_nominator_collateral {amount}");
let current_collateral = self.collateral.get(account).map(|x| *x).unwrap_or_default();
self.collateral.insert(account.clone(), current_collateral + amount);
self.collateral
.insert(account.clone(), current_collateral + FixedU128::from(amount));
self
}

pub fn withdraw_nominator_collateral(&mut self, account: &StakeId, amount: u128) -> &mut Self {
log::debug!("withdraw_nominator_collateral {amount}");
let current_collateral = self.collateral.get(account).map(|x| *x).unwrap_or_default();
self.collateral.insert(account.clone(), current_collateral - amount);
self.collateral
.insert(account.clone(), current_collateral - FixedU128::from(amount));
self
}

pub fn slash_collateral(&mut self, account: &VaultId, amount: u128) -> &mut Self {
log::error!("slash_collateral {amount}");
let amount = FixedU128::from(amount);
let nominators: Vec<_> = {
self.collateral
.iter()
.filter(|((vault, _nominator), _stake)| vault == account)
.map(|(key, value)| (key.clone(), value.clone()))
.collect()
};
let total_stake: u128 = nominators.iter().map(|(_key, value)| *value).sum();
let total_stake: FixedU128 = nominators
.iter()
.map(|(_key, value)| *value)
.fold(Zero::zero(), |x: FixedU128, y: FixedU128| x + y);
for (key, stake) in nominators {
let new_stake = stake - (stake * amount) / total_stake;
self.collateral.insert(key, new_stake);
Expand All @@ -77,26 +83,91 @@ impl IdealRewardPool {
return self;
}

for (stake_id, _) in self.collateral.iter() {
let stake = self.stake(stake_id);
let reward = (stake * reward) / total_stake;

let (vault_id, nominator_id) = stake_id;

let commission = self.commission.get(vault_id).cloned().unwrap_or_default();

let (vault_commission, vault_reward) = self.rewards.get(&vault_id.account_id).cloned().unwrap_or_default();
self.rewards.insert(
vault_id.account_id.clone(),
(vault_commission + reward * commission, vault_reward),
);

let (nominator_commission, nominator_reward) = self.rewards.get(&nominator_id).cloned().unwrap_or_default();
self.rewards.insert(
nominator_id.clone(),
(nominator_commission, nominator_reward + (reward - reward * commission)),
);
let vault_stakes: HashMap<_, _> = self
.collateral
.iter()
.map(|((vault, _nominator), collateral)| (vault, collateral))
.filter(|(vault, _)| *self.accept_new_issues.get(vault).unwrap_or(&true))
.into_group_map()
.into_iter()
.map(|(vault, nominator_collaterals)| {
let vault_collateral = nominator_collaterals
.into_iter()
.cloned()
.fold(Zero::zero(), |x: FixedU128, y: FixedU128| x + y);
let threshold = self.secure_threshold[vault];
let reward_stake = (vault_collateral / threshold).truncate_to_inner().unwrap();
(vault, reward_stake)
})
.collect();

let capacity_stakes: Vec<_> = vault_stakes
.iter()
.map(|(vault, stake)| (vault.collateral_currency(), stake))
.into_group_map()
.into_iter()
.map(|(currency, vault_stakes)| {
let currency_capacity: u128 = vault_stakes.into_iter().sum();
let exchange_rate = self.exchange_rate[&currency];
let capacity_stake = (FixedU128::from(currency_capacity) / exchange_rate)
.truncate_to_inner()
.unwrap();
(currency, capacity_stake)
})
.collect();

log::error!("Capacity_stakes: {capacity_stakes:?}");

let total_capacity: u128 = capacity_stakes.iter().map(|(_, capacity)| capacity).sum();
for (currency, capacity_stake) in capacity_stakes {
let currency_reward = (reward * FixedU128::from(capacity_stake)) / FixedU128::from(total_capacity);
let currency_reward = currency_reward.trunc();
// reward for this currency = reward * (capacity_stake / total_capacity)
let vaults: Vec<_> = vault_stakes
.iter()
.filter(|(vault, _)| vault.collateral_currency() == currency)
.collect();
let total_vault_stake: u128 = vaults.iter().map(|(_, stake)| **stake).sum();
for vault_stake in vaults.iter() {
let nominators: Vec<_> = self
.nominations()
.iter()
.cloned()
.filter(|((vault, _nominator), _stake)| &vault == vault_stake.0)
.map(|((_vault, nominator), stake)| (nominator, stake))
.collect();
let total_nomination = nominators
.iter()
.map(|(_, nomination)| *nomination)
.fold(Zero::zero(), |x: FixedU128, y: FixedU128| x + y);
let vault_reward =
(currency_reward * FixedU128::from(*vault_stake.1)) / FixedU128::from(total_vault_stake);
let vault_reward = vault_reward.trunc();
log::error!("vault_reward: {}", vault_reward.truncate_to_inner().unwrap());

let commission = self.commission.get(vault_stake.0).cloned().unwrap_or_default();

let vault = vault_stake.0.clone();
let (vault_commission, old_vault_reward) =
self.rewards.get(&vault.account_id).cloned().unwrap_or_default();
self.rewards.insert(
vault.account_id.clone(),
(vault_commission + vault_reward * commission, old_vault_reward),
);

for (nominator_id, nomination) in nominators {
let nominator_reward = (vault_reward - vault_reward * commission) * nomination / total_nomination;

let (nominator_commission, old_nominator_reward) =
self.rewards.get(&nominator_id).cloned().unwrap_or_default();
self.rewards.insert(
nominator_id.clone(),
(nominator_commission, old_nominator_reward + nominator_reward),
);
}
}
}

self
}

Expand All @@ -120,10 +191,12 @@ impl IdealRewardPool {
.iter()
.filter(|((vault, nominator), _stake)| nominator == account && vault.collateral_currency() == currency_id)
.map(|(_key, value)| *value)
.sum()
.fold(Zero::zero(), |x: FixedU128, y: FixedU128| x + y)
.truncate_to_inner()
.unwrap()
}

pub fn nominations(&self) -> Vec<(StakeId, u128)> {
pub fn nominations(&self) -> Vec<(StakeId, FixedU128)> {
self.collateral
.iter()
.map(|(key, value)| (key.clone(), value.clone()))
Expand Down
Loading

0 comments on commit 6b32be2

Please sign in to comment.