From c91f48edff6d977f50be7e108a7f21c7003b5e8f Mon Sep 17 00:00:00 2001 From: Malte Kliemann Date: Wed, 7 Feb 2024 11:32:51 +0100 Subject: [PATCH] Use `BoundedBTreeMap` in neo-swaps `Pool` struct --- zrml/neo-swaps/src/lib.rs | 10 ++--- zrml/neo-swaps/src/tests/sell.rs | 4 +- zrml/neo-swaps/src/types/max_assets.rs | 26 +++++++++++++ zrml/neo-swaps/src/types/mod.rs | 2 + zrml/neo-swaps/src/types/pool.rs | 51 ++++++++------------------ 5 files changed, 50 insertions(+), 43 deletions(-) create mode 100644 zrml/neo-swaps/src/types/max_assets.rs diff --git a/zrml/neo-swaps/src/lib.rs b/zrml/neo-swaps/src/lib.rs index ed0a3f30a..974dc031f 100644 --- a/zrml/neo-swaps/src/lib.rs +++ b/zrml/neo-swaps/src/lib.rs @@ -38,11 +38,11 @@ pub use pallet::*; #[frame_support::pallet] mod pallet { use crate::{ - consts::{LN_NUMERICAL_LIMIT, MAX_ASSETS}, + consts::LN_NUMERICAL_LIMIT, liquidity_tree::types::{BenchmarkInfo, LiquidityTree, LiquidityTreeError}, math::{Math, MathOps}, traits::{pool_operations::PoolOperations, LiquiditySharesManager}, - types::{FeeDistribution, Pool}, + types::{FeeDistribution, MaxAssets, Pool}, weights::*, }; use alloc::{collections::BTreeMap, vec, vec::Vec}; @@ -99,7 +99,7 @@ mod pallet { pub(crate) type MarketIdOf = <::MarketCommons as MarketCommonsPalletApi>::MarketId; pub(crate) type LiquidityTreeOf = LiquidityTree::MaxLiquidityTreeDepth>; - pub(crate) type PoolOf = Pool>; + pub(crate) type PoolOf = Pool, MaxAssets>; #[pallet::config] pub trait Config: frame_system::Config { @@ -833,7 +833,7 @@ mod pallet { ensure!(market.scoring_rule == ScoringRule::Lmsr, Error::::InvalidTradingMechanism); let asset_count = spot_prices.len(); ensure!(asset_count as u16 == market.outcomes(), Error::::IncorrectVecLen); - ensure!(market.outcomes() <= MAX_ASSETS, Error::::AssetCountAboveMax); + ensure!(market.outcomes() as u32 <= MaxAssets::get(), Error::::AssetCountAboveMax); ensure!(swap_fee >= MIN_SWAP_FEE.saturated_into(), Error::::SwapFeeBelowMin); ensure!(swap_fee <= T::MaxSwapFee::get(), Error::::SwapFeeAboveMax); ensure!( @@ -869,7 +869,7 @@ mod pallet { let collateral = market.base_asset; let pool = Pool { account_id: pool_account_id.clone(), - reserves: reserves.clone(), + reserves: reserves.clone().try_into().map_err(|_| Error::::Unexpected)?, collateral, liquidity_parameter, liquidity_shares_manager: LiquidityTree::new(who.clone(), amount)?, diff --git a/zrml/neo-swaps/src/tests/sell.rs b/zrml/neo-swaps/src/tests/sell.rs index ae6aa501f..45022ff6d 100644 --- a/zrml/neo-swaps/src/tests/sell.rs +++ b/zrml/neo-swaps/src/tests/sell.rs @@ -267,7 +267,7 @@ fn sell_fails_if_price_is_too_low() { // speaking this leaves the pool in an inconsistent state (reserve recorded in the `Pool` // struct is smaller than actual reserve), but this doesn't matter in this test. NeoSwaps::try_mutate_pool(&market_id, |pool| { - pool.reserves.insert(asset_in, 11 * pool.liquidity_parameter); + pool.reserves.try_insert(asset_in, 11 * pool.liquidity_parameter).unwrap(); Ok(()) }) .unwrap(); @@ -306,7 +306,7 @@ fn sell_fails_if_price_is_pushed_below_threshold() { NeoSwaps::try_mutate_pool(&market_id, |pool| { // The price is right at the brink here. Any further shift and sells won't be accepted // anymore. - pool.reserves.insert(asset_in, 10 * pool.liquidity_parameter); + pool.reserves.try_insert(asset_in, 10 * pool.liquidity_parameter).unwrap(); Ok(()) }) .unwrap(); diff --git a/zrml/neo-swaps/src/types/max_assets.rs b/zrml/neo-swaps/src/types/max_assets.rs new file mode 100644 index 000000000..1a5e96b7c --- /dev/null +++ b/zrml/neo-swaps/src/types/max_assets.rs @@ -0,0 +1,26 @@ +// Copyright 2023-2024 Forecasting Technologies LTD. +// +// This file is part of Zeitgeist. +// +// Zeitgeist is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the +// Free Software Foundation, either version 3 of the License, or (at +// your option) any later version. +// +// Zeitgeist is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Zeitgeist. If not, see . + +use sp_runtime::traits::Get; + +pub(crate) struct MaxAssets; + +impl Get for MaxAssets { + fn get() -> u32 { + 128 + } +} diff --git a/zrml/neo-swaps/src/types/mod.rs b/zrml/neo-swaps/src/types/mod.rs index 30734e23e..14da6c7fc 100644 --- a/zrml/neo-swaps/src/types/mod.rs +++ b/zrml/neo-swaps/src/types/mod.rs @@ -16,7 +16,9 @@ // along with Zeitgeist. If not, see . mod fee_distribution; +mod max_assets; mod pool; pub(crate) use fee_distribution::*; +pub(crate) use max_assets::*; pub(crate) use pool::*; diff --git a/zrml/neo-swaps/src/types/pool.rs b/zrml/neo-swaps/src/types/pool.rs index 301dc89d0..bf355919a 100644 --- a/zrml/neo-swaps/src/types/pool.rs +++ b/zrml/neo-swaps/src/types/pool.rs @@ -16,37 +16,43 @@ // along with Zeitgeist. If not, see . use crate::{ - consts::{EXP_NUMERICAL_LIMIT, MAX_ASSETS}, + consts::EXP_NUMERICAL_LIMIT, math::{Math, MathOps}, pallet::{AssetOf, BalanceOf, Config}, traits::{LiquiditySharesManager, PoolOperations}, Error, }; -use alloc::{collections::BTreeMap, vec::Vec}; +use alloc::vec::Vec; +use frame_support::{storage::bounded_btree_map::BoundedBTreeMap, CloneNoBound}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{CheckedAdd, CheckedSub}, + traits::{CheckedAdd, CheckedSub, Get}, DispatchError, DispatchResult, RuntimeDebug, SaturatedConversion, Saturating, }; -#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct Pool +#[derive(CloneNoBound, Decode, Encode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +#[scale_info(skip_type_params(S, T))] +pub struct Pool where - LSM: LiquiditySharesManager, + T: Config, + LSM: Clone + LiquiditySharesManager, + S: Get, { pub account_id: T::AccountId, - pub reserves: BTreeMap, BalanceOf>, + pub reserves: BoundedBTreeMap, BalanceOf, S>, pub collateral: AssetOf, pub liquidity_parameter: BalanceOf, pub liquidity_shares_manager: LSM, pub swap_fee: BalanceOf, } -impl + TypeInfo> PoolOperations for Pool +impl PoolOperations for Pool where + T: Config, BalanceOf: SaturatedConversion, + LSM: Clone + LiquiditySharesManager + TypeInfo, + S: Get, { fn assets(&self) -> Vec> { self.reserves.keys().cloned().collect() @@ -117,30 +123,3 @@ where Math::::calculate_buy_ln_argument(reserve, amount_in, self.liquidity_parameter) } } - -// TODO(#1214): Replace BTreeMap with BoundedBTreeMap and remove the unnecessary `MaxEncodedLen` -// implementation. -impl> MaxEncodedLen for Pool -where - T::AccountId: MaxEncodedLen, - AssetOf: MaxEncodedLen, - BalanceOf: MaxEncodedLen, - LSM: MaxEncodedLen, -{ - fn max_encoded_len() -> usize { - let len_account_id = T::AccountId::max_encoded_len(); - let len_reserves = 1usize.saturating_add((MAX_ASSETS as usize).saturating_mul( - >::max_encoded_len().saturating_add(BalanceOf::::max_encoded_len()), - )); - let len_collateral = AssetOf::::max_encoded_len(); - let len_liquidity_parameter = BalanceOf::::max_encoded_len(); - let len_liquidity_shares_manager = LSM::max_encoded_len(); - let len_swap_fee = BalanceOf::::max_encoded_len(); - len_account_id - .saturating_add(len_reserves) - .saturating_add(len_collateral) - .saturating_add(len_liquidity_parameter) - .saturating_add(len_liquidity_shares_manager) - .saturating_add(len_swap_fee) - } -}