Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Enable Runtime-Apis to update nav with estimates #1791

Merged
merged 10 commits into from
Apr 3, 2024
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
Loading