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

feat: add InvestmentPortfolio Runtime API #1608

Merged
merged 6 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 15 additions & 5 deletions libs/types/src/investments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,16 @@ pub struct ExecutedForeignCollect<Balance, Currency> {
/// claimable pool currency as well as tranche tokens.
#[derive(Encode, Decode, Default, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]

pub struct InvestmentPortfolio<Balance> {
pub struct InvestmentPortfolio<Balance, CurrencyId> {
/// The identifier of the pool currency
pub pool_currency_id: CurrencyId,
/// The unprocessed invest order amount in pool currency
pub pending_invest_currency: Balance,
/// The amount of tranche tokens which can be collected for an invest order
pub claimable_tranche_tokens: Balance,
/// The amount of tranche tokens which can be transferred
pub free_tranche_tokens: Balance,
/// The amount of tranche tokens which can not be used at all and get
/// The amount of tranche tokens which can not be used at all and could get
/// slashed
pub reserved_tranche_tokens: Balance,
/// The unprocessed redeem order amount in tranche tokens
Expand All @@ -260,9 +262,17 @@ pub struct InvestmentPortfolio<Balance> {
pub claimable_currency: Balance,
}

impl<Balance: Default> InvestmentPortfolio<Balance> {
pub fn new() -> Self {
Default::default()
impl<Balance: Default, CurrencyId> InvestmentPortfolio<Balance, CurrencyId> {
pub fn new(pool_currency_id: CurrencyId) -> Self {
Self {
pool_currency_id,
pending_invest_currency: Balance::default(),
claimable_tranche_tokens: Balance::default(),
free_tranche_tokens: Balance::default(),
reserved_tranche_tokens: Balance::default(),
pending_redeem_tranche_tokens: Balance::default(),
claimable_currency: Balance::default(),
}
}

pub fn with_pending_invest_currency(mut self, amount: Balance) -> Self {
Expand Down
4 changes: 2 additions & 2 deletions runtime/altair/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2165,8 +2165,8 @@ impl_runtime_apis! {


// Investment Runtime APIs
impl runtime_common::apis::InvestmentsApi<Block, AccountId, TrancheCurrency, InvestmentPortfolio<Balance>> for Runtime {
fn investment_portfolio(account_id: AccountId) -> Vec<(TrancheCurrency, InvestmentPortfolio<Balance>)> {
impl runtime_common::apis::InvestmentsApi<Block, AccountId, TrancheCurrency, InvestmentPortfolio<Balance, CurrencyId>> for Runtime {
fn investment_portfolio(account_id: AccountId) -> Vec<(TrancheCurrency, InvestmentPortfolio<Balance, CurrencyId>)> {
runtime_common::investment_portfolios::get_account_portfolio::<Runtime, PoolSystem>(account_id)
}
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/centrifuge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2202,8 +2202,8 @@ impl_runtime_apis! {
}

// Investment Runtime APIs
impl runtime_common::apis::InvestmentsApi<Block, AccountId, TrancheCurrency, InvestmentPortfolio<Balance>> for Runtime {
fn investment_portfolio(account_id: AccountId) -> Vec<(TrancheCurrency, InvestmentPortfolio<Balance>)> {
impl runtime_common::apis::InvestmentsApi<Block, AccountId, TrancheCurrency, InvestmentPortfolio<Balance, CurrencyId>> for Runtime {
fn investment_portfolio(account_id: AccountId) -> Vec<(TrancheCurrency, InvestmentPortfolio<Balance, CurrencyId>)> {
runtime_common::investment_portfolios::get_account_portfolio::<Runtime, PoolSystem>(account_id)
}
}
Expand Down
4 changes: 4 additions & 0 deletions runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pallet-liquidity-pools = { path = "../../pallets/liquidity-pools", default-featu
pallet-liquidity-pools-gateway = { path = "../../pallets/liquidity-pools-gateway", default-features = false }
pallet-loans = { path = "../../pallets/loans", default-features = false }
pallet-pool-system = { path = "../../pallets/pool-system", default-features = false }
pallet-restricted-tokens = { path = "../../pallets/restricted-tokens", default-features = false }

# Used for migrations
log = "0.4"
Expand Down Expand Up @@ -119,6 +120,7 @@ std = [
"pallet-liquidity-pools/std",
"pallet-loans/std",
"pallet-pool-system/std",
"pallet-restricted-tokens/std",
"pallet-treasury/std",
"parachain-info/std",
"polkadot-parachain/std",
Expand Down Expand Up @@ -156,6 +158,7 @@ runtime-benchmarks = [
"pallet-liquidity-pools/runtime-benchmarks",
"pallet-loans/runtime-benchmarks",
"pallet-pool-system/runtime-benchmarks",
"pallet-restricted-tokens/runtime-benchmarks",
"pallet-treasury/runtime-benchmarks",
"polkadot-parachain/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
Expand Down Expand Up @@ -193,6 +196,7 @@ try-runtime = [
"pallet-liquidity-pools/try-runtime",
"pallet-loans/try-runtime",
"pallet-pool-system/try-runtime",
"pallet-restricted-tokens/try-runtime",
"pallet-treasury/try-runtime",
"parachain-info/try-runtime",
"sp-runtime/try-runtime",
Expand Down
108 changes: 73 additions & 35 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,10 @@ pub mod investment_portfolios {
PoolInspect, Seconds,
};
use cfg_types::{investments::InvestmentPortfolio, tokens::CurrencyId};
use frame_support::traits::{
fungibles,
tokens::{Fortitude, Preservation},
};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};

/// Get the PoolId, CurrencyId, InvestmentId, and Balance for all
Expand All @@ -390,59 +394,88 @@ pub mod investment_portfolios {
investor: <T as frame_system::Config>::AccountId,
) -> Vec<(
<T as pallet_investments::Config>::InvestmentId,
InvestmentPortfolio<Balance>,
InvestmentPortfolio<Balance, CurrencyId>,
)>
where
T: frame_system::Config + pallet_investments::Config + orml_tokens::Config,
<T as pallet_investments::Config>::InvestmentId:
TrancheCurrency<PoolId, TrancheId> + Into<<T as orml_tokens::Config>::CurrencyId> + Ord,
CurrencyId: From<<T as orml_tokens::Config>::CurrencyId>,
T: frame_system::Config
+ pallet_investments::Config
+ orml_tokens::Config
+ pallet_restricted_tokens::Config,
<T as pallet_investments::Config>::InvestmentId: TrancheCurrency<PoolId, TrancheId>
+ Into<<T as orml_tokens::Config>::CurrencyId>
+ Ord
+ Into<<T as pallet_restricted_tokens::Config>::CurrencyId>,
CurrencyId: From<<T as orml_tokens::Config>::CurrencyId>
+ From<<T as pallet_restricted_tokens::Config>::CurrencyId>,
<T as pallet_restricted_tokens::Config>::CurrencyId:
From<<T as orml_tokens::Config>::CurrencyId>,
Balance: From<<T as pallet_investments::Config>::Amount>
+ From<<T as orml_tokens::Config>::Balance>,
+ From<<T as pallet_restricted_tokens::Config>::Balance>,
PoolInspector: PoolInspect<
<T as frame_system::Config>::AccountId,
<T as orml_tokens::Config>::CurrencyId,
<T as pallet_restricted_tokens::Config>::CurrencyId,
PoolId = PoolId,
TrancheId = TrancheId,
Moment = Seconds,
>,
{
let mut portfolio = BTreeMap::<
<T as pallet_investments::Config>::InvestmentId,
InvestmentPortfolio<Balance>,
InvestmentPortfolio<Balance, CurrencyId>,
>::new();

// Denote current tranche token balances before dry running collecting
orml_tokens::Accounts::<T>::iter_key_prefix(&investor).for_each(|currency| {
if let CurrencyId::Tranche(pool_id, tranche_id) = CurrencyId::from(currency) {
let balance = orml_tokens::Accounts::<T>::get(&investor, currency);
let pool_currency = PoolInspector::currency_for(pool_id)
.expect("Pool must exist; qed")
Copy link
Contributor Author

@wischli wischli Nov 20, 2023

Choose a reason for hiding this comment

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

I think we can safely expect here and the two below cases of querying the pool currency. If we want to be super duper safe, I can wrap the rest of the inner scopes into a .map. WDYT @mustermeiszer ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, I would also say so. I also think zo remember that api calls are wrapped in a panic catching-something, I will double check that.

But think the expect is fine!

.into();
let free_balance = <pallet_restricted_tokens::Pallet<T> as fungibles::Inspect<
T::AccountId,
>>::reducible_balance(
currency.into(),
&investor,
Preservation::Preserve,
Fortitude::Polite,
);
let reserved_balance = <pallet_restricted_tokens::Pallet<T> as fungibles::InspectHold<
T::AccountId,
>>::balance_on_hold(currency.into(), &(), &investor);

portfolio
.entry(TrancheCurrency::generate(pool_id, tranche_id))
.and_modify(|p| {
p.free_tranche_tokens = balance.free.into();
p.reserved_tranche_tokens = balance.reserved.into();
p.free_tranche_tokens = free_balance.into();
p.reserved_tranche_tokens = reserved_balance.into();
})
.or_insert(
InvestmentPortfolio::<Balance>::new()
.with_free_tranche_tokens(balance.free.into())
.with_reserved_tranche_tokens(balance.reserved.into()),
InvestmentPortfolio::<Balance, CurrencyId>::new(pool_currency)
.with_free_tranche_tokens(free_balance.into())
.with_reserved_tranche_tokens(reserved_balance.into()),
);
}
});

// Set pending invest currency and claimable tranche tokens
pallet_investments::InvestOrders::<T>::iter_key_prefix(&investor).for_each(|invest_id| {
let pool_currency =
PoolInspector::currency_for(invest_id.of_pool()).expect("Pool must exist; qed");

// Collect such that we can determine claimable tranche tokens
// NOTE: Does not modify storage since RtAPI is readonly
let _ =
pallet_investments::Pallet::<T>::collect_investment(investor.clone(), invest_id);
let amount = pallet_investments::InvestOrders::<T>::get(&investor, invest_id)
.map(|order| order.amount())
.unwrap_or_default();
let free_tranche_tokens_new =
orml_tokens::Accounts::<T>::get(&investor, invest_id.into())
.free
.into();
let free_tranche_tokens_new: Balance = <pallet_restricted_tokens::Pallet<T> as fungibles::Inspect<
T::AccountId,
>>::reducible_balance(
invest_id.into(),
&investor,
Preservation::Preserve,
Fortitude::Polite,
).into();

portfolio
.entry(invest_id)
Expand All @@ -454,22 +487,25 @@ pub mod investment_portfolios {
}
})
.or_insert(
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(pool_currency.into())
.with_pending_invest_currency(amount.into())
.with_claimable_tranche_tokens(free_tranche_tokens_new),
);
});

// Set pending tranche tokens and claimable invest currency
pallet_investments::RedeemOrders::<T>::iter_key_prefix(&investor).for_each(|invest_id| {
let pool_currency = PoolInspector::currency_for(invest_id.of_pool());
let balance_before: Balance = pool_currency
.map(|p_currency| {
orml_tokens::Accounts::<T>::get(&investor, p_currency)
.free
.into()
})
.unwrap_or_default();
let pool_currency =
PoolInspector::currency_for(invest_id.of_pool()).expect("Pool must exist; qed");
let balance_before: Balance =
<pallet_restricted_tokens::Pallet<T> as fungibles::Inspect<
T::AccountId,
>>::reducible_balance(
pool_currency,
&investor,
Preservation::Preserve,
Fortitude::Polite,
).into();

// Collect such that we can determine claimable invest currency
// NOTE: Does not modify storage since RtAPI is readonly
Expand All @@ -478,13 +514,15 @@ pub mod investment_portfolios {
let amount = pallet_investments::RedeemOrders::<T>::get(&investor, invest_id)
.map(|order| order.amount())
.unwrap_or_default();
let balance_after: Balance = pool_currency
.map(|p_currency| {
orml_tokens::Accounts::<T>::get(&investor, p_currency)
.free
.into()
})
.unwrap_or_default();
let balance_after: Balance =
<pallet_restricted_tokens::Pallet<T> as fungibles::Inspect<
T::AccountId,
>>::reducible_balance(
pool_currency,
&investor,
Preservation::Preserve,
Fortitude::Polite,
).into();

portfolio
.entry(invest_id)
Expand All @@ -495,7 +533,7 @@ pub mod investment_portfolios {
}
})
.or_insert(
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(pool_currency.into())
.with_pending_redeem_tranche_tokens(amount.into())
.with_claimable_currency(balance_after),
);
Expand Down
4 changes: 2 additions & 2 deletions runtime/development/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2295,8 +2295,8 @@ impl_runtime_apis! {
}

// Investment Runtime APIs
impl runtime_common::apis::InvestmentsApi<Block, AccountId, TrancheCurrency, InvestmentPortfolio<Balance>> for Runtime {
fn investment_portfolio(account_id: AccountId) -> Vec<(TrancheCurrency, InvestmentPortfolio<Balance>)> {
impl runtime_common::apis::InvestmentsApi<Block, AccountId, TrancheCurrency, InvestmentPortfolio<Balance, CurrencyId>> for Runtime {
fn investment_portfolio(account_id: AccountId) -> Vec<(TrancheCurrency, InvestmentPortfolio<Balance, CurrencyId>)> {
runtime_common::investment_portfolios::get_account_portfolio::<Runtime, PoolSystem>(account_id)
}
}
Expand Down
21 changes: 13 additions & 8 deletions runtime/integration-tests/src/generic/cases/investments.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use cfg_primitives::{AccountId, Balance, PoolId};
use cfg_traits::{investments::TrancheCurrency as _, Seconds};
use cfg_types::{investments::InvestmentPortfolio, permissions::PoolRole, tokens::TrancheCurrency};
use cfg_types::{
investments::InvestmentPortfolio,
permissions::PoolRole,
tokens::{CurrencyId, TrancheCurrency},
};
use frame_support::traits::fungibles::MutateHold;
use runtime_common::apis::{
runtime_decl_for_investments_api::InvestmentsApiV1, runtime_decl_for_pools_api::PoolsApiV1,
Expand Down Expand Up @@ -84,7 +88,7 @@ fn investment_portfolio_single_tranche<T: Runtime>() {
investment_portfolio,
vec![(
invest_id,
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(Usd6::ID)
.with_pending_invest_currency(EXPECTED_POOL_BALANCE)
)]
);
Expand All @@ -99,7 +103,7 @@ fn investment_portfolio_single_tranche<T: Runtime>() {
investment_portfolio,
vec![(
invest_id,
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(Usd6::ID)
.with_claimable_tranche_tokens(EXPECTED_POOL_BALANCE)
)]
);
Expand All @@ -113,7 +117,8 @@ fn investment_portfolio_single_tranche<T: Runtime>() {
investment_portfolio,
vec![(
invest_id,
InvestmentPortfolio::<Balance>::new().with_free_tranche_tokens(EXPECTED_POOL_BALANCE)
InvestmentPortfolio::<Balance, CurrencyId>::new(Usd6::ID)
.with_free_tranche_tokens(EXPECTED_POOL_BALANCE)
)]
);

Expand All @@ -126,7 +131,7 @@ fn investment_portfolio_single_tranche<T: Runtime>() {
investment_portfolio,
vec![(
invest_id,
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(Usd6::ID)
.with_free_tranche_tokens(EXPECTED_POOL_BALANCE - REDEEM_AMOUNT)
.with_pending_redeem_tranche_tokens(REDEEM_AMOUNT)
)]
Expand All @@ -142,7 +147,7 @@ fn investment_portfolio_single_tranche<T: Runtime>() {
investment_portfolio,
vec![(
invest_id,
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(Usd6::ID)
.with_free_tranche_tokens(EXPECTED_POOL_BALANCE - REDEEM_AMOUNT)
.with_claimable_currency(REDEEM_AMOUNT)
)]
Expand All @@ -157,7 +162,7 @@ fn investment_portfolio_single_tranche<T: Runtime>() {
investment_portfolio,
vec![(
invest_id,
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(Usd6::ID)
.with_free_tranche_tokens(EXPECTED_POOL_BALANCE - REDEEM_AMOUNT)
)]
);
Expand All @@ -177,7 +182,7 @@ fn investment_portfolio_single_tranche<T: Runtime>() {
investment_portfolio,
vec![(
invest_id,
InvestmentPortfolio::<Balance>::new()
InvestmentPortfolio::<Balance, CurrencyId>::new(Usd6::ID)
.with_free_tranche_tokens(EXPECTED_POOL_BALANCE - REDEEM_AMOUNT - HOLD_AMOUNT)
.with_reserved_tranche_tokens(HOLD_AMOUNT)
)]
Expand Down
2 changes: 1 addition & 1 deletion runtime/integration-tests/src/generic/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ pub trait Runtime:
Self::Block,
AccountId,
TrancheCurrency,
InvestmentPortfolio<Balance>,
InvestmentPortfolio<Balance, CurrencyId>,
>;

type MaxTranchesExt: Codec + Get<u32> + Member + PartialOrd + TypeInfo;
Expand Down