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
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.into())?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already notified in the consumer side of released(): https://github.com/centrifuge/centrifuge-chain/blob/main/pallets/oracle-collection/src/lib.rs#L244

Not sure if we want another event here.

Copy link
Contributor

@wischli wischli Apr 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICS, we are not emitting such an event for pool fees or for loans. IMO, it makes sense to add this here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the Events are quite confusing without showing that this came from a change that was released:

And if we are noting a change we are also emitting an event. I would keep it.


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::RuntimeCange,
},
/// The PoolFeesNAV exceeds the sum of the AUM and the total reserve of
/// the pool
NegativeBalanceSheet {
Expand Down
34 changes: 10 additions & 24 deletions runtime/altair/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1820,7 +1820,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 +2277,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 +2294,15 @@ 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()
Self::tranche_token_prices()?.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(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(pool_id).ok()
}
}

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

// LoansApi
impl runtime_common::apis::LoansApi<
Block,
PoolId,
Expand All @@ -2371,21 +2356,23 @@ impl_runtime_apis! {
fn portfolio(
pool_id: PoolId
) -> Vec<(LoanId, ActiveLoanInfo<Runtime>)> {
runtime_common::update_nav(pool_id).ok();
mustermeiszer marked this conversation as resolved.
Show resolved Hide resolved
Loans::get_active_loans_info(pool_id).unwrap_or_default()
}

fn portfolio_loan(
pool_id: PoolId,
loan_id: LoanId
) -> Option<ActiveLoanInfo<Runtime>> {
runtime_common::update_nav(pool_id).ok();
mustermeiszer marked this conversation as resolved.
Show resolved Hide resolved
Loans::get_active_loan_info(pool_id, loan_id).ok().flatten()
}

fn portfolio_valuation(
pool_id: PoolId,
input_prices: PriceCollectionInput<Runtime>
) -> Result<Balance, DispatchError> {
Ok(Loans::update_portfolio_valuation_for_pool(pool_id, input_prices)?.0)
runtime_common::update_nav_with_input(pool_id, input_prices)?.nav_aum
}
}

Expand All @@ -2412,8 +2399,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(pool_id).ok()?;
lemunozm marked this conversation as resolved.
Show resolved Hide resolved
Some(PoolFees::get_pool_fees(pool_id))
}
}
Expand Down
35 changes: 10 additions & 25 deletions runtime/centrifuge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1936,7 +1936,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 +2326,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 +2343,15 @@ 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()
Self::tranche_token_prices()?.get(index).cloned()
mustermeiszer marked this conversation as resolved.
Show resolved Hide resolved
}

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(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(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 @@ -2422,21 +2406,23 @@ impl_runtime_apis! {
fn portfolio(
pool_id: PoolId
) -> Vec<(LoanId, ActiveLoanInfo<Runtime>)> {
runtime_common::update_nav(pool_id).ok();
mustermeiszer marked this conversation as resolved.
Show resolved Hide resolved
Loans::get_active_loans_info(pool_id).unwrap_or_default()
}

fn portfolio_loan(
pool_id: PoolId,
loan_id: LoanId
) -> Option<ActiveLoanInfo<Runtime>> {
runtime_common::update_nav(pool_id).ok();
mustermeiszer marked this conversation as resolved.
Show resolved Hide resolved
Loans::get_active_loan_info(pool_id, loan_id).ok().flatten()
}

fn portfolio_valuation(
pool_id: PoolId,
input_prices: PriceCollectionInput<Runtime>
) -> Result<Balance, DispatchError> {
Ok(Loans::update_portfolio_valuation_for_pool(pool_id, input_prices)?.0)
runtime_common::update_nav_with_input(pool_id, input_prices)?.nav_aum
}
}

Expand Down Expand Up @@ -2464,8 +2450,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(pool_id).ok()?;
lemunozm marked this conversation as resolved.
Show resolved Hide resolved
Some(PoolFees::get_pool_fees(pool_id))
}
}
Expand Down
60 changes: 57 additions & 3 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ pub mod remarks;
pub mod transfer_filter;
pub mod xcm;

use cfg_primitives::Balance;
use cfg_types::{fee_keys::FeeKey, tokens::CurrencyId};
use cfg_primitives::{Balance, PoolId};
use cfg_traits::{data::DataRegistry, PoolNAV};
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, BoundedBTreeMap, DispatchError};
use sp_std::marker::PhantomData;

parameter_types! {
Expand Down Expand Up @@ -83,6 +86,57 @@ where
}
}

pub fn update_nav<T>(pool_id: T::PoolId) -> Result<PoolNav<T::Balance>, DispatchError>
where
T: pallet_loans::Config + pallet_pool_system::Config + pallet_pool_fees::Config,
{
let input_prices =
if let Ok(prices) = <T as pallet_loans::Config>::PriceRegistry::collection(pool_id) {
PriceCollectionInput::Custom(prices)
} 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::PoolId,
price_input: PriceCollectionInput<T>,
) -> Result<PoolNav<T::Balance>, DispatchError>
where
T: pallet_loans::Config + pallet_pool_system::Config + pallet_pool_fees::Config,
{
let mut pool = pallet_pool_system::Pool::<T>::get(pool_id)?;
let nav_loans =
pallet_loans::Pallet::<T>::update_portfolio_valuation_for_pool(pool_id, price_input)
.map(|(nav, _)| nav)?;
let nav_fees = pallet_pool_fees::Pallet::update_portfolio_valuation_for_pool(
pool_id,
&mut pool.reserve.total,
)
.ok()?;
let nav = Nav::new(nav_loans, nav_fees);
let total = nav.total(pool.reserve.total).unwrap_or(Balance::default());

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