diff --git a/api/bin/chainflip-lp-api/src/main.rs b/api/bin/chainflip-lp-api/src/main.rs index b26d0b5b8a..517dbee4a1 100644 --- a/api/bin/chainflip-lp-api/src/main.rs +++ b/api/bin/chainflip-lp-api/src/main.rs @@ -8,7 +8,7 @@ use chainflip_api::{ self, lp::{ types::{LimitOrder, RangeOrder}, - ApiWaitForResult, LpApi, Order, Tick, + ApiWaitForResult, LpApi, PoolPairsMap, Side, Tick, }, primitives::{ chains::{assets::any::OldAsset, Bitcoin, Ethereum, Polkadot}, @@ -28,7 +28,7 @@ use jsonrpsee::{ types::SubscriptionResult, SubscriptionSink, }; -use pallet_cf_pools::{AssetPair, AssetsMap, IncreaseOrDecrease, OrderId, RangeOrderSize}; +use pallet_cf_pools::{AssetPair, IncreaseOrDecrease, OrderId, RangeOrderSize}; use rpc_types::{AssetBalance, OpenSwapChannels, OrderIdJson, RangeOrderSizeJson}; use sp_core::U256; use std::{ @@ -44,8 +44,7 @@ pub mod rpc_types { use super::*; use anyhow::anyhow; use cf_utilities::rpc::NumberOrHex; - use chainflip_api::queries::SwapChannelInfo; - use pallet_cf_pools::AssetsMap; + use chainflip_api::{lp::PoolPairsMap, queries::SwapChannelInfo}; use serde::{Deserialize, Serialize}; #[derive(Copy, Clone, Debug, Serialize, Deserialize)] @@ -60,7 +59,7 @@ pub mod rpc_types { #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub enum RangeOrderSizeJson { - AssetAmounts { maximum: AssetsMap, minimum: AssetsMap }, + AssetAmounts { maximum: PoolPairsMap, minimum: PoolPairsMap }, Liquidity { liquidity: NumberOrHex }, } impl TryFrom for RangeOrderSize { @@ -156,7 +155,7 @@ pub trait Rpc { &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, id: OrderIdJson, tick: Option, amount_change: IncreaseOrDecrease, @@ -169,7 +168,7 @@ pub trait Rpc { &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, id: OrderIdJson, tick: Option, sell_amount: NumberOrHex, @@ -226,7 +225,7 @@ pub enum OrderFilled { lp: AccountId, base_asset: OldAsset, quote_asset: OldAsset, - side: Order, + side: Side, id: U256, tick: Tick, sold: U256, @@ -240,7 +239,7 @@ pub enum OrderFilled { quote_asset: OldAsset, id: U256, range: Range, - fees: AssetsMap, + fees: PoolPairsMap, liquidity: U256, }, } @@ -367,7 +366,7 @@ impl RpcServer for RpcServerImpl { &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, id: OrderIdJson, tick: Option, amount_change: IncreaseOrDecrease, @@ -394,7 +393,7 @@ impl RpcServer for RpcServerImpl { &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, id: OrderIdJson, tick: Option, sell_amount: NumberOrHex, @@ -558,7 +557,7 @@ where let updated_range_orders = &updated_range_orders; let updated_limit_orders = &updated_limit_orders; let previous_pools = &previous_pools; - [Order::Sell, Order::Buy] + [Side::Sell, Side::Buy] .into_iter() .flat_map(move |side| { pool.pool_state.limit_orders(side).filter_map( @@ -635,7 +634,7 @@ where collected .fees .zip(previous_collected.fees) - .map(|_, (fees, previous_fees)| fees - previous_fees) + .map(|(fees, previous_fees)| fees - previous_fees) } else { collected.fees } @@ -650,7 +649,7 @@ where quote_asset: asset_pair.assets().quote.into(), id: id.into(), range: range.clone(), - fees: fees.map(|_, fees| fees).into(), + fees: fees.map(|fees| fees), liquidity: position_info.liquidity.into(), }) } diff --git a/api/lib/src/lp.rs b/api/lib/src/lp.rs index f34db082b2..376f283bce 100644 --- a/api/lib/src/lp.rs +++ b/api/lib/src/lp.rs @@ -1,7 +1,7 @@ use anyhow::{bail, Context, Result}; use async_trait::async_trait; pub use cf_amm::{ - common::{Amount, Order, Side, SideMap, Tick}, + common::{Amount, PoolPairsMap, Side, Tick}, range_orders::Liquidity, }; use cf_chains::address::EncodedAddress; @@ -10,7 +10,7 @@ use chainflip_engine::state_chain_observer::client::{ extrinsic_api::signed::{SignedExtrinsicApi, UntilInBlock, WaitFor, WaitForResult}, StateChainClient, }; -use pallet_cf_pools::{AssetsMap, IncreaseOrDecrease, OrderId, RangeOrderSize}; +use pallet_cf_pools::{IncreaseOrDecrease, OrderId, RangeOrderSize}; use serde::{Deserialize, Serialize}; use sp_core::{H256, U256}; use state_chain_runtime::RuntimeCall; @@ -52,21 +52,21 @@ pub mod types { pub id: U256, pub tick_range: Range, pub liquidity_total: U256, - pub collected_fees: AssetsMap, + pub collected_fees: PoolPairsMap, pub size_change: Option>, } #[derive(Serialize, Deserialize, Clone)] pub struct RangeOrderChange { pub liquidity: U256, - pub amounts: AssetsMap, + pub amounts: PoolPairsMap, } #[derive(Serialize, Deserialize, Clone)] pub struct LimitOrder { pub base_asset: OldAsset, pub quote_asset: OldAsset, - pub side: Order, + pub side: Side, pub id: U256, pub tick: Tick, pub sell_amount_total: U256, @@ -313,7 +313,7 @@ pub trait LpApi: SignedExtrinsicApi { &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, id: OrderId, option_tick: Option, amount_change: IncreaseOrDecrease, @@ -340,7 +340,7 @@ pub trait LpApi: SignedExtrinsicApi { &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, id: OrderId, option_tick: Option, sell_amount: AssetAmount, diff --git a/state-chain/amm/src/common.rs b/state-chain/amm/src/common.rs index 7a31d7e6bb..1b90c02e98 100644 --- a/state-chain/amm/src/common.rs +++ b/state-chain/amm/src/common.rs @@ -40,42 +40,51 @@ pub enum SetFeesError { Hash, )] #[serde(rename_all = "snake_case")] -pub enum Order { +pub enum Side { Buy, Sell, } -impl Order { - pub fn to_sold_side(&self) -> Side { +impl Side { + pub fn to_sold_pair(&self) -> Pairs { match self { - Order::Buy => Side::One, - Order::Sell => Side::Zero, + Side::Buy => Pairs::Quote, + Side::Sell => Pairs::Base, } } } -impl core::ops::Not for Order { +impl core::ops::Not for Side { type Output = Self; fn not(self) -> Self::Output { match self { - Order::Sell => Order::Buy, - Order::Buy => Order::Sell, + Side::Sell => Side::Buy, + Side::Buy => Side::Sell, } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode, MaxEncodedLen, TypeInfo)] -pub enum Side { - Zero, - One, +pub enum Pairs { + Base, + Quote, } -impl core::ops::Not for Side { +impl core::ops::Not for Pairs { type Output = Self; fn not(self) -> Self::Output { match self { - Side::Zero => Side::One, - Side::One => Side::Zero, + Pairs::Base => Pairs::Quote, + Pairs::Quote => Pairs::Base, + } + } +} + +impl Pairs { + pub fn sell_order(&self) -> Side { + match self { + Pairs::Base => Side::Sell, + Pairs::Quote => Side::Buy, } } } @@ -95,69 +104,81 @@ impl core::ops::Not for Side { Serialize, Deserialize, )] -pub struct SideMap { - pub zero: T, - pub one: T, +pub struct PoolPairsMap { + pub base: T, + pub quote: T, } -impl SideMap { + +impl PoolPairsMap { pub fn from_array(array: [T; 2]) -> Self { - let [zero, one] = array; - Self { zero, one } + let [base, quote] = array; + Self { base, quote } } - pub fn map(self, mut f: impl FnMut(Side, T) -> R) -> SideMap { - SideMap { zero: f(Side::Zero, self.zero), one: f(Side::One, self.one) } + pub fn map R>(self, mut f: F) -> PoolPairsMap { + PoolPairsMap { base: f(self.base), quote: f(self.quote) } } - pub fn try_map( + pub fn try_map Result>( self, - mut f: impl FnMut(Side, T) -> Result, - ) -> Result, E> { - Ok(SideMap { zero: f(Side::Zero, self.zero)?, one: f(Side::One, self.one)? }) + mut f: F, + ) -> Result, E> { + Ok(PoolPairsMap { base: f(self.base)?, quote: f(self.quote)? }) + } + + pub fn try_map_with_pair( + self, + mut f: impl FnMut(Pairs, T) -> Result, + ) -> Result, E> { + Ok(PoolPairsMap { base: f(Pairs::Base, self.base)?, quote: f(Pairs::Quote, self.quote)? }) + } + + pub fn as_ref(&self) -> PoolPairsMap<&T> { + PoolPairsMap { base: &self.base, quote: &self.quote } } - pub fn as_ref(&self) -> SideMap<&T> { - SideMap { zero: &self.zero, one: &self.one } + pub fn as_mut(&mut self) -> PoolPairsMap<&mut T> { + PoolPairsMap { base: &mut self.base, quote: &mut self.quote } } - pub fn as_mut(&mut self) -> SideMap<&mut T> { - SideMap { zero: &mut self.zero, one: &mut self.one } + pub fn zip(self, other: PoolPairsMap) -> PoolPairsMap<(T, S)> { + PoolPairsMap { base: (self.base, other.base), quote: (self.quote, other.quote) } } - pub fn zip(self, other: SideMap) -> SideMap<(T, S)> { - SideMap { zero: (self.zero, other.zero), one: (self.one, other.one) } + pub fn map_with_pair R>(self, mut f: F) -> PoolPairsMap { + PoolPairsMap { base: f(Pairs::Base, self.base), quote: f(Pairs::Quote, self.quote) } } } -impl IntoIterator for SideMap { - type Item = (Side, T); +impl IntoIterator for PoolPairsMap { + type Item = (Pairs, T); - type IntoIter = core::array::IntoIter<(Side, T), 2>; + type IntoIter = core::array::IntoIter<(Pairs, T), 2>; fn into_iter(self) -> Self::IntoIter { - [(Side::Zero, self.zero), (Side::One, self.one)].into_iter() + [(Pairs::Base, self.base), (Pairs::Quote, self.quote)].into_iter() } } -impl core::ops::Index for SideMap { +impl core::ops::Index for PoolPairsMap { type Output = T; - fn index(&self, side: Side) -> &T { + fn index(&self, side: Pairs) -> &T { match side { - Side::Zero => &self.zero, - Side::One => &self.one, + Pairs::Base => &self.base, + Pairs::Quote => &self.quote, } } } -impl core::ops::IndexMut for SideMap { - fn index_mut(&mut self, side: Side) -> &mut T { +impl core::ops::IndexMut for PoolPairsMap { + fn index_mut(&mut self, side: Pairs) -> &mut T { match side { - Side::Zero => &mut self.zero, - Side::One => &mut self.one, + Pairs::Base => &mut self.base, + Pairs::Quote => &mut self.quote, } } } -impl, R> core::ops::Add> for SideMap { - type Output = SideMap<>::Output>; - fn add(self, rhs: SideMap) -> Self::Output { - SideMap { zero: self.zero + rhs.zero, one: self.one + rhs.one } +impl, R> core::ops::Add> for PoolPairsMap { + type Output = PoolPairsMap<>::Output>; + fn add(self, rhs: PoolPairsMap) -> Self::Output { + PoolPairsMap { base: self.base + rhs.base, quote: self.quote + rhs.quote } } } @@ -211,14 +232,14 @@ pub fn bounded_sqrt_price(quote: Amount, base: Amount) -> SqrtPriceQ64F96 { } } -/// A marker type to represent a swap that buys asset One, and sells asset Zero -pub(super) struct ZeroToOne {} -/// A marker type to represent a swap that buys asset Zero, and sells asset One -pub(super) struct OneToZero {} +/// A marker type to represent a swap that buys asset Quote, and sells asset Base +pub(super) struct BaseToQuote {} +/// A marker type to represent a swap that buys asset Base, and sells asset Quote +pub(super) struct QuoteToBase {} pub(super) trait SwapDirection { /// The asset this type of swap sells, i.e. the asset the swapper provides - const INPUT_SIDE: Side; + const INPUT_SIDE: Pairs; /// The worst price in this swap direction const WORST_SQRT_PRICE: SqrtPriceQ64F96; @@ -236,8 +257,8 @@ pub(super) trait SwapDirection { /// asset at a specific tick, will return None iff the tick is invalid fn input_to_output_amount_floor(amount: Amount, tick: Tick) -> Option; } -impl SwapDirection for ZeroToOne { - const INPUT_SIDE: Side = Side::Zero; +impl SwapDirection for BaseToQuote { + const INPUT_SIDE: Pairs = Pairs::Base; const WORST_SQRT_PRICE: SqrtPriceQ64F96 = MIN_SQRT_PRICE; @@ -265,8 +286,8 @@ impl SwapDirection for ZeroToOne { } } } -impl SwapDirection for OneToZero { - const INPUT_SIDE: Side = Side::One; +impl SwapDirection for QuoteToBase { + const INPUT_SIDE: Pairs = Pairs::Quote; const WORST_SQRT_PRICE: SqrtPriceQ64F96 = MAX_SQRT_PRICE; @@ -689,8 +710,8 @@ mod test { } } - inner::(); - inner::(); + inner::(); + inner::(); } #[cfg(feature = "slow-tests")] diff --git a/state-chain/amm/src/lib.rs b/state-chain/amm/src/lib.rs index 2bbaf679ea..fcdeb794fd 100644 --- a/state-chain/amm/src/lib.rs +++ b/state-chain/amm/src/lib.rs @@ -8,8 +8,8 @@ use core::convert::Infallible; use codec::{Decode, Encode}; use common::{ is_sqrt_price_valid, price_to_sqrt_price, sqrt_price_to_price, tick_at_sqrt_price, Amount, - OneToZero, Order, Price, SetFeesError, Side, SideMap, SqrtPriceQ64F96, SwapDirection, Tick, - ZeroToOne, + BaseToQuote, Pairs, PoolPairsMap, Price, QuoteToBase, SetFeesError, Side, SqrtPriceQ64F96, + SwapDirection, Tick, }; use limit_orders::{Collected, PositionInfo}; use range_orders::Liquidity; @@ -50,32 +50,32 @@ impl PoolState { } /// Returns the current price for a given direction of swap. The price is measured in units of - /// the specified Side argument - pub fn current_price(&mut self, order: Order) -> Option<(Price, SqrtPriceQ64F96, Tick)> { + /// the specified Pairs argument + pub fn current_price(&mut self, order: Side) -> Option<(Price, SqrtPriceQ64F96, Tick)> { self.current_sqrt_price(order).map(|sqrt_price| { (sqrt_price_to_price(sqrt_price), sqrt_price, tick_at_sqrt_price(sqrt_price)) }) } /// Returns the current sqrt price for a given direction of swap. The price is measured in units - /// of the specified Side argument - pub fn current_sqrt_price(&mut self, order: Order) -> Option { - match order.to_sold_side() { - Side::Zero => self.inner_current_sqrt_price::(), - Side::One => self.inner_current_sqrt_price::(), + /// of the specified Pairs argument + pub fn current_sqrt_price(&mut self, order: Side) -> Option { + match order.to_sold_pair() { + Pairs::Base => self.inner_current_sqrt_price::(), + Pairs::Quote => self.inner_current_sqrt_price::(), } } - fn inner_worst_price(order: Order) -> SqrtPriceQ64F96 { - match order.to_sold_side() { - Side::One => OneToZero::WORST_SQRT_PRICE, - Side::Zero => ZeroToOne::WORST_SQRT_PRICE, + fn inner_worst_price(order: Side) -> SqrtPriceQ64F96 { + match order.to_sold_pair() { + Pairs::Quote => QuoteToBase::WORST_SQRT_PRICE, + Pairs::Base => BaseToQuote::WORST_SQRT_PRICE, } } pub fn logarithm_sqrt_price_sequence( &mut self, - order: Order, + order: Side, count: u32, ) -> Vec { let worst_sqrt_price = Self::inner_worst_price(order); @@ -127,14 +127,14 @@ impl PoolState { pub fn relative_sqrt_price( &self, - order: Order, + order: Side, sqrt_price: SqrtPriceQ64F96, delta: Tick, ) -> Option { if is_sqrt_price_valid(sqrt_price) { Some(match order { - Order::Buy => OneToZero::increase_sqrt_price(sqrt_price, delta), - Order::Sell => ZeroToOne::increase_sqrt_price(sqrt_price, delta), + Side::Buy => QuoteToBase::increase_sqrt_price(sqrt_price, delta), + Side::Sell => BaseToQuote::increase_sqrt_price(sqrt_price, delta), }) } else { None @@ -167,13 +167,13 @@ impl PoolState { /// This function never panics. pub fn swap( &mut self, - order: Order, + order: Side, sold_amount: Amount, sqrt_price_limit: Option, ) -> (Amount, Amount) { - match order.to_sold_side() { - Side::Zero => self.inner_swap::(sold_amount, sqrt_price_limit), - Side::One => self.inner_swap::(sold_amount, sqrt_price_limit), + match order.to_sold_pair() { + Pairs::Base => self.inner_swap::(sold_amount, sqrt_price_limit), + Pairs::Quote => self.inner_swap::(sold_amount, sqrt_price_limit), } } @@ -227,36 +227,42 @@ impl PoolState { pub fn collect_and_mint_limit_order( &mut self, lp: &LiquidityProvider, - order: Order, + order: Side, tick: Tick, sold_amount: Amount, ) -> Result< (limit_orders::Collected, limit_orders::PositionInfo), limit_orders::PositionError, > { - match order.to_sold_side() { - Side::Zero => self.limit_orders.collect_and_mint::(lp, tick, sold_amount), - Side::One => self.limit_orders.collect_and_mint::(lp, tick, sold_amount), + match order.to_sold_pair() { + Pairs::Base => self.limit_orders.collect_and_mint::(lp, tick, sold_amount), + Pairs::Quote => + self.limit_orders.collect_and_mint::(lp, tick, sold_amount), } } pub fn collect_and_burn_limit_order( &mut self, lp: &LiquidityProvider, - order: Order, + order: Side, tick: Tick, sold_amount: Amount, ) -> Result< (Amount, limit_orders::Collected, limit_orders::PositionInfo), limit_orders::PositionError, > { - match order.to_sold_side() { - Side::Zero => self.limit_orders.collect_and_burn::(lp, tick, sold_amount), - Side::One => self.limit_orders.collect_and_burn::(lp, tick, sold_amount), + match order.to_sold_pair() { + Pairs::Base => self.limit_orders.collect_and_burn::(lp, tick, sold_amount), + Pairs::Quote => + self.limit_orders.collect_and_burn::(lp, tick, sold_amount), } } - pub fn collect_and_mint_range_order) -> Result>( + pub fn collect_and_mint_range_order< + T, + E, + TryDebit: FnOnce(PoolPairsMap) -> Result, + >( &mut self, lp: &LiquidityProvider, tick_range: core::ops::Range, @@ -277,7 +283,7 @@ impl PoolState { size: range_orders::Size, ) -> Result< ( - SideMap, + PoolPairsMap, range_orders::Liquidity, range_orders::Collected, range_orders::PositionInfo, @@ -291,7 +297,7 @@ impl PoolState { &self, tick_range: core::ops::Range, liquidity: Liquidity, - ) -> Result, range_orders::LiquidityToAmountsError> { + ) -> Result, range_orders::LiquidityToAmountsError> { self.range_orders .liquidity_to_amounts::(liquidity, tick_range.start, tick_range.end) } @@ -299,7 +305,7 @@ impl PoolState { pub fn required_asset_ratio_for_range_order( &self, tick_range: core::ops::Range, - ) -> Result, range_orders::RequiredAssetRatioError> { + ) -> Result, range_orders::RequiredAssetRatioError> { self.range_orders .required_asset_ratio::(tick_range.start, tick_range.end) } @@ -336,21 +342,21 @@ impl PoolState { pub fn limit_order( &self, lp: &LiquidityProvider, - order: Order, + order: Side, tick: Tick, ) -> Result< (limit_orders::Collected, limit_orders::PositionInfo), limit_orders::PositionError, > { match order { - Order::Sell => self.limit_orders.position::(lp, tick), - Order::Buy => self.limit_orders.position::(lp, tick), + Side::Sell => self.limit_orders.position::(lp, tick), + Side::Buy => self.limit_orders.position::(lp, tick), } } pub fn limit_orders( &self, - order: Order, + order: Side, ) -> sp_std::boxed::Box< dyn '_ + Iterator< @@ -363,8 +369,8 @@ impl PoolState { >, > { match order { - Order::Sell => sp_std::boxed::Box::new(self.limit_orders.positions::()), - Order::Buy => sp_std::boxed::Box::new(self.limit_orders.positions::()), + Side::Sell => sp_std::boxed::Box::new(self.limit_orders.positions::()), + Side::Buy => sp_std::boxed::Box::new(self.limit_orders.positions::()), } } @@ -376,10 +382,10 @@ impl PoolState { self.range_orders.fee_hundredth_pips } - pub fn limit_order_liquidity(&self, order: Order) -> Vec<(Tick, Amount)> { + pub fn limit_order_liquidity(&self, order: Side) -> Vec<(Tick, Amount)> { match order { - Order::Sell => self.limit_orders.liquidity::(), - Order::Buy => self.limit_orders.liquidity::(), + Side::Sell => self.limit_orders.liquidity::(), + Side::Buy => self.limit_orders.liquidity::(), } } @@ -390,15 +396,15 @@ impl PoolState { pub fn limit_order_depth( &mut self, range: core::ops::Range, - ) -> Result, Amount)>, limit_orders::DepthError> { - Ok(SideMap { - zero: ( - self.limit_orders.current_sqrt_price::(), - self.limit_orders.depth::(range.clone())?, + ) -> Result, Amount)>, limit_orders::DepthError> { + Ok(PoolPairsMap { + base: ( + self.limit_orders.current_sqrt_price::(), + self.limit_orders.depth::(range.clone())?, ), - one: ( - self.limit_orders.current_sqrt_price::(), - self.limit_orders.depth::(range)?, + quote: ( + self.limit_orders.current_sqrt_price::(), + self.limit_orders.depth::(range)?, ), }) } @@ -406,15 +412,15 @@ impl PoolState { pub fn range_order_depth( &self, range: core::ops::Range, - ) -> Result, Amount)>, range_orders::DepthError> { - self.range_orders.depth(range.start, range.end).map(|assets| SideMap { - zero: ( - self.range_orders.current_sqrt_price::().map(sqrt_price_to_price), - assets[Side::Zero], + ) -> Result, Amount)>, range_orders::DepthError> { + self.range_orders.depth(range.start, range.end).map(|assets| PoolPairsMap { + base: ( + self.range_orders.current_sqrt_price::().map(sqrt_price_to_price), + assets[Pairs::Base], ), - one: ( - self.range_orders.current_sqrt_price::().map(sqrt_price_to_price), - assets[Side::One], + quote: ( + self.range_orders.current_sqrt_price::().map(sqrt_price_to_price), + assets[Pairs::Quote], ), }) } @@ -423,7 +429,8 @@ impl PoolState { pub fn set_fees( &mut self, fee_hundredth_pips: u32, - ) -> Result>, SetFeesError> { + ) -> Result>, SetFeesError> + { self.range_orders.set_fees(fee_hundredth_pips)?; self.limit_orders.set_fees(fee_hundredth_pips) } @@ -446,8 +453,9 @@ impl PoolState { pub fn collect_all_limit_orders( &mut self, - ) -> SideMap> - { + ) -> PoolPairsMap< + Vec<(LiquidityProvider, Tick, limit_orders::Collected, limit_orders::PositionInfo)>, + > { self.limit_orders.collect_all() } diff --git a/state-chain/amm/src/limit_orders.rs b/state-chain/amm/src/limit_orders.rs index 8a84a1ee6e..51a1862c76 100644 --- a/state-chain/amm/src/limit_orders.rs +++ b/state-chain/amm/src/limit_orders.rs @@ -32,8 +32,8 @@ use sp_std::vec::Vec; use crate::common::{ is_tick_valid, mul_div_ceil, mul_div_floor, sqrt_price_at_tick, sqrt_price_to_price, - tick_at_sqrt_price, Amount, OneToZero, Price, SetFeesError, SideMap, SqrtPriceQ64F96, Tick, - ZeroToOne, MAX_LP_FEE, ONE_IN_HUNDREDTH_PIPS, PRICE_FRACTIONAL_BITS, + tick_at_sqrt_price, Amount, BaseToQuote, PoolPairsMap, Price, QuoteToBase, SetFeesError, + SqrtPriceQ64F96, Tick, MAX_LP_FEE, ONE_IN_HUNDREDTH_PIPS, PRICE_FRACTIONAL_BITS, }; // This is the maximum liquidity/amount of an asset that can be sold at a single tick/price. If an @@ -205,13 +205,13 @@ pub(super) trait SwapDirection: crate::common::SwapDirection { pools: &'_ mut BTreeMap, ) -> Option>; } -impl SwapDirection for ZeroToOne { +impl SwapDirection for BaseToQuote { fn input_amount_ceil(output: Amount, price: Price) -> Amount { mul_div_ceil(output, U256::one() << PRICE_FRACTIONAL_BITS, price) } fn input_amount_floor(output: Amount, price: Price) -> Amount { - OneToZero::output_amount_floor(output, price) + QuoteToBase::output_amount_floor(output, price) } fn output_amount_floor(input: Amount, price: Price) -> Amount { @@ -224,13 +224,13 @@ impl SwapDirection for ZeroToOne { pools.last_entry() } } -impl SwapDirection for OneToZero { +impl SwapDirection for QuoteToBase { fn input_amount_ceil(output: Amount, price: Price) -> Amount { mul_div_ceil(output, price, U256::one() << PRICE_FRACTIONAL_BITS) } fn input_amount_floor(output: Amount, price: Price) -> Amount { - ZeroToOne::output_amount_floor(output, price) + BaseToQuote::output_amount_floor(output, price) } fn output_amount_floor(input: Amount, price: Price) -> Amount { @@ -381,19 +381,20 @@ pub(super) struct PoolState { /// The ID the next FixedPool that is created will use. next_pool_instance: u128, /// All the FixedPools that have some liquidity. They are grouped into all those that are - /// selling asset `Zero` and all those that are selling asset `One` used the SideMap. - fixed_pools: SideMap>, + /// selling asset `Base` and all those that are selling asset `Quote` used the PoolPairsMap. + fixed_pools: PoolPairsMap>, /// All the Positions that either are providing liquidity currently, or were providing /// liquidity directly after the last time they where updated. They are grouped into all those - /// that are selling asset `Zero` and all those that are selling asset `One` used the SideMap. - /// Therefore there can be positions stored here that don't provide any liquidity. - positions: SideMap>, + /// that are selling asset `Base` and all those that are selling asset `Quote` used the + /// PoolPairsMap. Therefore there can be positions stored here that don't provide any + /// liquidity. + positions: PoolPairsMap>, /// Total fees earned over all time - total_fees_earned: SideMap, + total_fees_earned: PoolPairsMap, /// Total of all swap inputs over all time (not including fees) - total_swap_inputs: SideMap, + total_swap_inputs: PoolPairsMap, /// Total of all swap outputs over all time - total_swap_outputs: SideMap, + total_swap_outputs: PoolPairsMap, } impl PoolState { @@ -441,38 +442,38 @@ impl PoolState { }) } - /// Runs collect for all positions in the pool. Returns a SideMap + /// Runs collect for all positions in the pool. Returns a PoolPairsMap /// containing the state and fees collected from every position. The positions are grouped into - /// a SideMap by the asset they sell. + /// a PoolPairsMap by the asset they sell. /// /// This function never panics. #[allow(clippy::type_complexity)] pub(super) fn collect_all( &mut self, - ) -> SideMap> { + ) -> PoolPairsMap> { // We must collect all positions before we can change the fee, otherwise the fee and swapped // liquidity calculations would be wrong. - SideMap::from_array([ - self.positions[!::INPUT_SIDE] + PoolPairsMap::from_array([ + self.positions[!::INPUT_SIDE] .keys() .cloned() .collect::>() .into_iter() .map(|(sqrt_price, lp)| { let (collected, position_info) = - self.inner_collect::(&lp, sqrt_price).unwrap(); + self.inner_collect::(&lp, sqrt_price).unwrap(); (lp.clone(), tick_at_sqrt_price(sqrt_price), collected, position_info) }) .collect(), - self.positions[!::INPUT_SIDE] + self.positions[!::INPUT_SIDE] .keys() .cloned() .collect::>() .into_iter() .map(|(sqrt_price, lp)| { let (collected, position_info) = - self.inner_collect::(&lp, sqrt_price).unwrap(); + self.inner_collect::(&lp, sqrt_price).unwrap(); (lp.clone(), tick_at_sqrt_price(sqrt_price), collected, position_info) }) @@ -481,16 +482,17 @@ impl PoolState { } /// Sets the fee for the pool. This will apply to future swaps. The fee may not be set - /// higher than 50%. Also runs collect for all positions in the pool. Returns a SideMap + /// higher than 50%. Also runs collect for all positions in the pool. Returns a PoolPairsMap /// containing the state and fees collected from every position as part of the set_fees - /// operation. The positions are grouped into a SideMap by the asset they sell. + /// operation. The positions are grouped into a PoolPairsMap by the asset they sell. /// /// This function never panics. #[allow(clippy::type_complexity)] pub(super) fn set_fees( &mut self, fee_hundredth_pips: u32, - ) -> Result>, SetFeesError> { + ) -> Result>, SetFeesError> + { Self::validate_fees(fee_hundredth_pips) .then_some(()) .ok_or(SetFeesError::InvalidFeeAmount)?; @@ -509,8 +511,8 @@ impl PoolState { /// Swaps the specified Amount into the other currency until sqrt_price_limit is reached (If /// Some), and returns the resulting Amount and the remaining input Amount. The direction of the - /// swap is controlled by the generic type parameter `SD`, by setting it to `ZeroToOne` or - /// `OneToZero`. Note sqrt_price_limit is inclusive. + /// swap is controlled by the generic type parameter `SD`, by setting it to `BaseToQuote` or + /// `QuoteToBase`. Note sqrt_price_limit is inclusive. /// /// This function never panics pub(super) fn swap( diff --git a/state-chain/amm/src/limit_orders/tests.rs b/state-chain/amm/src/limit_orders/tests.rs index d30fad9b6a..e7d8cacf89 100644 --- a/state-chain/amm/src/limit_orders/tests.rs +++ b/state-chain/amm/src/limit_orders/tests.rs @@ -29,8 +29,8 @@ fn max_liquidity() { } for price in [MIN_SQRT_PRICE, MAX_SQRT_PRICE].map(sqrt_price_to_price) { - checks!(ZeroToOne, price); - checks!(OneToZero, price); + checks!(BaseToQuote, price); + checks!(QuoteToBase, price); } } @@ -294,7 +294,7 @@ fn historics() { let amount: Amount = 1000.into(); let mut pool_state = PoolState::new(MAX_LP_FEE).unwrap(); assert_eq!( - assert_ok!(pool_state.collect_and_mint::(&lp, 0, amount)), + assert_ok!(pool_state.collect_and_mint::(&lp, 0, amount)), ( Collected { fees: Amount::zero(), @@ -311,10 +311,10 @@ fn historics() { let bought_amount = Amount::from(24); let fees = Amount::from(24); - pool_state.swap::(swap_amount, None); + pool_state.swap::(swap_amount, None); assert_eq!( - assert_ok!(pool_state.collect::(&lp, 0)), + assert_ok!(pool_state.collect::(&lp, 0)), ( Collected { fees, @@ -327,10 +327,10 @@ fn historics() { ) ); - pool_state.swap::(swap_amount, None); + pool_state.swap::(swap_amount, None); assert_eq!( - assert_ok!(pool_state.collect::(&lp, 0)), + assert_ok!(pool_state.collect::(&lp, 0)), ( Collected { fees, @@ -343,10 +343,10 @@ fn historics() { ) ); - pool_state.swap::(swap_amount, None); + pool_state.swap::(swap_amount, None); assert_eq!( - assert_ok!(pool_state.collect::(&lp, 0)), + assert_ok!(pool_state.collect::(&lp, 0)), ( Collected { fees, @@ -360,7 +360,7 @@ fn historics() { ); assert_eq!( - assert_ok!(pool_state.collect_and_burn::(&lp, 0, amount)), + assert_ok!(pool_state.collect_and_burn::(&lp, 0, amount)), ( amount - Amount::from(75), Collected { @@ -424,8 +424,8 @@ fn mint() { } } - inner::(); - inner::(); + inner::(); + inner::(); } #[test] @@ -581,8 +581,8 @@ fn burn() { } } - inner::(); - inner::(); + inner::(); + inner::(); } #[test] @@ -634,8 +634,8 @@ fn swap() { } } - inner::(); - inner::(); + inner::(); + inner::(); // Partial liquidity, multiple prices { @@ -645,18 +645,18 @@ fn swap() { (U256::from(150000000)..=U256::from(150010000), 1), ] { let mut pool_state = PoolState::new(0).unwrap(); - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), tick, 100000000.into() )); - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), offset + tick_at_sqrt_price(sqrt_price_at_tick(tick) * U256::from(4).integer_sqrt()), 100000000.into() )); - let (output, remaining) = pool_state.swap::(75000000.into(), None); + let (output, remaining) = pool_state.swap::(75000000.into(), None); assert!(range.contains(&output)); assert_eq!(remaining, Amount::zero()); } @@ -668,18 +668,18 @@ fn swap() { (U256::from(119998000)..=U256::from(120000000), 1), ] { let mut pool_state = PoolState::new(0).unwrap(); - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), tick, 100000000.into() )); - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), offset + tick_at_sqrt_price(sqrt_price_at_tick(tick) * U256::from(4).integer_sqrt()), 100000000.into() )); - let (output, remaining) = pool_state.swap::(180000000.into(), None); + let (output, remaining) = pool_state.swap::(180000000.into(), None); assert!(range.contains(&output)); assert_eq!(remaining, Amount::zero()); } @@ -689,32 +689,32 @@ fn swap() { { let mut pool_state = PoolState::new(0).unwrap(); let tick = 0; - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), tick, 100.into() )); - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), tick_at_sqrt_price(sqrt_price_at_tick(tick) * U256::from(4).integer_sqrt()), 100.into() )); - assert_eq!(pool_state.swap::(150.into(), None), (200.into(), 24.into())); + assert_eq!(pool_state.swap::(150.into(), None), (200.into(), 24.into())); } { let mut pool_state = PoolState::new(0).unwrap(); let tick = 0; - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), tick, 100.into() )); - assert_ok!(pool_state.collect_and_mint::( + assert_ok!(pool_state.collect_and_mint::( &LiquidityProvider::from([0; 32]), tick_at_sqrt_price(sqrt_price_at_tick(tick) * U256::from(4).integer_sqrt()), 100.into() )); - assert_eq!(pool_state.swap::(550.into(), None), (200.into(), 50.into())); + assert_eq!(pool_state.swap::(550.into(), None), (200.into(), 50.into())); } } @@ -726,7 +726,7 @@ fn maximum_liquidity_swap() { for tick in MIN_TICK..=MAX_TICK { assert_eq!( pool_state - .collect_and_mint::( + .collect_and_mint::( &LiquidityProvider::from([0; 32]), tick, MAX_FIXED_POOL_LIQUIDITY @@ -738,7 +738,7 @@ fn maximum_liquidity_swap() { assert_eq!( MAX_FIXED_POOL_LIQUIDITY * (1 + MAX_TICK - MIN_TICK), - std::iter::repeat_with(|| { pool_state.swap::(Amount::MAX, None).0 }) + std::iter::repeat_with(|| { pool_state.swap::(Amount::MAX, None).0 }) .take_while(|x| !x.is_zero()) .fold(Amount::zero(), |acc, x| acc + x) ); diff --git a/state-chain/amm/src/range_orders.rs b/state-chain/amm/src/range_orders.rs index 1bbc98c3b4..d1a5e30d2a 100644 --- a/state-chain/amm/src/range_orders.rs +++ b/state-chain/amm/src/range_orders.rs @@ -31,8 +31,9 @@ use sp_core::{U256, U512}; use crate::common::{ is_sqrt_price_valid, is_tick_valid, mul_div_ceil, mul_div_floor, sqrt_price_at_tick, - tick_at_sqrt_price, Amount, OneToZero, SetFeesError, Side, SideMap, SqrtPriceQ64F96, Tick, - ZeroToOne, MAX_LP_FEE, MAX_TICK, MIN_TICK, ONE_IN_HUNDREDTH_PIPS, SQRT_PRICE_FRACTIONAL_BITS, + tick_at_sqrt_price, Amount, BaseToQuote, Pairs, PoolPairsMap, QuoteToBase, SetFeesError, + SqrtPriceQ64F96, Tick, MAX_LP_FEE, MAX_TICK, MIN_TICK, ONE_IN_HUNDREDTH_PIPS, + SQRT_PRICE_FRACTIONAL_BITS, }; /// This is the invariant wrt xy = k. It represents / is proportional to the depth of the @@ -55,8 +56,8 @@ pub struct Position { /// The `depth` of this range order, this value is proportional to the value of the order i.e. /// the amount of assets that make up the order. liquidity: Liquidity, - last_fee_growth_inside: SideMap, - accumulative_fees: SideMap, + last_fee_growth_inside: PoolPairsMap, + accumulative_fees: PoolPairsMap, original_sqrt_price: SqrtPriceQ64F96, } @@ -69,7 +70,7 @@ impl Position { upper_tick: Tick, upper_delta: &TickDelta, ) -> Collected { - let fee_growth_inside = SideMap::default().map(|side, ()| { + let fee_growth_inside = PoolPairsMap::default().map_with_pair(|side, ()| { let fee_growth_below = if pool_state.current_tick < lower_tick { pool_state.global_fee_growth[side] - lower_delta.fee_growth_outside[side] } else { @@ -84,7 +85,7 @@ impl Position { pool_state.global_fee_growth[side] - fee_growth_below - fee_growth_above }); - let fees = SideMap::default().map(|side, ()| { + let fees = PoolPairsMap::default().map_with_pair(|side, ()| { // DIFF: This behaviour is different than Uniswap's. We use U256 instead of u128 to // calculate fees, therefore it is not possible to overflow the fees here. @@ -101,7 +102,7 @@ impl Position { }); self.accumulative_fees = self .accumulative_fees - .map(|side, accumulative_fees| accumulative_fees.saturating_add(fees[side])); + .map_with_pair(|side, accumulative_fees| accumulative_fees.saturating_add(fees[side])); let collected_fees = Collected { fees, accumulative_fees: self.accumulative_fees, @@ -149,7 +150,7 @@ pub struct TickDelta { /// calculate the fees earned by an order. It is stored this way as this value will only change /// when the price moves across this tick, thereby limiting the computation/state changes /// needed during a swap. - fee_growth_outside: SideMap, + fee_growth_outside: PoolPairsMap, } #[derive(Clone, Debug, TypeInfo, Encode, Decode, Serialize, Deserialize)] @@ -160,26 +161,26 @@ pub struct PoolState { /// Note the current_sqrt_price can reach MAX_SQRT_PRICE, but only if the tick is MAX_TICK current_sqrt_price: SqrtPriceQ64F96, /// This is the highest tick that represents a strictly lower price than the - /// current_sqrt_price. `current_tick` is the tick that when you swap ZeroToOne the + /// current_sqrt_price. `current_tick` is the tick that when you swap BaseToQuote the /// `current_sqrt_price` is moving towards (going down in literal value), and will cross when /// `current_sqrt_price` reaches it. `current_tick + 1` is the tick the price is moving towards - /// (going up in literal value) when you swap OneToZero and will cross when + /// (going up in literal value) when you swap QuoteToBase and will cross when /// `current_sqrt_price` reaches it, current_tick: Tick, /// The total liquidity/depth at the `current_sqrt_price` current_liquidity: Liquidity, /// The total fees earned over all time per unit liquidity - global_fee_growth: SideMap, + global_fee_growth: PoolPairsMap, /// All the ticks that have at least one range order that starts or ends at it, i.e. those /// ticks where liquidity_gross is non-zero. liquidity_map: BTreeMap, positions: BTreeMap<(LiquidityProvider, Tick, Tick), Position>, /// Total fees earned over all time - total_fees_earned: SideMap, + total_fees_earned: PoolPairsMap, /// Total of all swap inputs over all time (not including fees) - total_swap_inputs: SideMap, + total_swap_inputs: PoolPairsMap, /// Total of all swap outputs over all time - total_swap_outputs: SideMap, + total_swap_outputs: PoolPairsMap, } pub(super) trait SwapDirection: crate::common::SwapDirection { @@ -225,7 +226,7 @@ pub(super) trait SwapDirection: crate::common::SwapDirection { fn current_tick_after_crossing_tick(tick: Tick) -> Tick; } -impl SwapDirection for ZeroToOne { +impl SwapDirection for BaseToQuote { fn further_liquidity(current_tick: Tick) -> bool { current_tick >= MIN_TICK } @@ -294,7 +295,7 @@ impl SwapDirection for ZeroToOne { } } -impl SwapDirection for OneToZero { +impl SwapDirection for QuoteToBase { fn further_liquidity(current_tick: Tick) -> bool { current_tick < MAX_TICK } @@ -414,15 +415,15 @@ pub enum LiquidityToAmountsError { #[derive(Default, Debug, PartialEq, Eq, TypeInfo, Encode, Decode, MaxEncodedLen)] pub struct Collected { - pub fees: SideMap, - pub accumulative_fees: SideMap, + pub fees: PoolPairsMap, + pub accumulative_fees: PoolPairsMap, pub original_sqrt_price: SqrtPriceQ64F96, } #[derive(Debug, PartialEq, Eq, TypeInfo, Encode, Decode, MaxEncodedLen)] pub enum Size { Liquidity { liquidity: Liquidity }, - Amount { maximum: SideMap, minimum: SideMap }, + Amount { maximum: PoolPairsMap, minimum: PoolPairsMap }, } #[derive(Default, Debug, PartialEq, Eq, TypeInfo, Encode, Decode, MaxEncodedLen)] @@ -532,7 +533,7 @@ impl PoolState { /// This function never panics /// /// If this function returns an `Err(_)` no state changes have occurred - pub(super) fn collect_and_mint) -> Result>( + pub(super) fn collect_and_mint) -> Result>( &mut self, lp: &LiquidityProvider, lower_tick: Tick, @@ -648,7 +649,8 @@ impl PoolState { lower_tick: Tick, upper_tick: Tick, size: Size, - ) -> Result<(SideMap, Liquidity, Collected, PositionInfo), PositionError> { + ) -> Result<(PoolPairsMap, Liquidity, Collected, PositionInfo), PositionError> + { Self::validate_position_range(lower_tick, upper_tick)?; if let Some(mut position) = self.positions.get(&(lp.clone(), lower_tick, upper_tick)).cloned() @@ -753,8 +755,8 @@ impl PoolState { /// Swaps the specified Amount into the other currency until sqrt_price_limit is reached (If /// Some), and returns the resulting Amount and the remaining input Amount. The direction of the - /// swap is controlled by the generic type parameter `SD`, by setting it to `ZeroToOne` or - /// `OneToZero`. + /// swap is controlled by the generic type parameter `SD`, by setting it to `BaseToQuote` or + /// `QuoteToBase`. /// /// This function never panics pub(super) fn swap( @@ -872,8 +874,9 @@ impl PoolState { assert!(!SD::sqrt_price_op_more_than(sqrt_price_next, sqrt_price_at_delta)); if sqrt_price_next == sqrt_price_at_delta { - delta.fee_growth_outside = SideMap::default() - .map(|side, ()| self.global_fee_growth[side] - delta.fee_growth_outside[side]); + delta.fee_growth_outside = PoolPairsMap::default().map_with_pair(|side, ()| { + self.global_fee_growth[side] - delta.fee_growth_outside[side] + }); self.current_sqrt_price = sqrt_price_next; self.current_tick = SD::current_tick_after_crossing_tick(*tick_at_delta); @@ -910,7 +913,7 @@ impl PoolState { &self, lower_tick: Tick, upper_tick: Tick, - ) -> Result, RequiredAssetRatioError> { + ) -> Result, RequiredAssetRatioError> { Self::validate_position_range::(lower_tick, upper_tick) .map_err(|_err| RequiredAssetRatioError::InvalidTickRange)?; Ok(self @@ -932,7 +935,7 @@ impl PoolState { liquidity: Liquidity, lower_tick: Tick, upper_tick: Tick, - ) -> Result, LiquidityToAmountsError> { + ) -> Result, LiquidityToAmountsError> { Self::validate_position_range::(lower_tick, upper_tick) .map_err(|_err| LiquidityToAmountsError::InvalidTickRange)?; if liquidity > MAX_TICK_GROSS_LIQUIDITY { @@ -947,10 +950,10 @@ impl PoolState { liquidity: Liquidity, lower_tick: Tick, upper_tick: Tick, - ) -> (SideMap, Liquidity) { + ) -> (PoolPairsMap, Liquidity) { if self.current_tick < lower_tick { ( - SideMap::from_array([ + PoolPairsMap::from_array([ (if ROUND_UP { zero_amount_delta_ceil } else { zero_amount_delta_floor })( sqrt_price_at_tick(lower_tick), sqrt_price_at_tick(upper_tick), @@ -962,7 +965,7 @@ impl PoolState { ) } else if self.current_tick < upper_tick { ( - SideMap::from_array([ + PoolPairsMap::from_array([ (if ROUND_UP { zero_amount_delta_ceil } else { zero_amount_delta_floor })( self.current_sqrt_price, sqrt_price_at_tick(upper_tick), @@ -978,7 +981,7 @@ impl PoolState { ) } else { ( - SideMap::from_array([ + PoolPairsMap::from_array([ 0.into(), (if ROUND_UP { one_amount_delta_ceil } else { one_amount_delta_floor })( sqrt_price_at_tick(lower_tick), @@ -1005,8 +1008,8 @@ impl PoolState { let (possible, _) = self.inner_liquidity_to_amounts::(liquidity, lower_tick, upper_tick); - if possible[Side::Zero] < minimum[Side::Zero] || - possible[Side::One] < minimum[Side::One] + if possible[Pairs::Base] < minimum[Pairs::Base] || + possible[Pairs::Quote] < minimum[Pairs::Quote] { None } else { @@ -1020,16 +1023,16 @@ impl PoolState { &self, lower_tick: Tick, upper_tick: Tick, - amounts: SideMap, + amounts: PoolPairsMap, ) -> Liquidity { // Inverse of `zero_amount_delta_ceil` fn zero_amount_to_liquidity( lower_sqrt_price: SqrtPriceQ64F96, upper_sqrt_price: SqrtPriceQ64F96, - amounts: SideMap, + amounts: PoolPairsMap, ) -> U512 { (U512::saturating_mul( - amounts[Side::Zero].into(), + amounts[Pairs::Base].into(), U256::full_mul(lower_sqrt_price, upper_sqrt_price), ) / U512::from(upper_sqrt_price - lower_sqrt_price)) >> SQRT_PRICE_FRACTIONAL_BITS @@ -1039,9 +1042,9 @@ impl PoolState { fn one_amount_to_liquidity( lower_sqrt_price: SqrtPriceQ64F96, upper_sqrt_price: SqrtPriceQ64F96, - amounts: SideMap, + amounts: PoolPairsMap, ) -> U512 { - U256::full_mul(amounts[Side::One], U256::one() << SQRT_PRICE_FRACTIONAL_BITS) / + U256::full_mul(amounts[Pairs::Quote], U256::one() << SQRT_PRICE_FRACTIONAL_BITS) / (upper_sqrt_price - lower_sqrt_price) } @@ -1127,7 +1130,7 @@ impl PoolState { .iter() .map(|(tick, tick_delta)| { liquidity = liquidity - .checked_add_signed(OneToZero::liquidity_delta_on_crossing_tick(tick_delta)) + .checked_add_signed(QuoteToBase::liquidity_delta_on_crossing_tick(tick_delta)) .unwrap(); (*tick, liquidity) @@ -1139,7 +1142,7 @@ impl PoolState { &self, lower_tick: Tick, upper_tick: Tick, - ) -> Result, DepthError> { + ) -> Result, DepthError> { if !is_tick_valid(lower_tick) || !is_tick_valid(upper_tick) { return Err(DepthError::InvalidTick) } @@ -1156,7 +1159,7 @@ impl PoolState { .map(|(tick, tick_delta)| (tick, tick_delta.liquidity_delta)) .chain(core::iter::once((&upper_tick, 0 /* value doesn't matter */))) .fold( - (liquidity_at_lower_tick, lower_tick, SideMap::::default()), + (liquidity_at_lower_tick, lower_tick, PoolPairsMap::::default()), |(liquidity, previous_tick, assets), (current_tick, liquidity_delta)| { ( // Addition is guaranteed to never overflow, see test `max_liquidity` diff --git a/state-chain/amm/src/range_orders/tests.rs b/state-chain/amm/src/range_orders/tests.rs index 35aa2ee58b..80c8ad47b0 100644 --- a/state-chain/amm/src/range_orders/tests.rs +++ b/state-chain/amm/src/range_orders/tests.rs @@ -4,7 +4,7 @@ use rand::{prelude::Distribution, Rng, SeedableRng}; #[cfg(feature = "slow-tests")] use crate::common::MIN_SQRT_PRICE; -use crate::{common::Side, test_utilities::rng_u256_inclusive_bound}; +use crate::{common::Pairs, test_utilities::rng_u256_inclusive_bound}; use super::*; @@ -59,14 +59,14 @@ fn r_non_zero() { #[test] fn output_amounts_bounded() { // Note these values are significant over-estimates of the maximum output amount - OneToZero::output_amount_delta_floor( + QuoteToBase::output_amount_delta_floor( sqrt_price_at_tick(MIN_TICK), sqrt_price_at_tick(MAX_TICK), MAX_TICK_GROSS_LIQUIDITY, ) .checked_mul((1 + MAX_TICK - MIN_TICK).into()) .unwrap(); - ZeroToOne::output_amount_delta_floor( + BaseToQuote::output_amount_delta_floor( sqrt_price_at_tick(MAX_TICK), sqrt_price_at_tick(MIN_TICK), MAX_TICK_GROSS_LIQUIDITY, @@ -82,7 +82,7 @@ fn maximum_liquidity_swap() { let mut pool_state = PoolState::new(0, MIN_SQRT_PRICE).unwrap(); - let minted_amounts: SideMap = (MIN_TICK..0) + let minted_amounts: PoolPairsMap = (MIN_TICK..0) .map(|lower_tick| (lower_tick, -lower_tick)) .map(|(lower_tick, upper_tick)| { pool_state @@ -98,9 +98,9 @@ fn maximum_liquidity_swap() { }) .fold(Default::default(), |acc, x| acc + x); - let (output, _remaining) = pool_state.swap::(Amount::MAX, None); + let (output, _remaining) = pool_state.swap::(Amount::MAX, None); - assert!(((minted_amounts[Side::Zero] - (MAX_TICK - MIN_TICK) /* Maximum rounding down by one per swap iteration */)..minted_amounts[Side::Zero]).contains(&output)); + assert!(((minted_amounts[Pairs::Base] - (MAX_TICK - MIN_TICK) /* Maximum rounding down by one per swap iteration */)..minted_amounts[Pairs::Base]).contains(&output)); } #[test] @@ -157,7 +157,7 @@ fn test_amounts_to_liquidity() { pool_state.inner_amounts_to_liquidity(lower, upper, amounts); let maximum_error_from_rounding_amount = - [amounts[Side::Zero], amounts[Side::One]] + [amounts[Pairs::Base], amounts[Pairs::Quote]] .into_iter() .filter(|amount| !amount.is_zero()) .map(|amount| { diff --git a/state-chain/amm/src/tests.rs b/state-chain/amm/src/tests.rs index c5885b7bd7..a0d1c9110a 100644 --- a/state-chain/amm/src/tests.rs +++ b/state-chain/amm/src/tests.rs @@ -15,7 +15,7 @@ type PoolState = super::PoolState; #[test] fn test_basic_swaps() { - fn inner(order: Order) { + fn inner(order: Side) { { let mut pool_state = PoolState { limit_orders: limit_orders::PoolState::new(0).unwrap(), @@ -50,9 +50,9 @@ fn test_basic_swaps() { } { - let initial_sqrt_price = match order.to_sold_side() { - Side::Zero => MAX_SQRT_PRICE, - Side::One => MIN_SQRT_PRICE, + let initial_sqrt_price = match order.to_sold_pair() { + Pairs::Base => MAX_SQRT_PRICE, + Pairs::Quote => MIN_SQRT_PRICE, }; let mut pool_state = PoolState { limit_orders: limit_orders::PoolState::new(0).unwrap(), @@ -82,16 +82,16 @@ fn test_basic_swaps() { assert_eq!( pool_state.swap(order, Amount::MAX, None), ( - minted_amounts[!order.to_sold_side()] - 1, /* -1 is due to rounding down */ - Amount::MAX - minted_amounts[!order.to_sold_side()] + minted_amounts[!order.to_sold_pair()] - 1, /* -1 is due to rounding down */ + Amount::MAX - minted_amounts[!order.to_sold_pair()] ) ); } { - let initial_sqrt_price = match order.to_sold_side() { - Side::Zero => MAX_SQRT_PRICE, - Side::One => MIN_SQRT_PRICE, + let initial_sqrt_price = match order.to_sold_pair() { + Pairs::Base => MAX_SQRT_PRICE, + Pairs::Quote => MIN_SQRT_PRICE, }; let mut pool_state = PoolState { limit_orders: limit_orders::PoolState::new(0).unwrap(), @@ -133,21 +133,21 @@ fn test_basic_swaps() { assert_eq!( pool_state.swap(order, Amount::MAX, None), ( - limit_order_liquidity + range_order_minted_amounts[!order.to_sold_side()] - 1, /* -1 is due + limit_order_liquidity + range_order_minted_amounts[!order.to_sold_pair()] - 1, /* -1 is due * to rounding * down */ Amount::MAX - (limit_order_liquidity + - range_order_minted_amounts[!order.to_sold_side()]) - + range_order_minted_amounts[!order.to_sold_pair()]) - 1 /* -1 is due to rounding down */ ) ); } { - let initial_sqrt_price = match order.to_sold_side() { - Side::Zero => MAX_SQRT_PRICE, - Side::One => MIN_SQRT_PRICE, + let initial_sqrt_price = match order.to_sold_pair() { + Pairs::Base => MAX_SQRT_PRICE, + Pairs::Quote => MIN_SQRT_PRICE, }; let mut pool_state = PoolState { limit_orders: limit_orders::PoolState::new(0).unwrap(), @@ -193,19 +193,19 @@ fn test_basic_swaps() { assert_eq!( pool_state.swap(order, Amount::MAX, None), ( - limit_order_liquidity + range_order_minted_amounts[!order.to_sold_side()] - 2, /* -2 is due + limit_order_liquidity + range_order_minted_amounts[!order.to_sold_pair()] - 2, /* -2 is due * to rounding * down */ Amount::MAX - (limit_order_liquidity + - range_order_minted_amounts[!order.to_sold_side()]) + range_order_minted_amounts[!order.to_sold_pair()]) ) ); } } - inner(Order::Sell); - inner(Order::Buy); + inner(Side::Sell); + inner(Side::Buy); } #[test] diff --git a/state-chain/custom-rpc/src/lib.rs b/state-chain/custom-rpc/src/lib.rs index 91663b46c6..dd37483ff6 100644 --- a/state-chain/custom-rpc/src/lib.rs +++ b/state-chain/custom-rpc/src/lib.rs @@ -1,5 +1,5 @@ use cf_amm::{ - common::{Amount, Order, Tick}, + common::{Amount, PoolPairsMap, Side, Tick}, range_orders::Liquidity, }; use cf_chains::{ @@ -21,9 +21,7 @@ use jsonrpsee::{ SubscriptionSink, }; use pallet_cf_governance::GovCallHash; -use pallet_cf_pools::{ - AskBidMap, AssetsMap, PoolInfo, PoolLiquidity, PoolPriceV1, UnidirectionalPoolDepth, -}; +use pallet_cf_pools::{AskBidMap, PoolInfo, PoolLiquidity, PoolPriceV1, UnidirectionalPoolDepth}; use sc_client_api::{BlockchainEvents, HeaderBackend}; use serde::{Deserialize, Serialize}; use sp_core::U256; @@ -243,7 +241,7 @@ pub struct PoolPriceV2 { pub struct RpcPrewitnessedSwap { pub base_asset: OldAsset, pub quote_asset: OldAsset, - pub side: Order, + pub side: Side, pub amounts: Vec, } @@ -368,7 +366,7 @@ pub trait CustomApi { quote_asset: Asset, tick_range: Range, at: Option, - ) -> RpcResult>; + ) -> RpcResult>; #[method(name = "pool_orderbook")] fn cf_pool_orderbook( &self, @@ -415,7 +413,7 @@ pub trait CustomApi { tick_range: Range, liquidity: Liquidity, at: Option, - ) -> RpcResult>; + ) -> RpcResult>; #[method(name = "funding_environment")] fn cf_funding_environment( &self, @@ -449,14 +447,14 @@ pub trait CustomApi { #[subscription(name = "subscribe_pool_price_v2", item = BlockUpdate)] fn cf_subscribe_pool_price_v2(&self, base_asset: Asset, quote_asset: Asset); #[subscription(name = "subscribe_prewitness_swaps", item = BlockUpdate)] - fn cf_subscribe_prewitness_swaps(&self, base_asset: Asset, quote_asset: Asset, side: Order); + fn cf_subscribe_prewitness_swaps(&self, base_asset: Asset, quote_asset: Asset, side: Side); #[method(name = "prewitness_swaps")] fn cf_prewitness_swaps( &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, at: Option, ) -> RpcResult; @@ -898,7 +896,7 @@ where quote_asset: Asset, tick_range: Range, at: Option, - ) -> RpcResult> { + ) -> RpcResult> { self.client .runtime_api() .cf_required_asset_ratio_for_range_order( @@ -946,7 +944,7 @@ where tick_range: Range, liquidity: Liquidity, at: Option, - ) -> RpcResult> { + ) -> RpcResult> { self.client .runtime_api() .cf_pool_range_order_liquidity_value( @@ -1126,7 +1124,7 @@ where sink: SubscriptionSink, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, ) -> Result<(), SubscriptionEmptyError> { self.new_subscription( false, /* only_on_changes */ @@ -1152,7 +1150,7 @@ where &self, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, at: Option, ) -> RpcResult { Ok(RpcPrewitnessedSwap { diff --git a/state-chain/pallets/cf-pools/src/benchmarking.rs b/state-chain/pallets/cf-pools/src/benchmarking.rs index 36c497dab7..dea03d1fbd 100644 --- a/state-chain/pallets/cf-pools/src/benchmarking.rs +++ b/state-chain/pallets/cf-pools/src/benchmarking.rs @@ -136,7 +136,7 @@ mod benchmarks { RawOrigin::Signed(caller.clone()), Asset::Eth, Asset::Usdc, - Order::Sell, + Side::Sell, 0, Some(100), IncreaseOrDecrease::Increase(1_000_000), @@ -161,7 +161,7 @@ mod benchmarks { RawOrigin::Signed(caller.clone()), Asset::Eth, Asset::Usdc, - Order::Sell, + Side::Sell, 0, Some(100), 1_000, @@ -184,7 +184,7 @@ mod benchmarks { RawOrigin::Signed(caller.clone()).into(), Asset::Eth, Asset::Usdc, - Order::Buy, + Side::Buy, 0, Some(0), 10_000, @@ -193,7 +193,7 @@ mod benchmarks { RawOrigin::Signed(caller.clone()).into(), Asset::Eth, Asset::Usdc, - Order::Sell, + Side::Sell, 1, Some(0), 10_000, @@ -240,7 +240,7 @@ mod benchmarks { Box::new(Call::::set_limit_order { base_asset: Asset::Eth, quote_asset: Asset::Usdc, - side: Order::Sell, + side: Side::Sell, id: 0, option_tick: Some(0), sell_amount: 100, diff --git a/state-chain/pallets/cf-pools/src/lib.rs b/state-chain/pallets/cf-pools/src/lib.rs index 773f6b58c6..e39af16fea 100644 --- a/state-chain/pallets/cf-pools/src/lib.rs +++ b/state-chain/pallets/cf-pools/src/lib.rs @@ -2,7 +2,7 @@ use core::ops::Range; use cf_amm::{ - common::{Amount, Order, Price, Side, SideMap, SqrtPriceQ64F96, Tick}, + common::{Amount, PoolPairsMap, Price, Side, SqrtPriceQ64F96, Tick}, limit_orders, limit_orders::{Collected, PositionInfo}, range_orders, @@ -44,7 +44,7 @@ impl_pallet_safe_mode!(PalletSafeMode; range_order_update_enabled, limit_order_u // nature. #[derive(Copy, Clone, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, PartialEq, Eq, Hash)] pub struct AssetPair { - assets: AssetsMap, + assets: PoolPairsMap, } impl AssetPair { pub fn new(base_asset: Asset, quote_asset: Asset) -> Option { @@ -52,7 +52,7 @@ impl AssetPair { assets: match (base_asset, quote_asset) { (STABLE_ASSET, STABLE_ASSET) => None, (_unstable_asset, STABLE_ASSET) => - Some(AssetsMap { base: base_asset, quote: quote_asset }), + Some(PoolPairsMap { base: base_asset, quote: quote_asset }), _ => None, }?, }) @@ -62,81 +62,29 @@ impl AssetPair { Self::new(base_asset, quote_asset).ok_or(Error::::PoolDoesNotExist) } - pub fn from_swap(from: Asset, to: Asset) -> Option<(Self, Order)> { + pub fn from_swap(from: Asset, to: Asset) -> Option<(Self, Side)> { #[allow(clippy::manual_map)] if let Some(asset_pair) = Self::new(from, to) { - Some((asset_pair, Order::Sell)) + Some((asset_pair, Side::Sell)) } else if let Some(asset_pair) = Self::new(to, from) { - Some((asset_pair, Order::Buy)) + Some((asset_pair, Side::Buy)) } else { None } } - pub fn to_swap(base_asset: Asset, quote_asset: Asset, side: Order) -> (Asset, Asset) { + pub fn to_swap(base_asset: Asset, quote_asset: Asset, side: Side) -> (Asset, Asset) { match side { - Order::Buy => (quote_asset, base_asset), - Order::Sell => (base_asset, quote_asset), + Side::Buy => (quote_asset, base_asset), + Side::Sell => (base_asset, quote_asset), } } - pub fn assets(&self) -> AssetsMap { + pub fn assets(&self) -> PoolPairsMap { self.assets } } -#[derive( - Copy, - Clone, - Debug, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - PartialEq, - Eq, - Deserialize, - Serialize, -)] -pub enum Assets { - Base, - Quote, -} -impl core::ops::Not for Assets { - type Output = Self; - - fn not(self) -> Self::Output { - match self { - Assets::Base => Assets::Quote, - Assets::Quote => Assets::Base, - } - } -} -impl From for Assets { - fn from(value: Side) -> Self { - match value { - Side::Zero => Self::Base, - Side::One => Self::Quote, - } - } -} -impl From for Side { - fn from(value: Assets) -> Self { - match value { - Assets::Base => Self::Zero, - Assets::Quote => Self::One, - } - } -} -impl Assets { - fn sell_order(&self) -> Order { - match self { - Assets::Base => Order::Sell, - Assets::Quote => Order::Buy, - } - } -} - #[derive( Copy, Clone, @@ -158,12 +106,12 @@ pub struct AskBidMap { impl AskBidMap { /// Takes a map from an asset to details regarding selling that asset, and returns a map from /// ask/bid to the details associated with the asks or the bids - pub fn from_sell_map(map: AssetsMap) -> Self { + pub fn from_sell_map(map: PoolPairsMap) -> Self { Self { asks: map.base, bids: map.quote } } - pub fn from_fn T>(mut f: F) -> Self { - Self::from_sell_map(AssetsMap { base: f(Order::Sell), quote: f(Order::Buy) }) + pub fn from_fn T>(mut f: F) -> Self { + Self::from_sell_map(PoolPairsMap { base: f(Side::Sell), quote: f(Side::Buy) }) } pub fn map S>(self, mut f: F) -> AskBidMap { @@ -171,84 +119,6 @@ impl AskBidMap { } } -// TODO Move into AMM crate -#[derive( - Copy, - Clone, - Debug, - Default, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - PartialEq, - Eq, - Deserialize, - Serialize, - Hash, -)] -pub struct AssetsMap { - pub base: S, - pub quote: S, -} -impl AssetsMap { - pub fn try_map Result>(self, mut f: F) -> Result, E> { - Ok(AssetsMap { base: f(self.base)?, quote: f(self.quote)? }) - } - - pub fn map R>(self, mut f: F) -> AssetsMap { - AssetsMap { base: f(self.base), quote: f(self.quote) } - } - - pub fn map_with_asset R>(self, mut f: F) -> AssetsMap { - AssetsMap { base: f(Assets::Base, self.base), quote: f(Assets::Quote, self.quote) } - } - - pub fn zip(self, x: AssetsMap) -> AssetsMap<(S, T)> { - AssetsMap { base: (self.base, x.base), quote: (self.quote, x.quote) } - } - - pub fn as_ref(&self) -> AssetsMap<&S> { - AssetsMap { base: &self.base, quote: &self.quote } - } -} -impl IntoIterator for AssetsMap { - type Item = (Assets, T); - - type IntoIter = core::array::IntoIter<(Assets, T), 2>; - - fn into_iter(self) -> Self::IntoIter { - [(Assets::Base, self.base), (Assets::Quote, self.quote)].into_iter() - } -} -impl core::ops::Index for AssetsMap { - type Output = T; - fn index(&self, assets: Assets) -> &T { - match assets { - Assets::Base => &self.base, - Assets::Quote => &self.quote, - } - } -} -impl core::ops::IndexMut for AssetsMap { - fn index_mut(&mut self, assets: Assets) -> &mut T { - match assets { - Assets::Base => &mut self.base, - Assets::Quote => &mut self.quote, - } - } -} -impl From> for AssetsMap { - fn from(value: SideMap) -> Self { - Self { base: value.zero, quote: value.one } - } -} -impl From> for SideMap { - fn from(value: AssetsMap) -> Self { - Self { zero: value.base, one: value.quote } - } -} - pub const PALLET_VERSION: StorageVersion = StorageVersion::new(2); #[frame_support::pallet] @@ -281,13 +151,13 @@ pub mod pallet { pub range_orders_cache: BTreeMap>>, /// A cache of all the limit orders that exist in the pool. This must be kept up to date /// with the underlying pool. These are grouped by the asset the limit order is selling - pub limit_orders_cache: AssetsMap>>, + pub limit_orders_cache: PoolPairsMap>>, pub pool_state: PoolState<(T::AccountId, OrderId)>, } pub type OrderId = u64; - pub type AssetAmounts = AssetsMap; + pub type AssetAmounts = PoolPairsMap; /// Represents an amount of liquidity, either as an exact amount, or through maximum and minimum /// amounts of both assets. Internally those max/min are converted into exact liquidity amounts, @@ -573,7 +443,7 @@ pub mod pallet { lp: T::AccountId, base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, id: OrderId, tick: Tick, sell_amount_change: Option>, @@ -749,7 +619,7 @@ pub mod pallet { new_tick_range.clone(), IncreaseOrDecrease::Increase(range_orders::Size::Amount { minimum: Default::default(), - maximum: withdrawn_asset_amounts.map(Into::into).into(), + maximum: withdrawn_asset_amounts.map(Into::into), }), /* allow_noop */ true, )?; @@ -769,8 +639,8 @@ pub mod pallet { range_orders::Size::Liquidity { liquidity }, RangeOrderSize::AssetAmounts { maximum, minimum } => range_orders::Size::Amount { - maximum: maximum.map(Into::into).into(), - minimum: minimum.map(Into::into).into(), + maximum: maximum.map(Into::into), + minimum: minimum.map(Into::into), }, }), /* allow_noop */ false, @@ -836,8 +706,8 @@ pub mod pallet { range_orders::Size::Liquidity { liquidity }, RangeOrderSize::AssetAmounts { maximum, minimum } => range_orders::Size::Amount { - maximum: maximum.map(Into::into).into(), - minimum: minimum.map(Into::into).into(), + maximum: maximum.map(Into::into), + minimum: minimum.map(Into::into), }, }), /* allow noop */ true, @@ -861,7 +731,7 @@ pub mod pallet { origin: OriginFor, base_asset: any::Asset, quote_asset: any::Asset, - side: Order, + side: Side, id: OrderId, option_tick: Option, amount_change: IncreaseOrDecrease, @@ -873,7 +743,7 @@ pub mod pallet { let lp = T::AccountRoleRegistry::ensure_liquidity_provider(origin)?; Self::try_mutate_order(&lp, base_asset, quote_asset, |asset_pair, pool| { let tick = match ( - pool.limit_orders_cache[side.to_sold_side().into()] + pool.limit_orders_cache[side.to_sold_pair()] .get(&lp) .and_then(|limit_orders| limit_orders.get(&id)) .cloned(), @@ -937,7 +807,7 @@ pub mod pallet { origin: OriginFor, base_asset: any::Asset, quote_asset: any::Asset, - side: Order, + side: Side, id: OrderId, option_tick: Option, sell_amount: AssetAmount, @@ -949,7 +819,7 @@ pub mod pallet { let lp = T::AccountRoleRegistry::ensure_liquidity_provider(origin)?; Self::try_mutate_order(&lp, base_asset, quote_asset, |asset_pair, pool| { let tick = match ( - pool.limit_orders_cache[side.to_sold_side().into()] + pool.limit_orders_cache[side.to_sold_pair()] .get(&lp) .and_then(|limit_orders| limit_orders.get(&id)) .cloned(), @@ -1017,14 +887,14 @@ pub mod pallet { pool.pool_state .set_fees(fee_hundredth_pips) .map_err(|_| Error::::InvalidFeeAmount)? - .try_map(|side, collected_fees| { + .try_map_with_pair(|asset, collected_fees| { for ((lp, id), tick, collected, position_info) in collected_fees.into_iter() { Self::process_limit_order_update( pool, asset_pair, &lp, - Assets::from(side).sell_order(), + asset.sell_order(), id, tick, collected, @@ -1184,7 +1054,7 @@ pub struct RangeOrder { pub id: Amount, pub range: Range, pub liquidity: Liquidity, - pub fees_earned: AssetsMap, + pub fees_earned: PoolPairsMap, } #[derive(Clone, Debug, Encode, Decode, TypeInfo, PartialEq, Eq, Serialize, Deserialize)] @@ -1323,7 +1193,7 @@ impl Pallet { pool: &mut Pool, lp: &T::AccountId, asset_pair: &AssetPair, - side: Order, + side: Side, id: OrderId, tick: cf_amm::common::Tick, sold_amount_change: IncreaseOrDecrease, @@ -1357,7 +1227,7 @@ impl Pallet { let debited_amount: AssetAmount = sold_amount.try_into()?; T::LpBalance::try_debit_account( lp, - asset_pair.assets()[side.to_sold_side().into()], + asset_pair.assets()[side.to_sold_pair()], debited_amount, )?; @@ -1384,7 +1254,7 @@ impl Pallet { let withdrawn_amount: AssetAmount = sold_amount.try_into()?; T::LpBalance::try_credit_account( lp, - asset_pair.assets()[side.to_sold_side().into()], + asset_pair.assets()[side.to_sold_pair()], withdrawn_amount, )?; @@ -1426,7 +1296,7 @@ impl Pallet { tick_range.clone(), size, |required_amounts| { - asset_pair.assets().zip(required_amounts.into()).try_map( + asset_pair.assets().zip(required_amounts).try_map( |(asset, required_amount)| { AssetAmount::try_from(required_amount) .map_err(Into::into) @@ -1493,7 +1363,7 @@ impl Pallet { }), }?; - let assets_withdrawn = asset_pair.assets().zip(assets_withdrawn.into()).try_map( + let assets_withdrawn = asset_pair.assets().zip(assets_withdrawn).try_map( |(asset, amount_withdrawn)| { AssetAmount::try_from(amount_withdrawn).map_err(Into::into).and_then( |amount_withdrawn| { @@ -1514,17 +1384,14 @@ impl Pallet { }; let collected_fees = - asset_pair - .assets() - .zip(collected.fees.into()) - .try_map(|(asset, collected_fees)| { - AssetAmount::try_from(collected_fees).map_err(Into::into).and_then( - |collected_fees| { - T::LpBalance::try_credit_account(lp, asset, collected_fees) - .map(|()| collected_fees) - }, - ) - })?; + asset_pair.assets().zip(collected.fees).try_map(|(asset, collected_fees)| { + AssetAmount::try_from(collected_fees).map_err(Into::into).and_then( + |collected_fees| { + T::LpBalance::try_credit_account(lp, asset, collected_fees) + .map(|()| collected_fees) + }, + ) + })?; if position_info.liquidity == 0 { if let Some(range_orders) = pool.range_orders_cache.get_mut(lp) { @@ -1627,8 +1494,8 @@ impl Pallet { let asset_pair = AssetPair::try_new::(base_asset, quote_asset)?; let mut pool = Pools::::get(asset_pair).ok_or(Error::::PoolDoesNotExist)?; Ok(PoolPriceV2 { - sell: pool.pool_state.current_price(Order::Sell).map(|(_, sqrt_price, _)| sqrt_price), - buy: pool.pool_state.current_price(Order::Buy).map(|(_, sqrt_price, _)| sqrt_price), + sell: pool.pool_state.current_price(Side::Sell).map(|(_, sqrt_price, _)| sqrt_price), + buy: pool.pool_state.current_price(Side::Buy).map(|(_, sqrt_price, _)| sqrt_price), }) } @@ -1636,7 +1503,7 @@ impl Pallet { base_asset: any::Asset, quote_asset: any::Asset, tick_range: Range, - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { let pool_state = Pools::::get(AssetPair::try_new::(base_asset, quote_asset)?) .ok_or(Error::::PoolDoesNotExist)? .pool_state; @@ -1671,13 +1538,13 @@ impl Pallet { Ok(PoolOrderbook { asks: { let mut pool_state = pool_state.clone(); - let sqrt_prices = pool_state.logarithm_sqrt_price_sequence(Order::Buy, orders); + let sqrt_prices = pool_state.logarithm_sqrt_price_sequence(Side::Buy, orders); sqrt_prices .into_iter() .filter_map(|sqrt_price| { let (sold_base_amount, remaining_quote_amount) = - pool_state.swap(Order::Buy, Amount::MAX, Some(sqrt_price)); + pool_state.swap(Side::Buy, Amount::MAX, Some(sqrt_price)); let bought_quote_amount = Amount::MAX - remaining_quote_amount; @@ -1697,13 +1564,13 @@ impl Pallet { }, bids: { let mut pool_state = pool_state; - let sqrt_prices = pool_state.logarithm_sqrt_price_sequence(Order::Sell, orders); + let sqrt_prices = pool_state.logarithm_sqrt_price_sequence(Side::Sell, orders); sqrt_prices .into_iter() .filter_map(|sqrt_price| { let (sold_quote_amount, remaining_base_amount) = - pool_state.swap(Order::Sell, Amount::MAX, Some(sqrt_price)); + pool_state.swap(Side::Sell, Amount::MAX, Some(sqrt_price)); let bought_base_amount = Amount::MAX - remaining_base_amount; @@ -1746,19 +1613,15 @@ impl Pallet { range_orders::DepthError::InvalidTick => Error::::InvalidTick, })?; - Ok(AskBidMap::from_sell_map( - limit_orders - .zip(range_orders) - .map(|_, (limit_orders, range_orders)| { - let to_single_depth = - |(price, depth)| UnidirectionalSubPoolDepth { price, depth }; - UnidirectionalPoolDepth { - limit_orders: to_single_depth(limit_orders), - range_orders: to_single_depth(range_orders), - } - }) - .into(), - )) + Ok(AskBidMap::from_sell_map(limit_orders.zip(range_orders).map( + |(limit_orders, range_orders)| { + let to_single_depth = |(price, depth)| UnidirectionalSubPoolDepth { price, depth }; + UnidirectionalPoolDepth { + limit_orders: to_single_depth(limit_orders), + range_orders: to_single_depth(range_orders), + } + }, + ))) } pub fn pool_liquidity_providers( @@ -1791,7 +1654,7 @@ impl Pallet { .collect()) } - pub fn pools() -> Vec> { + pub fn pools() -> Vec> { Pools::::iter_keys().map(|asset_pair| asset_pair.assets()).collect() } @@ -1840,8 +1703,8 @@ impl Pallet { .ok_or(Error::::PoolDoesNotExist)?; let option_lp = option_lp.as_ref(); Ok(PoolOrders { - limit_orders: AskBidMap::from_sell_map( - pool.limit_orders_cache.as_ref().map_with_asset(|asset, limit_orders_cache| { + limit_orders: AskBidMap::from_sell_map(pool.limit_orders_cache.as_ref().map_with_pair( + |asset, limit_orders_cache| { cf_utilities::conditional::conditional( option_lp, |lp| { @@ -1879,8 +1742,8 @@ impl Pallet { } }) .collect() - }), - ), + }, + )), range_orders: cf_utilities::conditional::conditional( option_lp, |lp| { @@ -1907,7 +1770,7 @@ impl Pallet { id: id.into(), range: tick_range.clone(), liquidity: position_info.liquidity, - fees_earned: collected.accumulative_fees.into(), + fees_earned: collected.accumulative_fees, } }) .collect(), @@ -1919,7 +1782,7 @@ impl Pallet { quote_asset: any::Asset, tick_range: Range, liquidity: Liquidity, - ) -> Result, DispatchError> { + ) -> Result, DispatchError> { let pool = Pools::::get(AssetPair::try_new::(base_asset, quote_asset)?) .ok_or(Error::::PoolDoesNotExist)?; pool.pool_state @@ -1945,7 +1808,7 @@ impl Pallet { pool: &mut Pool, asset_pair: &AssetPair, lp: &T::AccountId, - order: Order, + order: Side, id: OrderId, tick: Tick, collected: Collected, @@ -1955,18 +1818,18 @@ impl Pallet { let collected_fees: AssetAmount = collected.fees.try_into()?; T::LpBalance::try_credit_account( lp, - asset_pair.assets()[(!order.to_sold_side()).into()], + asset_pair.assets()[!order.to_sold_pair()], collected_fees, )?; let bought_amount: AssetAmount = collected.bought_amount.try_into()?; T::LpBalance::try_credit_account( lp, - asset_pair.assets()[(!order.to_sold_side()).into()], + asset_pair.assets()[!order.to_sold_pair()], bought_amount, )?; - let limit_orders = &mut pool.limit_orders_cache[order.to_sold_side().into()]; + let limit_orders = &mut pool.limit_orders_cache[order.to_sold_pair()]; if position_info.amount.is_zero() { if let Some(lp_limit_orders) = limit_orders.get_mut(lp) { lp_limit_orders.remove(&id); diff --git a/state-chain/pallets/cf-pools/src/tests.rs b/state-chain/pallets/cf-pools/src/tests.rs index 878c7bcc3c..7f3ed5a59c 100644 --- a/state-chain/pallets/cf-pools/src/tests.rs +++ b/state-chain/pallets/cf-pools/src/tests.rs @@ -1,9 +1,10 @@ use crate::{ - self as pallet_cf_pools, mock::*, utilities, AskBidMap, AssetAmounts, AssetPair, AssetsMap, + self as pallet_cf_pools, mock::*, utilities, AskBidMap, AssetAmounts, AssetPair, CollectedNetworkFee, Error, Event, FlipBuyInterval, FlipToBurn, LimitOrder, PoolInfo, - PoolOrders, Pools, RangeOrder, RangeOrderSize, ScheduledLimitOrderUpdates, STABLE_ASSET, + PoolOrders, PoolPairsMap, Pools, RangeOrder, RangeOrderSize, ScheduledLimitOrderUpdates, + STABLE_ASSET, }; -use cf_amm::common::{price_at_tick, tick_at_price, Order, Tick, PRICE_FRACTIONAL_BITS}; +use cf_amm::common::{price_at_tick, tick_at_price, Side, Tick, PRICE_FRACTIONAL_BITS}; use cf_primitives::{chains::assets::any::Asset, AssetAmount, SwapOutput}; use cf_test_utilities::{assert_events_match, assert_has_event, last_event}; use cf_traits::AssetConverter; @@ -149,7 +150,7 @@ fn test_sweeping() { RuntimeOrigin::signed(ALICE), ETH, STABLE_ASSET, - Order::Buy, + Side::Buy, 0, Some(TICK), POSITION_0_SIZE, @@ -171,7 +172,7 @@ fn test_sweeping() { RuntimeOrigin::signed(ALICE), ETH, STABLE_ASSET, - Order::Sell, + Side::Sell, 1, Some(TICK), POSITION_1_SIZE, @@ -199,7 +200,7 @@ fn test_buy_back_flip() { Default::default(), price_at_tick(0).unwrap(), )); - for side in [Order::Buy, Order::Sell] { + for side in [Side::Buy, Side::Sell] { assert_ok!(LiquidityPools::set_limit_order( RuntimeOrigin::signed(ALICE), FLIP, @@ -297,7 +298,7 @@ fn can_update_pool_liquidity_fee_and_collect_for_limit_order() { RuntimeOrigin::signed(ALICE), Asset::Eth, STABLE_ASSET, - Order::Sell, + Side::Sell, 0, Some(0), 5_000, @@ -306,7 +307,7 @@ fn can_update_pool_liquidity_fee_and_collect_for_limit_order() { RuntimeOrigin::signed(ALICE), Asset::Eth, STABLE_ASSET, - Order::Buy, + Side::Buy, 1, Some(0), 1_000, @@ -315,7 +316,7 @@ fn can_update_pool_liquidity_fee_and_collect_for_limit_order() { RuntimeOrigin::signed(BOB), Asset::Eth, STABLE_ASSET, - Order::Sell, + Side::Sell, 0, Some(0), 10_000, @@ -324,7 +325,7 @@ fn can_update_pool_liquidity_fee_and_collect_for_limit_order() { RuntimeOrigin::signed(BOB), Asset::Eth, STABLE_ASSET, - Order::Buy, + Side::Buy, 1, Some(0), 10_000, @@ -510,7 +511,7 @@ fn pallet_limit_order_is_in_sync_with_pool() { RuntimeOrigin::signed(ALICE), Asset::Eth, STABLE_ASSET, - Order::Sell, + Side::Sell, 0, Some(0), 100, @@ -519,7 +520,7 @@ fn pallet_limit_order_is_in_sync_with_pool() { RuntimeOrigin::signed(BOB), Asset::Eth, STABLE_ASSET, - Order::Sell, + Side::Sell, 0, Some(tick), 100_000, @@ -528,7 +529,7 @@ fn pallet_limit_order_is_in_sync_with_pool() { RuntimeOrigin::signed(BOB), Asset::Eth, STABLE_ASSET, - Order::Buy, + Side::Buy, 1, Some(tick), 10_000, @@ -585,7 +586,7 @@ fn pallet_limit_order_is_in_sync_with_pool() { lp: ALICE, base_asset: Asset::Eth, quote_asset: STABLE_ASSET, - side: Order::Sell, + side: Side::Sell, id: 0, tick: 0, sell_amount_change: None, @@ -597,7 +598,7 @@ fn pallet_limit_order_is_in_sync_with_pool() { lp: BOB, base_asset: Asset::Eth, quote_asset: STABLE_ASSET, - side: Order::Sell, + side: Side::Sell, id: 0, tick: 100, sell_amount_change: None, @@ -609,7 +610,7 @@ fn pallet_limit_order_is_in_sync_with_pool() { lp: BOB, base_asset: Asset::Eth, quote_asset: STABLE_ASSET, - side: Order::Buy, + side: Side::Buy, id: 1, tick: 100, sell_amount_change: None, @@ -691,7 +692,7 @@ fn update_pool_liquidity_fee_collects_fees_for_range_order() { id: 0.into(), range: range.clone(), liquidity: 1_000_000, - fees_earned: AssetsMap { base: 999.into(), quote: 997.into() } + fees_earned: PoolPairsMap { base: 999.into(), quote: 997.into() } }] }) ); @@ -704,7 +705,7 @@ fn update_pool_liquidity_fee_collects_fees_for_range_order() { id: 0.into(), range: range.clone(), liquidity: 1_000_000, - fees_earned: AssetsMap { base: 999.into(), quote: 997.into() } + fees_earned: PoolPairsMap { base: 999.into(), quote: 997.into() } }] }) ); @@ -757,7 +758,7 @@ fn can_execute_scheduled_limit_order() { Box::new(pallet_cf_pools::Call::::set_limit_order { base_asset: Asset::Flip, quote_asset: STABLE_ASSET, - side: Order::Buy, + side: Side::Buy, id: order_id, option_tick: Some(100), sell_amount: 55, @@ -816,7 +817,7 @@ fn cant_schedule_in_the_past() { Box::new(pallet_cf_pools::Call::::set_limit_order { base_asset: Asset::Flip, quote_asset: STABLE_ASSET, - side: Order::Buy, + side: Side::Buy, id: 0, option_tick: Some(0), sell_amount: 55, @@ -881,7 +882,7 @@ fn can_get_all_pool_orders() { RuntimeOrigin::signed(ALICE), Asset::Eth, STABLE_ASSET, - Order::Sell, + Side::Sell, 4, Some(100), 500_000, @@ -890,7 +891,7 @@ fn can_get_all_pool_orders() { RuntimeOrigin::signed(ALICE), Asset::Eth, STABLE_ASSET, - Order::Sell, + Side::Sell, 5, Some(1000), 600_000, @@ -899,7 +900,7 @@ fn can_get_all_pool_orders() { RuntimeOrigin::signed(ALICE), Asset::Eth, STABLE_ASSET, - Order::Sell, + Side::Sell, 6, Some(100), 700_000, @@ -908,7 +909,7 @@ fn can_get_all_pool_orders() { RuntimeOrigin::signed(ALICE), Asset::Eth, STABLE_ASSET, - Order::Buy, + Side::Buy, 7, Some(1000), 800_000, diff --git a/state-chain/runtime/src/lib.rs b/state-chain/runtime/src/lib.rs index 4be9d27b96..130fa0f2ee 100644 --- a/state-chain/runtime/src/lib.rs +++ b/state-chain/runtime/src/lib.rs @@ -17,7 +17,7 @@ use crate::{ }, }; use cf_amm::{ - common::{Amount, Order, Tick}, + common::{Amount, PoolPairsMap, Side, Tick}, range_orders::Liquidity, }; use cf_chains::{ @@ -36,7 +36,7 @@ pub use frame_system::Call as SystemCall; use pallet_cf_governance::GovCallHash; use pallet_cf_ingress_egress::{ChannelAction, DepositWitness}; use pallet_cf_pools::{ - AskBidMap, AssetPair, AssetsMap, PoolLiquidity, PoolOrderbook, PoolPriceV1, PoolPriceV2, + AskBidMap, AssetPair, PoolLiquidity, PoolOrderbook, PoolPriceV1, PoolPriceV2, UnidirectionalPoolDepth, }; use pallet_cf_reputation::ExclusionList; @@ -1186,7 +1186,7 @@ impl_runtime_apis! { base_asset: Asset, quote_asset: Asset, tick_range: Range, - ) -> Result, DispatchErrorWithMessage> { + ) -> Result, DispatchErrorWithMessage> { LiquidityPools::required_asset_ratio_for_range_order(base_asset, quote_asset, tick_range).map_err(Into::into) } @@ -1211,7 +1211,7 @@ impl_runtime_apis! { quote_asset: Asset, tick_range: Range, liquidity: Liquidity, - ) -> Result, DispatchErrorWithMessage> { + ) -> Result, DispatchErrorWithMessage> { LiquidityPools::pool_range_order_liquidity_value(base_asset, quote_asset, tick_range, liquidity).map_err(Into::into) } @@ -1317,7 +1317,7 @@ impl_runtime_apis! { /// This should *not* be fully trusted as if the deposits that are pre-witnessed will definitely go through. /// This returns a list of swaps in the requested direction that are pre-witnessed in the current block. - fn cf_prewitness_swaps(base_asset: Asset, quote_asset: Asset, side: Order) -> Vec { + fn cf_prewitness_swaps(base_asset: Asset, quote_asset: Asset, side: Side) -> Vec { let (from, to) = AssetPair::to_swap(base_asset, quote_asset, side); fn filter_deposit_swaps(from: Asset, to: Asset, deposit_witnesses: Vec>) -> Vec diff --git a/state-chain/runtime/src/runtime_apis.rs b/state-chain/runtime/src/runtime_apis.rs index 80ead5d508..d35d1da2ae 100644 --- a/state-chain/runtime/src/runtime_apis.rs +++ b/state-chain/runtime/src/runtime_apis.rs @@ -1,6 +1,6 @@ use crate::chainflip::Offence; use cf_amm::{ - common::{Amount, Order, Tick}, + common::{Amount, PoolPairsMap, Side, Tick}, range_orders::Liquidity, }; use cf_chains::{eth::Address as EthereumAddress, Chain, ForeignChainAddress}; @@ -13,8 +13,8 @@ use core::ops::Range; use frame_support::sp_runtime::AccountId32; use pallet_cf_governance::GovCallHash; use pallet_cf_pools::{ - AskBidMap, AssetsMap, PoolInfo, PoolLiquidity, PoolOrderbook, PoolOrders, PoolPriceV1, - PoolPriceV2, UnidirectionalPoolDepth, + AskBidMap, PoolInfo, PoolLiquidity, PoolOrderbook, PoolOrders, PoolPriceV1, PoolPriceV2, + UnidirectionalPoolDepth, }; use pallet_cf_witnesser::CallHash; use scale_info::{prelude::string::String, TypeInfo}; @@ -154,7 +154,7 @@ decl_runtime_apis!( base_asset: Asset, quote_asset: Asset, tick_range: Range, - ) -> Result, DispatchErrorWithMessage>; + ) -> Result, DispatchErrorWithMessage>; fn cf_pool_orderbook( base_asset: Asset, quote_asset: Asset, @@ -170,7 +170,7 @@ decl_runtime_apis!( quote_asset: Asset, tick_range: Range, liquidity: Liquidity, - ) -> Result, DispatchErrorWithMessage>; + ) -> Result, DispatchErrorWithMessage>; fn cf_max_swap_amount(asset: Asset) -> Option; fn cf_min_deposit_amount(asset: Asset) -> AssetAmount; @@ -178,7 +178,7 @@ decl_runtime_apis!( fn cf_prewitness_swaps( base_asset: Asset, quote_asset: Asset, - side: Order, + side: Side, ) -> Vec; fn cf_liquidity_provider_info(account_id: AccountId32) -> Option; fn cf_account_role(account_id: AccountId32) -> Option;