Skip to content

Commit

Permalink
fix: wrong calculation and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
mustermeiszer committed Jun 4, 2024
1 parent 178fa27 commit 8596d6c
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 1 deletion.
12 changes: 11 additions & 1 deletion pallets/pool-system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ pub mod pallet {
traits::{tokens::Preservation, Contains, EnsureOriginWithArg},
PalletId,
};
use rev_slice::SliceExt;
use sp_runtime::{traits::BadOrigin, ArithmeticError};

use super::*;
Expand Down Expand Up @@ -1245,7 +1246,11 @@ pub mod pallet {
.map(|tranches| {
tranches
.iter()
.zip(&executed_amounts)
// NOTE: Reversing amounts, as residual amount is on top.
// NOTE: Iterator of executed amounts is one time larger than the
// non_residual_tranche-iterator, but we anyways push all reamaining
// ratio to the residual tranche.
.zip(executed_amounts.rev())
.map(|(tranche, &(invest, redeem))| {
Ok(Perquintill::from_rational(
tranche.supply.ensure_add(invest)?.ensure_sub(redeem)?,
Expand All @@ -1260,8 +1265,13 @@ pub mod pallet {
.iter()
.try_fold(Perquintill::zero(), |acc, ratio| acc.ensure_add(*ratio))?;

// Pushing all remaining ratio to the residual tranche
tranche_ratios.push(Perquintill::one().ensure_sub(non_residual_tranche_ratio_sum)?);

// NOTE: We need to reverse the ratios here, as the residual tranche is on top
// all the time
tranche_ratios.reverse();

pool.tranches.rebalance_tranches(
T::Time::now(),
pool.reserve.total,
Expand Down
2 changes: 2 additions & 0 deletions pallets/pool-system/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ use crate::{
UnhealthyState,
};

mod ratios;

const AUSD_CURRENCY_ID: CurrencyId = CurrencyId::ForeignAsset(1);

pub mod util {
Expand Down
163 changes: 163 additions & 0 deletions pallets/pool-system/src/tests/ratios.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use sp_arithmetic::traits::EnsureSub;

// Copyright 2021 Centrifuge Foundation (centrifuge.io).
//
// This file is part of the Centrifuge chain project.
// Centrifuge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version (see http://www.gnu.org/licenses).
// Centrifuge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
use super::*;

#[test]
fn ensure_ratios_are_distributed_correctly() {
new_test_ext().execute_with(|| {
let pool_owner = DEFAULT_POOL_OWNER;
let pool_owner_origin = RuntimeOrigin::signed(pool_owner);

// Initialize pool with initial investments
let senior_interest_rate = Rate::saturating_from_rational(10, 100)
/ Rate::saturating_from_integer(SECONDS_PER_YEAR)
+ One::one();

assert_ok!(PoolSystem::create(
pool_owner.clone(),
pool_owner.clone(),
0,
vec![
TrancheInput {
tranche_type: TrancheType::Residual,
seniority: None,
metadata: TrancheMetadata {
token_name: BoundedVec::default(),
token_symbol: BoundedVec::default(),
}
},
TrancheInput {
tranche_type: TrancheType::NonResidual {
interest_rate_per_sec: senior_interest_rate,
min_risk_buffer: Perquintill::from_percent(10),
},
seniority: None,
metadata: TrancheMetadata {
token_name: BoundedVec::default(),
token_symbol: BoundedVec::default(),
}
},
],
AUSD_CURRENCY_ID,
10_000 * CURRENCY,
vec![],
));

/// Assert ratios are all zero
crate::Pool::<Runtime>::get(0)
.unwrap()
.tranches
.residual_top_slice()
.iter()
.for_each(|tranche| {
assert_eq!(tranche.ratio, Perquintill::from_percent(0));
});

// Force min_epoch_time to 0 without using update
// as this breaks the runtime-defined pool
// parameter bounds and update will not allow this.
crate::Pool::<Runtime>::try_mutate(0, |maybe_pool| -> Result<(), ()> {
maybe_pool.as_mut().unwrap().parameters.min_epoch_time = 0;
maybe_pool.as_mut().unwrap().parameters.max_nav_age = u64::MAX;
Ok(())
})
.unwrap();

invest_close_and_collect(
0,
vec![
(0, JuniorTrancheId::get(), 500 * CURRENCY),
(0, SeniorTrancheId::get(), 500 * CURRENCY),
],
);

// Ensure ratios are 50/50
crate::Pool::<Runtime>::get(0)
.unwrap()
.tranches
.residual_top_slice()
.iter()
.for_each(|tranche| {
assert_eq!(tranche.ratio, Perquintill::from_percent(50));
});

// Attempt to redeem half
assert_ok!(Investments::update_redeem_order(
RuntimeOrigin::signed(0),
TrancheCurrency::generate(0, SeniorTrancheId::get()),
200 * CURRENCY
));
assert_ok!(PoolSystem::close_epoch(pool_owner_origin.clone(), 0));
assert_ok!(Investments::collect_redemptions(
RuntimeOrigin::signed(0),
TrancheCurrency::generate(0, SeniorTrancheId::get()),
));

let new_residual_ratio = Perquintill::from_rational(5u64, 8u64);
let mut next_ratio = new_residual_ratio;

// Ensure ratios are 500/800 and 300/800
crate::Pool::<Runtime>::get(0)
.unwrap()
.tranches
.residual_top_slice()
.iter()
.for_each(|tranche| {
assert_eq!(tranche.ratio, next_ratio);
next_ratio = Perquintill::one().ensure_sub(next_ratio).unwrap();
});

// Attempt to redeem everything
assert_ok!(Investments::update_redeem_order(
RuntimeOrigin::signed(0),
TrancheCurrency::generate(0, SeniorTrancheId::get()),
300 * CURRENCY
));
assert_ok!(PoolSystem::close_epoch(pool_owner_origin.clone(), 0));
assert_ok!(Investments::collect_redemptions(
RuntimeOrigin::signed(0),
TrancheCurrency::generate(0, SeniorTrancheId::get()),
));

let new_residual_ratio = Perquintill::one();
let mut next_ratio = new_residual_ratio;

// Ensure ratios are 100/0
crate::Pool::<Runtime>::get(0)
.unwrap()
.tranches
.residual_top_slice()
.iter()
.for_each(|tranche| {
assert_eq!(tranche.ratio, next_ratio);
next_ratio = Perquintill::one().ensure_sub(next_ratio).unwrap();
});

/// Ensure ratio goes up again
invest_close_and_collect(0, vec![(0, SeniorTrancheId::get(), 300 * CURRENCY)]);
let new_residual_ratio = Perquintill::from_rational(5u64, 8u64);
let mut next_ratio = new_residual_ratio;

// Ensure ratios are 500/800 and 300/800
crate::Pool::<Runtime>::get(0)
.unwrap()
.tranches
.residual_top_slice()
.iter()
.for_each(|tranche| {
assert_eq!(tranche.ratio, next_ratio);
next_ratio = Perquintill::one().ensure_sub(next_ratio).unwrap();
});
});
}

0 comments on commit 8596d6c

Please sign in to comment.