From 55d661f5394979a29d89081837dea9d28a85dac0 Mon Sep 17 00:00:00 2001 From: lemunozm Date: Thu, 27 Jun 2024 11:58:50 +0200 Subject: [PATCH] add token price UTs --- libs/mocks/src/pools.rs | 14 +++-- libs/traits/src/lib.rs | 29 +--------- pallets/liquidity-pools/src/lib.rs | 6 +- pallets/liquidity-pools/src/mock.rs | 4 +- pallets/liquidity-pools/src/tests.rs | 85 ++++++++++++++++++++++++++-- pallets/pool-system/src/impls.rs | 20 ++----- 6 files changed, 100 insertions(+), 58 deletions(-) diff --git a/libs/mocks/src/pools.rs b/libs/mocks/src/pools.rs index 23f6da4fa7..7d0f67e0fe 100644 --- a/libs/mocks/src/pools.rs +++ b/libs/mocks/src/pools.rs @@ -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::*; @@ -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, @@ -168,10 +173,7 @@ pub mod pallet { type PoolId = T::PoolId; type TrancheId = T::TrancheId; - fn get( - a: T::PoolId, - b: T::TrancheId, - ) -> Option> { + fn get_price(a: T::PoolId, b: T::TrancheId) -> Option<(T::BalanceRatio, Seconds)> { execute_call!((a, b)) } } diff --git a/libs/traits/src/lib.rs b/libs/traits/src/lib.rs index ec97102eb5..d7eb9042b0 100644 --- a/libs/traits/src/lib.rs +++ b/libs/traits/src/lib.rs @@ -96,10 +96,10 @@ pub trait TrancheTokenPrice { type BalanceRatio; type Moment; - fn get( + fn get_price( pool_id: Self::PoolId, tranche_id: Self::TrancheId, - ) -> Option>; + ) -> Option<(Self::BalanceRatio, Self::Moment)>; } /// Variants for valid Pool updates to send out as events @@ -206,31 +206,6 @@ pub trait PoolWriteOffPolicyMutate { fn worst_case_policy() -> Self::Policy; } -/// A trait that can be used to retrieve the current price for a currency -pub struct CurrencyPair { - pub base: CurrencyId, - pub quote: CurrencyId, -} - -pub struct PriceValue { - pub pair: CurrencyPair, - pub price: Rate, - pub last_updated: Moment, -} - -pub trait CurrencyPrice { - 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, - ) -> Option>; -} - pub trait Permissions { type Scope; type Role; diff --git a/pallets/liquidity-pools/src/lib.rs b/pallets/liquidity-pools/src/lib.rs index 76d8c827b6..03ce4cd5c0 100644 --- a/pallets/liquidity-pools/src/lib.rs +++ b/pallets/liquidity-pools/src/lib.rs @@ -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) .ok_or(Error::::MissingTranchePrice)?; // Check that the registered asset location matches the destination @@ -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, }, )?; diff --git a/pallets/liquidity-pools/src/mock.rs b/pallets/liquidity-pools/src/mock.rs index aaff960192..94279987b8 100644 --- a/pallets/liquidity-pools/src/mock.rs +++ b/pallets/liquidity-pools/src/mock.rs @@ -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 { diff --git a/pallets/liquidity-pools/src/tests.rs b/pallets/liquidity-pools/src/tests.rs index 439fe35362..3077979839 100644 --- a/pallets/liquidity-pools/src/tests.rs +++ b/pallets/liquidity-pools/src/tests.rs @@ -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::*; @@ -118,7 +119,7 @@ mod transfer { }) } - mod erroring_out_when { + mod erroring_out { use super::*; #[test] @@ -326,7 +327,7 @@ mod transfer_tranche_tokens { }) } - mod erroring_out_when { + mod erroring_out { use super::*; #[test] @@ -461,7 +462,7 @@ mod add_pool { }) } - mod erroring_out_when { + mod erroring_out { use super::*; #[test] @@ -540,7 +541,7 @@ mod add_tranche { }) } - mod erroring_out_when { + mod erroring_out { use super::*; #[test] @@ -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::::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::::AssetNotLiquidityPoolsTransferable, + ); + }) + } + } +} + #[test] fn receiving_output_message() { System::externalities().execute_with(|| { diff --git a/pallets/pool-system/src/impls.rs b/pallets/pool-system/src/impls.rs index da2a469df2..cf80f26ec8 100644 --- a/pallets/pool-system/src/impls.rs +++ b/pallets/pool-system/src/impls.rs @@ -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::{ @@ -62,10 +62,10 @@ impl TrancheTokenPrice for Pallet { type PoolId = T::PoolId; type TrancheId = T::TrancheId; - fn get( + fn get_price( pool_id: Self::PoolId, tranche_id: Self::TrancheId, - ) -> Option> { + ) -> Option<(T::BalanceRatio, Seconds)> { let now = T::Time::now(); let mut pool = Pool::::get(pool_id)?; @@ -84,21 +84,9 @@ impl TrancheTokenPrice for Pallet { .calculate_prices::(total_assets, now) .ok()?; - let base = pool - .tranches - .tranche_currency(TrancheLoc::Id(tranche_id))? - .into(); - let price = prices.get(tranche_index).cloned()?; - Some(PriceValue { - pair: CurrencyPair { - base, - quote: pool.currency, - }, - price, - last_updated: nav_last_updated, - }) + Some((price, nav_last_updated)) } }