Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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