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

Liquidity pools: Add UTs to for update_token_price() #1890

Merged
merged 11 commits into from
Jul 9, 2024
14 changes: 8 additions & 6 deletions libs/mocks/src/pools.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#[frame_support::pallet(dev_mode)]
pub mod pallet {
use cfg_traits::{
investments::InvestmentAccountant, PoolInspect, PoolReserve, PriceValue, Seconds,
TrancheTokenPrice,
investments::InvestmentAccountant, PoolInspect, PoolReserve, Seconds, TrancheTokenPrice,
};
use cfg_types::investments::InvestmentInfo;
use frame_support::pallet_prelude::*;
Expand Down Expand Up @@ -86,6 +85,12 @@ pub mod pallet {
register_call!(move |(a, b, c, d)| f(a, b, c, d));
}

pub fn mock_get_price(
f: impl Fn(T::PoolId, T::TrancheId) -> Option<(T::BalanceRatio, Seconds)> + 'static,
) {
register_call!(move |(a, b)| f(a, b));
}

#[allow(non_snake_case)]
pub fn mock_InvestmentAccountant_deposit(
f: impl Fn(&T::AccountId, T::TrancheCurrency, T::Balance) -> DispatchResult + 'static,
Expand Down Expand Up @@ -168,10 +173,7 @@ pub mod pallet {
type PoolId = T::PoolId;
type TrancheId = T::TrancheId;

fn get(
a: T::PoolId,
b: T::TrancheId,
) -> Option<PriceValue<T::CurrencyId, T::BalanceRatio, Seconds>> {
fn get_price(a: T::PoolId, b: T::TrancheId) -> Option<(T::BalanceRatio, Seconds)> {
execute_call!((a, b))
}
}
Expand Down
29 changes: 2 additions & 27 deletions libs/traits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ pub trait TrancheTokenPrice<AccountId, CurrencyId> {
type BalanceRatio;
type Moment;

fn get(
fn get_price(
pool_id: Self::PoolId,
tranche_id: Self::TrancheId,
) -> Option<PriceValue<CurrencyId, Self::BalanceRatio, Self::Moment>>;
) -> Option<(Self::BalanceRatio, Self::Moment)>;
}

/// Variants for valid Pool updates to send out as events
Expand Down Expand Up @@ -206,31 +206,6 @@ pub trait PoolWriteOffPolicyMutate<PoolId> {
fn worst_case_policy() -> Self::Policy;
}

/// A trait that can be used to retrieve the current price for a currency
pub struct CurrencyPair<CurrencyId> {
pub base: CurrencyId,
pub quote: CurrencyId,
}

pub struct PriceValue<CurrencyId, Rate, Moment> {
pub pair: CurrencyPair<CurrencyId>,
pub price: Rate,
pub last_updated: Moment,
}

pub trait CurrencyPrice<CurrencyId> {
type Rate;
type Moment;

/// Retrieve the latest price of `base` currency, denominated in the `quote`
/// currency If `quote` currency is not passed, then the default `quote`
/// currency is used (when possible)
fn get_latest(
base: CurrencyId,
quote: Option<CurrencyId>,
) -> Option<PriceValue<CurrencyId, Self::Rate, Self::Moment>>;
}

Comment on lines -209 to -233
Copy link
Contributor Author

@lemunozm lemunozm Jun 27, 2024

Choose a reason for hiding this comment

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

This is not used, but if it's intended to be used very soon, I can revert this. Otherwise, I would left removed.

pub trait Permissions<AccountId> {
type Scope;
type Role;
Expand Down
6 changes: 3 additions & 3 deletions pallets/liquidity-pools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ pub mod pallet {
// TODO(future): Once we diverge from 1-to-1 conversions for foreign and pool
// currencies, this price must be first converted into the currency_id and then
// re-denominated to 18 decimals (i.e. `Ratio` precision)
let price_value = T::TrancheTokenPrice::get(pool_id, tranche_id)
let (price, computed_at) = T::TrancheTokenPrice::get_price(pool_id, tranche_id)
Copy link
Collaborator

Choose a reason for hiding this comment

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

@lemunozm can we in the same run also close this todo and computed the conversion?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if it's super straightforward. Do we need to add the order-book dependency to know the market price used for foreign/pool currencies?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree it isn't. But we are not only touching the UTs here but also chaning the return types, naming etc. Then we could also close the todo IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done here: 15424a8 @mustermeiszer

Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice, thanks a lot!

.ok_or(Error::<T>::MissingTranchePrice)?;

// Check that the registered asset location matches the destination
Expand All @@ -447,8 +447,8 @@ pub mod pallet {
pool_id,
tranche_id,
currency,
price: price_value.price,
computed_at: price_value.last_updated,
price,
computed_at,
},
)?;

Expand Down
4 changes: 2 additions & 2 deletions pallets/liquidity-pools/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use cfg_types::{
};
use frame_support::derive_impl;
use orml_traits::parameter_type_with_key;
use sp_runtime::{traits::IdentityLookup, AccountId32, DispatchResult, FixedU64};
use sp_runtime::{traits::IdentityLookup, AccountId32, DispatchResult, FixedU128};

use crate::pallet as pallet_liquidity_pools;

pub type Balance = u128;
pub type AccountId = AccountId32;
pub type Ratio = FixedU64;
pub type Ratio = FixedU128;

frame_support::construct_runtime!(
pub enum Runtime {
Expand Down
85 changes: 81 additions & 4 deletions pallets/liquidity-pools/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const NAME: &[u8] = b"Token name";
const SYMBOL: &[u8] = b"Token symbol";
const DECIMALS: u8 = 6;
const TRANCHE_CURRENCY: CurrencyId = CurrencyId::Tranche(POOL_ID, TRANCHE_ID);
const PRICE: Ratio = Ratio::from_rational(10, 1);

mod util {
use super::*;
Expand Down Expand Up @@ -118,7 +119,7 @@ mod transfer {
})
}

mod erroring_out_when {
mod erroring_out {
use super::*;

#[test]
Expand Down Expand Up @@ -326,7 +327,7 @@ mod transfer_tranche_tokens {
})
}

mod erroring_out_when {
mod erroring_out {
use super::*;

#[test]
Expand Down Expand Up @@ -461,7 +462,7 @@ mod add_pool {
})
}

mod erroring_out_when {
mod erroring_out {
use super::*;

#[test]
Expand Down Expand Up @@ -540,7 +541,7 @@ mod add_tranche {
})
}

mod erroring_out_when {
mod erroring_out {
use super::*;

#[test]
Expand Down Expand Up @@ -619,6 +620,82 @@ mod add_tranche {
}
}

mod update_token_price {
use super::*;

#[test]
fn success() {
System::externalities().execute_with(|| {
Pools::mock_get_price(|_, _| Some((PRICE, 1234)));
AssetRegistry::mock_metadata(|_| Some(util::wrapped_transferable_metadata()));
Gateway::mock_submit(|sender, destination, msg| {
assert_eq!(sender, ALICE);
assert_eq!(destination, EVM_ADDRESS.domain());
assert_eq!(
msg,
Message::UpdateTrancheTokenPrice {
pool_id: POOL_ID,
tranche_id: TRANCHE_ID,
currency: util::currency_index(CURRENCY_ID),
price: PRICE,
computed_at: 1234
}
);
Ok(())
});

assert_ok!(LiquidityPools::update_token_price(
RuntimeOrigin::signed(ALICE),
POOL_ID,
TRANCHE_ID,
CURRENCY_ID,
EVM_ADDRESS.domain(),
));
})
}

mod erroring_out {
use super::*;

#[test]
fn with_missing_tranche_price() {
System::externalities().execute_with(|| {
Pools::mock_get_price(|_, _| None);

assert_noop!(
LiquidityPools::update_token_price(
RuntimeOrigin::signed(ALICE),
POOL_ID,
TRANCHE_ID,
CURRENCY_ID,
EVM_ADDRESS.domain(),
),
Error::<Runtime>::MissingTranchePrice,
);
})
}

#[test]
fn with_no_transferible_asset() {
System::externalities().execute_with(|| {
Pools::mock_get_price(|_, _| Some((PRICE, 1234)));
AssetRegistry::mock_metadata(|_| Some(util::default_metadata()));

assert_noop!(
LiquidityPools::update_token_price(
RuntimeOrigin::signed(ALICE),
POOL_ID,
TRANCHE_ID,
CURRENCY_ID,
EVM_ADDRESS.domain(),
),
Error::<Runtime>::AssetNotLiquidityPoolsTransferable,
);
})
}
}
}

#[test]
fn receiving_output_message() {
System::externalities().execute_with(|| {
Expand Down
20 changes: 4 additions & 16 deletions pallets/pool-system/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use cfg_traits::{
changes::ChangeGuard,
fee::{PoolFeeBucket, PoolFeesMutate},
investments::{InvestmentAccountant, TrancheCurrency},
CurrencyPair, PoolUpdateGuard, PriceValue, TrancheTokenPrice, UpdateState,
PoolUpdateGuard, TrancheTokenPrice, UpdateState,
};
use cfg_types::{epoch::EpochState, investments::InvestmentInfo, pools::PoolFeeInfo};
use frame_support::traits::{
Expand Down Expand Up @@ -62,10 +62,10 @@ impl<T: Config> TrancheTokenPrice<T::AccountId, T::CurrencyId> for Pallet<T> {
type PoolId = T::PoolId;
type TrancheId = T::TrancheId;

fn get(
fn get_price(
pool_id: Self::PoolId,
tranche_id: Self::TrancheId,
) -> Option<PriceValue<T::CurrencyId, T::BalanceRatio, Seconds>> {
) -> Option<(T::BalanceRatio, Seconds)> {
let now = T::Time::now();
let mut pool = Pool::<T>::get(pool_id)?;

Expand All @@ -84,21 +84,9 @@ impl<T: Config> TrancheTokenPrice<T::AccountId, T::CurrencyId> for Pallet<T> {
.calculate_prices::<T::BalanceRatio, T::Tokens, _>(total_assets, now)
.ok()?;

let base = pool
.tranches
.tranche_currency(TrancheLoc::Id(tranche_id))?
.into();

let price = prices.get(tranche_index).cloned()?;

Some(PriceValue {
Copy link
Collaborator

Choose a reason for hiding this comment

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

@hieronx you added this change. Why did you wanted to have the TrancheCurrency and the PoolCurrency named here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't fully remember. I think we just set up the PriceValue for some other purpose, and then used that here.

pair: CurrencyPair {
base,
quote: pool.currency,
},
price,
last_updated: nav_last_updated,
})
Some((price, nav_last_updated))
}
}

Expand Down
32 changes: 0 additions & 32 deletions runtime/integration-tests/src/cases/liquidity_pools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,38 +773,6 @@ mod add_allow_upgrade {
});
}

#[test_runtimes([development])]
fn update_token_price<T: Runtime + FudgeSupport>() {
let mut env = FudgeEnv::<T>::from_parachain_storage(
Genesis::default()
.add(genesis::balances::<T>(cfg(1_000)))
.add(genesis::tokens::<T>(vec![(
GLMR_CURRENCY_ID,
DEFAULT_BALANCE_GLMR,
)]))
.storage(),
);

setup_test(&mut env);

env.parachain_state_mut(|| {
let currency_id = AUSD_CURRENCY_ID;
let pool_id = POOL_ID;

enable_liquidity_pool_transferability::<T>(currency_id);

create_ausd_pool::<T>(pool_id);

assert_ok!(pallet_liquidity_pools::Pallet::<T>::update_token_price(
RawOrigin::Signed(Keyring::Bob.into()).into(),
pool_id,
default_tranche_id::<T>(pool_id),
currency_id,
Domain::EVM(MOONBEAM_EVM_CHAIN_ID),
));
});
}

#[test_runtimes([development])]
fn add_currency<T: Runtime + FudgeSupport>() {
let mut env = FudgeEnv::<T>::from_parachain_storage(
Expand Down
19 changes: 10 additions & 9 deletions runtime/integration-tests/src/cases/lp/pool_management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

use cfg_primitives::{Balance, PoolId, SECONDS_PER_YEAR};
use cfg_primitives::{AccountId, Balance, PoolId, SECONDS_PER_YEAR};
use cfg_traits::{PoolMetadata, TimeAsSecs, TrancheTokenPrice};
use cfg_types::{
domain_address::{Domain, DomainAddress},
Expand Down Expand Up @@ -561,12 +561,13 @@ fn update_tranche_token_price<T: Runtime>() {
assert_eq!(computed_evm, 0);
});

let pre_price_cfg = env.state_mut(|_evm| {
let price = <pallet_pool_system::Pallet<T> as TrancheTokenPrice<
<T as frame_system::Config>::AccountId,
CurrencyId,
>>::get(POOL_A, pool_a_tranche_1_id::<T>())
.unwrap();
let (price, last_updated) = env.state_mut(|_evm| {
let price =
<pallet_pool_system::Pallet<T> as TrancheTokenPrice<AccountId, CurrencyId>>::get_price(
POOL_A,
pool_a_tranche_1_id::<T>(),
)
.unwrap();

assert_ok!(pallet_liquidity_pools::Pallet::<T>::update_token_price(
OriginFor::<T>::signed(Keyring::Alice.into()),
Expand Down Expand Up @@ -596,7 +597,7 @@ fn update_tranche_token_price<T: Runtime>() {
.value,
);

assert_eq!(pre_price_cfg.last_updated, computed_at_evm);
assert_eq!(price_evm, pre_price_cfg.price.into_inner());
assert_eq!(last_updated, computed_at_evm);
assert_eq!(price.into_inner(), price_evm);
});
}
Loading