Skip to content

Commit

Permalink
add RuntimeAPI portfolio update with fake prices
Browse files Browse the repository at this point in the history
  • Loading branch information
lemunozm committed Feb 29, 2024
1 parent e4180ea commit 12a3beb
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 80 deletions.
8 changes: 0 additions & 8 deletions libs/mocks/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,6 @@ pub mod pallet {
}
}

impl<DataId, Data> Default for MockDataCollection<DataId, Data> {
fn default() -> Self {
Self(Box::new(|_| {
Err(DispatchError::Other("MockDataCollection: Data not found"))
}))
}
}

impl<DataId, Data> DataCollection<DataId> for MockDataCollection<DataId, Data> {
type Data = Data;

Expand Down
2 changes: 1 addition & 1 deletion libs/traits/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub trait DataRegistry<DataId, CollectionId> {
}

/// Abstration to represent a collection of data in memory
pub trait DataCollection<DataId>: Default {
pub trait DataCollection<DataId> {
/// Represents a data
type Data;

Expand Down
10 changes: 9 additions & 1 deletion pallets/loans/src/entities/input.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use frame_support::RuntimeDebugNoBound;
use frame_support::{storage::bounded_btree_map::BoundedBTreeMap, RuntimeDebugNoBound};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{ArithmeticError, DispatchError};
Expand Down Expand Up @@ -56,3 +56,11 @@ impl<T: Config> RepaidInput<T> {
})
}
}

#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, RuntimeDebugNoBound, MaxEncodedLen)]
#[scale_info(skip_type_params(T))]
pub enum PriceCollectionInput<T: Config> {
Empty,
Custom(BoundedBTreeMap<T::PriceId, T::Balance, T::MaxActiveLoansPerPool>),
FromRegistry,
}
18 changes: 12 additions & 6 deletions pallets/loans/src/entities/loans.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use cfg_traits::{
self,
data::DataCollection,
interest::{InterestAccrual, InterestRate, RateCollection},
Seconds, TimeAsSecs,
};
Expand All @@ -14,6 +13,7 @@ use sp_runtime::{
},
DispatchError,
};
use sp_std::collections::btree_map::BTreeMap;

use crate::{
entities::{
Expand All @@ -24,7 +24,7 @@ use crate::{
Pricing,
},
},
pallet::{AssetOf, Config, Error, PriceOf},
pallet::{AssetOf, Config, Error},
types::{
policy::{WriteOffStatus, WriteOffTrigger},
BorrowLoanError, BorrowRestrictions, CloseLoanError, CreateLoanError, LoanRestrictions,
Expand Down Expand Up @@ -229,6 +229,13 @@ impl<T: Config> ActiveLoan<T> {
&self.pricing
}

pub fn price_id(&self) -> Option<T::PriceId> {
match &self.pricing {
ActivePricing::Internal(_) => None,
ActivePricing::External(inner) => Some(inner.price_id()),
}
}

pub fn write_off_status(&self) -> WriteOffStatus<T::Rate> {
WriteOffStatus {
percentage: self.write_off_percentage,
Expand Down Expand Up @@ -278,15 +285,14 @@ impl<T: Config> ActiveLoan<T> {
/// An optimized version of `ActiveLoan::present_value()` when some input
/// data can be used from cached collections. Instead of fetch the current
/// debt and prices from the pallets,
/// it get the values from caches previously fetched.
pub fn present_value_by<Rates, Prices>(
/// it the values from caches previously fetched.
pub fn present_value_by<Rates>(
&self,
rates: &Rates,
prices: &Prices,
prices: &BTreeMap<T::PriceId, T::Balance>,
) -> Result<T::Balance, DispatchError>
where
Rates: RateCollection<T::Rate, T::Balance, T::Balance>,
Prices: DataCollection<T::PriceId, Data = PriceOf<T>>,
{
let maturity_date = self.schedule.maturity.date();
let value = match &self.pricing {
Expand Down
25 changes: 12 additions & 13 deletions pallets/loans/src/entities/pricing/external.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use cfg_traits::{
self,
data::{DataCollection, DataRegistry},
interest::InterestRate,
IntoSeconds, Seconds, TimeAsSecs,
self, data::DataRegistry, interest::InterestRate, IntoSeconds, Seconds, TimeAsSecs,
};
use cfg_types::adjustments::Adjustment;
use frame_support::{self, ensure, RuntimeDebug, RuntimeDebugNoBound};
Expand All @@ -12,10 +9,11 @@ use sp_runtime::{
traits::{EnsureAdd, EnsureFixedPointNumber, EnsureSub, Zero},
ArithmeticError, DispatchError, DispatchResult, FixedPointNumber,
};
use sp_std::collections::btree_map::BTreeMap;

use crate::{
entities::interest::ActiveInterestRate,
pallet::{Config, Error, PriceOf},
pallet::{Config, Error},
};

#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, RuntimeDebugNoBound, MaxEncodedLen)]
Expand Down Expand Up @@ -137,6 +135,10 @@ impl<T: Config> ExternalActivePricing<T> {
Ok((self.info, self.interest.deactivate()?))
}

pub fn price_id(&self) -> T::PriceId {
self.info.price_id
}

pub fn has_registered_price(&self, pool_id: T::PoolId) -> bool {
T::PriceRegistry::get(&self.info.price_id, &pool_id).is_ok()
}
Expand Down Expand Up @@ -193,17 +195,14 @@ impl<T: Config> ExternalActivePricing<T> {
self.outstanding_principal(pool_id, maturity)
}

pub fn present_value_cached<Prices>(
pub fn present_value_cached(
&self,
cache: &Prices,
cache: &BTreeMap<T::PriceId, T::Balance>,
maturity: Seconds,
) -> Result<T::Balance, DispatchError>
where
Prices: DataCollection<T::PriceId, Data = PriceOf<T>>,
{
) -> Result<T::Balance, DispatchError> {
let price = match cache.get(&self.info.price_id) {
Ok(data) => data.0,
Err(_) => self.linear_accrual_price(maturity)?,
Some(data) => *data,
None => self.linear_accrual_price(maturity)?,
};
Ok(self.outstanding_quantity.ensure_mul_int(price)?)
}
Expand Down
49 changes: 39 additions & 10 deletions pallets/loans/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,12 @@ pub use weights::WeightInfo;
#[frame_support::pallet]
pub mod pallet {
use cfg_traits::{
self, changes::ChangeGuard, data::DataRegistry, interest::InterestAccrual, IntoSeconds,
Permissions, PoolInspect, PoolNAV, PoolReserve, PoolWriteOffPolicyMutate, Seconds,
TimeAsSecs,
self,
changes::ChangeGuard,
data::{DataCollection, DataRegistry},
interest::InterestAccrual,
IntoSeconds, Permissions, PoolInspect, PoolNAV, PoolReserve, PoolWriteOffPolicyMutate,
Seconds, TimeAsSecs,
};
use cfg_types::{
adjustments::Adjustment,
Expand All @@ -84,7 +87,7 @@ pub mod pallet {
};
use entities::{
changes::{Change, LoanMutation},
input::{PrincipalInput, RepaidInput},
input::{PriceCollectionInput, PrincipalInput, RepaidInput},
loans::{self, ActiveLoan, ActiveLoanInfo, LoanInfo},
};
use frame_support::{
Expand All @@ -103,7 +106,7 @@ pub mod pallet {
traits::{BadOrigin, EnsureAdd, EnsureAddAssign, EnsureInto, One, Zero},
ArithmeticError, FixedPointOperand, TransactionOutcome,
};
use sp_std::{vec, vec::Vec};
use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec};
use types::{
self,
policy::{self, WriteOffRule, WriteOffStatus},
Expand Down Expand Up @@ -150,7 +153,7 @@ pub mod pallet {
+ One;

/// Identify a loan in the pallet
type PriceId: Parameter + Member + TypeInfo + Copy + MaxEncodedLen;
type PriceId: Parameter + Member + TypeInfo + Copy + MaxEncodedLen + Ord;

/// Defines the rate type used for math computations
type Rate: Parameter + Member + FixedPointNumber + TypeInfo + MaxEncodedLen;
Expand Down Expand Up @@ -775,7 +778,10 @@ pub mod pallet {
ensure_signed(origin)?;
Self::ensure_pool_exists(pool_id)?;

let (_, count) = Self::update_portfolio_valuation_for_pool(pool_id)?;
let (_, count) = Self::update_portfolio_valuation_for_pool(
pool_id,
PriceCollectionInput::FromRegistry,
)?;

Ok(Some(T::WeightInfo::update_portfolio_valuation(count)).into())
}
Expand Down Expand Up @@ -1051,11 +1057,33 @@ pub mod pallet {
.map_err(|_| Error::<T>::NoLoanChangeId.into())
}

fn update_portfolio_valuation_for_pool(
fn registered_prices(
pool_id: T::PoolId,
) -> Result<BTreeMap<T::PriceId, T::Balance>, DispatchError> {
let collection = T::PriceRegistry::collection(&pool_id)?;
Ok(ActiveLoans::<T>::get(pool_id)
.iter()
.filter_map(|(_, loan)| loan.price_id())
.filter_map(|price_id| {
collection
.get(&price_id)
.map(|price| (price_id, price.0))
.ok()
})
.collect::<BTreeMap<_, _>>())
}

pub fn update_portfolio_valuation_for_pool(
pool_id: T::PoolId,
input_prices: PriceCollectionInput<T>,
) -> Result<(T::Balance, u32), DispatchError> {
let rates = T::InterestAccrual::rates();
let prices = T::PriceRegistry::collection(&pool_id)?;
let prices = match input_prices {
PriceCollectionInput::Empty => BTreeMap::default(),
PriceCollectionInput::Custom(prices) => prices.into(),
PriceCollectionInput::FromRegistry => Self::registered_prices(pool_id)?,
};

let loans = ActiveLoans::<T>::get(pool_id);
let values = loans
.iter()
Expand Down Expand Up @@ -1208,7 +1236,8 @@ pub mod pallet {
}

fn update_nav(pool_id: T::PoolId) -> Result<T::Balance, DispatchError> {
Ok(Self::update_portfolio_valuation_for_pool(pool_id)?.0)
Self::update_portfolio_valuation_for_pool(pool_id, PriceCollectionInput::FromRegistry)
.map(|portfolio| portfolio.0)
}

fn initialise(_: OriginFor<T>, _: T::PoolId, _: T::ItemId) -> DispatchResult {
Expand Down
18 changes: 16 additions & 2 deletions runtime/altair/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2144,7 +2144,7 @@ impl fp_rpc::ConvertTransaction<sp_runtime::OpaqueExtrinsic> for TransactionConv

#[cfg(not(feature = "disable-runtime-api"))]
mod __runtime_api_use {
pub use pallet_loans::entities::loans::ActiveLoanInfo;
pub use pallet_loans::entities::{input::PriceCollectionInput, loans::ActiveLoanInfo};
}

#[cfg(not(feature = "disable-runtime-api"))]
Expand Down Expand Up @@ -2356,7 +2356,14 @@ impl_runtime_apis! {
}
}

impl runtime_common::apis::LoansApi<Block, PoolId, LoanId, ActiveLoanInfo<Runtime>> for Runtime {
impl runtime_common::apis::LoansApi<
Block,
PoolId,
LoanId,
ActiveLoanInfo<Runtime>,
Balance,
PriceCollectionInput<Runtime>
> for Runtime {
fn portfolio(
pool_id: PoolId
) -> Vec<(LoanId, ActiveLoanInfo<Runtime>)> {
Expand All @@ -2369,6 +2376,13 @@ impl_runtime_apis! {
) -> Option<ActiveLoanInfo<Runtime>> {
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)
}
}


Expand Down
18 changes: 16 additions & 2 deletions runtime/centrifuge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2193,7 +2193,7 @@ impl fp_rpc::ConvertTransaction<sp_runtime::OpaqueExtrinsic> for TransactionConv

#[cfg(not(feature = "disable-runtime-api"))]
mod __runtime_api_use {
pub use pallet_loans::entities::loans::ActiveLoanInfo;
pub use pallet_loans::entities::{input::PriceCollectionInput, loans::ActiveLoanInfo};
}

#[cfg(not(feature = "disable-runtime-api"))]
Expand Down Expand Up @@ -2407,7 +2407,14 @@ impl_runtime_apis! {
}

// LoansApi
impl runtime_common::apis::LoansApi<Block, PoolId, LoanId, ActiveLoanInfo<Runtime>> for Runtime {
impl runtime_common::apis::LoansApi<
Block,
PoolId,
LoanId,
ActiveLoanInfo<Runtime>,
Balance,
PriceCollectionInput<Runtime>
> for Runtime {
fn portfolio(
pool_id: PoolId
) -> Vec<(LoanId, ActiveLoanInfo<Runtime>)> {
Expand All @@ -2420,6 +2427,13 @@ impl_runtime_apis! {
) -> Option<ActiveLoanInfo<Runtime>> {
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)
}
}

// Investment Runtime APIs
Expand Down
6 changes: 5 additions & 1 deletion runtime/common/src/apis/loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,21 @@

use parity_scale_codec::Codec;
use sp_api::decl_runtime_apis;
use sp_runtime::DispatchError;
use sp_std::vec::Vec;

decl_runtime_apis! {
/// Runtime API for the rewards pallet.
pub trait LoansApi<PoolId, LoanId, Loan>
pub trait LoansApi<PoolId, LoanId, Loan, Balance, PriceCollectionInput>
where
PoolId: Codec,
LoanId: Codec,
Loan: Codec,
Balance: Codec,
PriceCollectionInput: Codec
{
fn portfolio(pool_id: PoolId) -> Vec<(LoanId, Loan)>;
fn portfolio_loan(pool_id: PoolId, loan_id: LoanId) -> Option<Loan>;
fn portfolio_valuation(pool_id: PoolId, input_prices: PriceCollectionInput) -> Result<Balance, DispatchError>;
}
}
18 changes: 16 additions & 2 deletions runtime/development/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2233,7 +2233,7 @@ impl fp_rpc::ConvertTransaction<sp_runtime::OpaqueExtrinsic> for TransactionConv

#[cfg(not(feature = "disable-runtime-api"))]
mod __runtime_api_use {
pub use pallet_loans::entities::loans::ActiveLoanInfo;
pub use pallet_loans::entities::{input::PriceCollectionInput, loans::ActiveLoanInfo};
}

#[cfg(not(feature = "disable-runtime-api"))]
Expand Down Expand Up @@ -2449,7 +2449,14 @@ impl_runtime_apis! {
}

// LoansApi
impl runtime_common::apis::LoansApi<Block, PoolId, LoanId, ActiveLoanInfo<Runtime>> for Runtime {
impl runtime_common::apis::LoansApi<
Block,
PoolId,
LoanId,
ActiveLoanInfo<Runtime>,
Balance,
PriceCollectionInput<Runtime>
> for Runtime {
fn portfolio(
pool_id: PoolId
) -> Vec<(LoanId, ActiveLoanInfo<Runtime>)> {
Expand All @@ -2462,6 +2469,13 @@ impl_runtime_apis! {
) -> Option<ActiveLoanInfo<Runtime>> {
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)
}
}

// Investment Runtime APIs
Expand Down
Loading

0 comments on commit 12a3beb

Please sign in to comment.