Skip to content

Commit

Permalink
fix: Enable Runtime-Apis to update nav with estimates (#1791)
Browse files Browse the repository at this point in the history
* wip: Make runtime apis work

* Revert "wip: Make runtime apis work"

This reverts commit 8f09fc0.

* feat: update nav always working for runtime api

* fix: update nav on apis differently

* feat: creep, deposit event when change is released

* fix: update nav correctlu for all apis

* fix: rm usage of OrmlTokens

* fix: build
  • Loading branch information
mustermeiszer authored Apr 3, 2024
1 parent dc0952e commit b73e1dd
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 85 deletions.
2 changes: 1 addition & 1 deletion pallets/loans/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,7 @@ pub mod pallet {
.map_err(|_| Error::<T>::NoLoanChangeId.into())
}

fn registered_prices(
pub fn registered_prices(
pool_id: T::PoolId,
) -> Result<BTreeMap<T::PriceId, T::Balance>, DispatchError> {
let collection = T::PriceRegistry::collection(&pool_id)?;
Expand Down
12 changes: 10 additions & 2 deletions pallets/pool-system/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,12 +454,20 @@ impl<T: Config> ChangeGuard for Pallet<T> {
}
}

allowed
let change = allowed
.then(|| {
NotedChange::<T>::remove(pool_id, change_id);
change
})
.ok_or(Error::<T>::ChangeNotReady.into())
.ok_or(Error::<T>::ChangeNotReady)?;

Self::deposit_event(Event::ReleasedChange {
pool_id,
change_id,
change: change.clone(),
});

Ok(change)
}
}

Expand Down
6 changes: 6 additions & 0 deletions pallets/pool-system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,12 @@ pub mod pallet {
change_id: T::Hash,
change: T::RuntimeChange,
},
/// A change was released
ReleasedChange {
pool_id: T::PoolId,
change_id: T::Hash,
change: T::RuntimeChange,
},
/// The PoolFeesNAV exceeds the sum of the AUM and the total reserve of
/// the pool
NegativeBalanceSheet {
Expand Down
36 changes: 10 additions & 26 deletions runtime/altair/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ use cfg_primitives::{
};
use cfg_traits::{
investments::{OrderManager, TrancheCurrency as _},
Millis, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, Seconds,
TryConvert,
Millis, Permissions as PermissionsT, PoolUpdateGuard, PreConditions, Seconds, TryConvert,
};
use cfg_types::{
consts::pools::{MaxTrancheNameLengthBytes, MaxTrancheSymbolLengthBytes},
Expand Down Expand Up @@ -1820,7 +1819,7 @@ impl pallet_token_mux::Config for Runtime {
type OrderId = OrderId;
type PalletId = TokenMuxPalletId;
type RuntimeEvent = RuntimeEvent;
type Tokens = OrmlTokens;
type Tokens = Tokens;
type WeightInfo = weights::pallet_token_mux::WeightInfo<Runtime>;
}

Expand Down Expand Up @@ -2277,6 +2276,7 @@ impl_runtime_apis! {
}
}

// PoolsAPI
impl runtime_common::apis::PoolsApi<Block, PoolId, TrancheId, Balance, CurrencyId, Quantity, MaxTranches> for Runtime {
fn currency(pool_id: PoolId) -> Option<CurrencyId>{
pallet_pool_system::Pool::<Runtime>::get(pool_id).map(|details| details.currency)
Expand All @@ -2293,26 +2293,16 @@ impl_runtime_apis! {
}

fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc<TrancheId>) -> Option<Quantity>{
let now = <Timestamp as UnixTime>::now().as_secs();
let mut pool = PoolSystem::pool(pool_id)?;
let nav = Loans::update_nav(pool_id).ok()?;
let total_assets = pool.reserve.total.saturating_add(nav);
let index: usize = pool.tranches.tranche_index(&tranche)?.try_into().ok()?;
let prices = pool
.tranches
.calculate_prices::<_, OrmlTokens, _>(total_assets, now)
.ok()?;
prices.get(index).cloned()
let index: usize = PoolSystem::pool(pool_id)?.tranches.tranche_index(&tranche)?.try_into().ok()?;
Self::tranche_token_prices(pool_id)?.get(index).cloned()
}

fn tranche_token_prices(pool_id: PoolId) -> Option<Vec<Quantity>>{
let now = <Timestamp as UnixTime>::now().as_secs();
let mut pool = PoolSystem::pool(pool_id)?;
let nav = Loans::update_nav(pool_id).ok()?;
let total_assets = pool.reserve.total.saturating_add(nav);
pool
.tranches
.calculate_prices::<_, OrmlTokens, AccountId>(total_assets, now)
.calculate_prices::<_, Tokens, AccountId>(runtime_common::update_nav::<Runtime>(pool_id).ok()?.total, now)
.ok()
}

Expand All @@ -2333,13 +2323,7 @@ impl_runtime_apis! {
}

fn nav(pool_id: PoolId) -> Option<PoolNav<Balance>> {
let pool = pallet_pool_system::Pool::<Runtime>::get(pool_id)?;
let nav_loans = Loans::update_nav(pool_id).ok()?;
let nav_fees = PoolFees::update_nav(pool_id).ok()?;
let nav = pallet_pool_system::Nav::new(nav_loans, nav_fees);
let total = nav.total(pool.reserve.total).unwrap_or(Balance::default());

Some(PoolNav { nav_aum: nav.nav_aum, nav_fees: nav.nav_fees, reserve: pool.reserve.total, total })
runtime_common::update_nav::<Runtime>(pool_id).ok()
}
}

Expand All @@ -2360,6 +2344,7 @@ impl_runtime_apis! {
}
}

// LoansApi
impl runtime_common::apis::LoansApi<
Block,
PoolId,
Expand All @@ -2385,7 +2370,7 @@ impl_runtime_apis! {
pool_id: PoolId,
input_prices: PriceCollectionInput<Runtime>
) -> Result<Balance, DispatchError> {
Ok(Loans::update_portfolio_valuation_for_pool(pool_id, input_prices)?.0)
Ok(runtime_common::update_nav_with_input(pool_id, input_prices)?.nav_aum)
}
}

Expand All @@ -2412,8 +2397,7 @@ impl_runtime_apis! {
// PoolFeesApi
impl runtime_common::apis::PoolFeesApi<Block, PoolId, PoolFeeId, AccountId, Balance, Rate> for Runtime {
fn list_fees(pool_id: PoolId) -> Option<cfg_types::pools::PoolFeesList<PoolFeeId, AccountId, Balance, Rate>> {
let pool = pallet_pool_system::Pool::<Runtime>::get(pool_id)?;
PoolFees::update_portfolio_valuation_for_pool(pool_id, &mut pool.reserve.total.clone()).ok()?;
runtime_common::update_nav::<Runtime>(pool_id).ok()?;
Some(PoolFees::get_pool_fees(pool_id))
}
}
Expand Down
37 changes: 10 additions & 27 deletions runtime/centrifuge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ use cfg_primitives::{
};
use cfg_traits::{
investments::{OrderManager, TrancheCurrency as _},
Millis, Permissions as PermissionsT, PoolNAV, PoolUpdateGuard, PreConditions, Seconds,
TryConvert,
Millis, Permissions as PermissionsT, PoolUpdateGuard, PreConditions, Seconds, TryConvert,
};
use cfg_types::{
consts::pools::{MaxTrancheNameLengthBytes, MaxTrancheSymbolLengthBytes},
Expand Down Expand Up @@ -1936,7 +1935,7 @@ impl pallet_token_mux::Config for Runtime {
type OrderId = OrderId;
type PalletId = TokenMuxPalletId;
type RuntimeEvent = RuntimeEvent;
type Tokens = OrmlTokens;
type Tokens = Tokens;
type WeightInfo = weights::pallet_token_mux::WeightInfo<Runtime>;
}

Expand Down Expand Up @@ -2326,7 +2325,7 @@ impl_runtime_apis! {
}
}

// PoolsApi
// PoolsAPI
impl runtime_common::apis::PoolsApi<Block, PoolId, TrancheId, Balance, CurrencyId, Quantity, MaxTranches> for Runtime {
fn currency(pool_id: PoolId) -> Option<CurrencyId>{
pallet_pool_system::Pool::<Runtime>::get(pool_id).map(|details| details.currency)
Expand All @@ -2343,26 +2342,16 @@ impl_runtime_apis! {
}

fn tranche_token_price(pool_id: PoolId, tranche: TrancheLoc<TrancheId>) -> Option<Quantity>{
let now = <Timestamp as UnixTime>::now().as_secs();
let mut pool = PoolSystem::pool(pool_id)?;
let nav = Loans::update_nav(pool_id).ok()?;
let total_assets = pool.reserve.total.saturating_add(nav);
let index: usize = pool.tranches.tranche_index(&tranche)?.try_into().ok()?;
let prices = pool
.tranches
.calculate_prices::<_, Tokens, _>(total_assets, now)
.ok()?;
prices.get(index).cloned()
let index: usize = PoolSystem::pool(pool_id)?.tranches.tranche_index(&tranche)?.try_into().ok()?;
Self::tranche_token_prices(pool_id)?.get(index).cloned()
}

fn tranche_token_prices(pool_id: PoolId) -> Option<Vec<Quantity>>{
let now = <Timestamp as UnixTime>::now().as_secs();
let mut pool = PoolSystem::pool(pool_id)?;
let nav = Loans::update_nav(pool_id).ok()?;
let total_assets = pool.reserve.total.saturating_add(nav);
pool
.tranches
.calculate_prices::<_, Tokens, AccountId>(total_assets, now)
.calculate_prices::<_, Tokens, AccountId>(runtime_common::update_nav::<Runtime>(pool_id).ok()?.total, now)
.ok()
}

Expand All @@ -2383,16 +2372,11 @@ impl_runtime_apis! {
}

fn nav(pool_id: PoolId) -> Option<PoolNav<Balance>> {
let pool = pallet_pool_system::Pool::<Runtime>::get(pool_id)?;
let nav_loans = Loans::update_nav(pool_id).ok()?;
let nav_fees = PoolFees::update_nav(pool_id).ok()?;
let nav = pallet_pool_system::Nav::new(nav_loans, nav_fees);
let total = nav.total(pool.reserve.total).unwrap_or(Balance::default());

Some(PoolNav { nav_aum: nav.nav_aum, nav_fees: nav.nav_fees, reserve: pool.reserve.total, total })
runtime_common::update_nav::<Runtime>(pool_id).ok()
}
}


// RewardsApi
impl runtime_common::apis::RewardsApi<Block, AccountId, Balance, CurrencyId> for Runtime {
fn list_currencies(domain: runtime_common::apis::RewardDomain, account_id: AccountId) -> Vec<CurrencyId> {
Expand Down Expand Up @@ -2436,7 +2420,7 @@ impl_runtime_apis! {
pool_id: PoolId,
input_prices: PriceCollectionInput<Runtime>
) -> Result<Balance, DispatchError> {
Ok(Loans::update_portfolio_valuation_for_pool(pool_id, input_prices)?.0)
Ok(runtime_common::update_nav_with_input(pool_id, input_prices)?.nav_aum)
}
}

Expand Down Expand Up @@ -2464,8 +2448,7 @@ impl_runtime_apis! {
// PoolFeesApi
impl runtime_common::apis::PoolFeesApi<Block, PoolId, PoolFeeId, AccountId, Balance, Rate> for Runtime {
fn list_fees(pool_id: PoolId) -> Option<cfg_types::pools::PoolFeesList<PoolFeeId, AccountId, Balance, Rate>> {
let pool = pallet_pool_system::Pool::<Runtime>::get(pool_id)?;
PoolFees::update_portfolio_valuation_for_pool(pool_id, &mut pool.reserve.total.clone()).ok()?;
runtime_common::update_nav::<Runtime>(pool_id).ok()?;
Some(PoolFees::get_pool_fees(pool_id))
}
}
Expand Down
79 changes: 77 additions & 2 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@ pub mod transfer_filter;
pub mod xcm;

use cfg_primitives::Balance;
use cfg_types::{fee_keys::FeeKey, tokens::CurrencyId};
use cfg_types::{fee_keys::FeeKey, pools::PoolNav, tokens::CurrencyId};
use orml_traits::GetByKey;
use pallet_loans::entities::input::PriceCollectionInput;
use pallet_pool_system::Nav;
use sp_core::parameter_types;
use sp_runtime::traits::Get;
use sp_runtime::{
traits::{Get, Zero},
DispatchError,
};
use sp_std::marker::PhantomData;

parameter_types! {
Expand Down Expand Up @@ -83,6 +88,76 @@ where
}
}

pub fn update_nav<T>(
pool_id: <T as pallet_pool_system::Config>::PoolId,
) -> Result<PoolNav<<T as pallet_pool_system::Config>::Balance>, DispatchError>
where
T: pallet_loans::Config<
PoolId = <T as pallet_pool_system::Config>::PoolId,
Balance = <T as pallet_pool_system::Config>::Balance,
> + pallet_pool_system::Config
+ pallet_pool_fees::Config<
PoolId = <T as pallet_pool_system::Config>::PoolId,
Balance = <T as pallet_pool_system::Config>::Balance,
>,
{
let input_prices: PriceCollectionInput<T> =
if let Ok(prices) = pallet_loans::Pallet::<T>::registered_prices(pool_id) {
PriceCollectionInput::Custom(prices.try_into().map_err(|_| {
DispatchError::Other("Map expected to fit as it is coming from loans itself.")
})?)
} else {
PriceCollectionInput::Empty
};

update_nav_with_input::<T>(pool_id, input_prices)
}

/// ## Updates the nav for a pool.
///
/// NOTE: Should NEVER be used in consensus relevant state changes!
///
/// ### Execution infos
/// * For external assets it is either using the latest
/// oracle prices if they are not outdated or it is using no prices and allows
/// the chain to use the estimates based on the linear accrual of the last
/// settlement prices.
/// * IF `nav_fees > nav_loans` then the `nav_total` will saturate at 0
pub fn update_nav_with_input<T>(
pool_id: <T as pallet_pool_system::Config>::PoolId,
price_input: PriceCollectionInput<T>,
) -> Result<PoolNav<<T as pallet_pool_system::Config>::Balance>, DispatchError>
where
T: pallet_loans::Config<
PoolId = <T as pallet_pool_system::Config>::PoolId,
Balance = <T as pallet_pool_system::Config>::Balance,
> + pallet_pool_system::Config
+ pallet_pool_fees::Config<
PoolId = <T as pallet_pool_system::Config>::PoolId,
Balance = <T as pallet_pool_system::Config>::Balance,
>,
{
let mut pool = pallet_pool_system::Pool::<T>::get(pool_id)
.ok_or(pallet_pool_system::Error::<T>::NoSuchPool)?;
let (nav_loans, _) =
pallet_loans::Pallet::<T>::update_portfolio_valuation_for_pool(pool_id, price_input)?;
let (nav_fees, _) = pallet_pool_fees::Pallet::<T>::update_portfolio_valuation_for_pool(
pool_id,
&mut pool.reserve.total,
)?;
let nav = Nav::new(nav_loans, nav_fees);
let total = nav
.total(pool.reserve.total)
.unwrap_or(<T as pallet_pool_system::Config>::Balance::zero());

Ok(PoolNav {
nav_aum: nav.nav_aum,
nav_fees: nav.nav_fees,
reserve: pool.reserve.total,
total,
})
}

pub mod xcm_fees {
use cfg_primitives::{constants::currency_decimals, types::Balance};
use frame_support::weights::constants::{ExtrinsicBaseWeight, WEIGHT_REF_TIME_PER_SECOND};
Expand Down
Loading

0 comments on commit b73e1dd

Please sign in to comment.