From 39935e96c255657f2d41125cbe4328a944bd2807 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 15 Sep 2023 12:28:22 +0200 Subject: [PATCH 01/69] move swap trait and impl into separate module --- substrate/frame/asset-conversion/src/lib.rs | 62 ++--------- substrate/frame/asset-conversion/src/swap.rs | 101 ++++++++++++++++++ substrate/frame/asset-conversion/src/types.rs | 37 ------- 3 files changed, 110 insertions(+), 90 deletions(-) create mode 100644 substrate/frame/asset-conversion/src/swap.rs diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 8d811473e861f..a3f5159743ec0 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -57,15 +57,18 @@ use frame_support::traits::{DefensiveOption, Incrementable}; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; - -mod types; -pub mod weights; - +#[cfg(test)] +mod mock; +mod swap; #[cfg(test)] mod tests; +mod types; +pub mod weights; -#[cfg(test)] -mod mock; +pub use pallet::*; +pub use swap::Swap; +pub use types::*; +pub use weights::WeightInfo; use codec::Codec; use frame_support::{ @@ -76,7 +79,6 @@ use frame_system::{ ensure_signed, pallet_prelude::{BlockNumberFor, OriginFor}, }; -pub use pallet::*; use sp_arithmetic::traits::Unsigned; use sp_runtime::{ traits::{ @@ -85,8 +87,6 @@ use sp_runtime::{ DispatchError, }; use sp_std::prelude::*; -pub use types::*; -pub use weights::WeightInfo; #[frame_support::pallet] pub mod pallet { @@ -1238,50 +1238,6 @@ pub mod pallet { } } -impl Swap for Pallet { - fn swap_exact_tokens_for_tokens( - sender: T::AccountId, - path: Vec, - amount_in: T::HigherPrecisionBalance, - amount_out_min: Option, - send_to: T::AccountId, - keep_alive: bool, - ) -> Result { - let path = path.try_into().map_err(|_| Error::::PathError)?; - let amount_out_min = amount_out_min.map(Self::convert_hpb_to_asset_balance).transpose()?; - let amount_out = Self::do_swap_exact_tokens_for_tokens( - sender, - path, - Self::convert_hpb_to_asset_balance(amount_in)?, - amount_out_min, - send_to, - keep_alive, - )?; - Ok(amount_out.into()) - } - - fn swap_tokens_for_exact_tokens( - sender: T::AccountId, - path: Vec, - amount_out: T::HigherPrecisionBalance, - amount_in_max: Option, - send_to: T::AccountId, - keep_alive: bool, - ) -> Result { - let path = path.try_into().map_err(|_| Error::::PathError)?; - let amount_in_max = amount_in_max.map(Self::convert_hpb_to_asset_balance).transpose()?; - let amount_in = Self::do_swap_tokens_for_exact_tokens( - sender, - path, - Self::convert_hpb_to_asset_balance(amount_out)?, - amount_in_max, - send_to, - keep_alive, - )?; - Ok(amount_in.into()) - } -} - sp_api::decl_runtime_apis! { /// This runtime api allows people to query the size of the liquidity pools /// and quote prices for swaps. diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs new file mode 100644 index 0000000000000..7c4468d24b7c4 --- /dev/null +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -0,0 +1,101 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Traits and implementations for swap between the various asset classes. + +use super::*; + +/// Trait for providing methods to swap between the various asset classes. +pub trait Swap { + /// Swap exactly `amount_in` of asset `path[0]` for asset `path[1]`. + /// If an `amount_out_min` is specified, it will return an error if it is unable to acquire + /// the amount desired. + /// + /// Withdraws the `path[0]` asset from `sender`, deposits the `path[1]` asset to `send_to`, + /// respecting `keep_alive`. + /// + /// If successful, returns the amount of `path[1]` acquired for the `amount_in`. + fn swap_exact_tokens_for_tokens( + sender: AccountId, + path: Vec, + amount_in: Balance, + amount_out_min: Option, + send_to: AccountId, + keep_alive: bool, + ) -> Result; + + /// Take the `path[0]` asset and swap some amount for `amount_out` of the `path[1]`. If an + /// `amount_in_max` is specified, it will return an error if acquiring `amount_out` would be + /// too costly. + /// + /// Withdraws `path[0]` asset from `sender`, deposits `path[1]` asset to `send_to`, + /// respecting `keep_alive`. + /// + /// If successful returns the amount of the `path[0]` taken to provide `path[1]`. + fn swap_tokens_for_exact_tokens( + sender: AccountId, + path: Vec, + amount_out: Balance, + amount_in_max: Option, + send_to: AccountId, + keep_alive: bool, + ) -> Result; +} + +impl Swap for Pallet { + fn swap_exact_tokens_for_tokens( + sender: T::AccountId, + path: Vec, + amount_in: T::HigherPrecisionBalance, + amount_out_min: Option, + send_to: T::AccountId, + keep_alive: bool, + ) -> Result { + let path = path.try_into().map_err(|_| Error::::PathError)?; + let amount_out_min = amount_out_min.map(Self::convert_hpb_to_asset_balance).transpose()?; + let amount_out = Self::do_swap_exact_tokens_for_tokens( + sender, + path, + Self::convert_hpb_to_asset_balance(amount_in)?, + amount_out_min, + send_to, + keep_alive, + )?; + Ok(amount_out.into()) + } + + fn swap_tokens_for_exact_tokens( + sender: T::AccountId, + path: Vec, + amount_out: T::HigherPrecisionBalance, + amount_in_max: Option, + send_to: T::AccountId, + keep_alive: bool, + ) -> Result { + let path = path.try_into().map_err(|_| Error::::PathError)?; + let amount_in_max = amount_in_max.map(Self::convert_hpb_to_asset_balance).transpose()?; + let amount_in = Self::do_swap_tokens_for_exact_tokens( + sender, + path, + Self::convert_hpb_to_asset_balance(amount_out)?, + amount_in_max, + send_to, + keep_alive, + )?; + Ok(amount_in.into()) + } +} diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index ffdc63ce0ce7b..0bec61705c11c 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -83,43 +83,6 @@ where } } -/// Trait for providing methods to swap between the various asset classes. -pub trait Swap { - /// Swap exactly `amount_in` of asset `path[0]` for asset `path[1]`. - /// If an `amount_out_min` is specified, it will return an error if it is unable to acquire - /// the amount desired. - /// - /// Withdraws the `path[0]` asset from `sender`, deposits the `path[1]` asset to `send_to`, - /// respecting `keep_alive`. - /// - /// If successful, returns the amount of `path[1]` acquired for the `amount_in`. - fn swap_exact_tokens_for_tokens( - sender: AccountId, - path: Vec, - amount_in: Balance, - amount_out_min: Option, - send_to: AccountId, - keep_alive: bool, - ) -> Result; - - /// Take the `path[0]` asset and swap some amount for `amount_out` of the `path[1]`. If an - /// `amount_in_max` is specified, it will return an error if acquiring `amount_out` would be - /// too costly. - /// - /// Withdraws `path[0]` asset from `sender`, deposits `path[1]` asset to `send_to`, - /// respecting `keep_alive`. - /// - /// If successful returns the amount of the `path[0]` taken to provide `path[1]`. - fn swap_tokens_for_exact_tokens( - sender: AccountId, - path: Vec, - amount_out: Balance, - amount_in_max: Option, - send_to: AccountId, - keep_alive: bool, - ) -> Result; -} - /// An implementation of MultiAssetId that can be either Native or an asset. #[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Copy, Debug)] pub enum NativeOrAssetId From d8ab7c104fe02b0aca89c43f82df2245b4cabec7 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 15 Sep 2023 12:51:45 +0200 Subject: [PATCH 02/69] restructure imports --- substrate/frame/asset-conversion/src/lib.rs | 47 ++++++++------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index a3f5159743ec0..bdf25c175821b 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -72,44 +72,33 @@ pub use weights::WeightInfo; use codec::Codec; use frame_support::{ - ensure, - traits::tokens::{AssetId, Balance}, -}; -use frame_system::{ - ensure_signed, - pallet_prelude::{BlockNumberFor, OriginFor}, + traits::{ + fungible::{Inspect as InspectFungible, Mutate as MutateFungible}, + fungibles::{Create, Inspect, Mutate}, + tokens::{ + AssetId, Balance, + Fortitude::Polite, + Precision::Exact, + Preservation::{Expendable, Preserve}, + }, + AccountTouch, ContainsPair, + }, + BoundedBTreeSet, PalletId, }; -use sp_arithmetic::traits::Unsigned; use sp_runtime::{ traits::{ - CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, MaybeDisplay, TrailingZeroInput, + CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, + One, TrailingZeroInput, Zero, }, - DispatchError, + DispatchError, Saturating, }; -use sp_std::prelude::*; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{ - pallet_prelude::*, - traits::{ - fungible::{Inspect as InspectFungible, Mutate as MutateFungible}, - fungibles::{Create, Inspect, Mutate}, - tokens::{ - Fortitude::Polite, - Precision::Exact, - Preservation::{Expendable, Preserve}, - }, - AccountTouch, ContainsPair, - }, - BoundedBTreeSet, PalletId, - }; - use sp_arithmetic::Permill; - use sp_runtime::{ - traits::{IntegerSquareRoot, One, Zero}, - Saturating, - }; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use sp_arithmetic::{traits::Unsigned, Permill}; #[pallet::pallet] pub struct Pallet(_); From 6d6cc181d861624f008303c640ed01ea4b2e7fa2 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 20 Sep 2023 17:46:07 +0200 Subject: [PATCH 03/69] transfer swap --- substrate/frame/asset-conversion/src/lib.rs | 280 +++++++++++------- substrate/frame/asset-conversion/src/types.rs | 79 +++++ 2 files changed, 260 insertions(+), 99 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index bdf25c175821b..926c1790e871e 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -53,7 +53,6 @@ //! (This can be run against the kitchen sync node in the `node` folder of this repo.) #![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::{DefensiveOption, Incrementable}; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -73,15 +72,18 @@ pub use weights::WeightInfo; use codec::Codec; use frame_support::{ traits::{ - fungible::{Inspect as InspectFungible, Mutate as MutateFungible}, - fungibles::{Create, Inspect, Mutate}, + fungible::{ + Balanced as BalancedFungible, Credit as CreditFungible, Inspect as InspectFungible, + Mutate as MutateFungible, + }, + fungibles::{Balanced, Create, Credit as CreditFungibles, Inspect, Mutate}, tokens::{ AssetId, Balance, Fortitude::Polite, Precision::Exact, Preservation::{Expendable, Preserve}, }, - AccountTouch, ContainsPair, + AccountTouch, ContainsPair, Imbalance, Incrementable, }, BoundedBTreeSet, PalletId, }; @@ -90,7 +92,7 @@ use sp_runtime::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, One, TrailingZeroInput, Zero, }, - DispatchError, Saturating, + BoundedVec, DispatchError, Saturating, }; #[frame_support::pallet] @@ -110,7 +112,8 @@ pub mod pallet { /// Currency type that this works on. type Currency: InspectFungible - + MutateFungible; + + MutateFungible + + BalancedFungible; /// The `Currency::Balance` type of the native currency. type Balance: Balance; @@ -151,7 +154,8 @@ pub mod pallet { type Assets: Inspect + Mutate + AccountTouch - + ContainsPair; + + ContainsPair + + Balanced; /// Registry for the lp tokens. Ideally only this pallet should have create permissions on /// the assets. @@ -350,10 +354,8 @@ pub mod pallet { NonUniquePath, /// It was not possible to get or increment the Id of the pool. IncorrectPoolAssetId, - /// Unable to find an element in an array/vec that should have one-to-one correspondence - /// with another. For example, an array of assets constituting a `path` should have a - /// corresponding array of `amounts` along the path. - CorrespondenceError, + /// Account cannot exist with the funds that would be given. + BelowMinimum, } #[pallet::hooks] @@ -702,6 +704,9 @@ pub mod pallet { /// respecting `keep_alive`. /// /// If successful, returns the amount of `path[1]` acquired for the `amount_in`. + /// + /// Note: + /// * this function might modify storage even if an error occurs. pub fn do_swap_exact_tokens_for_tokens( sender: T::AccountId, path: BoundedVec, @@ -716,11 +721,9 @@ pub mod pallet { } Self::validate_swap_path(&path)?; + let path = Self::balance_path_from_amount_in(amount_in, path)?; - let amounts = Self::get_amounts_out(&amount_in, &path)?; - let amount_out = - *amounts.last().defensive_ok_or("get_amounts_out() returned an empty result")?; - + let amount_out = path.last().map(|(_, a)| a.clone()).ok_or(Error::::InvalidPath)?; if let Some(amount_out_min) = amount_out_min { ensure!( amount_out >= amount_out_min, @@ -728,7 +731,15 @@ pub mod pallet { ); } - Self::do_swap(sender, &amounts, path, send_to, keep_alive)?; + Self::transfer_swap(&sender, &path, &send_to, keep_alive)?; + + Self::deposit_event(Event::SwapExecuted { + who: sender, + send_to, + amount_in, + amount_out, + path: BoundedVec::truncate_from(path.into_iter().map(|(a, _)| a).collect()), + }); Ok(amount_out) } @@ -740,6 +751,9 @@ pub mod pallet { /// respecting `keep_alive`. /// /// If successful returns the amount of the `path[0]` taken to provide `path[1]`. + /// + /// Note: + /// * this function might modify storage even if an error occurs. pub fn do_swap_tokens_for_exact_tokens( sender: T::AccountId, path: BoundedVec, @@ -754,11 +768,9 @@ pub mod pallet { } Self::validate_swap_path(&path)?; + let path = Self::balance_path_from_amount_out(amount_out, path)?; - let amounts = Self::get_amounts_in(&amount_out, &path)?; - let amount_in = - *amounts.first().defensive_ok_or("get_amounts_in() returned an empty result")?; - + let amount_in = path.first().map(|(_, a)| a.clone()).ok_or(Error::::InvalidPath)?; if let Some(amount_in_max) = amount_in_max { ensure!( amount_in <= amount_in_max, @@ -766,7 +778,16 @@ pub mod pallet { ); } - Self::do_swap(sender, &amounts, path, send_to, keep_alive)?; + Self::transfer_swap(&sender, &path, &send_to, keep_alive)?; + + Self::deposit_event(Event::SwapExecuted { + who: sender, + send_to, + amount_in, + amount_out, + path: BoundedVec::truncate_from(path.into_iter().map(|(a, _)| a).collect()), + }); + Ok(amount_in) } @@ -809,6 +830,40 @@ pub mod pallet { result } + /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit` + /// cannot be countered, then nothing is changed and the original `credit` is returned in an + /// `Err`. + fn resolve(who: &T::AccountId, credit: Credit) -> Result<(), Credit> { + match credit { + Credit::Native(c) => T::Currency::resolve(who, c).map_err(|c| c.into()), + Credit::Asset(c) => T::Assets::resolve(who, c).map_err(|c| c.into()), + } + } + + /// Removes `value` balance of `asset` from `who` account if possible. + fn withdraw( + asset: &T::MultiAssetId, + who: &T::AccountId, + value: T::AssetBalance, + keep_alive: bool, + ) -> Result, DispatchError> { + let preservation = match keep_alive { + true => Preserve, + false => Expendable, + }; + match T::MultiAssetIdConverter::try_convert(asset) { + MultiAssetIdConversionResult::Converted(asset) => + T::Assets::withdraw(asset, who, value, Exact, preservation, Polite) + .map(|c| c.into()), + MultiAssetIdConversionResult::Native => { + let value = Self::convert_asset_balance_to_native_balance(value)?; + T::Currency::withdraw(who, value, Exact, preservation, Polite).map(|c| c.into()) + }, + MultiAssetIdConversionResult::Unsupported(_) => + Err(Error::::UnsupportedAsset.into()), + } + } + /// Convert a `Balance` type to an `AssetBalance`. pub(crate) fn convert_native_balance_to_asset_balance( amount: T::Balance, @@ -834,63 +889,80 @@ pub mod pallet { amount.try_into().map_err(|_| Error::::Overflow) } - /// Swap assets along a `path`, depositing in `send_to`. - pub(crate) fn do_swap( - sender: T::AccountId, - amounts: &Vec, - path: BoundedVec, - send_to: T::AccountId, + /// Swap assets along the `path`, withdrawing from `sender` and depositing in `send_to`. + /// + /// Note: + /// * this function might modify storage even if an error occurs. + /// * it's assumed that the provided `path` is valid. + fn transfer_swap( + sender: &T::AccountId, + path: &BalancePath, + send_to: &T::AccountId, keep_alive: bool, ) -> Result<(), DispatchError> { - ensure!(amounts.len() > 1, Error::::CorrespondenceError); - if let Some([asset1, asset2]) = &path.get(0..2) { - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let pool_account = Self::get_pool_account(&pool_id); - // amounts should always contain a corresponding element to path. - let first_amount = amounts.first().ok_or(Error::::CorrespondenceError)?; - - Self::transfer(asset1, &sender, &pool_account, *first_amount, keep_alive)?; - - let mut i = 0; - let path_len = path.len() as u32; - for assets_pair in path.windows(2) { - if let [asset1, asset2] = assets_pair { - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let pool_account = Self::get_pool_account(&pool_id); - - let amount_out = - amounts.get((i + 1) as usize).ok_or(Error::::CorrespondenceError)?; - - let to = if i < path_len - 2 { - let asset3 = path.get((i + 2) as usize).ok_or(Error::::PathError)?; - Self::get_pool_account(&Self::get_pool_id( - asset2.clone(), - asset3.clone(), - )) - } else { - send_to.clone() - }; + let (asset_in, amount_in) = path.first().ok_or(Error::::InvalidPath)?; + let credit_in = Self::withdraw(asset_in, sender, *amount_in, keep_alive)?; - let reserve = Self::get_balance(&pool_account, asset2)?; + let credit_out = Self::credit_swap(credit_in, path).map_err(|(_, e)| e)?; + Self::resolve(send_to, credit_out).map_err(|_| Error::::BelowMinimum)?; + + Ok(()) + } + + /// Swap assets along the specified `path`, consuming `credit_in` and producing + /// `credit_out`. + /// + /// Note: + /// * this function might modify storage even if an error occurs. + /// * if an error occurs, `credit_in` is returned back. + /// * it's assumed that the provided `path` is valid and `credit_in` corresponds to the + /// first asset in the `path`. + fn credit_swap( + credit_in: Credit, + path: &BalancePath, + ) -> Result, (Credit, DispatchError)> { + let resolve_path = || -> Result, DispatchError> { + for pos in 0..=path.len() { + if let Some([(asset1, _), (asset2, amount_out)]) = path.get(pos..=pos + 1) { + let pool_from = Self::get_pool_account(&Self::get_pool_id( + asset1.clone(), + asset2.clone(), + )); + + let reserve = Self::get_balance(&pool_from, asset2)?; let reserve_left = reserve.saturating_sub(*amount_out); Self::validate_minimal_amount(reserve_left, asset2) .map_err(|_| Error::::ReserveLeftLessThanMinimal)?; - Self::transfer(asset2, &pool_account, &to, *amount_out, true)?; + if let Some((asset3, _)) = path.get(pos + 2) { + let pool_to = Self::get_pool_account(&Self::get_pool_id( + asset2.clone(), + asset3.clone(), + )); + Self::transfer(asset2, &pool_from, &pool_to, *amount_out, true)?; + } else { + let credit_out = Self::withdraw(asset2, &pool_from, *amount_out, true)?; + return Ok(credit_out) + } } - i.saturating_inc(); } - Self::deposit_event(Event::SwapExecuted { - who: sender, - send_to, - path, - amount_in: *first_amount, - amount_out: *amounts.last().expect("Always has more than 1 element"), - }); - } else { return Err(Error::::InvalidPath.into()) - } - Ok(()) + }; + + let credit_out = match resolve_path() { + Ok(c) => c, + Err(e) => return Err((credit_in, e)), + }; + + let pool_to = if let Some([(asset1, _), (asset2, _)]) = path.get(0..2) { + Self::get_pool_account(&Self::get_pool_id(asset1.clone(), asset2.clone())) + } else { + return Err((credit_in, Error::::InvalidPath.into())) + }; + + Self::resolve(&pool_to, credit_in).map_err(|c| (c, Error::::BelowMinimum.into()))?; + + Ok(credit_out) } /// The account ID of the pool. @@ -967,42 +1039,52 @@ pub mod pallet { } /// Leading to an amount at the end of a `path`, get the required amounts in. - pub(crate) fn get_amounts_in( - amount_out: &T::AssetBalance, - path: &BoundedVec, - ) -> Result, DispatchError> { - let mut amounts: Vec = vec![*amount_out]; - - for assets_pair in path.windows(2).rev() { - if let [asset1, asset2] = assets_pair { - let (reserve_in, reserve_out) = Self::get_reserves(asset1, asset2)?; - let prev_amount = amounts.last().expect("Always has at least one element"); - let amount_in = Self::get_amount_in(prev_amount, &reserve_in, &reserve_out)?; - amounts.push(amount_in); - } + pub(crate) fn balance_path_from_amount_out( + amount_out: T::AssetBalance, + path: BoundedVec, + ) -> Result, DispatchError> { + let mut balance_path: BalancePath = Vec::with_capacity(path.len()); + let mut amount_out: T::AssetBalance = amount_out; + + let mut iter = path.into_iter().rev().peekable(); + while let Some(asset2) = iter.next() { + let asset1 = match iter.peek() { + Some(a) => a, + None => { + balance_path.push((asset2, amount_out)); + break + }, + }; + let (reserve_in, reserve_out) = Self::get_reserves(asset1, &asset2)?; + balance_path.push((asset2, amount_out)); + amount_out = Self::get_amount_in(&amount_out, &reserve_in, &reserve_out)?; } - - amounts.reverse(); - Ok(amounts) + balance_path.reverse(); + Ok(balance_path) } /// Following an amount into a `path`, get the corresponding amounts out. - pub(crate) fn get_amounts_out( - amount_in: &T::AssetBalance, - path: &BoundedVec, - ) -> Result, DispatchError> { - let mut amounts: Vec = vec![*amount_in]; - - for assets_pair in path.windows(2) { - if let [asset1, asset2] = assets_pair { - let (reserve_in, reserve_out) = Self::get_reserves(asset1, asset2)?; - let prev_amount = amounts.last().expect("Always has at least one element"); - let amount_out = Self::get_amount_out(prev_amount, &reserve_in, &reserve_out)?; - amounts.push(amount_out); - } + pub(crate) fn balance_path_from_amount_in( + amount_in: T::AssetBalance, + path: BoundedVec, + ) -> Result, DispatchError> { + let mut balance_path: BalancePath = Vec::with_capacity(path.len()); + let mut amount_out: T::AssetBalance = amount_in; + + let mut iter = path.into_iter().peekable(); + while let Some(asset1) = iter.next() { + let asset2 = match iter.peek() { + Some(a) => a, + None => { + balance_path.push((asset1, amount_out)); + break + }, + }; + let (reserve_in, reserve_out) = Self::get_reserves(&asset1, asset2)?; + balance_path.push((asset1, amount_out)); + amount_out = Self::get_amount_out(&amount_out, &reserve_in, &reserve_out)?; } - - Ok(amounts) + Ok(balance_path) } /// Used by the RPC service to provide current prices. diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 0bec61705c11c..175ac11e375f3 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -27,6 +27,17 @@ use sp_std::{cmp::Ordering, marker::PhantomData}; /// migration. pub(super) type PoolIdOf = (::MultiAssetId, ::MultiAssetId); +/// Represents a swap path with associated amounts for input and output. +/// +/// Each pair of neighboring assets forms a pool. +/// +/// Example: +/// Given path [(asset1, amount_in), (asset2, amount_out2), (asset3, amount_out3)], can be resolved: +/// 1. `asset(asset1, amount_in)` take from `user` and move to the pool(asset1, asset2); +/// 2. `asset(asset2, amount_out2)` transfer from pool(asset1, asset2) to pool(asset2, asset3); +/// 3. `asset(asset3, amount_out3)` move from pool(asset2, asset3) to `user`. +pub(super) type BalancePath = Vec<(::MultiAssetId, ::AssetBalance)>; + /// Stores the lp_token asset id a particular pool has been assigned. #[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)] pub struct PoolInfo { @@ -149,3 +160,71 @@ impl MultiAssetIdConverter, Asset } } } + +/// Credit of [Config::Currency]. +pub type NativeCredit = + CreditFungible<::AccountId, ::Currency>; + +/// Credit of [Config::Assets]. +pub type AssetCredit = + CreditFungibles<::AccountId, ::Assets>; + +/// Credit that can be either [`NativeCredit`] or [`AssetCredit`]. +pub enum Credit { + /// Native credit. + Native(NativeCredit), + /// Asset credit. + Asset(AssetCredit), +} + +impl From> for Credit { + fn from(value: NativeCredit) -> Self { + Credit::Native(value) + } +} + +impl From> for Credit { + fn from(value: AssetCredit) -> Self { + Credit::Asset(value) + } +} + +impl Credit { + /// Amount of `self`. + pub fn peek(&self) -> Result { + let amount = match self { + Credit::Native(c) => T::HigherPrecisionBalance::from(c.peek()) + .try_into() + .map_err(|_| Error::::Overflow)?, + Credit::Asset(c) => c.peek(), + }; + Ok(amount) + } + + /// Asset class of `self`. + pub fn asset(&self) -> T::MultiAssetId { + match self { + Credit::Native(_) => T::MultiAssetIdConverter::get_native(), + Credit::Asset(c) => c.asset().into(), + } + } + + /// Consume `self` and return two independent instances; the first is guaranteed to be at most + /// `amount` and the second will be the remainder. + pub fn split(self, amount: T::AssetBalance) -> Result<(Self, Self), (Self, DispatchError)> { + match self { + Credit::Native(c) => { + let amount = match T::HigherPrecisionBalance::from(amount).try_into() { + Ok(a) => a, + Err(_) => return Err((Self::Native(c), Error::::Overflow.into())), + }; + let (left, right) = c.split(amount); + Ok((left.into(), right.into())) + }, + Credit::Asset(c) => { + let (left, right) = c.split(amount); + Ok((left.into(), right.into())) + }, + } + } +} From a3552419b1c07689c524b3bc673990ea558a18c7 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 22 Sep 2023 12:24:55 +0200 Subject: [PATCH 04/69] swap credit --- substrate/frame/asset-conversion/src/lib.rs | 205 ++++++++++++------ substrate/frame/asset-conversion/src/swap.rs | 67 ++++++ substrate/frame/asset-conversion/src/tests.rs | 6 +- substrate/frame/asset-conversion/src/types.rs | 13 +- 4 files changed, 220 insertions(+), 71 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 926c1790e871e..80d2c6e09f468 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -65,7 +65,7 @@ mod types; pub mod weights; pub use pallet::*; -pub use swap::Swap; +pub use swap::*; pub use types::*; pub use weights::WeightInfo; @@ -276,24 +276,15 @@ pub mod pallet { who: T::AccountId, /// The account that the assets were transferred to. send_to: T::AccountId, - /// The route of asset ids that the swap went through. - /// E.g. A -> Dot -> B - path: BoundedVec, - /// The amount of the first asset that was swapped. - amount_in: T::AssetBalance, - /// The amount of the second asset that was received. - amount_out: T::AssetBalance, + /// The route of asset ids with amounts that the swap went through. + /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) + path: BalancePath, }, - /// An amount has been transferred from one account to another. - Transfer { - /// The account that the assets were transferred from. - from: T::AccountId, - /// The account that the assets were transferred to. - to: T::AccountId, - /// The asset that was transferred. - asset: T::MultiAssetId, - /// The amount of the asset that was transferred. - amount: T::AssetBalance, + /// Assets have been converted from one to another. + CreditSwapExecuted { + /// The route of asset ids with amounts that the swap went through. + /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) + path: BalancePath, }, } @@ -705,9 +696,10 @@ pub mod pallet { /// /// If successful, returns the amount of `path[1]` acquired for the `amount_in`. /// - /// Note: - /// * this function might modify storage even if an error occurs. - pub fn do_swap_exact_tokens_for_tokens( + /// WARNING: This may return an error after a partial storage mutation. It should be used + /// only inside a transactional storage context and an Err result must imply a storage + /// rollback. + pub(crate) fn do_swap_exact_tokens_for_tokens( sender: T::AccountId, path: BoundedVec, amount_in: T::AssetBalance, @@ -723,7 +715,7 @@ pub mod pallet { Self::validate_swap_path(&path)?; let path = Self::balance_path_from_amount_in(amount_in, path)?; - let amount_out = path.last().map(|(_, a)| a.clone()).ok_or(Error::::InvalidPath)?; + let amount_out = path.last().map(|(_, a)| *a).ok_or(Error::::InvalidPath)?; if let Some(amount_out_min) = amount_out_min { ensure!( amount_out >= amount_out_min, @@ -731,15 +723,9 @@ pub mod pallet { ); } - Self::transfer_swap(&sender, &path, &send_to, keep_alive)?; + Self::swap(&sender, &path, &send_to, keep_alive)?; - Self::deposit_event(Event::SwapExecuted { - who: sender, - send_to, - amount_in, - amount_out, - path: BoundedVec::truncate_from(path.into_iter().map(|(a, _)| a).collect()), - }); + Self::deposit_event(Event::SwapExecuted { who: sender, send_to, path }); Ok(amount_out) } @@ -752,9 +738,10 @@ pub mod pallet { /// /// If successful returns the amount of the `path[0]` taken to provide `path[1]`. /// - /// Note: - /// * this function might modify storage even if an error occurs. - pub fn do_swap_tokens_for_exact_tokens( + /// WARNING: This may return an error after a partial storage mutation. It should be used + /// only inside a transactional storage context and an Err result must imply a storage + /// rollback. + pub(crate) fn do_swap_tokens_for_exact_tokens( sender: T::AccountId, path: BoundedVec, amount_out: T::AssetBalance, @@ -770,7 +757,7 @@ pub mod pallet { Self::validate_swap_path(&path)?; let path = Self::balance_path_from_amount_out(amount_out, path)?; - let amount_in = path.first().map(|(_, a)| a.clone()).ok_or(Error::::InvalidPath)?; + let amount_in = path.first().map(|(_, a)| *a).ok_or(Error::::InvalidPath)?; if let Some(amount_in_max) = amount_in_max { ensure!( amount_in <= amount_in_max, @@ -778,19 +765,109 @@ pub mod pallet { ); } - Self::transfer_swap(&sender, &path, &send_to, keep_alive)?; + Self::swap(&sender, &path, &send_to, keep_alive)?; - Self::deposit_event(Event::SwapExecuted { - who: sender, - send_to, - amount_in, - amount_out, - path: BoundedVec::truncate_from(path.into_iter().map(|(a, _)| a).collect()), - }); + Self::deposit_event(Event::SwapExecuted { who: sender, send_to, path }); Ok(amount_in) } + /// Swap exactly `credit_in` of asset `path[0]` for asset `path[last]`. If `amount_out_min` + /// is provided and the swap can't achieve at least this amount, an error is returned. + /// + /// On a successful swap, the function returns the `credit_out` of `path[last]` obtained + /// from the `credit_in`. On failure, it returns an `Err` containing the original + /// `credit_in` and the associated error code. + /// + /// WARNING: This may return an error after a partial storage mutation. It should be used + /// only inside a transactional storage context and an Err result must imply a storage + /// rollback. + pub(crate) fn do_swap_exact_credit_tokens_for_tokens( + path: BoundedVec, + credit_in: Credit, + amount_out_min: Option, + ) -> Result, (Credit, DispatchError)> { + let amount_in = match credit_in.peek() { + Ok(a) => a, + Err(e) => return Err((credit_in, e)), + }; + let inspect_path = |credit_asset| { + ensure!(path.get(0).map_or(false, |a| *a == credit_asset), Error::::InvalidPath); + ensure!(!amount_in.is_zero(), Error::::ZeroAmount); + ensure!(amount_out_min.map_or(true, |a| !a.is_zero()), Error::::ZeroAmount); + + Self::validate_swap_path(&path)?; + let path = Self::balance_path_from_amount_in(amount_in, path)?; + + let amount_out = path.last().map(|(_, a)| *a).ok_or(Error::::InvalidPath)?; + ensure!( + amount_out_min.map_or(true, |a| amount_out >= a), + Error::::ProvidedMinimumNotSufficientForSwap + ); + Ok(path) + }; + let path = match inspect_path(credit_in.asset()) { + Ok(p) => p, + Err(e) => return Err((credit_in, e)), + }; + + let credit_out = Self::credit_swap(credit_in, &path)?; + + Self::deposit_event(Event::CreditSwapExecuted { path }); + + Ok(credit_out) + } + + /// Swaps a portion of `credit_in` of `path[0]` asset to obtain the desired `amount_out` of + /// the `path[last]` asset. The provided `credit_in` must be adequate to achieve the target + /// `amount_out`, or an error will occur. + /// + /// On success, the function returns a (`credit_out`, `credit_change`) tuple, where + /// `credit_out` represents the acquired amount of the `path[last]` asset, and + /// `credit_change` is the remaining portion from the `credit_in`. On failure, an `Err` with + /// the initial `credit_in` and error code is returned. + /// + /// WARNING: This may return an error after a partial storage mutation. It should be used + /// only inside a transactional storage context and an Err result must imply a storage + /// rollback. + pub(crate) fn do_swap_credit_tokens_for_exact_tokens( + path: BoundedVec, + credit_in: Credit, + amount_out: T::AssetBalance, + ) -> Result<(Credit, Credit), (Credit, DispatchError)> { + let amount_in_max = match credit_in.peek() { + Ok(a) => a, + Err(e) => return Err((credit_in, e)), + }; + let inspect_path = |credit_asset| { + ensure!(path.get(0).map_or(false, |a| a == &credit_asset), Error::::InvalidPath); + ensure!(amount_in_max > Zero::zero(), Error::::ZeroAmount); + ensure!(amount_out > Zero::zero(), Error::::ZeroAmount); + + Self::validate_swap_path(&path)?; + let path = Self::balance_path_from_amount_out(amount_out, path)?; + + let amount_in = path.first().map(|(_, a)| *a).ok_or(Error::::InvalidPath)?; + ensure!( + amount_in <= amount_in_max, + Error::::ProvidedMaximumNotSufficientForSwap + ); + + Ok((path, amount_in)) + }; + let (path, amount_in) = match inspect_path(credit_in.asset()) { + Ok((p, a)) => (p, a), + Err(e) => return Err((credit_in, e)), + }; + + let (credit_in, credit_change) = credit_in.split(amount_in)?; + let credit_out = Self::credit_swap(credit_in, &path)?; + + Self::deposit_event(Event::CreditSwapExecuted { path }); + + Ok((credit_out, credit_change)) + } + /// Transfer an `amount` of `asset_id`, respecting the `keep_alive` requirements. fn transfer( asset_id: &T::MultiAssetId, @@ -799,7 +876,7 @@ pub mod pallet { amount: T::AssetBalance, keep_alive: bool, ) -> Result { - let result = match T::MultiAssetIdConverter::try_convert(asset_id) { + match T::MultiAssetIdConverter::try_convert(asset_id) { MultiAssetIdConversionResult::Converted(asset_id) => T::Assets::transfer(asset_id, from, to, amount, Expendable), MultiAssetIdConversionResult::Native => { @@ -817,17 +894,7 @@ pub mod pallet { }, MultiAssetIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedAsset.into()), - }; - - if result.is_ok() { - Self::deposit_event(Event::Transfer { - from: from.clone(), - to: to.clone(), - asset: (*asset_id).clone(), - amount, - }); } - result } /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit` @@ -891,10 +958,12 @@ pub mod pallet { /// Swap assets along the `path`, withdrawing from `sender` and depositing in `send_to`. /// - /// Note: - /// * this function might modify storage even if an error occurs. - /// * it's assumed that the provided `path` is valid. - fn transfer_swap( + /// Note: It's assumed that the provided `path` is valid. + /// + /// WARNING: This may return an error after a partial storage mutation. It should be used + /// only inside a transactional storage context and an Err result must imply a storage + /// rollback. + fn swap( sender: &T::AccountId, path: &BalancePath, send_to: &T::AccountId, @@ -912,11 +981,14 @@ pub mod pallet { /// Swap assets along the specified `path`, consuming `credit_in` and producing /// `credit_out`. /// - /// Note: - /// * this function might modify storage even if an error occurs. - /// * if an error occurs, `credit_in` is returned back. - /// * it's assumed that the provided `path` is valid and `credit_in` corresponds to the - /// first asset in the `path`. + /// If an error occurs, `credit_in` is returned back. + /// + /// Note: It's assumed that the provided `path` is valid and `credit_in` corresponds to the + /// first asset in the `path`. + /// + /// WARNING: This may return an error after a partial storage mutation. It should be used + /// only inside a transactional storage context and an Err result must imply a storage + /// rollback. fn credit_swap( credit_in: Credit, path: &BalancePath, @@ -1044,22 +1116,23 @@ pub mod pallet { path: BoundedVec, ) -> Result, DispatchError> { let mut balance_path: BalancePath = Vec::with_capacity(path.len()); - let mut amount_out: T::AssetBalance = amount_out; + let mut amount_in: T::AssetBalance = amount_out; let mut iter = path.into_iter().rev().peekable(); while let Some(asset2) = iter.next() { let asset1 = match iter.peek() { Some(a) => a, None => { - balance_path.push((asset2, amount_out)); + balance_path.push((asset2, amount_in)); break }, }; let (reserve_in, reserve_out) = Self::get_reserves(asset1, &asset2)?; - balance_path.push((asset2, amount_out)); - amount_out = Self::get_amount_in(&amount_out, &reserve_in, &reserve_out)?; + balance_path.push((asset2, amount_in)); + amount_in = Self::get_amount_in(&amount_in, &reserve_in, &reserve_out)?; } balance_path.reverse(); + Ok(balance_path) } diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index 7c4468d24b7c4..8724e99a16787 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -56,6 +56,43 @@ pub trait Swap { ) -> Result; } +/// Trait providing methods to swap between the various asset classes. +pub trait SwapCredit { + /// Measure units of the asset classes for swapping. + type Balance; + /// Kind of assets that are going to be swapped. + type MultiAssetId; + /// Credit implying a negative imbalance in the system that can be placed into an account or + /// alter the total supply. + type Credit; + + /// Swap exactly `credit_in` of asset `path[0]` for asset `path[last]`. If `amount_out_min` is + /// provided and the swap can't achieve at least this amount, an error is returned. + /// + /// On a successful swap, the function returns the `credit_out` of `path[last]` obtained from + /// the `credit_in`. On failure, it returns an `Err` containing the original `credit_in` and the + /// associated error code. + fn swap_exact_tokens_for_tokens( + path: Vec, + credit_in: Self::Credit, + amount_out_min: Option, + ) -> Result; + + /// Swaps a portion of `credit_in` of `path[0]` asset to obtain the desired `amount_out` of + /// the `path[last]` asset. The provided `credit_in` must be adequate to achieve the target + /// `amount_out`, or an error will occur. + /// + /// On success, the function returns a (`credit_out`, `credit_change`) tuple, where `credit_out` + /// represents the acquired amount of the `path[last]` asset, and `credit_change` is the + /// remaining portion from the `credit_in`. On failure, an `Err` with the initial `credit_in` + /// and error code is returned. + fn swap_tokens_for_exact_tokens( + path: Vec, + credit_in: Self::Credit, + amount_out: Self::Balance, + ) -> Result<(Self::Credit, Self::Credit), (Self::Credit, DispatchError)>; +} + impl Swap for Pallet { fn swap_exact_tokens_for_tokens( sender: T::AccountId, @@ -99,3 +136,33 @@ impl Swap f Ok(amount_in.into()) } } + +impl SwapCredit for Pallet { + type Balance = T::AssetBalance; + type MultiAssetId = T::MultiAssetId; + type Credit = Credit; + + fn swap_exact_tokens_for_tokens( + path: Vec, + credit_in: Self::Credit, + amount_out_min: Option, + ) -> Result { + let path = match path.try_into() { + Ok(p) => p, + Err(_) => return Err((credit_in, Error::::PathError.into())), + }; + Self::do_swap_exact_credit_tokens_for_tokens(path, credit_in, amount_out_min) + } + + fn swap_tokens_for_exact_tokens( + path: Vec, + credit_in: Self::Credit, + amount_out: Self::Balance, + ) -> Result<(Self::Credit, Self::Credit), (Self::Credit, DispatchError)> { + let path = match path.try_into() { + Ok(p) => p, + Err(_) => return Err((credit_in, Error::::PathError.into())), + }; + Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out) + } +} diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 1c1267ab87b3f..609d8b2316c14 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -948,9 +948,9 @@ fn can_swap_with_realistic_values() { assert!(events().contains(&Event::::SwapExecuted { who: user, send_to: user, - path: bvec![usd, dot], - amount_in: 10 * UNIT, // usd - amount_out: 1_993_980_120, // About 2 dot after div by UNIT. + path: bvec![(usd, 10 * UNIT), (dot, 1_993_980_120)], + // amount_in: 10 * UNIT, // usd + // amount_out: 1_993_980_120, // About 2 dot after div by UNIT. })); }); } diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 175ac11e375f3..7fe8e3d255db3 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -27,7 +27,7 @@ use sp_std::{cmp::Ordering, marker::PhantomData}; /// migration. pub(super) type PoolIdOf = (::MultiAssetId, ::MultiAssetId); -/// Represents a swap path with associated amounts for input and output. +/// Represents a swap path with associated asset amounts for input and output. /// /// Each pair of neighboring assets forms a pool. /// @@ -162,14 +162,23 @@ impl MultiAssetIdConverter, Asset } /// Credit of [Config::Currency]. +/// +/// Implies a negative imbalance in the system that can be placed into an account or alter the total +/// supply. pub type NativeCredit = CreditFungible<::AccountId, ::Currency>; -/// Credit of [Config::Assets]. +/// Credit (aka negative imbalance) of [Config::Assets]. +/// +/// Implies a negative imbalance in the system that can be placed into an account or alter the total +/// supply. pub type AssetCredit = CreditFungibles<::AccountId, ::Assets>; /// Credit that can be either [`NativeCredit`] or [`AssetCredit`]. +/// +/// Implies a negative imbalance in the system that can be placed into an account or alter the total +/// supply. pub enum Credit { /// Native credit. Native(NativeCredit), From a78ac716d36ed075b4390b847cdafc106219c0bd Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 22 Sep 2023 13:15:24 +0200 Subject: [PATCH 05/69] with transaction --- substrate/frame/asset-conversion/src/lib.rs | 3 +- substrate/frame/asset-conversion/src/swap.rs | 65 ++++++++++++++----- substrate/frame/asset-conversion/src/tests.rs | 2 - substrate/frame/asset-conversion/src/types.rs | 5 ++ 4 files changed, 54 insertions(+), 21 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 80d2c6e09f468..bf2476d8293fa 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -71,6 +71,7 @@ pub use weights::WeightInfo; use codec::Codec; use frame_support::{ + storage::{with_storage_layer, with_transaction}, traits::{ fungible::{ Balanced as BalancedFungible, Credit as CreditFungible, Inspect as InspectFungible, @@ -92,7 +93,7 @@ use sp_runtime::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, One, TrailingZeroInput, Zero, }, - BoundedVec, DispatchError, Saturating, + BoundedVec, DispatchError, Saturating, TransactionOutcome, }; #[frame_support::pallet] diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index 8724e99a16787..e64fd39782d4e 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -104,14 +104,16 @@ impl Swap f ) -> Result { let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_out_min = amount_out_min.map(Self::convert_hpb_to_asset_balance).transpose()?; - let amount_out = Self::do_swap_exact_tokens_for_tokens( - sender, - path, - Self::convert_hpb_to_asset_balance(amount_in)?, - amount_out_min, - send_to, - keep_alive, - )?; + let amount_out = with_storage_layer(|| { + Self::do_swap_exact_tokens_for_tokens( + sender, + path, + Self::convert_hpb_to_asset_balance(amount_in)?, + amount_out_min, + send_to, + keep_alive, + ) + })?; Ok(amount_out.into()) } @@ -125,14 +127,16 @@ impl Swap f ) -> Result { let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_in_max = amount_in_max.map(Self::convert_hpb_to_asset_balance).transpose()?; - let amount_in = Self::do_swap_tokens_for_exact_tokens( - sender, - path, - Self::convert_hpb_to_asset_balance(amount_out)?, - amount_in_max, - send_to, - keep_alive, - )?; + let amount_in = with_storage_layer(|| { + Self::do_swap_tokens_for_exact_tokens( + sender, + path, + Self::convert_hpb_to_asset_balance(amount_out)?, + amount_in_max, + send_to, + keep_alive, + ) + })?; Ok(amount_in.into()) } } @@ -151,7 +155,20 @@ impl SwapCredit for Pallet { Ok(p) => p, Err(_) => return Err((credit_in, Error::::PathError.into())), }; - Self::do_swap_exact_credit_tokens_for_tokens(path, credit_in, amount_out_min) + let transaction_res = + with_transaction(|| -> TransactionOutcome> { + let res = + Self::do_swap_exact_credit_tokens_for_tokens(path, credit_in, amount_out_min); + match &res { + Ok(_) => TransactionOutcome::Commit(Ok(res)), + Err(_) => TransactionOutcome::Rollback(Ok(res)), + } + }); + match transaction_res { + Ok(r) => r, + // should never happen, `with_transaction` above never returns an `Err` variant. + Err(_) => Err((Self::Credit::native_zero(), DispatchError::Corruption)), + } } fn swap_tokens_for_exact_tokens( @@ -163,6 +180,18 @@ impl SwapCredit for Pallet { Ok(p) => p, Err(_) => return Err((credit_in, Error::::PathError.into())), }; - Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out) + let transaction_res = + with_transaction(|| -> TransactionOutcome> { + let res = Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out); + match &res { + Ok(_) => TransactionOutcome::Commit(Ok(res)), + Err(_) => TransactionOutcome::Rollback(Ok(res)), + } + }); + match transaction_res { + Ok(r) => r, + // should never happen, `with_transaction` above never returns an `Err` variant. + Err(_) => Err((Self::Credit::native_zero(), DispatchError::Corruption)), + } } } diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 609d8b2316c14..b5d56cbc7155e 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -949,8 +949,6 @@ fn can_swap_with_realistic_values() { who: user, send_to: user, path: bvec![(usd, 10 * UNIT), (dot, 1_993_980_120)], - // amount_in: 10 * UNIT, // usd - // amount_out: 1_993_980_120, // About 2 dot after div by UNIT. })); }); } diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 7fe8e3d255db3..1b921a757a5a5 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -199,6 +199,11 @@ impl From> for Credit { } impl Credit { + /// Create zero native credit. + pub fn native_zero() -> Self { + NativeCredit::::zero().into() + } + /// Amount of `self`. pub fn peek(&self) -> Result { let amount = match self { From 888c9fad09e2bacadf70dccd304c11c13691310b Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 22 Sep 2023 15:14:07 +0200 Subject: [PATCH 06/69] preservation --- substrate/frame/asset-conversion/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index bf2476d8293fa..d549fe04512c2 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -877,14 +877,14 @@ pub mod pallet { amount: T::AssetBalance, keep_alive: bool, ) -> Result { + let preservation = match keep_alive { + true => Preserve, + false => Expendable, + }; match T::MultiAssetIdConverter::try_convert(asset_id) { MultiAssetIdConversionResult::Converted(asset_id) => - T::Assets::transfer(asset_id, from, to, amount, Expendable), + T::Assets::transfer(asset_id, from, to, amount, preservation), MultiAssetIdConversionResult::Native => { - let preservation = match keep_alive { - true => Preserve, - false => Expendable, - }; let amount = Self::convert_asset_balance_to_native_balance(amount)?; Ok(Self::convert_native_balance_to_asset_balance(T::Currency::transfer( from, @@ -1213,7 +1213,7 @@ pub mod pallet { reserve1: &T::AssetBalance, reserve2: &T::AssetBalance, ) -> Result> { - // amount * reserve2 / reserve1 + // (amount * reserve2) / reserve1 Self::mul_div(amount, reserve2, reserve1) } From 793b61253d51402df5f64d704ac41df8241cb611 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 22 Sep 2023 16:25:49 +0200 Subject: [PATCH 07/69] add amounts to the event --- substrate/frame/asset-conversion/src/lib.rs | 34 +++++++++++++++---- substrate/frame/asset-conversion/src/tests.rs | 2 ++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index d549fe04512c2..cbc2bb3b40ad9 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -277,12 +277,20 @@ pub mod pallet { who: T::AccountId, /// The account that the assets were transferred to. send_to: T::AccountId, + /// The amount of the first asset that was swapped. + amount_in: T::AssetBalance, + /// The amount of the second asset that was received. + amount_out: T::AssetBalance, /// The route of asset ids with amounts that the swap went through. /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) path: BalancePath, }, /// Assets have been converted from one to another. CreditSwapExecuted { + /// The amount of the first asset that was swapped. + amount_in: T::AssetBalance, + /// The amount of the second asset that was received. + amount_out: T::AssetBalance, /// The route of asset ids with amounts that the swap went through. /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) path: BalancePath, @@ -726,7 +734,13 @@ pub mod pallet { Self::swap(&sender, &path, &send_to, keep_alive)?; - Self::deposit_event(Event::SwapExecuted { who: sender, send_to, path }); + Self::deposit_event(Event::SwapExecuted { + who: sender, + send_to, + amount_in, + amount_out, + path, + }); Ok(amount_out) } @@ -768,7 +782,13 @@ pub mod pallet { Self::swap(&sender, &path, &send_to, keep_alive)?; - Self::deposit_event(Event::SwapExecuted { who: sender, send_to, path }); + Self::deposit_event(Event::SwapExecuted { + who: sender, + send_to, + amount_in, + amount_out, + path, + }); Ok(amount_in) } @@ -805,16 +825,16 @@ pub mod pallet { amount_out_min.map_or(true, |a| amount_out >= a), Error::::ProvidedMinimumNotSufficientForSwap ); - Ok(path) + Ok((path, amount_out)) }; - let path = match inspect_path(credit_in.asset()) { - Ok(p) => p, + let (path, amount_out) = match inspect_path(credit_in.asset()) { + Ok((p, a)) => (p, a), Err(e) => return Err((credit_in, e)), }; let credit_out = Self::credit_swap(credit_in, &path)?; - Self::deposit_event(Event::CreditSwapExecuted { path }); + Self::deposit_event(Event::CreditSwapExecuted { amount_in, amount_out, path }); Ok(credit_out) } @@ -864,7 +884,7 @@ pub mod pallet { let (credit_in, credit_change) = credit_in.split(amount_in)?; let credit_out = Self::credit_swap(credit_in, &path)?; - Self::deposit_event(Event::CreditSwapExecuted { path }); + Self::deposit_event(Event::CreditSwapExecuted { amount_in, amount_out, path }); Ok((credit_out, credit_change)) } diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index b5d56cbc7155e..639ecafb8ed75 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -948,6 +948,8 @@ fn can_swap_with_realistic_values() { assert!(events().contains(&Event::::SwapExecuted { who: user, send_to: user, + amount_in: 10 * UNIT, // usd + amount_out: 1_993_980_120, // About 2 dot after div by UNIT. path: bvec![(usd, 10 * UNIT), (dot, 1_993_980_120)], })); }); From cdaf50027ef83bb52b9b148584ef4eb941cd3c8a Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 25 Sep 2023 15:59:57 +0200 Subject: [PATCH 08/69] not expendable constraint --- substrate/frame/asset-conversion/src/lib.rs | 26 ++-- substrate/frame/asset-conversion/src/tests.rs | 144 +++++++++++++++++- 2 files changed, 154 insertions(+), 16 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index cbc2bb3b40ad9..37cdfbca5f89f 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -93,7 +93,7 @@ use sp_runtime::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, One, TrailingZeroInput, Zero, }, - BoundedVec, DispatchError, Saturating, TransactionOutcome, + BoundedVec, DispatchError, Saturating, TokenError, TransactionOutcome, }; #[frame_support::pallet] @@ -940,11 +940,25 @@ pub mod pallet { false => Expendable, }; match T::MultiAssetIdConverter::try_convert(asset) { - MultiAssetIdConversionResult::Converted(asset) => + MultiAssetIdConversionResult::Converted(asset) => { + if preservation == Preserve { + // TODO drop the ensure! when this issue addressed + // https://github.com/paritytech/polkadot-sdk/issues/1698 + let free = + T::Assets::reducible_balance(asset.clone(), who, preservation, Polite); + ensure!(free >= value, TokenError::NotExpendable); + } T::Assets::withdraw(asset, who, value, Exact, preservation, Polite) - .map(|c| c.into()), + .map(|c| c.into()) + }, MultiAssetIdConversionResult::Native => { let value = Self::convert_asset_balance_to_native_balance(value)?; + if preservation == Preserve { + // TODO drop the ensure! when this issue addressed + // https://github.com/paritytech/polkadot-sdk/issues/1698 + let free = T::Currency::reducible_balance(who, preservation, Polite); + ensure!(free >= value, TokenError::NotExpendable); + } T::Currency::withdraw(who, value, Exact, preservation, Polite).map(|c| c.into()) }, MultiAssetIdConversionResult::Unsupported(_) => @@ -1021,12 +1035,6 @@ pub mod pallet { asset1.clone(), asset2.clone(), )); - - let reserve = Self::get_balance(&pool_from, asset2)?; - let reserve_left = reserve.saturating_sub(*amount_out); - Self::validate_minimal_amount(reserve_left, asset2) - .map_err(|_| Error::::ReserveLeftLessThanMinimal)?; - if let Some((asset3, _)) = path.get(pos + 2) { let pool_to = Self::get_pool_account(&Self::get_pool_id( asset2.clone(), diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 639ecafb8ed75..86fb61edcb775 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -19,7 +19,7 @@ use crate::{mock::*, *}; use frame_support::{ assert_noop, assert_ok, instances::Instance1, - traits::{fungible::Inspect, fungibles::InspectEnumerable, Get}, + traits::{fungible, fungibles, fungibles::InspectEnumerable, Get}, }; use sp_arithmetic::Permill; use sp_runtime::{DispatchError, TokenError}; @@ -65,13 +65,17 @@ fn pool_assets() -> Vec { } fn create_tokens(owner: u128, tokens: Vec>) { + create_tokens_with_ed(owner, tokens, 1) +} + +fn create_tokens_with_ed(owner: u128, tokens: Vec>, ed: u128) { for token_id in tokens { let MultiAssetIdConversionResult::Converted(asset_id) = NativeOrAssetIdConverter::try_convert(&token_id) else { unreachable!("invalid token") }; - assert_ok!(Assets::force_create(RuntimeOrigin::root(), asset_id, owner, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), asset_id, owner, false, ed)); } } @@ -444,8 +448,14 @@ fn can_remove_liquidity() { let lp_token = AssetConversion::get_next_pool_asset_id(); assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); - assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000000000)); - assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 100000)); + let ed_token_1 = >::minimum_balance(); + let ed_token_2 = >::minimum_balance(2); + assert_ok!(Balances::force_set_balance( + RuntimeOrigin::root(), + user, + 10000000000 + ed_token_1 + )); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 100000 + ed_token_2)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), @@ -487,8 +497,8 @@ fn can_remove_liquidity() { assert_eq!(balance(pool_account, token_2), 10001); assert_eq!(pool_balance(pool_account, lp_token), 100); - assert_eq!(balance(user, token_1), 10000000000 - 1000000000 + 899991000); - assert_eq!(balance(user, token_2), 89999); + assert_eq!(balance(user, token_1), 10000000000 - 1000000000 + 899991000 + ed_token_1); + assert_eq!(balance(user, token_2), 89999 + ed_token_2); assert_eq!(pool_balance(user, lp_token), 0); }); } @@ -1050,7 +1060,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { user, false, ), - Error::::ReserveLeftLessThanMinimal + TokenError::NotExpendable, ); assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( @@ -1308,6 +1318,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 101)); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 10000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user2, 1000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user, 2)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), @@ -1343,6 +1354,125 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { ), DispatchError::Token(TokenError::NotExpendable) ); + + assert_noop!( + AssetConversion::swap_tokens_for_exact_tokens( + RuntimeOrigin::signed(user), + bvec![token_2, token_1], + 51, // amount_out + 2, // amount_in_max + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); + + assert_noop!( + AssetConversion::swap_exact_tokens_for_tokens( + RuntimeOrigin::signed(user), + bvec![token_2, token_1], + 2, // amount_in + 1, // amount_out_min + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); + }); +} + +#[test] +fn swap_when_existential_deposit_would_cause_reaping_pool_account() { + new_test_ext().execute_with(|| { + let user = 1; + let user2 = 2; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + let token_3 = NativeOrAssetId::Asset(3); + + let ed_assets = 100; + create_tokens_with_ed(user2, vec![token_2, token_3], ed_assets); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_2)); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_3)); + + let ed = get_ed(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user2, 200 + ed_assets)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 3, user2, 10000 + ed_assets)); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user, 400 + ed_assets)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 3, user, 20000 + ed_assets)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user2), + token_1, + token_2, + 10000, + 200, + 1, + 1, + user2, + )); + + assert_noop!( + AssetConversion::swap_tokens_for_exact_tokens( + RuntimeOrigin::signed(user), + bvec![token_1, token_2], + 110, // amount_out + 20000, // amount_in_max + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); + + assert_noop!( + AssetConversion::swap_exact_tokens_for_tokens( + RuntimeOrigin::signed(user), + bvec![token_1, token_2], + 15000, // amount_in + 110, // amount_out_min + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user2), + token_1, + token_3, + 200, + 10000, + 1, + 1, + user2, + )); + + assert_noop!( + AssetConversion::swap_tokens_for_exact_tokens( + RuntimeOrigin::signed(user), + bvec![token_3, token_1], + 110, // amount_out + 20000, // amount_in_max + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); + + assert_noop!( + AssetConversion::swap_exact_tokens_for_tokens( + RuntimeOrigin::signed(user), + bvec![token_3, token_1], + 15000, // amount_in + 110, // amount_out_min + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); }); } From e237dfc651de6d0a80977996b7657fe132df5123 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 25 Sep 2023 17:15:17 +0200 Subject: [PATCH 09/69] vec import --- substrate/frame/asset-conversion/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 37cdfbca5f89f..bb084f143e50d 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -95,6 +95,7 @@ use sp_runtime::{ }, BoundedVec, DispatchError, Saturating, TokenError, TransactionOutcome, }; +use sp_std::vec::Vec; #[frame_support::pallet] pub mod pallet { From 0c13c85c4eeb58ced65a5a21f27d748b624ce62c Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 25 Sep 2023 18:14:09 +0200 Subject: [PATCH 10/69] fix tests, preserve account --- .../asset-conversion-tx-payment/src/tests.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs index 9e9b74a0ddb2e..cad301dc9599c 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs @@ -19,7 +19,10 @@ use frame_support::{ assert_ok, dispatch::{DispatchInfo, PostDispatchInfo}, pallet_prelude::*, - traits::{fungible::Inspect, fungibles::Mutate}, + traits::{ + fungible::Inspect, + fungibles::{Inspect as FungiblesInspect, Mutate}, + }, weights::Weight, }; use frame_system as system; @@ -110,13 +113,19 @@ fn default_post_info() -> PostDispatchInfo { fn setup_lp(asset_id: u32, balance_factor: u64) { let lp_provider = 5; + let ed = Balances::minimum_balance(); + let ed_asset = Assets::minimum_balance(asset_id); assert_ok!(Balances::force_set_balance( RuntimeOrigin::root(), lp_provider, - 10_000 * balance_factor + 10_000 * balance_factor + ed, )); let lp_provider_account = ::Lookup::unlookup(lp_provider); - assert_ok!(Assets::mint_into(asset_id.into(), &lp_provider_account, 10_000 * balance_factor)); + assert_ok!(Assets::mint_into( + asset_id.into(), + &lp_provider_account, + 10_000 * balance_factor + ed_asset + )); let token_1 = NativeOrAssetId::Native; let token_2 = NativeOrAssetId::Asset(asset_id); From 24654b88c235dc0b9b7a4d150fbff83909785723 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 26 Sep 2023 16:08:57 +0200 Subject: [PATCH 11/69] tests --- substrate/frame/asset-conversion/src/tests.rs | 86 ++++++++++++++++--- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 86fb61edcb775..e3530ea3e2061 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -1394,12 +1394,13 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { create_tokens_with_ed(user2, vec![token_2, token_3], ed_assets); assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_2)); assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_3)); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_2, token_3)); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 20000 + ed)); - assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user2, 200 + ed_assets)); - assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 3, user2, 10000 + ed_assets)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user2, 400 + ed_assets)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 3, user2, 20000 + ed_assets)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user, 400 + ed_assets)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 3, user, 20000 + ed_assets)); @@ -1415,6 +1416,29 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { user2, )); + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user2), + token_1, + token_3, + 200, + 10000, + 1, + 1, + user2, + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user2), + token_2, + token_3, + 200, + 10000, + 1, + 1, + user2, + )); + + // causes an account removal for asset token 2 assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), @@ -1427,6 +1451,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { DispatchError::Token(TokenError::NotExpendable) ); + // causes an account removal for asset token 2 assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), @@ -1439,17 +1464,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { DispatchError::Token(TokenError::NotExpendable) ); - assert_ok!(AssetConversion::add_liquidity( - RuntimeOrigin::signed(user2), - token_1, - token_3, - 200, - 10000, - 1, - 1, - user2, - )); - + // causes an account removal for native token 1 assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), @@ -1462,6 +1477,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { DispatchError::Token(TokenError::NotExpendable) ); + // causes an account removal for native token 1 assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), @@ -1473,6 +1489,50 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { ), DispatchError::Token(TokenError::NotExpendable) ); + + // causes an account removal for native token 1 locate in the middle of a swap path + let amount_in = AssetConversion::balance_path_from_amount_out( + 110, + vec![token_3, token_1].try_into().unwrap(), + ) + .unwrap() + .first() + .map(|(_, a)| a.clone()) + .unwrap(); + + assert_noop!( + AssetConversion::swap_exact_tokens_for_tokens( + RuntimeOrigin::signed(user), + bvec![token_3, token_1, token_2], + amount_in, // amount_in + 1, // amount_out_min + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); + + // causes an account removal for asset token 2 locate in the middle of a swap path + let amount_in = AssetConversion::balance_path_from_amount_out( + 110, + vec![token_1, token_2].try_into().unwrap(), + ) + .unwrap() + .first() + .map(|(_, a)| a.clone()) + .unwrap(); + + assert_noop!( + AssetConversion::swap_exact_tokens_for_tokens( + RuntimeOrigin::signed(user), + bvec![token_1, token_2, token_3], + amount_in, // amount_in + 1, // amount_out_min + user, + true, + ), + DispatchError::Token(TokenError::NotExpendable) + ); }); } From e0bd8b71cbe2607c96f331d90216a2cc2eb96ebb Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 26 Sep 2023 16:15:33 +0200 Subject: [PATCH 12/69] max lenght of the swap path in swap trait --- substrate/frame/asset-conversion/src/lib.rs | 1 + substrate/frame/asset-conversion/src/swap.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index bb084f143e50d..a3fa1464dd526 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -88,6 +88,7 @@ use frame_support::{ }, BoundedBTreeSet, PalletId, }; +use sp_core::Get; use sp_runtime::{ traits::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index e64fd39782d4e..2bff86392b388 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -21,6 +21,9 @@ use super::*; /// Trait for providing methods to swap between the various asset classes. pub trait Swap { + /// Returns the upper limit on the length of the swap path. + fn max_path_len() -> u32; + /// Swap exactly `amount_in` of asset `path[0]` for asset `path[1]`. /// If an `amount_out_min` is specified, it will return an error if it is unable to acquire /// the amount desired. @@ -66,6 +69,9 @@ pub trait SwapCredit { /// alter the total supply. type Credit; + /// Returns the upper limit on the length of the swap path. + fn max_path_len() -> u32; + /// Swap exactly `credit_in` of asset `path[0]` for asset `path[last]`. If `amount_out_min` is /// provided and the swap can't achieve at least this amount, an error is returned. /// @@ -94,6 +100,10 @@ pub trait SwapCredit { } impl Swap for Pallet { + fn max_path_len() -> u32 { + T::MaxSwapPathLength::get() + } + fn swap_exact_tokens_for_tokens( sender: T::AccountId, path: Vec, @@ -146,6 +156,10 @@ impl SwapCredit for Pallet { type MultiAssetId = T::MultiAssetId; type Credit = Credit; + fn max_path_len() -> u32 { + T::MaxSwapPathLength::get() + } + fn swap_exact_tokens_for_tokens( path: Vec, credit_in: Self::Credit, From 80dbcab83f26e29ec6801c7d30d15f35a726e780 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 26 Sep 2023 16:39:45 +0200 Subject: [PATCH 13/69] fix clippy --- substrate/frame/asset-conversion/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index e3530ea3e2061..6503c4b7d8c0c 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -1497,7 +1497,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { ) .unwrap() .first() - .map(|(_, a)| a.clone()) + .map(|(_, a)| *a) .unwrap(); assert_noop!( @@ -1519,7 +1519,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { ) .unwrap() .first() - .map(|(_, a)| a.clone()) + .map(|(_, a)| *a) .unwrap(); assert_noop!( From 847207be9dc286137dd68601f325debb343cb459 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 26 Sep 2023 18:24:38 +0200 Subject: [PATCH 14/69] debug impls for imbalances --- .../src/traits/tokens/fungible/imbalance.rs | 22 +++++++++++-- .../src/traits/tokens/fungibles/imbalance.rs | 33 +++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index de85924a4de7c..1357056d3a07e 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -23,7 +23,7 @@ use crate::traits::{ misc::{SameOrOther, TryDrop}, tokens::Balance, }; -use sp_runtime::{traits::Zero, RuntimeDebug}; +use sp_runtime::traits::Zero; use sp_std::marker::PhantomData; /// Handler for when an imbalance gets dropped. This could handle either a credit (negative) or @@ -43,7 +43,7 @@ impl HandleImbalanceDrop for () { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] -#[derive(RuntimeDebug, Eq, PartialEq)] +#[derive(Eq, PartialEq)] pub struct Imbalance< B: Balance, OnDrop: HandleImbalanceDrop, @@ -141,6 +141,24 @@ impl, OppositeOnDrop: HandleImbalance } } +#[cfg(any(feature = "std", feature = "force-debug"))] +impl, OppositeOnDrop: HandleImbalanceDrop> + sp_std::fmt::Debug for Imbalance +{ + fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fmt.debug_struct("Imbalance").field("amount", &self.amount).finish() + } +} + +#[cfg(all(not(feature = "std"), not(feature = "force-debug")))] +impl, OppositeOnDrop: HandleImbalanceDrop> + sp_std::fmt::Debug for Imbalance +{ + fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fmt.write_str("") + } +} + /// Imbalance implying that the total_issuance value is less than the sum of all account balances. pub type Debt = Imbalance< >::Balance, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 1668268ea2dcf..17e22cf917e78 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -23,7 +23,7 @@ use crate::traits::{ misc::{SameOrOther, TryDrop}, tokens::{AssetId, Balance}, }; -use sp_runtime::{traits::Zero, RuntimeDebug}; +use sp_runtime::traits::Zero; use sp_std::marker::PhantomData; /// Handler for when an imbalance gets dropped. This could handle either a credit (negative) or @@ -38,7 +38,7 @@ pub trait HandleImbalanceDrop { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] -#[derive(RuntimeDebug, Eq, PartialEq)] +#[derive(Eq, PartialEq)] pub struct Imbalance< A: AssetId, B: Balance, @@ -158,6 +158,35 @@ impl< } } +#[cfg(any(feature = "std", feature = "force-debug"))] +impl< + A: AssetId, + B: Balance, + OnDrop: HandleImbalanceDrop, + OppositeOnDrop: HandleImbalanceDrop, + > sp_std::fmt::Debug for Imbalance +{ + fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fmt.debug_struct("Imbalance") + .field("asset", &self.asset) + .field("amount", &self.amount) + .finish() + } +} + +#[cfg(all(not(feature = "std"), not(feature = "force-debug")))] +impl< + A: AssetId, + B: Balance, + OnDrop: HandleImbalanceDrop, + OppositeOnDrop: HandleImbalanceDrop, + > sp_std::fmt::Debug for Imbalance +{ + fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + fmt.write_str("") + } +} + /// Imbalance implying that the total_issuance value is less than the sum of all account balances. pub type Debt = Imbalance< >::AssetId, From 53c699f3745927984e1729538cc738f0f6efdaa5 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 28 Sep 2023 13:16:13 +0200 Subject: [PATCH 15/69] eq and partial_eq impls for imbalance --- .../src/traits/tokens/fungible/imbalance.rs | 20 ++++++++++++++-- .../src/traits/tokens/fungibles/imbalance.rs | 24 ++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index 1357056d3a07e..49b0b506db09b 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -43,7 +43,6 @@ impl HandleImbalanceDrop for () { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] -#[derive(Eq, PartialEq)] pub struct Imbalance< B: Balance, OnDrop: HandleImbalanceDrop, @@ -141,12 +140,29 @@ impl, OppositeOnDrop: HandleImbalance } } +impl, OppositeOnDrop: HandleImbalanceDrop> PartialEq + for Imbalance +{ + fn eq(&self, other: &Self) -> bool { + self.amount.eq(&other.amount) + } +} + +impl, OppositeOnDrop: HandleImbalanceDrop> Eq + for Imbalance +{ +} + #[cfg(any(feature = "std", feature = "force-debug"))] impl, OppositeOnDrop: HandleImbalanceDrop> sp_std::fmt::Debug for Imbalance { fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - fmt.debug_struct("Imbalance").field("amount", &self.amount).finish() + fmt.debug_struct("Imbalance") + .field("amount", &self.amount) + .field("OnDrop", &sp_std::any::type_name::()) + .field("OppositeOnDrop", &sp_std::any::type_name::()) + .finish() } } diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 17e22cf917e78..c1880cf087a51 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -38,7 +38,6 @@ pub trait HandleImbalanceDrop { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] -#[derive(Eq, PartialEq)] pub struct Imbalance< A: AssetId, B: Balance, @@ -158,6 +157,27 @@ impl< } } +impl< + A: AssetId, + B: Balance, + OnDrop: HandleImbalanceDrop, + OppositeOnDrop: HandleImbalanceDrop, + > PartialEq for Imbalance +{ + fn eq(&self, other: &Self) -> bool { + self.amount.eq(&other.amount) && self.asset.eq(&other.asset) + } +} + +impl< + A: AssetId, + B: Balance, + OnDrop: HandleImbalanceDrop, + OppositeOnDrop: HandleImbalanceDrop, + > Eq for Imbalance +{ +} + #[cfg(any(feature = "std", feature = "force-debug"))] impl< A: AssetId, @@ -170,6 +190,8 @@ impl< fmt.debug_struct("Imbalance") .field("asset", &self.asset) .field("amount", &self.amount) + .field("OnDrop", &sp_std::any::type_name::()) + .field("OppositeOnDrop", &sp_std::any::type_name::()) .finish() } } From 827ce1bf93049f74f0c53e619063be531443419b Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 28 Sep 2023 13:20:41 +0200 Subject: [PATCH 16/69] eq, partial_eq, runtime debug for credit --- substrate/frame/asset-conversion/src/lib.rs | 2 +- substrate/frame/asset-conversion/src/types.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index a3fa1464dd526..b1fd109aa8fe6 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -94,7 +94,7 @@ use sp_runtime::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, One, TrailingZeroInput, Zero, }, - BoundedVec, DispatchError, Saturating, TokenError, TransactionOutcome, + BoundedVec, DispatchError, RuntimeDebug, Saturating, TokenError, TransactionOutcome, }; use sp_std::vec::Vec; diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 1b921a757a5a5..466faf4340318 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -179,6 +179,7 @@ pub type AssetCredit = /// /// Implies a negative imbalance in the system that can be placed into an account or alter the total /// supply. +#[derive(RuntimeDebug, Eq, PartialEq)] pub enum Credit { /// Native credit. Native(NativeCredit), From d533acf69137a79c8fe79f84e6053f0b06f1bff0 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 28 Sep 2023 13:21:10 +0200 Subject: [PATCH 17/69] tests --- substrate/frame/asset-conversion/src/tests.rs | 404 +++++++++++++++++- 1 file changed, 403 insertions(+), 1 deletion(-) diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 6503c4b7d8c0c..f86cb6c12d75e 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -17,7 +17,7 @@ use crate::{mock::*, *}; use frame_support::{ - assert_noop, assert_ok, + assert_noop, assert_ok, assert_storage_noop, instances::Instance1, traits::{fungible, fungibles, fungibles::InspectEnumerable, Get}, }; @@ -1875,3 +1875,405 @@ fn cannot_block_pool_creation() { )); }); } + +#[test] +fn swap_transactional() { + new_test_ext().execute_with(|| { + let user = 1; + let user2 = 2; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + let token_3 = NativeOrAssetId::Asset(3); + + let asset_ed = 150; + create_tokens_with_ed(user, vec![token_2, token_3], asset_ed); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_3)); + + let ed = get_ed(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 3, user, 1000)); + + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, 1000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 3, user2, 1000)); + + let liquidity1 = 10000; + let liquidity2 = 200; + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_2, + liquidity1, + liquidity2, + 1, + 1, + user, + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_3, + liquidity1, + liquidity2, + 1, + 1, + user, + )); + + let pool_1 = AssetConversion::get_pool_account(&(token_1, token_2)); + let pool_2 = AssetConversion::get_pool_account(&(token_1, token_3)); + + assert_eq!(Balances::balance(&pool_1), liquidity1); + assert_eq!(Assets::balance(2, &pool_1), liquidity2); + assert_eq!(Balances::balance(&pool_2), liquidity1); + assert_eq!(Assets::balance(3, &pool_2), liquidity2); + + // the amount that would cause a transfer from the last pool in the path to fail + let expected_out = liquidity2 - asset_ed + 1; + let amount_in = AssetConversion::balance_path_from_amount_out( + expected_out, + vec![token_2, token_1, token_3].try_into().unwrap(), + ) + .unwrap() + .first() + .map(|(_, a)| *a) + .unwrap(); + + // swap credit with `swap_tokens_for_exact_tokens` transactional + let credit_in = Assets::issue(2, amount_in); + let credit_in_err_expected = Assets::issue(2, amount_in); + // avoiding drop of any credit, to assert any storage mutation from an actual call. + let error; + assert_storage_noop!( + error = >::swap_tokens_for_exact_tokens( + bvec![token_2, token_1, token_3], + credit_in.into(), + expected_out, + ) + .unwrap_err() + ); + assert_eq!(error, (credit_in_err_expected.into(), TokenError::NotExpendable.into())); + + // swap credit with `swap_exact_tokens_for_tokens` transactional + let credit_in = Assets::issue(2, amount_in); + let credit_in_err_expected = Assets::issue(2, amount_in); + // avoiding drop of any credit, to assert any storage mutation from an actual call. + let error; + assert_storage_noop!( + error = >::swap_exact_tokens_for_tokens( + bvec![token_2, token_1, token_3], + credit_in.into(), + Some(expected_out), + ) + .unwrap_err() + ); + assert_eq!(error, (credit_in_err_expected.into(), TokenError::NotExpendable.into())); + + // swap with `swap_exact_tokens_for_tokens` transactional + assert_noop!( + >::swap_exact_tokens_for_tokens( + user2, + bvec![token_2, token_1, token_3], + amount_in.into(), + Some(expected_out.into()), + user2, + true, + ), + TokenError::NotExpendable + ); + + // swap with `swap_exact_tokens_for_tokens` transactional + assert_noop!( + >::swap_tokens_for_exact_tokens( + user2, + bvec![token_2, token_1, token_3], + expected_out.into(), + Some(amount_in.into()), + user2, + true, + ), + TokenError::NotExpendable + ); + + assert_eq!(Balances::balance(&pool_1), liquidity1); + assert_eq!(Assets::balance(2, &pool_1), liquidity2); + assert_eq!(Balances::balance(&pool_2), liquidity1); + assert_eq!(Assets::balance(3, &pool_2), liquidity2); + }) +} + +#[test] +fn swap_credit_returns_change() { + new_test_ext().execute_with(|| { + let user = 1; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + + create_tokens(user, vec![token_2]); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + + let ed = get_ed(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + let liquidity1 = 10000; + let liquidity2 = 200; + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_2, + liquidity1, + liquidity2, + 1, + 1, + user, + )); + + let expected_change = Balances::issue(100); + let expected_credit_out = Assets::issue(2, 20); + + let amount_in_max = + AssetConversion::get_amount_in(&expected_credit_out.peek(), &liquidity1, &liquidity2) + .unwrap(); + + let credit_in = Balances::issue(amount_in_max + expected_change.peek()); + assert_ok!( + >::swap_tokens_for_exact_tokens( + bvec![token_1, token_2], + credit_in.into(), + expected_credit_out.peek(), + ), + (expected_credit_out.into(), expected_change.into()) + ); + }) +} + +#[test] +fn swap_credit_insufficient_amount_bounds() { + new_test_ext().execute_with(|| { + let user = 1; + let user2 = 2; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + + create_tokens(user, vec![token_2]); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + + let ed = get_ed(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, 1000)); + + let liquidity1 = 10000; + let liquidity2 = 200; + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_2, + liquidity1, + liquidity2, + 1, + 1, + user, + )); + + // provided `credit_in` is not sufficient to swap for desired `amount_out_min` + let amount_out_min = 20; + let amount_in = + AssetConversion::get_amount_in(&(amount_out_min - 1), &liquidity2, &liquidity1) + .unwrap(); + let credit_in = Balances::issue(amount_in); + let expected_credit_in = Balances::issue(amount_in); + let error = >::swap_exact_tokens_for_tokens( + bvec![token_1, token_2], + credit_in.into(), + Some(amount_out_min), + ) + .unwrap_err(); + assert_eq!( + error, + (expected_credit_in.into(), Error::::ProvidedMinimumNotSufficientForSwap.into()) + ); + + // provided `credit_in` is not sufficient to swap for desired `amount_out` + let amount_out = 20; + let amount_in_max = + AssetConversion::get_amount_in(&(amount_out - 1), &liquidity2, &liquidity1).unwrap(); + let credit_in = Balances::issue(amount_in_max); + let expected_credit_in = Balances::issue(amount_in_max); + let error = >::swap_tokens_for_exact_tokens( + bvec![token_1, token_2], + credit_in.into(), + amount_out, + ) + .unwrap_err(); + assert_eq!( + error, + (expected_credit_in.into(), Error::::ProvidedMaximumNotSufficientForSwap.into()) + ); + }) +} + +#[test] +fn swap_credit_zero_amount() { + new_test_ext().execute_with(|| { + let user = 1; + let user2 = 2; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + + create_tokens(user, vec![token_2]); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + + let ed = get_ed(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, 1000)); + + let liquidity1 = 10000; + let liquidity2 = 200; + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_2, + liquidity1, + liquidity2, + 1, + 1, + user, + )); + + // swap with zero credit fails for `swap_exact_tokens_for_tokens` + let credit_in = Credit::native_zero(); + let expected_credit_in = Credit::native_zero(); + let error = >::swap_exact_tokens_for_tokens( + bvec![token_1, token_2], + credit_in, + None, + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in, Error::::ZeroAmount.into())); + + // swap with zero credit fails for `swap_tokens_for_exact_tokens` + let credit_in = Credit::native_zero(); + let expected_credit_in = Credit::native_zero(); + let error = >::swap_tokens_for_exact_tokens( + bvec![token_1, token_2], + credit_in, + 10, + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in, Error::::ZeroAmount.into())); + + // swap with zero amount_out_min fails for `swap_exact_tokens_for_tokens` + let credit_in = Balances::issue(10); + let expected_credit_in = Balances::issue(10); + let error = >::swap_exact_tokens_for_tokens( + bvec![token_1, token_2], + credit_in.into(), + Some(0), + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in.into(), Error::::ZeroAmount.into())); + + // swap with zero amount_out fails with `swap_tokens_for_exact_tokens` fails + let credit_in = Balances::issue(10); + let expected_credit_in = Balances::issue(10); + let error = >::swap_tokens_for_exact_tokens( + bvec![token_1, token_2], + credit_in.into(), + 0, + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in.into(), Error::::ZeroAmount.into())); + }); +} + +#[test] +fn swap_credit_invalid_path() { + new_test_ext().execute_with(|| { + let user = 1; + let user2 = 2; + let token_1 = NativeOrAssetId::Native; + let token_2 = NativeOrAssetId::Asset(2); + + create_tokens(user, vec![token_2]); + assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + + let ed = get_ed(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 20000 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, 1000)); + + let liquidity1 = 10000; + let liquidity2 = 200; + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + token_1, + token_2, + liquidity1, + liquidity2, + 1, + 1, + user, + )); + + // swap with credit_in.asset different from path[0] asset fails + let credit_in = Balances::issue(10); + let expected_credit_in = Balances::issue(10); + let error = >::swap_exact_tokens_for_tokens( + bvec![token_2, token_1], + credit_in.into(), + None, + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + + // swap with credit_in.asset different from path[0] asset fails + let credit_in = Assets::issue(2, 10); + let expected_credit_in = Assets::issue(2, 10); + let error = >::swap_tokens_for_exact_tokens( + bvec![token_1, token_2], + credit_in.into(), + 10, + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + + // swap with path.len < 2 fails + let credit_in = Balances::issue(10); + let expected_credit_in = Balances::issue(10); + let error = >::swap_exact_tokens_for_tokens( + bvec![token_2], + credit_in.into(), + None, + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + + // swap with path.len < 2 fails + let credit_in = Assets::issue(2, 10); + let expected_credit_in = Assets::issue(2, 10); + let error = >::swap_tokens_for_exact_tokens( + bvec![], + credit_in.into(), + 10, + ) + .unwrap_err(); + assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + }); +} From 69b17f81634ed41daf4f922ae7159e93961dc771 Mon Sep 17 00:00:00 2001 From: Muharem Date: Thu, 28 Sep 2023 13:24:07 +0200 Subject: [PATCH 18/69] Apply suggestions from code review Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- substrate/frame/asset-conversion/src/lib.rs | 4 ++-- substrate/frame/asset-conversion/src/swap.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index b1fd109aa8fe6..33c761611e25b 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -283,7 +283,7 @@ pub mod pallet { amount_in: T::AssetBalance, /// The amount of the second asset that was received. amount_out: T::AssetBalance, - /// The route of asset ids with amounts that the swap went through. + /// The route of asset IDs with amounts that the swap went through. /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) path: BalancePath, }, @@ -293,7 +293,7 @@ pub mod pallet { amount_in: T::AssetBalance, /// The amount of the second asset that was received. amount_out: T::AssetBalance, - /// The route of asset ids with amounts that the swap went through. + /// The route of asset IDs with amounts that the swap went through. /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) path: BalancePath, }, diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index 2bff86392b388..fed03363b4973 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -24,7 +24,7 @@ pub trait Swap { /// Returns the upper limit on the length of the swap path. fn max_path_len() -> u32; - /// Swap exactly `amount_in` of asset `path[0]` for asset `path[1]`. + /// Swap exactly `amount_in` of asset `path[0]` for asset `path[last]`. /// If an `amount_out_min` is specified, it will return an error if it is unable to acquire /// the amount desired. /// From 28edff58cee8ef6026ad2273414d83fa51f89ed4 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 28 Sep 2023 13:26:23 +0200 Subject: [PATCH 19/69] correct docs --- substrate/frame/asset-conversion/src/swap.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index fed03363b4973..ec1f03a461b1b 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -28,10 +28,10 @@ pub trait Swap { /// If an `amount_out_min` is specified, it will return an error if it is unable to acquire /// the amount desired. /// - /// Withdraws the `path[0]` asset from `sender`, deposits the `path[1]` asset to `send_to`, + /// Withdraws the `path[0]` asset from `sender`, deposits the `path[last]` asset to `send_to`, /// respecting `keep_alive`. /// - /// If successful, returns the amount of `path[1]` acquired for the `amount_in`. + /// If successful, returns the amount of `path[last]` acquired for the `amount_in`. fn swap_exact_tokens_for_tokens( sender: AccountId, path: Vec, @@ -41,14 +41,14 @@ pub trait Swap { keep_alive: bool, ) -> Result; - /// Take the `path[0]` asset and swap some amount for `amount_out` of the `path[1]`. If an + /// Take the `path[0]` asset and swap some amount for `amount_out` of the `path[last]`. If an /// `amount_in_max` is specified, it will return an error if acquiring `amount_out` would be /// too costly. /// - /// Withdraws `path[0]` asset from `sender`, deposits `path[1]` asset to `send_to`, + /// Withdraws `path[0]` asset from `sender`, deposits `path[last]` asset to `send_to`, /// respecting `keep_alive`. /// - /// If successful returns the amount of the `path[0]` taken to provide `path[1]`. + /// If successful returns the amount of the `path[0]` taken to provide `path[last]`. fn swap_tokens_for_exact_tokens( sender: AccountId, path: Vec, From 697afa6b1ef1c2bfe4b774b648cd59dc0fb492ba Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 28 Sep 2023 13:32:50 +0200 Subject: [PATCH 20/69] dev comments --- substrate/frame/asset-conversion/src/swap.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index ec1f03a461b1b..e65ea08c36b59 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -175,6 +175,8 @@ impl SwapCredit for Pallet { Self::do_swap_exact_credit_tokens_for_tokens(path, credit_in, amount_out_min); match &res { Ok(_) => TransactionOutcome::Commit(Ok(res)), + // wrapping `res` with `Ok`, since our `Err` doesn't satisfy the + // `From` bound of the `with_transaction` function. Err(_) => TransactionOutcome::Rollback(Ok(res)), } }); @@ -199,6 +201,8 @@ impl SwapCredit for Pallet { let res = Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out); match &res { Ok(_) => TransactionOutcome::Commit(Ok(res)), + // wrapping `res` with `Ok`, since our `Err` doesn't satisfy the + // `From` bound of the `with_transaction` function. Err(_) => TransactionOutcome::Rollback(Ok(res)), } }); From 1c5022014cd21cc698406684209dc88edeb2aee4 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 29 Sep 2023 17:50:54 +0200 Subject: [PATCH 21/69] use eq/partial_eq/runtime_debug derives with no bound version --- .../src/traits/tokens/fungible/imbalance.rs | 37 +------------ .../src/traits/tokens/fungibles/imbalance.rs | 54 +------------------ 2 files changed, 4 insertions(+), 87 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index 49b0b506db09b..32a63fd25b291 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -23,6 +23,7 @@ use crate::traits::{ misc::{SameOrOther, TryDrop}, tokens::Balance, }; +use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; use sp_runtime::traits::Zero; use sp_std::marker::PhantomData; @@ -43,6 +44,7 @@ impl HandleImbalanceDrop for () { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] +#[derive(EqNoBound, PartialEqNoBound, RuntimeDebugNoBound)] pub struct Imbalance< B: Balance, OnDrop: HandleImbalanceDrop, @@ -140,41 +142,6 @@ impl, OppositeOnDrop: HandleImbalance } } -impl, OppositeOnDrop: HandleImbalanceDrop> PartialEq - for Imbalance -{ - fn eq(&self, other: &Self) -> bool { - self.amount.eq(&other.amount) - } -} - -impl, OppositeOnDrop: HandleImbalanceDrop> Eq - for Imbalance -{ -} - -#[cfg(any(feature = "std", feature = "force-debug"))] -impl, OppositeOnDrop: HandleImbalanceDrop> - sp_std::fmt::Debug for Imbalance -{ - fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - fmt.debug_struct("Imbalance") - .field("amount", &self.amount) - .field("OnDrop", &sp_std::any::type_name::()) - .field("OppositeOnDrop", &sp_std::any::type_name::()) - .finish() - } -} - -#[cfg(all(not(feature = "std"), not(feature = "force-debug")))] -impl, OppositeOnDrop: HandleImbalanceDrop> - sp_std::fmt::Debug for Imbalance -{ - fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - fmt.write_str("") - } -} - /// Imbalance implying that the total_issuance value is less than the sum of all account balances. pub type Debt = Imbalance< >::Balance, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index c1880cf087a51..9f660a5f16894 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -23,6 +23,7 @@ use crate::traits::{ misc::{SameOrOther, TryDrop}, tokens::{AssetId, Balance}, }; +use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; use sp_runtime::traits::Zero; use sp_std::marker::PhantomData; @@ -38,6 +39,7 @@ pub trait HandleImbalanceDrop { /// /// Importantly, it has a special `Drop` impl, and cannot be created outside of this module. #[must_use] +#[derive(EqNoBound, PartialEqNoBound, RuntimeDebugNoBound)] pub struct Imbalance< A: AssetId, B: Balance, @@ -157,58 +159,6 @@ impl< } } -impl< - A: AssetId, - B: Balance, - OnDrop: HandleImbalanceDrop, - OppositeOnDrop: HandleImbalanceDrop, - > PartialEq for Imbalance -{ - fn eq(&self, other: &Self) -> bool { - self.amount.eq(&other.amount) && self.asset.eq(&other.asset) - } -} - -impl< - A: AssetId, - B: Balance, - OnDrop: HandleImbalanceDrop, - OppositeOnDrop: HandleImbalanceDrop, - > Eq for Imbalance -{ -} - -#[cfg(any(feature = "std", feature = "force-debug"))] -impl< - A: AssetId, - B: Balance, - OnDrop: HandleImbalanceDrop, - OppositeOnDrop: HandleImbalanceDrop, - > sp_std::fmt::Debug for Imbalance -{ - fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - fmt.debug_struct("Imbalance") - .field("asset", &self.asset) - .field("amount", &self.amount) - .field("OnDrop", &sp_std::any::type_name::()) - .field("OppositeOnDrop", &sp_std::any::type_name::()) - .finish() - } -} - -#[cfg(all(not(feature = "std"), not(feature = "force-debug")))] -impl< - A: AssetId, - B: Balance, - OnDrop: HandleImbalanceDrop, - OppositeOnDrop: HandleImbalanceDrop, - > sp_std::fmt::Debug for Imbalance -{ - fn fmt(&self, fmt: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { - fmt.write_str("") - } -} - /// Imbalance implying that the total_issuance value is less than the sum of all account balances. pub type Debt = Imbalance< >::AssetId, From e7ffbb412cd62d47ecac5f2906f419755410df52 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 5 Oct 2023 13:39:17 +0200 Subject: [PATCH 22/69] swap trait update --- substrate/frame/asset-conversion/src/swap.rs | 44 +++++++++++-------- substrate/frame/asset-conversion/src/tests.rs | 4 +- .../src/payment.rs | 2 +- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index e65ea08c36b59..92cd4c8877a5d 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -20,7 +20,12 @@ use super::*; /// Trait for providing methods to swap between the various asset classes. -pub trait Swap { +pub trait Swap { + /// Measure units of the asset classes for swapping. + type Balance; + /// Kind of assets that are going to be swapped. + type MultiAssetId; + /// Returns the upper limit on the length of the swap path. fn max_path_len() -> u32; @@ -34,12 +39,12 @@ pub trait Swap { /// If successful, returns the amount of `path[last]` acquired for the `amount_in`. fn swap_exact_tokens_for_tokens( sender: AccountId, - path: Vec, - amount_in: Balance, - amount_out_min: Option, + path: Vec, + amount_in: Self::Balance, + amount_out_min: Option, send_to: AccountId, keep_alive: bool, - ) -> Result; + ) -> Result; /// Take the `path[0]` asset and swap some amount for `amount_out` of the `path[last]`. If an /// `amount_in_max` is specified, it will return an error if acquiring `amount_out` would be @@ -51,12 +56,12 @@ pub trait Swap { /// If successful returns the amount of the `path[0]` taken to provide `path[last]`. fn swap_tokens_for_exact_tokens( sender: AccountId, - path: Vec, - amount_out: Balance, - amount_in_max: Option, + path: Vec, + amount_out: Self::Balance, + amount_in_max: Option, send_to: AccountId, keep_alive: bool, - ) -> Result; + ) -> Result; } /// Trait providing methods to swap between the various asset classes. @@ -99,19 +104,22 @@ pub trait SwapCredit { ) -> Result<(Self::Credit, Self::Credit), (Self::Credit, DispatchError)>; } -impl Swap for Pallet { +impl Swap for Pallet { + type Balance = T::HigherPrecisionBalance; + type MultiAssetId = T::MultiAssetId; + fn max_path_len() -> u32 { T::MaxSwapPathLength::get() } fn swap_exact_tokens_for_tokens( sender: T::AccountId, - path: Vec, - amount_in: T::HigherPrecisionBalance, - amount_out_min: Option, + path: Vec, + amount_in: Self::Balance, + amount_out_min: Option, send_to: T::AccountId, keep_alive: bool, - ) -> Result { + ) -> Result { let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_out_min = amount_out_min.map(Self::convert_hpb_to_asset_balance).transpose()?; let amount_out = with_storage_layer(|| { @@ -129,12 +137,12 @@ impl Swap f fn swap_tokens_for_exact_tokens( sender: T::AccountId, - path: Vec, - amount_out: T::HigherPrecisionBalance, - amount_in_max: Option, + path: Vec, + amount_out: Self::Balance, + amount_in_max: Option, send_to: T::AccountId, keep_alive: bool, - ) -> Result { + ) -> Result { let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_in_max = amount_in_max.map(Self::convert_hpb_to_asset_balance).transpose()?; let amount_in = with_storage_layer(|| { diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index f86cb6c12d75e..05bdaf1018ed7 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -1975,7 +1975,7 @@ fn swap_transactional() { // swap with `swap_exact_tokens_for_tokens` transactional assert_noop!( - >::swap_exact_tokens_for_tokens( + >::swap_exact_tokens_for_tokens( user2, bvec![token_2, token_1, token_3], amount_in.into(), @@ -1988,7 +1988,7 @@ fn swap_transactional() { // swap with `swap_exact_tokens_for_tokens` transactional assert_noop!( - >::swap_tokens_for_exact_tokens( + >::swap_tokens_for_exact_tokens( user2, bvec![token_2, token_1, token_3], expected_out.into(), diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs index 0d090211d0352..ac13e121dd651 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs @@ -83,7 +83,7 @@ impl OnChargeAssetTransaction for AssetConversionAdapter where T: Config, C: Inspect<::AccountId>, - CON: Swap, + CON: Swap, T::HigherPrecisionBalance: From> + TryInto>, T::MultiAssetId: From>, BalanceOf: IsType<::AccountId>>::Balance>, From ee49f271e5187a3ade386066c14ca43332ad8734 Mon Sep 17 00:00:00 2001 From: muharem Date: Sat, 7 Oct 2023 16:23:36 +0200 Subject: [PATCH 23/69] box multi asset id --- substrate/frame/asset-conversion/src/lib.rs | 38 +- substrate/frame/asset-conversion/src/tests.rs | 475 ++++++++++++------ 2 files changed, 350 insertions(+), 163 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 33c761611e25b..356b7f41e9248 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -381,14 +381,14 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::create_pool())] pub fn create_pool( origin: OriginFor, - asset1: T::MultiAssetId, - asset2: T::MultiAssetId, + asset1: Box, + asset2: Box, ) -> DispatchResult { let sender = ensure_signed(origin)?; ensure!(asset1 != asset2, Error::::EqualAssets); // prepare pool_id - let pool_id = Self::get_pool_id(asset1, asset2); + let pool_id = Self::get_pool_id(*asset1, *asset2); ensure!(!Pools::::contains_key(&pool_id), Error::::PoolExists); let (asset1, asset2) = &pool_id; if !T::AllowMultiAssetPools::get() && !T::MultiAssetIdConverter::is_native(asset1) { @@ -459,8 +459,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::add_liquidity())] pub fn add_liquidity( origin: OriginFor, - asset1: T::MultiAssetId, - asset2: T::MultiAssetId, + asset1: Box, + asset2: Box, amount1_desired: T::AssetBalance, amount2_desired: T::AssetBalance, amount1_min: T::AssetBalance, @@ -469,10 +469,10 @@ pub mod pallet { ) -> DispatchResult { let sender = ensure_signed(origin)?; - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); + let pool_id = Self::get_pool_id(*asset1.clone(), *asset2); // swap params if needed let (amount1_desired, amount2_desired, amount1_min, amount2_min) = - if pool_id.0 == asset1 { + if pool_id.0 == *asset1 { (amount1_desired, amount2_desired, amount1_min, amount2_min) } else { (amount2_desired, amount1_desired, amount2_min, amount1_min) @@ -571,8 +571,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_liquidity())] pub fn remove_liquidity( origin: OriginFor, - asset1: T::MultiAssetId, - asset2: T::MultiAssetId, + asset1: Box, + asset2: Box, lp_token_burn: T::AssetBalance, amount1_min_receive: T::AssetBalance, amount2_min_receive: T::AssetBalance, @@ -580,9 +580,9 @@ pub mod pallet { ) -> DispatchResult { let sender = ensure_signed(origin)?; - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); + let pool_id = Self::get_pool_id(*asset1.clone(), *asset2); // swap params if needed - let (amount1_min_receive, amount2_min_receive) = if pool_id.0 == asset1 { + let (amount1_min_receive, amount2_min_receive) = if pool_id.0 == *asset1 { (amount1_min_receive, amount2_min_receive) } else { (amount2_min_receive, amount1_min_receive) @@ -650,7 +650,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_exact_tokens_for_tokens())] pub fn swap_exact_tokens_for_tokens( origin: OriginFor, - path: BoundedVec, + path: BoundedVec, T::MaxSwapPathLength>, amount_in: T::AssetBalance, amount_out_min: T::AssetBalance, send_to: T::AccountId, @@ -659,7 +659,11 @@ pub mod pallet { let sender = ensure_signed(origin)?; Self::do_swap_exact_tokens_for_tokens( sender, - path, + path.into_iter() + .map(|a| *a) + .collect::>() + .try_into() + .map_err(|_| Error::::InvalidPath)?, amount_in, Some(amount_out_min), send_to, @@ -678,7 +682,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_tokens_for_exact_tokens())] pub fn swap_tokens_for_exact_tokens( origin: OriginFor, - path: BoundedVec, + path: BoundedVec, T::MaxSwapPathLength>, amount_out: T::AssetBalance, amount_in_max: T::AssetBalance, send_to: T::AccountId, @@ -687,7 +691,11 @@ pub mod pallet { let sender = ensure_signed(origin)?; Self::do_swap_tokens_for_exact_tokens( sender, - path, + path.into_iter() + .map(|a| *a) + .collect::>() + .try_into() + .map_err(|_| Error::::InvalidPath)?, amount_out, Some(amount_in_max), send_to, diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 05bdaf1018ed7..d6a041f98e0ca 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -100,6 +100,12 @@ macro_rules! bvec { } } +macro_rules! bbvec { + ($( $x:ident ),*) => { + vec![$( Box::new( $x ), )*].try_into().unwrap() + } +} + #[test] fn check_pool_accounts_dont_collide() { use std::collections::HashSet; @@ -149,7 +155,11 @@ fn can_create_pool() { let lp_token = AssetConversion::get_next_pool_asset_id(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 1000)); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_2, token_1)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_2), + Box::new(token_1) + )); let setup_fee = <::PoolSetupFee as Get<::Balance>>::get(); let pool_account = <::PoolSetupFeeReceiver as Get>::get(); @@ -174,24 +184,40 @@ fn can_create_pool() { assert_eq!(pool_assets(), vec![lp_token]); assert_noop!( - AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_1), + AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_1) + ), Error::::EqualAssets ); assert_noop!( - AssetConversion::create_pool(RuntimeOrigin::signed(user), token_2, token_2), + AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_2), + Box::new(token_2) + ), Error::::EqualAssets ); // validate we can create Asset(1)/Asset(2) pool let token_1 = NativeOrAssetId::Asset(1); create_tokens(user, vec![token_1]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); // validate we can force the first asset to be the Native currency only AllowMultiAssetPools::set(&false); let token_1 = NativeOrAssetId::Asset(3); assert_noop!( - AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2), + AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + ), Error::::PoolMustContainNativeCurrency ); }); @@ -207,19 +233,31 @@ fn create_same_pool_twice_should_fail() { create_tokens(user, vec![token_2]); let lp_token = AssetConversion::get_next_pool_asset_id(); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_2, token_1)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_2), + Box::new(token_1) + )); let expected_free = lp_token + 1; assert_eq!(expected_free, AssetConversion::get_next_pool_asset_id()); assert_noop!( - AssetConversion::create_pool(RuntimeOrigin::signed(user), token_2, token_1), + AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_2), + Box::new(token_1) + ), Error::::PoolExists ); assert_eq!(expected_free, AssetConversion::get_next_pool_asset_id()); // Try switching the same tokens around: assert_noop!( - AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2), + AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + ), Error::::PoolExists ); assert_eq!(expected_free, AssetConversion::get_next_pool_asset_id()); @@ -239,7 +277,11 @@ fn different_pools_should_have_different_lp_tokens() { create_tokens(user, vec![token_2, token_3]); let lp_token2_1 = AssetConversion::get_next_pool_asset_id(); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_2, token_1)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_2), + Box::new(token_1) + )); let lp_token3_1 = AssetConversion::get_next_pool_asset_id(); assert_eq!( @@ -252,7 +294,11 @@ fn different_pools_should_have_different_lp_tokens() { }] ); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_3, token_1)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_3), + Box::new(token_1) + )); assert_eq!( events(), [Event::::PoolCreated { @@ -277,9 +323,17 @@ fn can_add_liquidity() { create_tokens(user, vec![token_2, token_3]); let lp_token1 = AssetConversion::get_next_pool_asset_id(); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let lp_token2 = AssetConversion::get_next_pool_asset_id(); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_3)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_3) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 * 2 + ed)); @@ -288,8 +342,8 @@ fn can_add_liquidity() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 10, 10000, @@ -317,8 +371,8 @@ fn can_add_liquidity() { // try to pass the non-native - native assets, the result should be the same assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_3, - token_1, + Box::new(token_3), + Box::new(token_1), 10, 10000, 10, @@ -353,7 +407,11 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 1000)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -361,8 +419,8 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { assert_noop!( AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 1, 1, 1, @@ -375,8 +433,8 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { assert_noop!( AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), get_ed(), 1, 1, @@ -397,8 +455,16 @@ fn add_tiny_liquidity_directly_to_pool_address() { let token_3 = NativeOrAssetId::Asset(3); create_tokens(user, vec![token_2, token_3]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_3)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_3) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 * 2 + ed)); @@ -411,8 +477,8 @@ fn add_tiny_liquidity_directly_to_pool_address() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 10, 10000, @@ -425,8 +491,8 @@ fn add_tiny_liquidity_directly_to_pool_address() { assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, pallet_account, 1)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_3, + Box::new(token_1), + Box::new(token_3), 10000, 10, 10000, @@ -446,7 +512,11 @@ fn can_remove_liquidity() { create_tokens(user, vec![token_2]); let lp_token = AssetConversion::get_next_pool_asset_id(); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed_token_1 = >::minimum_balance(); let ed_token_2 = >::minimum_balance(2); @@ -459,8 +529,8 @@ fn can_remove_liquidity() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 1000000000, 100000, 1000000000, @@ -473,8 +543,8 @@ fn can_remove_liquidity() { assert_ok!(AssetConversion::remove_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), total_lp_received, 0, 0, @@ -512,15 +582,19 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { let lp_token = AssetConversion::get_next_pool_asset_id(); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + get_ed())); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 10, 10000, @@ -534,8 +608,8 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { assert_noop!( AssetConversion::remove_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 216 + 1, // Try and redeem 10 lp tokens while only 9 minted. 0, 0, @@ -554,15 +628,19 @@ fn can_quote_price() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 200, 1, @@ -775,15 +853,19 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 200, 1, @@ -803,7 +885,7 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { assert_eq!(prior_dot_balance, balance(user2, token_1)); assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user2), - bvec![token_2, token_1], + bbvec![token_2, token_1], amount, 1, user2, @@ -823,15 +905,19 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 200, 1, @@ -853,7 +939,7 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { assert_eq!(prior_asset_balance, balance(user2, token_2)); assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user2), - bvec![token_2, token_1], + bbvec![token_2, token_1], amount, 1, user2, @@ -874,7 +960,11 @@ fn can_swap_with_native() { let pool_id = (token_1, token_2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + ed)); @@ -885,8 +975,8 @@ fn can_swap_with_native() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -902,7 +992,7 @@ fn can_swap_with_native() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], input_amount, 1, user, @@ -924,7 +1014,11 @@ fn can_swap_with_realistic_values() { let dot = NativeOrAssetId::Native; let usd = NativeOrAssetId::Asset(2); create_tokens(user, vec![usd]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), dot, usd)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(dot), + Box::new(usd) + )); const UNIT: u128 = 1_000_000_000; @@ -935,8 +1029,8 @@ fn can_swap_with_realistic_values() { let liquidity_usd = 1_000_000 * UNIT; assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - dot, - usd, + Box::new(dot), + Box::new(usd), liquidity_dot, liquidity_usd, 1, @@ -948,7 +1042,7 @@ fn can_swap_with_realistic_values() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![usd, dot], + bbvec![usd, dot], input_amount, 1, user, @@ -973,13 +1067,17 @@ fn can_not_swap_in_pool_with_no_liquidity_added_yet() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); // Check can't swap an empty pool assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], 10, 1, user, @@ -1000,7 +1098,11 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { let lp_token = AssetConversion::get_next_pool_asset_id(); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + ed)); @@ -1011,8 +1113,8 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1037,8 +1139,8 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(AssetConversion::remove_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), lp_token_minted, 1, 1, @@ -1054,7 +1156,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], 708 - ed + 1, // amount_out 500, // amount_in_max user, @@ -1065,7 +1167,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], 608, // amount_out 500, // amount_in_max user, @@ -1087,7 +1189,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], token_1_left - 1, // amount_out 1000, // amount_in_max user, @@ -1100,7 +1202,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], token_1_left, // amount_out 1000, // amount_in_max user, @@ -1119,7 +1221,11 @@ fn swap_should_not_work_if_too_much_slippage() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + get_ed())); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -1129,8 +1235,8 @@ fn swap_should_not_work_if_too_much_slippage() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1143,7 +1249,7 @@ fn swap_should_not_work_if_too_much_slippage() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], exchange_amount, // amount_in 4000, // amount_out_min user, @@ -1163,7 +1269,11 @@ fn can_swap_tokens_for_exact_tokens() { let pool_id = (token_1, token_2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); @@ -1178,8 +1288,8 @@ fn can_swap_tokens_for_exact_tokens() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1194,7 +1304,7 @@ fn can_swap_tokens_for_exact_tokens() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bbvec![token_1, token_2], exchange_out, // amount_out 3500, // amount_in_max user, @@ -1225,7 +1335,11 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { let lp_token = AssetConversion::get_next_pool_asset_id(); create_tokens(user2, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user2), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); let base1 = 10000; @@ -1245,8 +1359,8 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1264,7 +1378,7 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bbvec![token_1, token_2], exchange_out, // amount_out 3500, // amount_in_max user, @@ -1293,8 +1407,8 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(AssetConversion::remove_liquidity( RuntimeOrigin::signed(user2), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), lp_token_minted, 0, 0, @@ -1312,7 +1426,11 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user2, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user2), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 101)); @@ -1322,8 +1440,8 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 200, 1, @@ -1334,7 +1452,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bbvec![token_1, token_2], 1, // amount_out 101, // amount_in_max user, @@ -1346,7 +1464,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bbvec![token_1, token_2], 51, // amount_in 1, // amount_out_min user, @@ -1358,7 +1476,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], 51, // amount_out 2, // amount_in_max user, @@ -1370,7 +1488,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bbvec![token_2, token_1], 2, // amount_in 1, // amount_out_min user, @@ -1392,9 +1510,21 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { let ed_assets = 100; create_tokens_with_ed(user2, vec![token_2, token_3], ed_assets); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_2)); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_1, token_3)); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user2), token_2, token_3)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user2), + Box::new(token_1), + Box::new(token_2) + )); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user2), + Box::new(token_1), + Box::new(token_3) + )); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user2), + Box::new(token_2), + Box::new(token_3) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); @@ -1407,8 +1537,8 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 200, 1, @@ -1418,8 +1548,8 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - token_1, - token_3, + Box::new(token_1), + Box::new(token_3), 200, 10000, 1, @@ -1429,8 +1559,8 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - token_2, - token_3, + Box::new(token_2), + Box::new(token_3), 200, 10000, 1, @@ -1442,7 +1572,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bbvec![token_1, token_2], 110, // amount_out 20000, // amount_in_max user, @@ -1455,7 +1585,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bbvec![token_1, token_2], 15000, // amount_in 110, // amount_out_min user, @@ -1468,7 +1598,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_3, token_1], + bbvec![token_3, token_1], 110, // amount_out 20000, // amount_in_max user, @@ -1481,7 +1611,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_3, token_1], + bbvec![token_3, token_1], 15000, // amount_in 110, // amount_out_min user, @@ -1503,7 +1633,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_3, token_1, token_2], + bbvec![token_3, token_1, token_2], amount_in, // amount_in 1, // amount_out_min user, @@ -1525,7 +1655,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3], + bbvec![token_1, token_2, token_3], amount_in, // amount_in 1, // amount_out_min user, @@ -1544,7 +1674,11 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + get_ed())); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -1554,8 +1688,8 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1568,7 +1702,7 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bbvec![token_1, token_2], exchange_out, // amount_out 50, // amount_in_max just greater than slippage. user, @@ -1588,8 +1722,16 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { let token_3 = NativeOrAssetId::Asset(3); create_tokens(user, vec![token_2, token_3]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_2, token_3)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_2), + Box::new(token_3) + )); let ed = get_ed(); let base1 = 10000; @@ -1604,8 +1746,8 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1614,8 +1756,8 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { )); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_2, - token_3, + Box::new(token_2), + Box::new(token_3), liquidity2, liquidity3, 1, @@ -1634,7 +1776,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1], + bbvec![token_1], input_amount, 80, user, @@ -1646,7 +1788,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3, token_2], + bbvec![token_1, token_2, token_3, token_2], input_amount, 80, user, @@ -1657,7 +1799,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3], + bbvec![token_1, token_2, token_3], input_amount, // amount_in 80, // amount_out_min user, @@ -1687,8 +1829,16 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { let token_3 = NativeOrAssetId::Asset(3); create_tokens(user, vec![token_2, token_3]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_2, token_3)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_2), + Box::new(token_3) + )); let ed = get_ed(); let base1 = 10000; @@ -1703,8 +1853,8 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1713,8 +1863,8 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { )); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_2, - token_3, + Box::new(token_2), + Box::new(token_3), liquidity2, liquidity3, 1, @@ -1732,7 +1882,7 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3], + bbvec![token_1, token_2, token_3], exchange_out3, // amount_out 1000, // amount_in_max user, @@ -1758,6 +1908,7 @@ fn can_not_swap_same_asset() { new_test_ext().execute_with(|| { let user = 1; let token_1 = NativeOrAssetId::Asset(1); + let token_2 = NativeOrAssetId::Native; create_tokens(user, vec![token_1]); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 1, user, 1000)); @@ -1767,8 +1918,8 @@ fn can_not_swap_same_asset() { assert_noop!( AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_1, + Box::new(token_1), + Box::new(token_1), liquidity1, liquidity2, 1, @@ -1782,7 +1933,7 @@ fn can_not_swap_same_asset() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_1], + bbvec![token_1, token_1], exchange_amount, 1, user, @@ -1794,7 +1945,7 @@ fn can_not_swap_same_asset() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![NativeOrAssetId::Native, NativeOrAssetId::Native], + bbvec![token_2, token_2], exchange_amount, 1, user, @@ -1854,7 +2005,11 @@ fn cannot_block_pool_creation() { // User can still create the pool create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); // User has to transfer one Asset(2) token to the pool account (otherwise add_liquidity will // fail with `AssetTwoDepositDidNotMeetMinimum`) @@ -1865,8 +2020,8 @@ fn cannot_block_pool_creation() { // add_liquidity shouldn't fail because of the number of consumers assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 10000, 100, 10000, @@ -1887,8 +2042,16 @@ fn swap_transactional() { let asset_ed = 150; create_tokens_with_ed(user, vec![token_2, token_3], asset_ed); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_3)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_3) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); @@ -1904,8 +2067,8 @@ fn swap_transactional() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -1915,8 +2078,8 @@ fn swap_transactional() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_3, + Box::new(token_1), + Box::new(token_3), liquidity1, liquidity2, 1, @@ -2014,7 +2177,11 @@ fn swap_credit_returns_change() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); @@ -2025,8 +2192,8 @@ fn swap_credit_returns_change() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -2062,7 +2229,11 @@ fn swap_credit_insufficient_amount_bounds() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); @@ -2076,8 +2247,8 @@ fn swap_credit_insufficient_amount_bounds() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -2131,7 +2302,11 @@ fn swap_credit_zero_amount() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); @@ -2145,8 +2320,8 @@ fn swap_credit_zero_amount() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, @@ -2209,7 +2384,11 @@ fn swap_credit_invalid_path() { let token_2 = NativeOrAssetId::Asset(2); create_tokens(user, vec![token_2]); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(user), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1), + Box::new(token_2) + )); let ed = get_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); @@ -2223,8 +2402,8 @@ fn swap_credit_invalid_path() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), liquidity1, liquidity2, 1, From ee9d2ebc0b86368f92568a0895ffd3f9add1a10d Mon Sep 17 00:00:00 2001 From: muharem Date: Sat, 7 Oct 2023 16:32:54 +0200 Subject: [PATCH 24/69] use vec instead bounded vec --- substrate/frame/asset-conversion/src/lib.rs | 44 ++++----- substrate/frame/asset-conversion/src/swap.rs | 10 -- substrate/frame/asset-conversion/src/tests.rs | 98 +++++++++---------- 3 files changed, 63 insertions(+), 89 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 356b7f41e9248..37d304bf8494b 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -86,7 +86,7 @@ use frame_support::{ }, AccountTouch, ContainsPair, Imbalance, Incrementable, }, - BoundedBTreeSet, PalletId, + PalletId, }; use sp_core::Get; use sp_runtime::{ @@ -94,9 +94,9 @@ use sp_runtime::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, One, TrailingZeroInput, Zero, }, - BoundedVec, DispatchError, RuntimeDebug, Saturating, TokenError, TransactionOutcome, + DispatchError, RuntimeDebug, Saturating, TokenError, TransactionOutcome, }; -use sp_std::vec::Vec; +use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; #[frame_support::pallet] pub mod pallet { @@ -650,7 +650,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_exact_tokens_for_tokens())] pub fn swap_exact_tokens_for_tokens( origin: OriginFor, - path: BoundedVec, T::MaxSwapPathLength>, + path: Vec>, amount_in: T::AssetBalance, amount_out_min: T::AssetBalance, send_to: T::AccountId, @@ -659,11 +659,7 @@ pub mod pallet { let sender = ensure_signed(origin)?; Self::do_swap_exact_tokens_for_tokens( sender, - path.into_iter() - .map(|a| *a) - .collect::>() - .try_into() - .map_err(|_| Error::::InvalidPath)?, + path.into_iter().map(|a| *a).collect(), amount_in, Some(amount_out_min), send_to, @@ -682,7 +678,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_tokens_for_exact_tokens())] pub fn swap_tokens_for_exact_tokens( origin: OriginFor, - path: BoundedVec, T::MaxSwapPathLength>, + path: Vec>, amount_out: T::AssetBalance, amount_in_max: T::AssetBalance, send_to: T::AccountId, @@ -691,11 +687,7 @@ pub mod pallet { let sender = ensure_signed(origin)?; Self::do_swap_tokens_for_exact_tokens( sender, - path.into_iter() - .map(|a| *a) - .collect::>() - .try_into() - .map_err(|_| Error::::InvalidPath)?, + path.into_iter().map(|a| *a).collect(), amount_out, Some(amount_in_max), send_to, @@ -720,7 +712,7 @@ pub mod pallet { /// rollback. pub(crate) fn do_swap_exact_tokens_for_tokens( sender: T::AccountId, - path: BoundedVec, + path: Vec, amount_in: T::AssetBalance, amount_out_min: Option, send_to: T::AccountId, @@ -768,7 +760,7 @@ pub mod pallet { /// rollback. pub(crate) fn do_swap_tokens_for_exact_tokens( sender: T::AccountId, - path: BoundedVec, + path: Vec, amount_out: T::AssetBalance, amount_in_max: Option, send_to: T::AccountId, @@ -814,7 +806,7 @@ pub mod pallet { /// only inside a transactional storage context and an Err result must imply a storage /// rollback. pub(crate) fn do_swap_exact_credit_tokens_for_tokens( - path: BoundedVec, + path: Vec, credit_in: Credit, amount_out_min: Option, ) -> Result, (Credit, DispatchError)> { @@ -862,7 +854,7 @@ pub mod pallet { /// only inside a transactional storage context and an Err result must imply a storage /// rollback. pub(crate) fn do_swap_credit_tokens_for_exact_tokens( - path: BoundedVec, + path: Vec, credit_in: Credit, amount_out: T::AssetBalance, ) -> Result<(Credit, Credit), (Credit, DispatchError)> { @@ -1152,7 +1144,7 @@ pub mod pallet { /// Leading to an amount at the end of a `path`, get the required amounts in. pub(crate) fn balance_path_from_amount_out( amount_out: T::AssetBalance, - path: BoundedVec, + path: Vec, ) -> Result, DispatchError> { let mut balance_path: BalancePath = Vec::with_capacity(path.len()); let mut amount_in: T::AssetBalance = amount_out; @@ -1178,7 +1170,7 @@ pub mod pallet { /// Following an amount into a `path`, get the corresponding amounts out. pub(crate) fn balance_path_from_amount_in( amount_in: T::AssetBalance, - path: BoundedVec, + path: Vec, ) -> Result, DispatchError> { let mut balance_path: BalancePath = Vec::with_capacity(path.len()); let mut amount_out: T::AssetBalance = amount_in; @@ -1391,18 +1383,16 @@ pub mod pallet { } /// Ensure that a path is valid. - fn validate_swap_path( - path: &BoundedVec, - ) -> Result<(), DispatchError> { + fn validate_swap_path(path: &Vec) -> Result<(), DispatchError> { ensure!(path.len() >= 2, Error::::InvalidPath); + ensure!(path.len() as u32 <= T::MaxSwapPathLength::get(), Error::::InvalidPath); // validate all the pools in the path are unique - let mut pools = BoundedBTreeSet::, T::MaxSwapPathLength>::new(); + let mut pools = BTreeSet::>::new(); for assets_pair in path.windows(2) { if let [asset1, asset2] = assets_pair { let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let new_element = - pools.try_insert(pool_id).map_err(|_| Error::::Overflow)?; + let new_element = pools.insert(pool_id); if !new_element { return Err(Error::::NonUniquePath.into()) } diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index 92cd4c8877a5d..a86b55d41a536 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -120,7 +120,6 @@ impl Swap for Pallet { send_to: T::AccountId, keep_alive: bool, ) -> Result { - let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_out_min = amount_out_min.map(Self::convert_hpb_to_asset_balance).transpose()?; let amount_out = with_storage_layer(|| { Self::do_swap_exact_tokens_for_tokens( @@ -143,7 +142,6 @@ impl Swap for Pallet { send_to: T::AccountId, keep_alive: bool, ) -> Result { - let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_in_max = amount_in_max.map(Self::convert_hpb_to_asset_balance).transpose()?; let amount_in = with_storage_layer(|| { Self::do_swap_tokens_for_exact_tokens( @@ -173,10 +171,6 @@ impl SwapCredit for Pallet { credit_in: Self::Credit, amount_out_min: Option, ) -> Result { - let path = match path.try_into() { - Ok(p) => p, - Err(_) => return Err((credit_in, Error::::PathError.into())), - }; let transaction_res = with_transaction(|| -> TransactionOutcome> { let res = @@ -200,10 +194,6 @@ impl SwapCredit for Pallet { credit_in: Self::Credit, amount_out: Self::Balance, ) -> Result<(Self::Credit, Self::Credit), (Self::Credit, DispatchError)> { - let path = match path.try_into() { - Ok(p) => p, - Err(_) => return Err((credit_in, Error::::PathError.into())), - }; let transaction_res = with_transaction(|| -> TransactionOutcome> { let res = Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out); diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index d6a041f98e0ca..db6aca01dece7 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -95,14 +95,8 @@ fn get_ed() -> u128 { } macro_rules! bvec { - ($( $x:tt )*) => { - vec![$( $x )*].try_into().unwrap() - } -} - -macro_rules! bbvec { ($( $x:ident ),*) => { - vec![$( Box::new( $x ), )*].try_into().unwrap() + vec![$( Box::new( $x ), )*] } } @@ -885,7 +879,7 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { assert_eq!(prior_dot_balance, balance(user2, token_1)); assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user2), - bbvec![token_2, token_1], + bvec![token_2, token_1], amount, 1, user2, @@ -939,7 +933,7 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { assert_eq!(prior_asset_balance, balance(user2, token_2)); assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user2), - bbvec![token_2, token_1], + bvec![token_2, token_1], amount, 1, user2, @@ -992,7 +986,7 @@ fn can_swap_with_native() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], input_amount, 1, user, @@ -1042,7 +1036,7 @@ fn can_swap_with_realistic_values() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![usd, dot], + bvec![usd, dot], input_amount, 1, user, @@ -1054,7 +1048,7 @@ fn can_swap_with_realistic_values() { send_to: user, amount_in: 10 * UNIT, // usd amount_out: 1_993_980_120, // About 2 dot after div by UNIT. - path: bvec![(usd, 10 * UNIT), (dot, 1_993_980_120)], + path: vec![(usd, 10 * UNIT), (dot, 1_993_980_120)], })); }); } @@ -1077,7 +1071,7 @@ fn can_not_swap_in_pool_with_no_liquidity_added_yet() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], 10, 1, user, @@ -1156,7 +1150,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], 708 - ed + 1, // amount_out 500, // amount_in_max user, @@ -1167,7 +1161,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], 608, // amount_out 500, // amount_in_max user, @@ -1189,7 +1183,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], token_1_left - 1, // amount_out 1000, // amount_in_max user, @@ -1202,7 +1196,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], token_1_left, // amount_out 1000, // amount_in_max user, @@ -1249,7 +1243,7 @@ fn swap_should_not_work_if_too_much_slippage() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], exchange_amount, // amount_in 4000, // amount_out_min user, @@ -1304,7 +1298,7 @@ fn can_swap_tokens_for_exact_tokens() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2], + bvec![token_1, token_2], exchange_out, // amount_out 3500, // amount_in_max user, @@ -1378,7 +1372,7 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2], + bvec![token_1, token_2], exchange_out, // amount_out 3500, // amount_in_max user, @@ -1452,7 +1446,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2], + bvec![token_1, token_2], 1, // amount_out 101, // amount_in_max user, @@ -1464,7 +1458,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2], + bvec![token_1, token_2], 51, // amount_in 1, // amount_out_min user, @@ -1476,7 +1470,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], 51, // amount_out 2, // amount_in_max user, @@ -1488,7 +1482,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_1], + bvec![token_2, token_1], 2, // amount_in 1, // amount_out_min user, @@ -1572,7 +1566,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2], + bvec![token_1, token_2], 110, // amount_out 20000, // amount_in_max user, @@ -1585,7 +1579,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2], + bvec![token_1, token_2], 15000, // amount_in 110, // amount_out_min user, @@ -1598,7 +1592,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_3, token_1], + bvec![token_3, token_1], 110, // amount_out 20000, // amount_in_max user, @@ -1611,7 +1605,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_3, token_1], + bvec![token_3, token_1], 15000, // amount_in 110, // amount_out_min user, @@ -1633,7 +1627,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_3, token_1, token_2], + bvec![token_3, token_1, token_2], amount_in, // amount_in 1, // amount_out_min user, @@ -1655,7 +1649,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2, token_3], + bvec![token_1, token_2, token_3], amount_in, // amount_in 1, // amount_out_min user, @@ -1702,7 +1696,7 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2], + bvec![token_1, token_2], exchange_out, // amount_out 50, // amount_in_max just greater than slippage. user, @@ -1776,7 +1770,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_1], + bvec![token_1], input_amount, 80, user, @@ -1788,7 +1782,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2, token_3, token_2], + bvec![token_1, token_2, token_3, token_2], input_amount, 80, user, @@ -1799,7 +1793,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2, token_3], + bvec![token_1, token_2, token_3], input_amount, // amount_in 80, // amount_out_min user, @@ -1882,7 +1876,7 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_2, token_3], + bvec![token_1, token_2, token_3], exchange_out3, // amount_out 1000, // amount_in_max user, @@ -1933,7 +1927,7 @@ fn can_not_swap_same_asset() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_1, token_1], + bvec![token_1, token_1], exchange_amount, 1, user, @@ -1945,7 +1939,7 @@ fn can_not_swap_same_asset() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bbvec![token_2, token_2], + bvec![token_2, token_2], exchange_amount, 1, user, @@ -2113,7 +2107,7 @@ fn swap_transactional() { let error; assert_storage_noop!( error = >::swap_tokens_for_exact_tokens( - bvec![token_2, token_1, token_3], + vec![token_2, token_1, token_3], credit_in.into(), expected_out, ) @@ -2128,7 +2122,7 @@ fn swap_transactional() { let error; assert_storage_noop!( error = >::swap_exact_tokens_for_tokens( - bvec![token_2, token_1, token_3], + vec![token_2, token_1, token_3], credit_in.into(), Some(expected_out), ) @@ -2140,7 +2134,7 @@ fn swap_transactional() { assert_noop!( >::swap_exact_tokens_for_tokens( user2, - bvec![token_2, token_1, token_3], + vec![token_2, token_1, token_3], amount_in.into(), Some(expected_out.into()), user2, @@ -2153,7 +2147,7 @@ fn swap_transactional() { assert_noop!( >::swap_tokens_for_exact_tokens( user2, - bvec![token_2, token_1, token_3], + vec![token_2, token_1, token_3], expected_out.into(), Some(amount_in.into()), user2, @@ -2211,7 +2205,7 @@ fn swap_credit_returns_change() { let credit_in = Balances::issue(amount_in_max + expected_change.peek()); assert_ok!( >::swap_tokens_for_exact_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in.into(), expected_credit_out.peek(), ), @@ -2264,7 +2258,7 @@ fn swap_credit_insufficient_amount_bounds() { let credit_in = Balances::issue(amount_in); let expected_credit_in = Balances::issue(amount_in); let error = >::swap_exact_tokens_for_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in.into(), Some(amount_out_min), ) @@ -2281,7 +2275,7 @@ fn swap_credit_insufficient_amount_bounds() { let credit_in = Balances::issue(amount_in_max); let expected_credit_in = Balances::issue(amount_in_max); let error = >::swap_tokens_for_exact_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in.into(), amount_out, ) @@ -2333,7 +2327,7 @@ fn swap_credit_zero_amount() { let credit_in = Credit::native_zero(); let expected_credit_in = Credit::native_zero(); let error = >::swap_exact_tokens_for_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in, None, ) @@ -2344,7 +2338,7 @@ fn swap_credit_zero_amount() { let credit_in = Credit::native_zero(); let expected_credit_in = Credit::native_zero(); let error = >::swap_tokens_for_exact_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in, 10, ) @@ -2355,7 +2349,7 @@ fn swap_credit_zero_amount() { let credit_in = Balances::issue(10); let expected_credit_in = Balances::issue(10); let error = >::swap_exact_tokens_for_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in.into(), Some(0), ) @@ -2366,7 +2360,7 @@ fn swap_credit_zero_amount() { let credit_in = Balances::issue(10); let expected_credit_in = Balances::issue(10); let error = >::swap_tokens_for_exact_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in.into(), 0, ) @@ -2415,7 +2409,7 @@ fn swap_credit_invalid_path() { let credit_in = Balances::issue(10); let expected_credit_in = Balances::issue(10); let error = >::swap_exact_tokens_for_tokens( - bvec![token_2, token_1], + vec![token_2, token_1], credit_in.into(), None, ) @@ -2426,7 +2420,7 @@ fn swap_credit_invalid_path() { let credit_in = Assets::issue(2, 10); let expected_credit_in = Assets::issue(2, 10); let error = >::swap_tokens_for_exact_tokens( - bvec![token_1, token_2], + vec![token_1, token_2], credit_in.into(), 10, ) @@ -2437,7 +2431,7 @@ fn swap_credit_invalid_path() { let credit_in = Balances::issue(10); let expected_credit_in = Balances::issue(10); let error = >::swap_exact_tokens_for_tokens( - bvec![token_2], + vec![token_2], credit_in.into(), None, ) @@ -2448,7 +2442,7 @@ fn swap_credit_invalid_path() { let credit_in = Assets::issue(2, 10); let expected_credit_in = Assets::issue(2, 10); let error = >::swap_tokens_for_exact_tokens( - bvec![], + vec![], credit_in.into(), 10, ) From ced5e99159c6ce149b7865e68f5fcfb0ebc8a112 Mon Sep 17 00:00:00 2001 From: muharem Date: Sat, 7 Oct 2023 17:14:16 +0200 Subject: [PATCH 25/69] update to new api --- .../asset-hub-westend/src/tests/swap.rs | 56 +++++++++---------- .../assets/asset-hub-kusama/src/lib.rs | 10 ++-- .../assets/asset-hub-westend/src/lib.rs | 23 ++++---- .../common/src/local_and_foreign_assets.rs | 43 +++++++------- substrate/frame/asset-conversion/src/lib.rs | 2 +- .../asset-conversion-tx-payment/src/tests.rs | 10 +++- 6 files changed, 72 insertions(+), 72 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs index 7d1615c9e2918..d56a4c7e4de6c 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs @@ -17,11 +17,11 @@ use crate::*; #[test] fn swap_locally_on_chain_using_local_assets() { - let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get()); - let asset_one = Box::new(MultiLocation { + let asset_native = asset_hub_westend_runtime::xcm_config::WestendLocation::get(); + let asset_one = MultiLocation { parents: 0, interior: X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), - }); + }; AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; @@ -43,8 +43,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - asset_native.clone(), - asset_one.clone(), + Box::new(asset_native.clone()), + Box::new(asset_one.clone()), )); assert_expected_events!( @@ -56,8 +56,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::add_liquidity( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - asset_native.clone(), - asset_one.clone(), + Box::new(asset_native.clone()), + Box::new(asset_one.clone()), 1_000_000_000_000, 2_000_000_000_000, 0, @@ -72,7 +72,7 @@ fn swap_locally_on_chain_using_local_assets() { ] ); - let path = BoundedVec::<_, _>::truncate_from(vec![asset_native.clone(), asset_one.clone()]); + let path = vec![Box::new(asset_native.clone()), Box::new(asset_one.clone())]; assert_ok!(::AssetConversion::swap_exact_tokens_for_tokens( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), @@ -95,8 +95,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::remove_liquidity( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - asset_native, - asset_one, + Box::new(asset_native), + Box::new(asset_one), 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. 0, 0, @@ -109,16 +109,16 @@ fn swap_locally_on_chain_using_local_assets() { fn swap_locally_on_chain_using_foreign_assets() { use frame_support::weights::WeightToFee; - let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get()); + let asset_native = asset_hub_westend_runtime::xcm_config::WestendLocation::get(); - let foreign_asset1_at_asset_hub_westend = Box::new(MultiLocation { + let foreign_asset1_at_asset_hub_westend = MultiLocation { parents: 1, interior: X3( Parachain(PenpalWestendA::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), ), - }); + }; let assets_para_destination: VersionedMultiLocation = MultiLocation { parents: 1, interior: X1(Parachain(AssetHubWestend::para_id().into())) } @@ -163,7 +163,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ::Runtime, Instance2, >::create { - id: *foreign_asset1_at_asset_hub_westend, + id: foreign_asset1_at_asset_hub_westend, min_balance: 1000, admin: sov_penpal_on_asset_hub_westend.clone().into(), }) @@ -211,7 +211,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // Receive XCM message in Assets Parachain AssetHubWestend::execute_with(|| { assert!(::ForeignAssets::asset_exists( - *foreign_asset1_at_asset_hub_westend + foreign_asset1_at_asset_hub_westend )); // 3: Mint foreign asset on asset_hub_westend: @@ -225,7 +225,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed( sov_penpal_on_asset_hub_westend.clone().into() ), - *foreign_asset1_at_asset_hub_westend, + foreign_asset1_at_asset_hub_westend, sov_penpal_on_asset_hub_westend.clone().into(), 3_000_000_000_000, )); @@ -240,8 +240,8 @@ fn swap_locally_on_chain_using_foreign_assets() { // 4. Create pool: assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - asset_native.clone(), - foreign_asset1_at_asset_hub_westend.clone(), + Box::new(asset_native.clone()), + Box::new(foreign_asset1_at_asset_hub_westend.clone()), )); assert_expected_events!( @@ -256,8 +256,8 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed( sov_penpal_on_asset_hub_westend.clone() ), - asset_native.clone(), - foreign_asset1_at_asset_hub_westend.clone(), + Box::new(asset_native.clone()), + Box::new(foreign_asset1_at_asset_hub_westend.clone()), 1_000_000_000_000, 2_000_000_000_000, 0, @@ -275,10 +275,10 @@ fn swap_locally_on_chain_using_foreign_assets() { ); // 6. Swap! - let path = BoundedVec::<_, _>::truncate_from(vec![ - asset_native.clone(), - foreign_asset1_at_asset_hub_westend.clone(), - ]); + let path = vec![ + Box::new(asset_native.clone()), + Box::new(foreign_asset1_at_asset_hub_westend.clone()), + ]; assert_ok!(::AssetConversion::swap_exact_tokens_for_tokens( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), @@ -304,8 +304,8 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed( sov_penpal_on_asset_hub_westend.clone() ), - asset_native, - foreign_asset1_at_asset_hub_westend, + Box::new(asset_native), + Box::new(foreign_asset1_at_asset_hub_westend), 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. 0, 0, @@ -316,7 +316,7 @@ fn swap_locally_on_chain_using_foreign_assets() { #[test] fn cannot_create_pool_from_pool_assets() { - let asset_native = Box::new(asset_hub_westend_runtime::xcm_config::WestendLocation::get()); + let asset_native = asset_hub_westend_runtime::xcm_config::WestendLocation::get(); let mut asset_one = asset_hub_westend_runtime::xcm_config::PoolAssetsPalletLocation::get(); asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets"); @@ -341,7 +341,7 @@ fn cannot_create_pool_from_pool_assets() { assert_matches::assert_matches!( ::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - asset_native.clone(), + Box::new(asset_native.clone()), Box::new(asset_one), ), Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset")) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index 40ce122112d29..efadf4869bf14 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -347,7 +347,7 @@ impl pallet_asset_conversion::Config for Runtime { type PalletId = AssetConversionPalletId; type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; - type MultiAssetId = Box; + type MultiAssetId = MultiLocation; type MultiAssetIdConverter = MultiLocationConverter; type MintMinLiquidity = ConstU128<100>; @@ -1031,16 +1031,16 @@ impl_runtime_apis! { Block, Balance, u128, - Box, + MultiLocation, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: Box, asset2: Box) -> Option<(Balance, Balance)> { + fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> { AssetConversion::get_reserves(&asset1, &asset2).ok() } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 943332087627c..9a27a71bb16ae 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -323,7 +323,7 @@ impl pallet_asset_conversion::Config for Runtime { type PalletId = AssetConversionPalletId; type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; - type MultiAssetId = Box; + type MultiAssetId = MultiLocation; type MultiAssetIdConverter = MultiLocationConverter; type MintMinLiquidity = ConstU128<100>; @@ -1080,18 +1080,18 @@ impl_runtime_apis! { Block, Balance, u128, - Box, + MultiLocation, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: Box, asset2: Box) -> Option<(Balance, Balance)> { + fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> { AssetConversion::get_reserves(&asset1, &asset2).ok() } } @@ -1428,10 +1428,7 @@ pub mod migrations { /// `MultiLocation { parents: 1, interior: Here }` pub struct NativeAssetParents0ToParents1Migration(sp_std::marker::PhantomData); impl< - T: pallet_asset_conversion::Config< - MultiAssetId = Box, - AssetId = MultiLocation, - >, + T: pallet_asset_conversion::Config, > OnRuntimeUpgrade for NativeAssetParents0ToParents1Migration where ::PoolAssetId: Into, @@ -1457,14 +1454,14 @@ pub mod migrations { pallet_asset_conversion::Pallet::::get_pool_account(&old_pool_id); reads.saturating_accrue(1); let pool_asset_id = pool_info.lp_token.clone(); - if old_pool_id.0.as_ref() != &invalid_native_asset { + if old_pool_id.0 != invalid_native_asset { // skip, if ok continue } // fix new account let new_pool_id = pallet_asset_conversion::Pallet::::get_pool_id( - Box::new(valid_native_asset), + valid_native_asset, old_pool_id.1.clone(), ); let new_pool_account = @@ -1504,10 +1501,10 @@ pub mod migrations { // move LocalOrForeignAssets let _ = T::Assets::transfer( - *old_pool_id.1.as_ref(), + old_pool_id.1, &old_pool_account, &new_pool_account, - T::Assets::balance(*old_pool_id.1.as_ref(), &old_pool_account), + T::Assets::balance(old_pool_id.1, &old_pool_account), Preservation::Expendable, ); reads.saturating_accrue(1); diff --git a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs index 5c66d1cabe571..b0802d35de2d7 100644 --- a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs +++ b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs @@ -23,37 +23,36 @@ use frame_support::traits::{ use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter}; use parachains_common::AccountId; use sp_runtime::{traits::MaybeEquivalence, DispatchError, DispatchResult}; -use sp_std::{boxed::Box, marker::PhantomData}; +use sp_std::marker::PhantomData; use xcm::latest::MultiLocation; pub struct MultiLocationConverter, MultiLocationMatcher> { _phantom: PhantomData<(NativeAssetLocation, MultiLocationMatcher)>, } -impl - MultiAssetIdConverter, MultiLocation> +impl MultiAssetIdConverter for MultiLocationConverter where NativeAssetLocation: Get, MultiLocationMatcher: Contains, { - fn get_native() -> Box { - Box::new(NativeAssetLocation::get()) + fn get_native() -> MultiLocation { + NativeAssetLocation::get() } - fn is_native(asset_id: &Box) -> bool { + fn is_native(asset_id: &MultiLocation) -> bool { *asset_id == Self::get_native() } fn try_convert( - asset_id: &Box, - ) -> MultiAssetIdConversionResult, MultiLocation> { - if Self::is_native(&asset_id) { + asset_id: &MultiLocation, + ) -> MultiAssetIdConversionResult { + if Self::is_native(asset_id) { return MultiAssetIdConversionResult::Native } - if MultiLocationMatcher::contains(&asset_id) { - MultiAssetIdConversionResult::Converted(*asset_id.clone()) + if MultiLocationMatcher::contains(asset_id) { + MultiAssetIdConversionResult::Converted(asset_id.clone()) } else { MultiAssetIdConversionResult::Unsupported(asset_id.clone()) } @@ -442,27 +441,27 @@ mod tests { interior: X2(GlobalConsensus(ByGenesis([1; 32])), Parachain(2222)), }; - assert!(C::is_native(&Box::new(native_asset))); - assert!(!C::is_native(&Box::new(local_asset))); - assert!(!C::is_native(&Box::new(pool_asset))); - assert!(!C::is_native(&Box::new(foreign_asset1))); - assert!(!C::is_native(&Box::new(foreign_asset2))); + assert!(C::is_native(&native_asset)); + assert!(!C::is_native(&local_asset)); + assert!(!C::is_native(&pool_asset)); + assert!(!C::is_native(&foreign_asset1)); + assert!(!C::is_native(&foreign_asset2)); - assert_eq!(C::try_convert(&Box::new(native_asset)), MultiAssetIdConversionResult::Native); + assert_eq!(C::try_convert(&native_asset), MultiAssetIdConversionResult::Native); assert_eq!( - C::try_convert(&Box::new(local_asset)), + C::try_convert(&local_asset), MultiAssetIdConversionResult::Converted(local_asset) ); assert_eq!( - C::try_convert(&Box::new(pool_asset)), - MultiAssetIdConversionResult::Unsupported(Box::new(pool_asset)) + C::try_convert(&pool_asset), + MultiAssetIdConversionResult::Unsupported(pool_asset) ); assert_eq!( - C::try_convert(&Box::new(foreign_asset1)), + C::try_convert(&foreign_asset1), MultiAssetIdConversionResult::Converted(foreign_asset1) ); assert_eq!( - C::try_convert(&Box::new(foreign_asset2)), + C::try_convert(&foreign_asset2), MultiAssetIdConversionResult::Converted(foreign_asset2) ); } diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 37d304bf8494b..45dcdc0063fe9 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -96,7 +96,7 @@ use sp_runtime::{ }, DispatchError, RuntimeDebug, Saturating, TokenError, TransactionOutcome, }; -use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; +use sp_std::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec}; #[frame_support::pallet] pub mod pallet { diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs index cad301dc9599c..d50a051642358 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs @@ -129,12 +129,16 @@ fn setup_lp(asset_id: u32, balance_factor: u64) { let token_1 = NativeOrAssetId::Native; let token_2 = NativeOrAssetId::Asset(asset_id); - assert_ok!(AssetConversion::create_pool(RuntimeOrigin::signed(lp_provider), token_1, token_2)); + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider), + Box::new(token_1), + Box::new(token_2) + )); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(lp_provider), - token_1, - token_2, + Box::new(token_1), + Box::new(token_2), 1_000 * balance_factor, // 1 desired 10_000 * balance_factor, // 2 desired 1, // 1 min From 7fee81e62599885202b6a7a95fd1a0a26848011f Mon Sep 17 00:00:00 2001 From: muharem Date: Sat, 7 Oct 2023 19:42:55 +0200 Subject: [PATCH 26/69] drop clone --- .../runtimes/assets/common/src/local_and_foreign_assets.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs index b0802d35de2d7..a8bafa5e8b9ec 100644 --- a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs +++ b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs @@ -52,9 +52,9 @@ where } if MultiLocationMatcher::contains(asset_id) { - MultiAssetIdConversionResult::Converted(asset_id.clone()) + MultiAssetIdConversionResult::Converted(*asset_id) } else { - MultiAssetIdConversionResult::Unsupported(asset_id.clone()) + MultiAssetIdConversionResult::Unsupported(*asset_id) } } } From b63cd7349a60643feacce9f96e8c6013567e4788 Mon Sep 17 00:00:00 2001 From: muharem Date: Sun, 8 Oct 2023 15:09:07 +0200 Subject: [PATCH 27/69] box arguments and drop bounded vec from benches --- .../asset-conversion/src/benchmarking.rs | 112 ++++++++++++------ 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/substrate/frame/asset-conversion/src/benchmarking.rs b/substrate/frame/asset-conversion/src/benchmarking.rs index 87b541cd4744d..72033c58c8b27 100644 --- a/substrate/frame/asset-conversion/src/benchmarking.rs +++ b/substrate/frame/asset-conversion/src/benchmarking.rs @@ -21,7 +21,6 @@ use super::*; use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_support::{ assert_ok, - storage::bounded_vec::BoundedVec, traits::{ fungible::{Inspect as InspectFungible, Mutate as MutateFungible, Unbalanced}, fungibles::{Create, Inspect, Mutate}, @@ -80,8 +79,8 @@ where assert_ok!(AssetConversion::::create_pool( SystemOrigin::Signed(caller.clone()).into(), - asset1.clone(), - asset2.clone() + Box::new(asset1.clone()), + Box::new(asset2.clone()) )); let lp_token = get_lp_token_id::(); @@ -110,7 +109,7 @@ benchmarks! { let asset1 = T::MultiAssetIdConverter::get_native(); let asset2 = T::BenchmarkHelper::multiasset_id(0); let (caller, _) = create_asset::(&asset2); - }: _(SystemOrigin::Signed(caller.clone()), asset1.clone(), asset2.clone()) + }: _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone())) verify { let lp_token = get_lp_token_id::(); let pool_id = (asset1.clone(), asset2.clone()); @@ -128,7 +127,7 @@ benchmarks! { let (lp_token, caller, _) = create_asset_and_pool::(&asset1, &asset2); let ed: u128 = T::Currency::minimum_balance().into(); let add_amount = 1000 + ed; - }: _(SystemOrigin::Signed(caller.clone()), asset1.clone(), asset2.clone(), add_amount.into(), 1000.into(), 0.into(), 0.into(), caller.clone()) + }: _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone()), add_amount.into(), 1000.into(), 0.into(), 0.into(), caller.clone()) verify { let pool_id = (asset1.clone(), asset2.clone()); let lp_minted = AssetConversion::::calc_lp_amount_for_zero_supply(&add_amount.into(), &1000.into()).unwrap().into(); @@ -157,8 +156,8 @@ benchmarks! { AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - asset1.clone(), - asset2.clone(), + Box::new(asset1.clone()), + Box::new(asset2.clone()), add_amount.into(), 1000.into(), 0.into(), @@ -166,7 +165,7 @@ benchmarks! { caller.clone(), )?; let total_supply = >::total_issuance(lp_token.clone()); - }: _(SystemOrigin::Signed(caller.clone()), asset1, asset2, remove_lp_amount.into(), 0.into(), 0.into(), caller.clone()) + }: _(SystemOrigin::Signed(caller.clone()), Box::new(asset1), Box::new(asset2), remove_lp_amount.into(), 0.into(), 0.into(), caller.clone()) verify { let new_total_supply = >::total_issuance(lp_token.clone()); assert_eq!( @@ -185,8 +184,8 @@ benchmarks! { AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - asset1.clone(), + Box::new(native.clone()), + Box::new(asset1.clone()), (100 * ed).into(), 200.into(), 0.into(), @@ -199,29 +198,45 @@ benchmarks! { // if we only allow the native-asset pools, then the worst case scenario would be to swap // asset1-native-asset2 if !T::AllowMultiAssetPools::get() { - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), native.clone(), asset2.clone())?; + AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(native.clone()), + Box::new(asset2.clone()) + )?; AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - asset2.clone(), + Box::new(native.clone()), + Box::new(asset2.clone()), (500 * ed).into(), 1000.into(), 0.into(), 0.into(), caller.clone(), )?; - path = vec![asset1.clone(), native.clone(), asset2.clone()]; + path = vec![ + Box::new(asset1.clone()), + Box::new(native.clone()), + Box::new(asset2.clone()) + ]; swap_amount = 100.into(); } else { let asset3 = T::BenchmarkHelper::multiasset_id(3); - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone())?; + AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()) + )?; let (_, _) = create_asset::(&asset3); - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset2.clone(), asset3.clone())?; + AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset2.clone()), + Box::new(asset3.clone()) + )?; AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - asset1.clone(), - asset2.clone(), + Box::new(asset1.clone()), + Box::new(asset2.clone()), 200.into(), 2000.into(), 0.into(), @@ -230,19 +245,22 @@ benchmarks! { )?; AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - asset2.clone(), - asset3.clone(), + Box::new(asset2.clone()), + Box::new(asset3.clone()), 2000.into(), 2000.into(), 0.into(), 0.into(), caller.clone(), )?; - path = vec![native.clone(), asset1.clone(), asset2.clone(), asset3.clone()]; + path = vec![ + Box::new(native.clone()), + Box::new(asset1.clone()), + Box::new(asset2.clone()), + Box::new(asset3.clone()) + ]; swap_amount = ed.into(); } - - let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap(); let native_balance = T::Currency::balance(&caller); let asset1_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(1), &caller); }: _(SystemOrigin::Signed(caller.clone()), path, swap_amount, 1.into(), caller.clone(), false) @@ -266,8 +284,8 @@ benchmarks! { AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - asset1.clone(), + Box::new(native.clone()), + Box::new(asset1.clone()), (1000 * ed).into(), 500.into(), 0.into(), @@ -279,28 +297,44 @@ benchmarks! { // if we only allow the native-asset pools, then the worst case scenario would be to swap // asset1-native-asset2 if !T::AllowMultiAssetPools::get() { - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), native.clone(), asset2.clone())?; + AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(native.clone()), + Box::new(asset2.clone()) + )?; AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - asset2.clone(), + Box::new(native.clone()), + Box::new(asset2.clone()), (500 * ed).into(), 1000.into(), 0.into(), 0.into(), caller.clone(), )?; - path = vec![asset1.clone(), native.clone(), asset2.clone()]; + path = vec![ + Box::new(asset1.clone()), + Box::new(native.clone()), + Box::new(asset2.clone()) + ]; } else { - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone())?; + AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()) + )?; let asset3 = T::BenchmarkHelper::multiasset_id(3); let (_, _) = create_asset::(&asset3); - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset2.clone(), asset3.clone())?; + AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset2.clone()), + Box::new(asset3.clone()) + )?; AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - asset1.clone(), - asset2.clone(), + Box::new(asset1.clone()), + Box::new(asset2.clone()), 2000.into(), 2000.into(), 0.into(), @@ -309,18 +343,22 @@ benchmarks! { )?; AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - asset2.clone(), - asset3.clone(), + Box::new(asset2.clone()), + Box::new(asset3.clone()), 2000.into(), 2000.into(), 0.into(), 0.into(), caller.clone(), )?; - path = vec![native.clone(), asset1.clone(), asset2.clone(), asset3.clone()]; + path = vec![ + Box::new(native.clone()), + Box::new(asset1.clone()), + Box::new(asset2.clone()), + Box::new(asset3.clone()) + ]; } - let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap(); let asset2_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(2), &caller); let asset3_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(3), &caller); }: _(SystemOrigin::Signed(caller.clone()), path.clone(), 100.into(), (1000 * ed).into(), caller.clone(), false) From 01bd4da4499bb97a8cb02a1ab24cd8a8274221b2 Mon Sep 17 00:00:00 2001 From: muharem Date: Sun, 8 Oct 2023 16:27:38 +0200 Subject: [PATCH 28/69] no box for benchmarks impls --- .../runtimes/assets/asset-hub-kusama/src/xcm_config.rs | 7 +++---- .../runtimes/assets/asset-hub-westend/src/xcm_config.rs | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index 0c197598f8895..e29f9b6dfcc6c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs @@ -604,8 +604,7 @@ pub struct BenchmarkMultiLocationConverter { } #[cfg(feature = "runtime-benchmarks")] -impl - pallet_asset_conversion::BenchmarkHelper> +impl pallet_asset_conversion::BenchmarkHelper for BenchmarkMultiLocationConverter where SelfParaId: Get, @@ -620,7 +619,7 @@ where ), } } - fn multiasset_id(asset_id: u32) -> sp_std::boxed::Box { - sp_std::boxed::Box::new(Self::asset_id(asset_id)) + fn multiasset_id(asset_id: u32) -> MultiLocation { + Self::asset_id(asset_id) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 6981c290c98ce..611a920cc039f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -602,8 +602,7 @@ pub struct BenchmarkMultiLocationConverter { } #[cfg(feature = "runtime-benchmarks")] -impl - pallet_asset_conversion::BenchmarkHelper> +impl pallet_asset_conversion::BenchmarkHelper for BenchmarkMultiLocationConverter where SelfParaId: Get, @@ -619,7 +618,7 @@ where } } - fn multiasset_id(asset_id: u32) -> sp_std::boxed::Box { - sp_std::boxed::Box::new(Self::asset_id(asset_id)) + fn multiasset_id(asset_id: u32) -> MultiLocation { + Self::asset_id(asset_id) } } From e2b99f96f5828f6e04a490b4700658a5e902ab92 Mon Sep 17 00:00:00 2001 From: muharem Date: Sun, 8 Oct 2023 17:59:29 +0200 Subject: [PATCH 29/69] single balance type for Currency and Assets --- .../assets/asset-hub-kusama/src/lib.rs | 6 +- .../assets/asset-hub-westend/src/lib.rs | 6 +- substrate/bin/node/runtime/src/lib.rs | 6 +- .../asset-conversion/src/benchmarking.rs | 5 +- substrate/frame/asset-conversion/src/lib.rs | 210 +++++++----------- substrate/frame/asset-conversion/src/mock.rs | 3 +- substrate/frame/asset-conversion/src/swap.rs | 10 +- substrate/frame/asset-conversion/src/types.rs | 23 +- .../asset-conversion-tx-payment/src/mock.rs | 1 - .../src/payment.rs | 15 +- 10 files changed, 104 insertions(+), 181 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index efadf4869bf14..1237917100706 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -330,7 +330,6 @@ impl pallet_asset_conversion::Config for Runtime { type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; type Currency = Balances; - type AssetBalance = Balance; type AssetId = MultiLocation; type Assets = LocalAndForeignAssets< Assets, @@ -1030,14 +1029,13 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - u128, MultiLocation, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> { diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 9a27a71bb16ae..51f14bfef300e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -307,7 +307,6 @@ impl pallet_asset_conversion::Config for Runtime { type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; type Currency = Balances; - type AssetBalance = Balance; type AssetId = MultiLocation; type Assets = LocalAndForeignAssets< Assets, @@ -1079,15 +1078,14 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - u128, MultiLocation, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: u128, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f018639b732e3..2db3a3ed3ccad 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1632,7 +1632,6 @@ parameter_types! { impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type AssetBalance = ::Balance; type HigherPrecisionBalance = sp_core::U256; type Assets = Assets; type Balance = u128; @@ -2526,15 +2525,14 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - u128, NativeOrAssetId > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: NativeOrAssetId, asset2: NativeOrAssetId, amount: u128, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: NativeOrAssetId, asset2: NativeOrAssetId, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: NativeOrAssetId, asset2: NativeOrAssetId, amount: u128, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: NativeOrAssetId, asset2: NativeOrAssetId, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } diff --git a/substrate/frame/asset-conversion/src/benchmarking.rs b/substrate/frame/asset-conversion/src/benchmarking.rs index 72033c58c8b27..628953d0558f7 100644 --- a/substrate/frame/asset-conversion/src/benchmarking.rs +++ b/substrate/frame/asset-conversion/src/benchmarking.rs @@ -48,7 +48,7 @@ where fn create_asset(asset: &T::MultiAssetId) -> (T::AccountId, AccountIdLookupOf) where - T::AssetBalance: From, + T::Balance: From, T::Currency: Unbalanced, T::Assets: Create + Mutate, { @@ -69,7 +69,7 @@ fn create_asset_and_pool( asset2: &T::MultiAssetId, ) -> (T::PoolAssetId, T::AccountId, AccountIdLookupOf) where - T::AssetBalance: From, + T::Balance: From, T::Currency: Unbalanced, T::Assets: Create + Mutate, T::PoolAssetId: Into, @@ -98,7 +98,6 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { benchmarks! { where_clause { where - T::AssetBalance: From + Into, T::Currency: Unbalanced, T::Balance: From + Into, T::Assets: Create + Mutate, diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 45dcdc0063fe9..3e118996f8e93 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -118,21 +118,16 @@ pub mod pallet { + MutateFungible + BalancedFungible; - /// The `Currency::Balance` type of the native currency. + /// The type in which the assets for swapping are measured. type Balance: Balance; - /// The type used to describe the amount of fractions converted into assets. - type AssetBalance: Balance; - - /// A type used for conversions between `Balance` and `AssetBalance`. + /// A type used for calculations concerning the `Balance` type to avoid possible overflows. type HigherPrecisionBalance: IntegerSquareRoot + One + Ensure + Unsigned + From - + From + From - + TryInto + TryInto; /// Identifier for the class of non-native asset. @@ -154,7 +149,7 @@ pub mod pallet { type PoolAssetId: AssetId + PartialOrd + Incrementable + From; /// Registry for the assets. - type Assets: Inspect + type Assets: Inspect + Mutate + AccountTouch + ContainsPair @@ -162,7 +157,7 @@ pub mod pallet { /// Registry for the lp tokens. Ideally only this pallet should have create permissions on /// the assets. - type PoolAssets: Inspect + type PoolAssets: Inspect + Create + Mutate + AccountTouch; @@ -184,7 +179,7 @@ pub mod pallet { /// The minimum LP token amount that could be minted. Ameliorates rounding errors. #[pallet::constant] - type MintMinLiquidity: Get; + type MintMinLiquidity: Get; /// The max number of hops in a swap. #[pallet::constant] @@ -244,13 +239,13 @@ pub mod pallet { /// The pool id of the pool that the liquidity was added to. pool_id: PoolIdOf, /// The amount of the first asset that was added to the pool. - amount1_provided: T::AssetBalance, + amount1_provided: T::Balance, /// The amount of the second asset that was added to the pool. - amount2_provided: T::AssetBalance, + amount2_provided: T::Balance, /// The id of the lp token that was minted. lp_token: T::PoolAssetId, /// The amount of lp tokens that were minted of that id. - lp_token_minted: T::AssetBalance, + lp_token_minted: T::Balance, }, /// A successful call of the `RemoveLiquidity` extrinsic will create this event. @@ -262,13 +257,13 @@ pub mod pallet { /// The pool id that the liquidity was removed from. pool_id: PoolIdOf, /// The amount of the first asset that was removed from the pool. - amount1: T::AssetBalance, + amount1: T::Balance, /// The amount of the second asset that was removed from the pool. - amount2: T::AssetBalance, + amount2: T::Balance, /// The id of the lp token that was burned. lp_token: T::PoolAssetId, /// The amount of lp tokens that were burned of that id. - lp_token_burned: T::AssetBalance, + lp_token_burned: T::Balance, /// Liquidity withdrawal fee (%). withdrawal_fee: Permill, }, @@ -280,9 +275,9 @@ pub mod pallet { /// The account that the assets were transferred to. send_to: T::AccountId, /// The amount of the first asset that was swapped. - amount_in: T::AssetBalance, + amount_in: T::Balance, /// The amount of the second asset that was received. - amount_out: T::AssetBalance, + amount_out: T::Balance, /// The route of asset IDs with amounts that the swap went through. /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) path: BalancePath, @@ -290,9 +285,9 @@ pub mod pallet { /// Assets have been converted from one to another. CreditSwapExecuted { /// The amount of the first asset that was swapped. - amount_in: T::AssetBalance, + amount_in: T::Balance, /// The amount of the second asset that was received. - amount_out: T::AssetBalance, + amount_out: T::Balance, /// The route of asset IDs with amounts that the swap went through. /// E.g. (A, amount_in) -> (Dot, amount_out) -> (B, amount_out) path: BalancePath, @@ -461,10 +456,10 @@ pub mod pallet { origin: OriginFor, asset1: Box, asset2: Box, - amount1_desired: T::AssetBalance, - amount2_desired: T::AssetBalance, - amount1_min: T::AssetBalance, - amount2_min: T::AssetBalance, + amount1_desired: T::Balance, + amount2_desired: T::Balance, + amount1_min: T::Balance, + amount2_min: T::Balance, mint_to: T::AccountId, ) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -490,8 +485,8 @@ pub mod pallet { let reserve1 = Self::get_balance(&pool_account, asset1)?; let reserve2 = Self::get_balance(&pool_account, asset2)?; - let amount1: T::AssetBalance; - let amount2: T::AssetBalance; + let amount1: T::Balance; + let amount2: T::Balance; if reserve1.is_zero() || reserve2.is_zero() { amount1 = amount1_desired; amount2 = amount2_desired; @@ -530,7 +525,7 @@ pub mod pallet { let total_supply = T::PoolAssets::total_issuance(pool.lp_token.clone()); - let lp_token_amount: T::AssetBalance; + let lp_token_amount: T::Balance; if total_supply.is_zero() { lp_token_amount = Self::calc_lp_amount_for_zero_supply(&amount1, &amount2)?; T::PoolAssets::mint_into( @@ -573,9 +568,9 @@ pub mod pallet { origin: OriginFor, asset1: Box, asset2: Box, - lp_token_burn: T::AssetBalance, - amount1_min_receive: T::AssetBalance, - amount2_min_receive: T::AssetBalance, + lp_token_burn: T::Balance, + amount1_min_receive: T::Balance, + amount2_min_receive: T::Balance, withdraw_to: T::AccountId, ) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -651,8 +646,8 @@ pub mod pallet { pub fn swap_exact_tokens_for_tokens( origin: OriginFor, path: Vec>, - amount_in: T::AssetBalance, - amount_out_min: T::AssetBalance, + amount_in: T::Balance, + amount_out_min: T::Balance, send_to: T::AccountId, keep_alive: bool, ) -> DispatchResult { @@ -679,8 +674,8 @@ pub mod pallet { pub fn swap_tokens_for_exact_tokens( origin: OriginFor, path: Vec>, - amount_out: T::AssetBalance, - amount_in_max: T::AssetBalance, + amount_out: T::Balance, + amount_in_max: T::Balance, send_to: T::AccountId, keep_alive: bool, ) -> DispatchResult { @@ -713,11 +708,11 @@ pub mod pallet { pub(crate) fn do_swap_exact_tokens_for_tokens( sender: T::AccountId, path: Vec, - amount_in: T::AssetBalance, - amount_out_min: Option, + amount_in: T::Balance, + amount_out_min: Option, send_to: T::AccountId, keep_alive: bool, - ) -> Result { + ) -> Result { ensure!(amount_in > Zero::zero(), Error::::ZeroAmount); if let Some(amount_out_min) = amount_out_min { ensure!(amount_out_min > Zero::zero(), Error::::ZeroAmount); @@ -761,11 +756,11 @@ pub mod pallet { pub(crate) fn do_swap_tokens_for_exact_tokens( sender: T::AccountId, path: Vec, - amount_out: T::AssetBalance, - amount_in_max: Option, + amount_out: T::Balance, + amount_in_max: Option, send_to: T::AccountId, keep_alive: bool, - ) -> Result { + ) -> Result { ensure!(amount_out > Zero::zero(), Error::::ZeroAmount); if let Some(amount_in_max) = amount_in_max { ensure!(amount_in_max > Zero::zero(), Error::::ZeroAmount); @@ -808,12 +803,9 @@ pub mod pallet { pub(crate) fn do_swap_exact_credit_tokens_for_tokens( path: Vec, credit_in: Credit, - amount_out_min: Option, + amount_out_min: Option, ) -> Result, (Credit, DispatchError)> { - let amount_in = match credit_in.peek() { - Ok(a) => a, - Err(e) => return Err((credit_in, e)), - }; + let amount_in = credit_in.peek(); let inspect_path = |credit_asset| { ensure!(path.get(0).map_or(false, |a| *a == credit_asset), Error::::InvalidPath); ensure!(!amount_in.is_zero(), Error::::ZeroAmount); @@ -856,12 +848,9 @@ pub mod pallet { pub(crate) fn do_swap_credit_tokens_for_exact_tokens( path: Vec, credit_in: Credit, - amount_out: T::AssetBalance, + amount_out: T::Balance, ) -> Result<(Credit, Credit), (Credit, DispatchError)> { - let amount_in_max = match credit_in.peek() { - Ok(a) => a, - Err(e) => return Err((credit_in, e)), - }; + let amount_in_max = credit_in.peek(); let inspect_path = |credit_asset| { ensure!(path.get(0).map_or(false, |a| a == &credit_asset), Error::::InvalidPath); ensure!(amount_in_max > Zero::zero(), Error::::ZeroAmount); @@ -883,7 +872,7 @@ pub mod pallet { Err(e) => return Err((credit_in, e)), }; - let (credit_in, credit_change) = credit_in.split(amount_in)?; + let (credit_in, credit_change) = credit_in.split(amount_in); let credit_out = Self::credit_swap(credit_in, &path)?; Self::deposit_event(Event::CreditSwapExecuted { amount_in, amount_out, path }); @@ -896,9 +885,9 @@ pub mod pallet { asset_id: &T::MultiAssetId, from: &T::AccountId, to: &T::AccountId, - amount: T::AssetBalance, + amount: T::Balance, keep_alive: bool, - ) -> Result { + ) -> Result { let preservation = match keep_alive { true => Preserve, false => Expendable, @@ -906,15 +895,8 @@ pub mod pallet { match T::MultiAssetIdConverter::try_convert(asset_id) { MultiAssetIdConversionResult::Converted(asset_id) => T::Assets::transfer(asset_id, from, to, amount, preservation), - MultiAssetIdConversionResult::Native => { - let amount = Self::convert_asset_balance_to_native_balance(amount)?; - Ok(Self::convert_native_balance_to_asset_balance(T::Currency::transfer( - from, - to, - amount, - preservation, - )?)?) - }, + MultiAssetIdConversionResult::Native => + Ok(T::Currency::transfer(from, to, amount, preservation)?), MultiAssetIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedAsset.into()), } @@ -934,7 +916,7 @@ pub mod pallet { fn withdraw( asset: &T::MultiAssetId, who: &T::AccountId, - value: T::AssetBalance, + value: T::Balance, keep_alive: bool, ) -> Result, DispatchError> { let preservation = match keep_alive { @@ -954,7 +936,6 @@ pub mod pallet { .map(|c| c.into()) }, MultiAssetIdConversionResult::Native => { - let value = Self::convert_asset_balance_to_native_balance(value)?; if preservation == Preserve { // TODO drop the ensure! when this issue addressed // https://github.com/paritytech/polkadot-sdk/issues/1698 @@ -968,31 +949,6 @@ pub mod pallet { } } - /// Convert a `Balance` type to an `AssetBalance`. - pub(crate) fn convert_native_balance_to_asset_balance( - amount: T::Balance, - ) -> Result> { - T::HigherPrecisionBalance::from(amount) - .try_into() - .map_err(|_| Error::::Overflow) - } - - /// Convert an `AssetBalance` type to a `Balance`. - pub(crate) fn convert_asset_balance_to_native_balance( - amount: T::AssetBalance, - ) -> Result> { - T::HigherPrecisionBalance::from(amount) - .try_into() - .map_err(|_| Error::::Overflow) - } - - /// Convert a `HigherPrecisionBalance` type to an `AssetBalance`. - pub(crate) fn convert_hpb_to_asset_balance( - amount: T::HigherPrecisionBalance, - ) -> Result> { - amount.try_into().map_err(|_| Error::::Overflow) - } - /// Swap assets along the `path`, withdrawing from `sender` and depositing in `send_to`. /// /// Note: It's assumed that the provided `path` is valid. @@ -1080,19 +1036,17 @@ pub mod pallet { } /// Get the `owner`'s balance of `asset`, which could be the chain's native asset or another - /// fungible. Returns a value in the form of an `AssetBalance`. + /// fungible. Returns a value in the form of an `Balance`. fn get_balance( owner: &T::AccountId, asset: &T::MultiAssetId, - ) -> Result> { + ) -> Result> { match T::MultiAssetIdConverter::try_convert(asset) { MultiAssetIdConversionResult::Converted(asset_id) => Ok( <::Assets>::reducible_balance(asset_id, owner, Expendable, Polite), ), MultiAssetIdConversionResult::Native => - Self::convert_native_balance_to_asset_balance( - <::Currency>::reducible_balance(owner, Expendable, Polite), - ), + Ok(<::Currency>::reducible_balance(owner, Expendable, Polite)), MultiAssetIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedAsset.into()), } @@ -1127,7 +1081,7 @@ pub mod pallet { pub fn get_reserves( asset1: &T::MultiAssetId, asset2: &T::MultiAssetId, - ) -> Result<(T::AssetBalance, T::AssetBalance), Error> { + ) -> Result<(T::Balance, T::Balance), Error> { let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); let pool_account = Self::get_pool_account(&pool_id); @@ -1143,11 +1097,11 @@ pub mod pallet { /// Leading to an amount at the end of a `path`, get the required amounts in. pub(crate) fn balance_path_from_amount_out( - amount_out: T::AssetBalance, + amount_out: T::Balance, path: Vec, ) -> Result, DispatchError> { let mut balance_path: BalancePath = Vec::with_capacity(path.len()); - let mut amount_in: T::AssetBalance = amount_out; + let mut amount_in: T::Balance = amount_out; let mut iter = path.into_iter().rev().peekable(); while let Some(asset2) = iter.next() { @@ -1169,11 +1123,11 @@ pub mod pallet { /// Following an amount into a `path`, get the corresponding amounts out. pub(crate) fn balance_path_from_amount_in( - amount_in: T::AssetBalance, + amount_in: T::Balance, path: Vec, ) -> Result, DispatchError> { let mut balance_path: BalancePath = Vec::with_capacity(path.len()); - let mut amount_out: T::AssetBalance = amount_in; + let mut amount_out: T::Balance = amount_in; let mut iter = path.into_iter().peekable(); while let Some(asset1) = iter.next() { @@ -1195,9 +1149,9 @@ pub mod pallet { pub fn quote_price_exact_tokens_for_tokens( asset1: T::MultiAssetId, asset2: T::MultiAssetId, - amount: T::AssetBalance, + amount: T::Balance, include_fee: bool, - ) -> Option { + ) -> Option { let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); let pool_account = Self::get_pool_account(&pool_id); @@ -1218,9 +1172,9 @@ pub mod pallet { pub fn quote_price_tokens_for_exact_tokens( asset1: T::MultiAssetId, asset2: T::MultiAssetId, - amount: T::AssetBalance, + amount: T::Balance, include_fee: bool, - ) -> Option { + ) -> Option { let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); let pool_account = Self::get_pool_account(&pool_id); @@ -1239,18 +1193,18 @@ pub mod pallet { /// Calculates the optimal amount from the reserves. pub fn quote( - amount: &T::AssetBalance, - reserve1: &T::AssetBalance, - reserve2: &T::AssetBalance, - ) -> Result> { + amount: &T::Balance, + reserve1: &T::Balance, + reserve2: &T::Balance, + ) -> Result> { // (amount * reserve2) / reserve1 Self::mul_div(amount, reserve2, reserve1) } pub(super) fn calc_lp_amount_for_zero_supply( - amount1: &T::AssetBalance, - amount2: &T::AssetBalance, - ) -> Result> { + amount1: &T::Balance, + amount2: &T::Balance, + ) -> Result> { let amount1 = T::HigherPrecisionBalance::from(*amount1); let amount2 = T::HigherPrecisionBalance::from(*amount2); @@ -1264,11 +1218,7 @@ pub mod pallet { result.try_into().map_err(|_| Error::::Overflow) } - fn mul_div( - a: &T::AssetBalance, - b: &T::AssetBalance, - c: &T::AssetBalance, - ) -> Result> { + fn mul_div(a: &T::Balance, b: &T::Balance, c: &T::Balance) -> Result> { let a = T::HigherPrecisionBalance::from(*a); let b = T::HigherPrecisionBalance::from(*b); let c = T::HigherPrecisionBalance::from(*c); @@ -1287,10 +1237,10 @@ pub mod pallet { /// Given an input amount of an asset and pair reserves, returns the maximum output amount /// of the other asset. pub fn get_amount_out( - amount_in: &T::AssetBalance, - reserve_in: &T::AssetBalance, - reserve_out: &T::AssetBalance, - ) -> Result> { + amount_in: &T::Balance, + reserve_in: &T::Balance, + reserve_out: &T::Balance, + ) -> Result> { let amount_in = T::HigherPrecisionBalance::from(*amount_in); let reserve_in = T::HigherPrecisionBalance::from(*reserve_in); let reserve_out = T::HigherPrecisionBalance::from(*reserve_out); @@ -1322,10 +1272,10 @@ pub mod pallet { /// Given an output amount of an asset and pair reserves, returns a required input amount /// of the other asset. pub fn get_amount_in( - amount_out: &T::AssetBalance, - reserve_in: &T::AssetBalance, - reserve_out: &T::AssetBalance, - ) -> Result> { + amount_out: &T::Balance, + reserve_in: &T::Balance, + reserve_out: &T::Balance, + ) -> Result> { let amount_out = T::HigherPrecisionBalance::from(*amount_out); let reserve_in = T::HigherPrecisionBalance::from(*reserve_in); let reserve_out = T::HigherPrecisionBalance::from(*reserve_out); @@ -1360,10 +1310,7 @@ pub mod pallet { } /// Ensure that a `value` meets the minimum balance requirements of an `asset` class. - fn validate_minimal_amount( - value: T::AssetBalance, - asset: &T::MultiAssetId, - ) -> Result<(), ()> { + fn validate_minimal_amount(value: T::Balance, asset: &T::MultiAssetId) -> Result<(), ()> { if T::MultiAssetIdConverter::is_native(asset) { let ed = T::Currency::minimum_balance(); ensure!( @@ -1414,22 +1361,21 @@ pub mod pallet { sp_api::decl_runtime_apis! { /// This runtime api allows people to query the size of the liquidity pools /// and quote prices for swaps. - pub trait AssetConversionApi where - Balance: Codec + MaybeDisplay, - AssetBalance: frame_support::traits::tokens::Balance, + pub trait AssetConversionApi where + Balance: frame_support::traits::tokens::Balance + MaybeDisplay, AssetId: Codec { /// Provides a quote for [`Pallet::swap_tokens_for_exact_tokens`]. /// /// Note that the price may have changed by the time the transaction is executed. /// (Use `amount_in_max` to control slippage.) - fn quote_price_tokens_for_exact_tokens(asset1: AssetId, asset2: AssetId, amount: AssetBalance, include_fee: bool) -> Option; + fn quote_price_tokens_for_exact_tokens(asset1: AssetId, asset2: AssetId, amount: Balance, include_fee: bool) -> Option; /// Provides a quote for [`Pallet::swap_exact_tokens_for_tokens`]. /// /// Note that the price may have changed by the time the transaction is executed. /// (Use `amount_out_min` to control slippage.) - fn quote_price_exact_tokens_for_tokens(asset1: AssetId, asset2: AssetId, amount: AssetBalance, include_fee: bool) -> Option; + fn quote_price_exact_tokens_for_tokens(asset1: AssetId, asset2: AssetId, amount: Balance, include_fee: bool) -> Option; /// Returns the size of the liquidity pool for the given asset pair. fn get_reserves(asset1: AssetId, asset2: AssetId) -> Option<(Balance, Balance)>; diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 3a19f39e7ca62..03949afd07e7d 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -152,7 +152,6 @@ ord_parameter_types! { impl Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type AssetBalance = ::Balance; type AssetId = u32; type PoolAssetId = u32; type Assets = Assets; @@ -167,7 +166,7 @@ impl Config for Test { type MaxSwapPathLength = ConstU32<4>; type MintMinLiquidity = ConstU128<100>; // 100 is good enough when the main currency has 12 decimals. - type Balance = u128; + type Balance = ::Balance; type HigherPrecisionBalance = sp_core::U256; type MultiAssetId = NativeOrAssetId; diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index a86b55d41a536..a760ffd10a65a 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -105,7 +105,7 @@ pub trait SwapCredit { } impl Swap for Pallet { - type Balance = T::HigherPrecisionBalance; + type Balance = T::Balance; type MultiAssetId = T::MultiAssetId; fn max_path_len() -> u32 { @@ -120,12 +120,11 @@ impl Swap for Pallet { send_to: T::AccountId, keep_alive: bool, ) -> Result { - let amount_out_min = amount_out_min.map(Self::convert_hpb_to_asset_balance).transpose()?; let amount_out = with_storage_layer(|| { Self::do_swap_exact_tokens_for_tokens( sender, path, - Self::convert_hpb_to_asset_balance(amount_in)?, + amount_in, amount_out_min, send_to, keep_alive, @@ -142,12 +141,11 @@ impl Swap for Pallet { send_to: T::AccountId, keep_alive: bool, ) -> Result { - let amount_in_max = amount_in_max.map(Self::convert_hpb_to_asset_balance).transpose()?; let amount_in = with_storage_layer(|| { Self::do_swap_tokens_for_exact_tokens( sender, path, - Self::convert_hpb_to_asset_balance(amount_out)?, + amount_out, amount_in_max, send_to, keep_alive, @@ -158,7 +156,7 @@ impl Swap for Pallet { } impl SwapCredit for Pallet { - type Balance = T::AssetBalance; + type Balance = T::Balance; type MultiAssetId = T::MultiAssetId; type Credit = Credit; diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 466faf4340318..c2bc74c512265 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -36,7 +36,7 @@ pub(super) type PoolIdOf = (::MultiAssetId, ::Multi /// 1. `asset(asset1, amount_in)` take from `user` and move to the pool(asset1, asset2); /// 2. `asset(asset2, amount_out2)` transfer from pool(asset1, asset2) to pool(asset2, asset3); /// 3. `asset(asset3, amount_out3)` move from pool(asset2, asset3) to `user`. -pub(super) type BalancePath = Vec<(::MultiAssetId, ::AssetBalance)>; +pub(super) type BalancePath = Vec<(::MultiAssetId, ::Balance)>; /// Stores the lp_token asset id a particular pool has been assigned. #[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)] @@ -206,14 +206,11 @@ impl Credit { } /// Amount of `self`. - pub fn peek(&self) -> Result { - let amount = match self { - Credit::Native(c) => T::HigherPrecisionBalance::from(c.peek()) - .try_into() - .map_err(|_| Error::::Overflow)?, + pub fn peek(&self) -> T::Balance { + match self { + Credit::Native(c) => c.peek(), Credit::Asset(c) => c.peek(), - }; - Ok(amount) + } } /// Asset class of `self`. @@ -226,19 +223,15 @@ impl Credit { /// Consume `self` and return two independent instances; the first is guaranteed to be at most /// `amount` and the second will be the remainder. - pub fn split(self, amount: T::AssetBalance) -> Result<(Self, Self), (Self, DispatchError)> { + pub fn split(self, amount: T::Balance) -> (Self, Self) { match self { Credit::Native(c) => { - let amount = match T::HigherPrecisionBalance::from(amount).try_into() { - Ok(a) => a, - Err(_) => return Err((Self::Native(c), Error::::Overflow.into())), - }; let (left, right) = c.split(amount); - Ok((left.into(), right.into())) + (left.into(), right.into()) }, Credit::Asset(c) => { let (left, right) = c.split(amount); - Ok((left.into(), right.into())) + (left.into(), right.into()) }, } } diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index bfbe8b4178cee..0091861f85fc4 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -235,7 +235,6 @@ ord_parameter_types! { impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type AssetBalance = ::Balance; type AssetId = u32; type PoolAssetId = u32; type Assets = Assets; diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs index ac13e121dd651..ccea9e55bbed2 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs @@ -83,8 +83,8 @@ impl OnChargeAssetTransaction for AssetConversionAdapter where T: Config, C: Inspect<::AccountId>, - CON: Swap, - T::HigherPrecisionBalance: From> + TryInto>, + CON: Swap, MultiAssetId = T::MultiAssetId>, + BalanceOf: Into>, T::MultiAssetId: From>, BalanceOf: IsType<::AccountId>>::Balance>, { @@ -117,22 +117,18 @@ where let asset_consumed = CON::swap_tokens_for_exact_tokens( who.clone(), vec![asset_id.into(), T::MultiAssetIdConverter::get_native()], - T::HigherPrecisionBalance::from(native_asset_required), + native_asset_required, None, who.clone(), true, ) .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))?; - let asset_consumed = asset_consumed - .try_into() - .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))?; - ensure!(asset_consumed > Zero::zero(), InvalidTransaction::Payment); // charge the fee in native currency ::withdraw_fee(who, call, info, fee, tip) - .map(|r| (r, native_asset_required, asset_consumed)) + .map(|r| (r, native_asset_required, asset_consumed.into())) } /// Correct the fee and swap the refund back to asset. @@ -175,8 +171,7 @@ where T::MultiAssetIdConverter::get_native(), // we provide the native asset_id.into(), // we want asset_id back ], - T::HigherPrecisionBalance::from(swap_back), /* amount of the native asset to - * convert to `asset_id` */ + swap_back, // amount of the native asset to convert to `asset_id` None, // no minimum amount back who.clone(), // we will refund to `who` false, // no need to keep alive From 37b2e34f6dd1ee334566507c753a73e991055f42 Mon Sep 17 00:00:00 2001 From: muharem Date: Sun, 8 Oct 2023 18:00:15 +0200 Subject: [PATCH 30/69] Balance trait bound on Balance generic type --- substrate/frame/asset-conversion/src/swap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index a760ffd10a65a..5dff3403fb834 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -22,7 +22,7 @@ use super::*; /// Trait for providing methods to swap between the various asset classes. pub trait Swap { /// Measure units of the asset classes for swapping. - type Balance; + type Balance: Balance; /// Kind of assets that are going to be swapped. type MultiAssetId; @@ -67,7 +67,7 @@ pub trait Swap { /// Trait providing methods to swap between the various asset classes. pub trait SwapCredit { /// Measure units of the asset classes for swapping. - type Balance; + type Balance: Balance; /// Kind of assets that are going to be swapped. type MultiAssetId; /// Credit implying a negative imbalance in the system that can be placed into an account or From d9bc83607f349dde5dc11aae2a8a0169f8a90247 Mon Sep 17 00:00:00 2001 From: muharem Date: Sun, 8 Oct 2023 19:13:26 +0200 Subject: [PATCH 31/69] try into for credit --- substrate/frame/asset-conversion/src/types.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index c2bc74c512265..4e9ebf792ca26 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -161,6 +161,12 @@ impl MultiAssetIdConverter, Asset } } +/// Provides a way to retrieve an underlying value without changing the state of the object. +pub trait Inspectable { + /// Retrieves the underlying value without modifying it. + fn peek(&self) -> Value; +} + /// Credit of [Config::Currency]. /// /// Implies a negative imbalance in the system that can be placed into an account or alter the total @@ -199,6 +205,26 @@ impl From> for Credit { } } +impl TryInto> for Credit { + type Error = (); + fn try_into(self) -> Result, ()> { + match self { + Credit::Native(c) => Ok(c), + _ => Err(()), + } + } +} + +impl TryInto> for Credit { + type Error = (); + fn try_into(self) -> Result, ()> { + match self { + Credit::Asset(c) => Ok(c), + _ => Err(()), + } + } +} + impl Credit { /// Create zero native credit. pub fn native_zero() -> Self { From 01938649d7dc70d80ca864e05d7bd75d7d95a645 Mon Sep 17 00:00:00 2001 From: muharem Date: Sun, 8 Oct 2023 19:15:23 +0200 Subject: [PATCH 32/69] drop clone --- cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 51f14bfef300e..14170ed99af30 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1460,7 +1460,7 @@ pub mod migrations { // fix new account let new_pool_id = pallet_asset_conversion::Pallet::::get_pool_id( valid_native_asset, - old_pool_id.1.clone(), + *old_pool_id.1, ); let new_pool_account = pallet_asset_conversion::Pallet::::get_pool_account(&new_pool_id); From ae19bb86901d1f777210265e81693d7fda2726c2 Mon Sep 17 00:00:00 2001 From: muharem Date: Sun, 8 Oct 2023 20:12:17 +0200 Subject: [PATCH 33/69] fix --- cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 14170ed99af30..cd7fc226693ce 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -1460,7 +1460,7 @@ pub mod migrations { // fix new account let new_pool_id = pallet_asset_conversion::Pallet::::get_pool_id( valid_native_asset, - *old_pool_id.1, + old_pool_id.1, ); let new_pool_account = pallet_asset_conversion::Pallet::::get_pool_account(&new_pool_id); From 23722774b973c6f19a4ab6606097cfc3163049e4 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 9 Oct 2023 10:50:39 +0200 Subject: [PATCH 34/69] clippy fixes --- .../asset-hub-westend/src/tests/swap.rs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs index d56a4c7e4de6c..feb30fa0347e1 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs @@ -43,8 +43,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(asset_native.clone()), - Box::new(asset_one.clone()), + Box::new(asset_native), + Box::new(asset_one), )); assert_expected_events!( @@ -56,8 +56,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::add_liquidity( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(asset_native.clone()), - Box::new(asset_one.clone()), + Box::new(asset_native), + Box::new(asset_one), 1_000_000_000_000, 2_000_000_000_000, 0, @@ -72,7 +72,7 @@ fn swap_locally_on_chain_using_local_assets() { ] ); - let path = vec![Box::new(asset_native.clone()), Box::new(asset_one.clone())]; + let path = vec![Box::new(asset_native), Box::new(asset_one)]; assert_ok!(::AssetConversion::swap_exact_tokens_for_tokens( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), @@ -240,8 +240,8 @@ fn swap_locally_on_chain_using_foreign_assets() { // 4. Create pool: assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(asset_native.clone()), - Box::new(foreign_asset1_at_asset_hub_westend.clone()), + Box::new(asset_native), + Box::new(foreign_asset1_at_asset_hub_westend), )); assert_expected_events!( @@ -256,8 +256,8 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed( sov_penpal_on_asset_hub_westend.clone() ), - Box::new(asset_native.clone()), - Box::new(foreign_asset1_at_asset_hub_westend.clone()), + Box::new(asset_native), + Box::new(foreign_asset1_at_asset_hub_westend), 1_000_000_000_000, 2_000_000_000_000, 0, @@ -275,10 +275,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ); // 6. Swap! - let path = vec![ - Box::new(asset_native.clone()), - Box::new(foreign_asset1_at_asset_hub_westend.clone()), - ]; + let path = vec![Box::new(asset_native), Box::new(foreign_asset1_at_asset_hub_westend)]; assert_ok!(::AssetConversion::swap_exact_tokens_for_tokens( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), @@ -341,7 +338,7 @@ fn cannot_create_pool_from_pool_assets() { assert_matches::assert_matches!( ::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubWestendSender::get()), - Box::new(asset_native.clone()), + Box::new(asset_native), Box::new(asset_one), ), Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset")) From d1f37c781995eef02561f36a709f4bf554744e7b Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 9 Oct 2023 11:34:40 +0200 Subject: [PATCH 35/69] review fixes --- substrate/frame/asset-conversion/src/lib.rs | 8 +-- substrate/frame/asset-conversion/src/swap.rs | 53 ++++++++----------- substrate/frame/asset-conversion/src/types.rs | 5 +- 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 3e118996f8e93..e25725157c32b 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -283,7 +283,7 @@ pub mod pallet { path: BalancePath, }, /// Assets have been converted from one to another. - CreditSwapExecuted { + SwapCreditExecuted { /// The amount of the first asset that was swapped. amount_in: T::Balance, /// The amount of the second asset that was received. @@ -351,7 +351,7 @@ pub mod pallet { NonUniquePath, /// It was not possible to get or increment the Id of the pool. IncorrectPoolAssetId, - /// Account cannot exist with the funds that would be given. + /// The destination account cannot exist with the swapped funds. BelowMinimum, } @@ -828,7 +828,7 @@ pub mod pallet { let credit_out = Self::credit_swap(credit_in, &path)?; - Self::deposit_event(Event::CreditSwapExecuted { amount_in, amount_out, path }); + Self::deposit_event(Event::SwapCreditExecuted { amount_in, amount_out, path }); Ok(credit_out) } @@ -875,7 +875,7 @@ pub mod pallet { let (credit_in, credit_change) = credit_in.split(amount_in); let credit_out = Self::credit_swap(credit_in, &path)?; - Self::deposit_event(Event::CreditSwapExecuted { amount_in, amount_out, path }); + Self::deposit_event(Event::SwapCreditExecuted { amount_in, amount_out, path }); Ok((credit_out, credit_change)) } diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index 5dff3403fb834..26b5e45ca84b0 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -169,22 +169,17 @@ impl SwapCredit for Pallet { credit_in: Self::Credit, amount_out_min: Option, ) -> Result { - let transaction_res = - with_transaction(|| -> TransactionOutcome> { - let res = - Self::do_swap_exact_credit_tokens_for_tokens(path, credit_in, amount_out_min); - match &res { - Ok(_) => TransactionOutcome::Commit(Ok(res)), - // wrapping `res` with `Ok`, since our `Err` doesn't satisfy the - // `From` bound of the `with_transaction` function. - Err(_) => TransactionOutcome::Rollback(Ok(res)), - } - }); - match transaction_res { - Ok(r) => r, - // should never happen, `with_transaction` above never returns an `Err` variant. - Err(_) => Err((Self::Credit::native_zero(), DispatchError::Corruption)), - } + with_transaction(|| -> TransactionOutcome> { + let res = Self::do_swap_exact_credit_tokens_for_tokens(path, credit_in, amount_out_min); + match &res { + Ok(_) => TransactionOutcome::Commit(Ok(res)), + // wrapping `res` with `Ok`, since our `Err` doesn't satisfy the + // `From` bound of the `with_transaction` function. + Err(_) => TransactionOutcome::Rollback(Ok(res)), + } + }) + // should never map an error since `with_transaction` above never returns it. + .map_err(|_| (Self::Credit::native_zero(), DispatchError::Corruption))? } fn swap_tokens_for_exact_tokens( @@ -192,20 +187,16 @@ impl SwapCredit for Pallet { credit_in: Self::Credit, amount_out: Self::Balance, ) -> Result<(Self::Credit, Self::Credit), (Self::Credit, DispatchError)> { - let transaction_res = - with_transaction(|| -> TransactionOutcome> { - let res = Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out); - match &res { - Ok(_) => TransactionOutcome::Commit(Ok(res)), - // wrapping `res` with `Ok`, since our `Err` doesn't satisfy the - // `From` bound of the `with_transaction` function. - Err(_) => TransactionOutcome::Rollback(Ok(res)), - } - }); - match transaction_res { - Ok(r) => r, - // should never happen, `with_transaction` above never returns an `Err` variant. - Err(_) => Err((Self::Credit::native_zero(), DispatchError::Corruption)), - } + with_transaction(|| -> TransactionOutcome> { + let res = Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out); + match &res { + Ok(_) => TransactionOutcome::Commit(Ok(res)), + // wrapping `res` with `Ok`, since our `Err` doesn't satisfy the + // `From` bound of the `with_transaction` function. + Err(_) => TransactionOutcome::Rollback(Ok(res)), + } + }) + // should never map an error since `with_transaction` above never returns it. + .map_err(|_| (Self::Credit::native_zero(), DispatchError::Corruption))? } } diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 4e9ebf792ca26..849b1fc9a1cdc 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -27,9 +27,8 @@ use sp_std::{cmp::Ordering, marker::PhantomData}; /// migration. pub(super) type PoolIdOf = (::MultiAssetId, ::MultiAssetId); -/// Represents a swap path with associated asset amounts for input and output. -/// -/// Each pair of neighboring assets forms a pool. +/// Represents a swap path with associated asset amounts indicating how much of the asset needs to +/// be deposited to get the following asset's amount withdrawn (this is inclusive of fees). /// /// Example: /// Given path [(asset1, amount_in), (asset2, amount_out2), (asset3, amount_out3)], can be resolved: From 3a4935ec1a8e2b5244c886febc129069abec10e8 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 9 Oct 2023 12:56:28 +0200 Subject: [PATCH 36/69] remove unused trait --- substrate/frame/asset-conversion/src/types.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 849b1fc9a1cdc..d5ad8f590653c 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -160,12 +160,6 @@ impl MultiAssetIdConverter, Asset } } -/// Provides a way to retrieve an underlying value without changing the state of the object. -pub trait Inspectable { - /// Retrieves the underlying value without modifying it. - fn peek(&self) -> Value; -} - /// Credit of [Config::Currency]. /// /// Implies a negative imbalance in the system that can be placed into an account or alter the total From 75a7b8a3b53a054653b68e54298fa59ede77f18e Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 10 Oct 2023 12:53:59 +0200 Subject: [PATCH 37/69] note in docs for swap traits --- substrate/frame/asset-conversion/src/swap.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index 26b5e45ca84b0..7f59b8f9b8042 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -37,6 +37,8 @@ pub trait Swap { /// respecting `keep_alive`. /// /// If successful, returns the amount of `path[last]` acquired for the `amount_in`. + /// + /// This operation is expected to be atomic. fn swap_exact_tokens_for_tokens( sender: AccountId, path: Vec, @@ -54,6 +56,8 @@ pub trait Swap { /// respecting `keep_alive`. /// /// If successful returns the amount of the `path[0]` taken to provide `path[last]`. + /// + /// This operation is expected to be atomic. fn swap_tokens_for_exact_tokens( sender: AccountId, path: Vec, @@ -83,6 +87,8 @@ pub trait SwapCredit { /// On a successful swap, the function returns the `credit_out` of `path[last]` obtained from /// the `credit_in`. On failure, it returns an `Err` containing the original `credit_in` and the /// associated error code. + /// + /// This operation is expected to be atomic. fn swap_exact_tokens_for_tokens( path: Vec, credit_in: Self::Credit, @@ -97,6 +103,8 @@ pub trait SwapCredit { /// represents the acquired amount of the `path[last]` asset, and `credit_change` is the /// remaining portion from the `credit_in`. On failure, an `Err` with the initial `credit_in` /// and error code is returned. + /// + /// This operation is expected to be atomic. fn swap_tokens_for_exact_tokens( path: Vec, credit_in: Self::Credit, From ec2cf1d5085bcba7f9b6bf828eaae63551c2c6a1 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 18 Oct 2023 17:21:53 +0200 Subject: [PATCH 38/69] impl on_nonzero_unbalanced instead on_unbalanced --- .../traits/tokens/imbalance/on_unbalanced.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs b/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs index 27bfe46e181e2..4be6cec346b80 100644 --- a/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs +++ b/substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs @@ -53,3 +53,29 @@ pub trait OnUnbalanced { } impl OnUnbalanced for () {} + +/// Resolves received asset credit to account `A`, implementing [`OnUnbalanced`]. +/// +/// Credits that cannot be resolved to account `A` are dropped. This may occur if the account for +/// address `A` does not exist and the existential deposit requirement is not met. +pub struct ResolveTo(PhantomData<(A, F)>); +impl> OnUnbalanced> + for ResolveTo +{ + fn on_nonzero_unbalanced(credit: fungible::Credit) { + let _ = F::resolve(&A::get(), credit).map_err(|c| drop(c)); + } +} + +/// Resolves received asset credit to account `A`, implementing [`OnUnbalanced`]. +/// +/// Credits that cannot be resolved to account `A` are dropped. This may occur if the account for +/// address `A` does not exist and the existential deposit requirement is not met. +pub struct ResolveAssetTo(PhantomData<(A, F)>); +impl> OnUnbalanced> + for ResolveAssetTo +{ + fn on_nonzero_unbalanced(credit: fungibles::Credit) { + let _ = F::resolve(&A::get(), credit).map_err(|c| drop(c)); + } +} From 2b13f27e951c6fb76326a467a4afa8e369cb8359 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 24 Oct 2023 12:34:15 +0200 Subject: [PATCH 39/69] adjustments for rococo setup --- .../runtimes/assets/asset-hub-rococo/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 20b59368a5b52..b8487f2e8f9ed 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -338,7 +338,6 @@ impl pallet_asset_conversion::Config for Runtime { type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; type Currency = Balances; - type AssetBalance = Balance; type AssetId = MultiLocation; type Assets = LocalAndForeignAssets< Assets, @@ -355,7 +354,7 @@ impl pallet_asset_conversion::Config for Runtime { type PalletId = AssetConversionPalletId; type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; - type MultiAssetId = Box; + type MultiAssetId = MultiLocation; type MultiAssetIdConverter = MultiLocationConverter; type MintMinLiquidity = ConstU128<100>; @@ -1111,17 +1110,18 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - u128, - Box, + MultiLocation, > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: Box, asset2: Box, amount: u128, include_fee: bool) -> Option { + + fn quote_price_tokens_for_exact_tokens(asset1: MultiLocation, asset2: MultiLocation, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: Box, asset2: Box) -> Option<(Balance, Balance)> { + + fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> { AssetConversion::get_reserves(&asset1, &asset2).ok() } } From bbca52d63f72fccbe6d5e72ef7c4a0b5a092128f Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 24 Oct 2023 13:31:48 +0200 Subject: [PATCH 40/69] adjustments for rococo tests --- .../assets/asset-hub-rococo/src/tests/swap.rs | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs index f9da0bf946ed5..b16667eaeaecb 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs @@ -14,17 +14,17 @@ // limitations under the License. use crate::*; -use frame_support::{instances::Instance2, BoundedVec}; +use frame_support::instances::Instance2; use parachains_common::rococo::currency::EXISTENTIAL_DEPOSIT; use sp_runtime::{DispatchError, ModuleError}; #[test] fn swap_locally_on_chain_using_local_assets() { - let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); - let asset_one = Box::new(MultiLocation { + let asset_native = asset_hub_rococo_runtime::xcm_config::TokenLocation::get(); + let asset_one = MultiLocation { parents: 0, interior: X2(PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into())), - }); + }; AssetHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; @@ -52,8 +52,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - asset_native.clone(), - asset_one.clone(), + Box::new(asset_native), + Box::new(asset_one), )); assert_expected_events!( @@ -65,8 +65,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::add_liquidity( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - asset_native.clone(), - asset_one.clone(), + Box::new(asset_native), + Box::new(asset_one), 1_000_000_000_000, 2_000_000_000_000, 0, @@ -81,7 +81,7 @@ fn swap_locally_on_chain_using_local_assets() { ] ); - let path = BoundedVec::<_, _>::truncate_from(vec![asset_native.clone(), asset_one.clone()]); + let path = vec![Box::new(asset_native), Box::new(asset_one)]; assert_ok!( ::AssetConversion::swap_exact_tokens_for_tokens( @@ -106,8 +106,8 @@ fn swap_locally_on_chain_using_local_assets() { assert_ok!(::AssetConversion::remove_liquidity( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - asset_native, - asset_one, + Box::new(asset_native), + Box::new(asset_one), 1414213562273 - EXISTENTIAL_DEPOSIT * 2, // all but the 2 EDs can't be retrieved. 0, 0, @@ -120,16 +120,16 @@ fn swap_locally_on_chain_using_local_assets() { fn swap_locally_on_chain_using_foreign_assets() { use frame_support::weights::WeightToFee; - let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); + let asset_native = asset_hub_rococo_runtime::xcm_config::TokenLocation::get(); - let foreign_asset1_at_asset_hub_rococo = Box::new(MultiLocation { + let foreign_asset1_at_asset_hub_rococo = MultiLocation { parents: 1, interior: X3( Parachain(PenpalRococoA::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(ASSET_ID.into()), ), - }); + }; let assets_para_destination: VersionedMultiLocation = MultiLocation { parents: 1, interior: X1(Parachain(AssetHubRococo::para_id().into())) } @@ -175,7 +175,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ::Runtime, Instance2, >::create { - id: *foreign_asset1_at_asset_hub_rococo, + id: foreign_asset1_at_asset_hub_rococo, min_balance: 1000, admin: sov_penpal_on_asset_hub_rococo.clone().into(), }) @@ -223,7 +223,7 @@ fn swap_locally_on_chain_using_foreign_assets() { // Receive XCM message in Assets Parachain AssetHubRococo::execute_with(|| { assert!(::ForeignAssets::asset_exists( - *foreign_asset1_at_asset_hub_rococo + foreign_asset1_at_asset_hub_rococo )); // 3: Mint foreign asset on asset_hub_rococo: @@ -237,7 +237,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed( sov_penpal_on_asset_hub_rococo.clone().into() ), - *foreign_asset1_at_asset_hub_rococo, + foreign_asset1_at_asset_hub_rococo, sov_penpal_on_asset_hub_rococo.clone().into(), 3_000_000_000_000, )); @@ -252,8 +252,8 @@ fn swap_locally_on_chain_using_foreign_assets() { // 4. Create pool: assert_ok!(::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - asset_native.clone(), - foreign_asset1_at_asset_hub_rococo.clone(), + Box::new(asset_native), + Box::new(foreign_asset1_at_asset_hub_rococo), )); assert_expected_events!( @@ -268,8 +268,8 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed( sov_penpal_on_asset_hub_rococo.clone() ), - asset_native.clone(), - foreign_asset1_at_asset_hub_rococo.clone(), + Box::new(asset_native), + Box::new(foreign_asset1_at_asset_hub_rococo), 1_000_000_000_000, 2_000_000_000_000, 0, @@ -287,10 +287,7 @@ fn swap_locally_on_chain_using_foreign_assets() { ); // 6. Swap! - let path = BoundedVec::<_, _>::truncate_from(vec![ - asset_native.clone(), - foreign_asset1_at_asset_hub_rococo.clone(), - ]); + let path = vec![Box::new(asset_native), Box::new(foreign_asset1_at_asset_hub_rococo)]; assert_ok!( ::AssetConversion::swap_exact_tokens_for_tokens( @@ -318,8 +315,8 @@ fn swap_locally_on_chain_using_foreign_assets() { ::RuntimeOrigin::signed( sov_penpal_on_asset_hub_rococo.clone() ), - asset_native, - foreign_asset1_at_asset_hub_rococo, + Box::new(asset_native), + Box::new(foreign_asset1_at_asset_hub_rococo), 1414213562273 - 2_000_000_000, // all but the 2 EDs can't be retrieved. 0, 0, @@ -330,7 +327,7 @@ fn swap_locally_on_chain_using_foreign_assets() { #[test] fn cannot_create_pool_from_pool_assets() { - let asset_native = Box::new(asset_hub_rococo_runtime::xcm_config::TokenLocation::get()); + let asset_native = asset_hub_rococo_runtime::xcm_config::TokenLocation::get(); let mut asset_one = asset_hub_rococo_runtime::xcm_config::PoolAssetsPalletLocation::get(); asset_one.append_with(GeneralIndex(ASSET_ID.into())).expect("pool assets"); @@ -355,7 +352,7 @@ fn cannot_create_pool_from_pool_assets() { assert_matches::assert_matches!( ::AssetConversion::create_pool( ::RuntimeOrigin::signed(AssetHubRococoSender::get()), - asset_native.clone(), + Box::new(asset_native), Box::new(asset_one), ), Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset")) From 66a66110b7bf80aaa9de2d0b5701040f68caf6d6 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 24 Oct 2023 15:13:23 +0200 Subject: [PATCH 41/69] rococo benchmarks --- .../runtimes/assets/asset-hub-rococo/src/xcm_config.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index ae4a275d43ac4..b88de9efb09c0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -724,8 +724,7 @@ pub struct BenchmarkMultiLocationConverter { } #[cfg(feature = "runtime-benchmarks")] -impl - pallet_asset_conversion::BenchmarkHelper> +impl pallet_asset_conversion::BenchmarkHelper for BenchmarkMultiLocationConverter where SelfParaId: Get, @@ -740,8 +739,8 @@ where ), } } - fn multiasset_id(asset_id: u32) -> sp_std::boxed::Box { - sp_std::boxed::Box::new(Self::asset_id(asset_id)) + fn multiasset_id(asset_id: u32) -> MultiLocation { + Self::asset_id(asset_id) } } From b21d0aa400597f44176a958a0107b0dee50bfcaa Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:24:27 +0200 Subject: [PATCH 42/69] fungible/s union_of --- .../src/traits/tokens/fungible/imbalance.rs | 5 + .../src/traits/tokens/fungible/item_of.rs | 66 +- .../support/src/traits/tokens/fungible/mod.rs | 2 + .../src/traits/tokens/fungible/union_of.rs | 1005 +++++++++++++++++ .../src/traits/tokens/fungibles/imbalance.rs | 5 + .../src/traits/tokens/fungibles/mod.rs | 2 + .../src/traits/tokens/fungibles/union_of.rs | 986 ++++++++++++++++ 7 files changed, 2055 insertions(+), 16 deletions(-) create mode 100644 substrate/frame/support/src/traits/tokens/fungible/union_of.rs create mode 100644 substrate/frame/support/src/traits/tokens/fungibles/union_of.rs diff --git a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs index 995797bc8f66b..39bcca16553a5 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/imbalance.rs @@ -87,6 +87,11 @@ impl, OppositeOnDrop: HandleImbalance pub(crate) fn new(amount: B) -> Self { Self { amount, _phantom: PhantomData } } + + /// Forget the imbalance without invoking the on-drop handler. + pub(crate) fn forget(imbalance: Self) { + sp_std::mem::forget(imbalance); + } } impl, OppositeOnDrop: HandleImbalanceDrop> diff --git a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs index a47998eb134e9..3e054472a2f99 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/item_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/item_of.rs @@ -380,36 +380,64 @@ impl< value: Self::Balance, precision: Precision, ) -> Result, DispatchError> { - >::deposit(A::get(), who, value, precision) - .map(|debt| Imbalance::new(debt.peek())) + >::deposit(A::get(), who, value, precision).map( + |inner_debt| { + let debt = Imbalance::new(inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt + }, + ) } fn issue(amount: Self::Balance) -> Credit { - Imbalance::new(>::issue(A::get(), amount).peek()) + let inner_credit = >::issue(A::get(), amount); + let credit = Imbalance::new(inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit } fn pair(amount: Self::Balance) -> (Debt, Credit) { - let (a, b) = >::pair(A::get(), amount); - (Imbalance::new(a.peek()), Imbalance::new(b.peek())) + let (inner_a, inner_b) = >::pair(A::get(), amount); + let (a, b) = (Imbalance::new(inner_a.peek()), Imbalance::new(inner_b.peek())); + fungibles::Imbalance::forget(inner_a); + fungibles::Imbalance::forget(inner_b); + (a, b) } fn rescind(amount: Self::Balance) -> Debt { - Imbalance::new(>::rescind(A::get(), amount).peek()) + let inner_debt = >::rescind(A::get(), amount); + let debt = Imbalance::new(inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt } fn resolve( who: &AccountId, credit: Credit, ) -> Result<(), Credit> { - let credit = fungibles::Imbalance::new(A::get(), credit.peek()); - >::resolve(who, credit) - .map_err(|credit| Imbalance::new(credit.peek())) + let inner = fungibles::Imbalance::new(A::get(), credit.peek()); + Imbalance::forget(credit); + >::resolve(who, inner).map_err(|inner| { + let credit = Imbalance::new(inner.peek()); + fungibles::Imbalance::forget(inner); + credit + }) } fn settle( who: &AccountId, debt: Debt, preservation: Preservation, ) -> Result, Debt> { - let debt = fungibles::Imbalance::new(A::get(), debt.peek()); - >::settle(who, debt, preservation) - .map(|credit| Imbalance::new(credit.peek())) - .map_err(|debt| Imbalance::new(debt.peek())) + let inner_debt = fungibles::Imbalance::new(A::get(), debt.peek()); + Imbalance::forget(debt); + match >::settle(who, inner_debt, preservation) { + Ok(inner_credit) => { + let credit = Imbalance::new(inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + Ok(credit) + }, + Err(inner_debt) => { + let debt = Imbalance::new(inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + Err(debt) + }, + } } fn withdraw( who: &AccountId, @@ -426,7 +454,11 @@ impl< preservation, force, ) - .map(|credit| Imbalance::new(credit.peek())) + .map(|inner_credit| { + let credit = Imbalance::new(inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }) } } @@ -441,9 +473,11 @@ impl< who: &AccountId, amount: Self::Balance, ) -> (Credit, Self::Balance) { - let (credit, amount) = + let (inner_credit, amount) = >::slash(A::get(), reason, who, amount); - (Imbalance::new(credit.peek()), amount) + let credit = Imbalance::new(inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + (credit, amount) } } diff --git a/substrate/frame/support/src/traits/tokens/fungible/mod.rs b/substrate/frame/support/src/traits/tokens/fungible/mod.rs index 61b75fd6563c8..f8f378a449417 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/mod.rs @@ -44,6 +44,7 @@ pub mod hold; mod imbalance; mod item_of; mod regular; +mod union_of; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support_procedural::{CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; @@ -67,6 +68,7 @@ pub use regular::{ use sp_arithmetic::traits::Zero; use sp_core::Get; use sp_runtime::{traits::Convert, DispatchError}; +pub use union_of::{NativeFromLeft, NativeOrWithId, UnionOf}; use crate::{ ensure, diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs new file mode 100644 index 0000000000000..0ba8cc28d83c6 --- /dev/null +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -0,0 +1,1005 @@ +// This file is part of Substrate. + +// Copyright (Criterion) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types to combine some `fungible::*` and `fungibles::*` implementations into one union +//! `fungibles::*` implementation. + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::traits::{ + tokens::{ + fungible, fungibles, AssetId, DepositConsequence, Fortitude, Imbalance as ImbalanceT, + Precision, Preservation, Provenance, Restriction, WithdrawConsequence, + }, + AccountTouch, ContainsPair, +}; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::Convert, + DispatchError, DispatchResult, Either, + Either::{Left, Right}, +}; +use sp_std::cmp::Ordering; + +/// The `NativeOrWithId` enum classifies an asset as either `Native`` to the current chain or as an +/// asset with a specific ID. +#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Debug)] +pub enum NativeOrWithId +where + AssetId: Ord, +{ + /// Represents the native asset of the current chain. + /// + /// E.g., DOT for the Polkadot Asset Hub. + #[default] + Native, + /// Represents an asset identified by its underlying `AssetId`. + WithId(AssetId), +} +impl From for NativeOrWithId { + fn from(asset: AssetId) -> Self { + Self::WithId(asset) + } +} +impl Ord for NativeOrWithId { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Self::Native, Self::Native) => Ordering::Equal, + (Self::Native, Self::WithId(_)) => Ordering::Less, + (Self::WithId(_), Self::Native) => Ordering::Greater, + (Self::WithId(id1), Self::WithId(id2)) => ::cmp(id1, id2), + } + } +} +impl PartialOrd for NativeOrWithId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(::cmp(self, other)) + } +} +impl PartialEq for NativeOrWithId { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} +impl Eq for NativeOrWithId {} + +/// Criterion for [`UnionOf`] where a set for [`NativeOrWithId::Native`] asset located from the left +/// and for [`NativeOrWithId::WithId`] from the right. +pub struct NativeFromLeft; +impl Convert, Either<(), AssetId>> for NativeFromLeft { + fn convert(asset: NativeOrWithId) -> Either<(), AssetId> { + match asset { + NativeOrWithId::Native => Either::Left(()), + NativeOrWithId::WithId(id) => Either::Right(id), + } + } +} + +/// Type to combine some `fungible::*` and `fungibles::*` implementations into one union +/// `fungibles::*` implementation. +/// +/// ### Generic Parameters: +/// - `Left` is `fungible::*` implementation that is incorporated into the resulting union. +/// - `Right` is `fungibles::*` implementation that is incorporated into the resulting union. +/// - `Criterion` determines whether the `AssetKind` belongs to the `Left` or `Right` set. +/// - `AssetKind` is a superset type encompassing asset kinds from `Left`` and `Right` sets. +/// - `AccountId` is an account identifier type. +pub struct UnionOf( + sp_std::marker::PhantomData<(Left, Right, Criterion, AssetKind, AccountId)>, +); + +impl< + Left: fungible::Inspect, + Right: fungibles::Inspect, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Inspect for UnionOf +{ + type AssetId = AssetKind; + type Balance = Left::Balance; + + fn total_issuance(asset: Self::AssetId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::total_issuance(), + Right(a) => >::total_issuance(a), + } + } + fn active_issuance(asset: Self::AssetId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::active_issuance(), + Right(a) => >::active_issuance(a), + } + } + fn minimum_balance(asset: Self::AssetId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::minimum_balance(), + Right(a) => >::minimum_balance(a), + } + } + fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::balance(who), + Right(a) => >::balance(a, who), + } + } + fn total_balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::total_balance(who), + Right(a) => >::total_balance(a, who), + } + } + fn reducible_balance( + asset: Self::AssetId, + who: &AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => + >::reducible_balance(who, preservation, force), + Right(a) => >::reducible_balance( + a, + who, + preservation, + force, + ), + } + } + fn can_deposit( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + match Criterion::convert(asset) { + Left(()) => + >::can_deposit(who, amount, provenance), + Right(a) => + >::can_deposit(a, who, amount, provenance), + } + } + fn can_withdraw( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + match Criterion::convert(asset) { + Left(()) => >::can_withdraw(who, amount), + Right(a) => >::can_withdraw(a, who, amount), + } + } + fn asset_exists(asset: Self::AssetId) -> bool { + match Criterion::convert(asset) { + Left(()) => true, + Right(a) => >::asset_exists(a), + } + } +} + +impl< + Left: fungible::InspectHold, + Right: fungibles::InspectHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::InspectHold for UnionOf +{ + type Reason = Left::Reason; + + fn reducible_total_balance_on_hold( + asset: Self::AssetId, + who: &AccountId, + force: Fortitude, + ) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => + >::reducible_total_balance_on_hold( + who, force, + ), + Right(a) => + >::reducible_total_balance_on_hold( + a, who, force, + ), + } + } + fn hold_available(asset: Self::AssetId, reason: &Self::Reason, who: &AccountId) -> bool { + match Criterion::convert(asset) { + Left(()) => >::hold_available(reason, who), + Right(a) => + >::hold_available(a, reason, who), + } + } + fn total_balance_on_hold(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::total_balance_on_hold(who), + Right(a) => >::total_balance_on_hold(a, who), + } + } + fn balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + ) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::balance_on_hold(reason, who), + Right(a) => + >::balance_on_hold(a, reason, who), + } + } + fn can_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> bool { + match Criterion::convert(asset) { + Left(()) => >::can_hold(reason, who, amount), + Right(a) => + >::can_hold(a, reason, who, amount), + } + } +} + +impl< + Left: fungible::InspectFreeze, + Right: fungibles::InspectFreeze, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::InspectFreeze for UnionOf +{ + type Id = Left::Id; + fn balance_frozen(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::balance_frozen(id, who), + Right(a) => >::balance_frozen(a, id, who), + } + } + fn balance_freezable(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::balance_freezable(who), + Right(a) => >::balance_freezable(a, who), + } + } + fn can_freeze(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> bool { + match Criterion::convert(asset) { + Left(()) => >::can_freeze(id, who), + Right(a) => >::can_freeze(a, id, who), + } + } +} + +impl< + Left: fungible::Unbalanced, + Right: fungibles::Unbalanced, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Unbalanced for UnionOf +{ + fn handle_dust(dust: fungibles::Dust) + where + Self: Sized, + { + match Criterion::convert(dust.0) { + Left(()) => + >::handle_dust(fungible::Dust(dust.1)), + Right(a) => + >::handle_dust(fungibles::Dust(a, dust.1)), + } + } + fn write_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + match Criterion::convert(asset) { + Left(()) => >::write_balance(who, amount), + Right(a) => >::write_balance(a, who, amount), + } + } + fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) -> () { + match Criterion::convert(asset) { + Left(()) => >::set_total_issuance(amount), + Right(a) => >::set_total_issuance(a, amount), + } + } + fn decrease_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::decrease_balance( + who, + amount, + precision, + preservation, + force, + ), + Right(a) => >::decrease_balance( + a, + who, + amount, + precision, + preservation, + force, + ), + } + } + fn increase_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => + >::increase_balance(who, amount, precision), + Right(a) => >::increase_balance( + a, who, amount, precision, + ), + } + } +} + +impl< + Left: fungible::UnbalancedHold, + Right: fungibles::UnbalancedHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::UnbalancedHold for UnionOf +{ + fn set_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => >::set_balance_on_hold( + reason, who, amount, + ), + Right(a) => >::set_balance_on_hold( + a, reason, who, amount, + ), + } + } + fn decrease_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::decrease_balance_on_hold( + reason, who, amount, precision, + ), + Right(a) => >::decrease_balance_on_hold( + a, reason, who, amount, precision, + ), + } + } + fn increase_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::decrease_balance_on_hold( + reason, who, amount, precision, + ), + Right(a) => >::decrease_balance_on_hold( + a, reason, who, amount, precision, + ), + } + } +} + +impl< + Left: fungible::Mutate, + Right: fungibles::Mutate, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Mutate for UnionOf +{ + fn mint_into( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::mint_into(who, amount), + Right(a) => >::mint_into(a, who, amount), + } + } + fn burn_from( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => + >::burn_from(who, amount, precision, force), + Right(a) => + >::burn_from(a, who, amount, precision, force), + } + } + fn shelve( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::shelve(who, amount), + Right(a) => >::shelve(a, who, amount), + } + } + fn restore( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::restore(who, amount), + Right(a) => >::restore(a, who, amount), + } + } + fn transfer( + asset: Self::AssetId, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => + >::transfer(source, dest, amount, preservation), + Right(a) => >::transfer( + a, + source, + dest, + amount, + preservation, + ), + } + } + + fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::set_balance(who, amount), + Right(a) => >::set_balance(a, who, amount), + } + } +} + +impl< + Left: fungible::MutateHold, + Right: fungibles::MutateHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::MutateHold for UnionOf +{ + fn hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => >::hold(reason, who, amount), + Right(a) => >::hold(a, reason, who, amount), + } + } + fn release( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => + >::release(reason, who, amount, precision), + Right(a) => >::release( + a, reason, who, amount, precision, + ), + } + } + fn burn_held( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::burn_held( + reason, who, amount, precision, force, + ), + Right(a) => >::burn_held( + a, reason, who, amount, precision, force, + ), + } + } + fn transfer_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + mode: Restriction, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::transfer_on_hold( + reason, source, dest, amount, precision, mode, force, + ), + Right(a) => >::transfer_on_hold( + a, reason, source, dest, amount, precision, mode, force, + ), + } + } + fn transfer_and_hold( + asset: Self::AssetId, + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(()) => >::transfer_and_hold( + reason, + source, + dest, + amount, + precision, + preservation, + force, + ), + Right(a) => >::transfer_and_hold( + a, + reason, + source, + dest, + amount, + precision, + preservation, + force, + ), + } + } +} + +impl< + Left: fungible::MutateFreeze, + Right: fungibles::MutateFreeze, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::MutateFreeze for UnionOf +{ + fn set_freeze( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => >::set_freeze(id, who, amount), + Right(a) => + >::set_freeze(a, id, who, amount), + } + } + fn extend_freeze( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => >::extend_freeze(id, who, amount), + Right(a) => + >::extend_freeze(a, id, who, amount), + } + } + fn thaw(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => >::thaw(id, who), + Right(a) => >::thaw(a, id, who), + } + } +} + +pub struct ConvertImbalanceDropHandler< + Left, + Right, + Criterion, + AssetKind, + Balance, + AssetId, + AccountId, +>(sp_std::marker::PhantomData<(Left, Right, Criterion, AssetKind, Balance, AssetId, AccountId)>); + +impl< + Left: fungible::HandleImbalanceDrop, + Right: fungibles::HandleImbalanceDrop, + Criterion: Convert>, + AssetKind, + Balance, + AssetId, + AccountId, + > fungibles::HandleImbalanceDrop + for ConvertImbalanceDropHandler +{ + fn handle(asset: AssetKind, amount: Balance) { + match Criterion::convert(asset) { + Left(()) => Left::handle(amount), + Right(a) => Right::handle(a, amount), + } + } +} + +impl< + Left: fungible::Balanced, + Right: fungibles::Balanced, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Balanced for UnionOf +{ + type OnDropDebt = ConvertImbalanceDropHandler< + Left::OnDropDebt, + Right::OnDropDebt, + Criterion, + AssetKind, + Left::Balance, + Right::AssetId, + AccountId, + >; + type OnDropCredit = ConvertImbalanceDropHandler< + Left::OnDropCredit, + Right::OnDropCredit, + Criterion, + AssetKind, + Left::Balance, + Right::AssetId, + AccountId, + >; + + fn deposit( + asset: Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + ) -> Result, DispatchError> { + match Criterion::convert(asset.clone()) { + Left(()) => >::deposit(who, value, precision) + .map(|inner_debt| { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungible::Imbalance::forget(inner_debt); + debt + }), + Right(a) => >::deposit( + a, who, value, precision, + ) + .map(|inner_debt| { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt + }), + } + } + fn issue(asset: Self::AssetId, amount: Self::Balance) -> fungibles::Credit { + match Criterion::convert(asset.clone()) { + Left(()) => { + let inner_credit = >::issue(amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungible::Imbalance::forget(inner_credit); + credit + }, + Right(a) => { + let inner_credit = >::issue(a, amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }, + } + } + fn pair( + asset: Self::AssetId, + amount: Self::Balance, + ) -> (fungibles::Debt, fungibles::Credit) { + match Criterion::convert(asset.clone()) { + Left(()) => { + let (inner_a, inner_b) = >::pair(amount); + let (a, b) = ( + fungibles::Imbalance::new(asset.clone(), inner_a.peek()), + fungibles::Imbalance::new(asset, inner_b.peek()), + ); + fungible::Imbalance::forget(inner_a); + fungible::Imbalance::forget(inner_b); + (a, b) + }, + Right(a) => { + let (inner_a, inner_b) = >::pair(a, amount); + let (a, b) = ( + fungibles::Imbalance::new(asset.clone(), inner_a.peek()), + fungibles::Imbalance::new(asset, inner_b.peek()), + ); + fungibles::Imbalance::forget(inner_a); + fungibles::Imbalance::forget(inner_b); + (a, b) + }, + } + } + fn rescind(asset: Self::AssetId, amount: Self::Balance) -> fungibles::Debt { + match Criterion::convert(asset.clone()) { + Left(()) => { + let inner_debt = >::rescind(amount); + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungible::Imbalance::forget(inner_debt); + debt + }, + Right(a) => { + let inner_debt = >::rescind(a, amount); + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt + }, + } + } + fn resolve( + who: &AccountId, + credit: fungibles::Credit, + ) -> Result<(), fungibles::Credit> { + let asset = credit.asset(); + match Criterion::convert(asset.clone()) { + Left(()) => { + let inner_credit = fungible::Imbalance::new(credit.peek()); + fungibles::Imbalance::forget(credit); + >::resolve(who, inner_credit).map_err( + |inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungible::Imbalance::forget(inner_credit); + credit + }, + ) + }, + Right(a) => { + let inner_credit = fungibles::Imbalance::new(a, credit.peek()); + fungibles::Imbalance::forget(credit); + >::resolve(who, inner_credit).map_err( + |inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }, + ) + }, + } + } + fn settle( + who: &AccountId, + debt: fungibles::Debt, + preservation: Preservation, + ) -> Result, fungibles::Debt> { + let asset = debt.asset(); + match Criterion::convert(asset.clone()) { + Left(()) => { + let inner_debt = fungible::Imbalance::new(debt.peek()); + fungibles::Imbalance::forget(debt); + match >::settle(who, inner_debt, preservation) + { + Ok(inner_credit) => { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungible::Imbalance::forget(inner_credit); + Ok(credit) + }, + Err(inner_debt) => { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungible::Imbalance::forget(inner_debt); + Err(debt) + }, + } + }, + Right(a) => { + let inner_debt = fungibles::Imbalance::new(a, debt.peek()); + fungibles::Imbalance::forget(debt); + match >::settle( + who, + inner_debt, + preservation, + ) { + Ok(inner_credit) => { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + Ok(credit) + }, + Err(inner_debt) => { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + Err(debt) + }, + } + }, + } + } + fn withdraw( + asset: Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result, DispatchError> { + match Criterion::convert(asset.clone()) { + Left(()) => >::withdraw( + who, + value, + precision, + preservation, + force, + ) + .map(|inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungible::Imbalance::forget(inner_credit); + credit + }), + Right(a) => >::withdraw( + a, + who, + value, + precision, + preservation, + force, + ) + .map(|inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }), + } + } +} + +impl< + Left: fungible::BalancedHold, + Right: fungibles::BalancedHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::BalancedHold for UnionOf +{ + fn slash( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> (fungibles::Credit, Self::Balance) { + match Criterion::convert(asset.clone()) { + Left(()) => { + let (inner_credit, amount) = + >::slash(reason, who, amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungible::Imbalance::forget(inner_credit); + (credit, amount) + }, + Right(a) => { + let (inner_credit, amount) = + >::slash(a, reason, who, amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + (credit, amount) + }, + } + } +} + +impl< + Left: fungible::Inspect, + Right: fungibles::Inspect + fungibles::Create, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Create for UnionOf +{ + fn create( + asset: AssetKind, + admin: AccountId, + is_sufficient: bool, + min_balance: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + // no-op for `Left` since `Create` trait is not defined within `fungible::*`. + Left(()) => Ok(()), + Right(a) => >::create( + a, + admin, + is_sufficient, + min_balance, + ), + } + } +} + +impl< + Left: fungible::Inspect, + Right: fungibles::Inspect + + AccountTouch< + Right::AssetId, + AccountId, + Balance = >::Balance, + >, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > AccountTouch for UnionOf +{ + type Balance = >::Balance; + + fn deposit_required(asset: AssetKind) -> Self::Balance { + match Criterion::convert(asset) { + Left(()) => >::minimum_balance(), + Right(a) => >::deposit_required(a), + } + } + + fn touch(asset: AssetKind, who: AccountId, depositor: AccountId) -> DispatchResult { + match Criterion::convert(asset) { + // no-op for `Left` since `AccountTouch` trait is not defined within `fungible::*`. + Left(()) => Ok(()), + Right(a) => + >::touch(a, who, depositor), + } + } +} + +impl< + Left: fungible::Inspect, + Right: fungibles::Inspect + + ContainsPair, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > ContainsPair for UnionOf +{ + fn contains(asset: &AssetKind, who: &AccountId) -> bool { + match Criterion::convert(asset.clone()) { + Left(()) => + >::total_balance(who) >= + >::minimum_balance(), + Right(a) => >::contains(&a, who), + } + } +} diff --git a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs index 7c0d7721a2e60..2c43a0c9c7e2b 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs @@ -93,6 +93,11 @@ impl< Self { asset, amount, _phantom: PhantomData } } + /// Forget the imbalance without invoking the on-drop handler. + pub(crate) fn forget(imbalance: Self) { + sp_std::mem::forget(imbalance); + } + pub fn drop_zero(self) -> Result<(), Self> { if self.amount.is_zero() { sp_std::mem::forget(self); diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index 4fd6ef43a15fa..a7b7933aaf6d3 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -26,6 +26,7 @@ mod lifetime; pub mod metadata; mod regular; pub mod roles; +mod union_of; pub use enumerable::Inspect as InspectEnumerable; pub use freeze::{Inspect as InspectFreeze, Mutate as MutateFreeze}; @@ -38,3 +39,4 @@ pub use lifetime::{Create, Destroy}; pub use regular::{ Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, }; +pub use union_of::UnionOf; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs new file mode 100644 index 0000000000000..eb6927553d496 --- /dev/null +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -0,0 +1,986 @@ +// This file is part of Substrate. + +// Copyright (Criterion) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Type to combine two `fungibles::*` implementations into one union `fungibles::*` implementation. + +use frame_support::traits::{ + tokens::{ + fungibles, AssetId, DepositConsequence, Fortitude, Precision, Preservation, Provenance, + Restriction, WithdrawConsequence, + }, + AccountTouch, ContainsPair, +}; +use sp_runtime::{ + traits::Convert, + DispatchError, DispatchResult, Either, + Either::{Left, Right}, +}; + +/// Type to combine two `fungibles::*` implementations into one union `fungibles::*` implementation. +/// +/// ### Generic Parameters: +/// - `Left` is `fungibles::*` implementation that is incorporated into the resulting union. +/// - `Right` is `fungibles::*` implementation that is incorporated into the resulting union. +/// - `Criterion` determines whether the `AssetKind` belongs to the `Left` or `Right` set. +/// - `AssetKind` is a superset type encompassing asset kinds from `Left`` and `Right` sets. +/// - `AccountId` is an account identifier type. +pub struct UnionOf( + sp_std::marker::PhantomData<(Left, Right, Criterion, AssetKind, AccountId)>, +); + +impl< + Left: fungibles::Inspect, + Right: fungibles::Inspect, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Inspect for UnionOf +{ + type AssetId = AssetKind; + type Balance = Left::Balance; + + fn total_issuance(asset: Self::AssetId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::total_issuance(a), + Right(a) => >::total_issuance(a), + } + } + fn active_issuance(asset: Self::AssetId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::active_issuance(a), + Right(a) => >::active_issuance(a), + } + } + fn minimum_balance(asset: Self::AssetId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::minimum_balance(a), + Right(a) => >::minimum_balance(a), + } + } + fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::balance(a, who), + Right(a) => >::balance(a, who), + } + } + fn total_balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::total_balance(a, who), + Right(a) => >::total_balance(a, who), + } + } + fn reducible_balance( + asset: Self::AssetId, + who: &AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::reducible_balance( + a, + who, + preservation, + force, + ), + Right(a) => >::reducible_balance( + a, + who, + preservation, + force, + ), + } + } + fn can_deposit( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + match Criterion::convert(asset) { + Left(a) => + >::can_deposit(a, who, amount, provenance), + Right(a) => + >::can_deposit(a, who, amount, provenance), + } + } + fn can_withdraw( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + match Criterion::convert(asset) { + Left(a) => >::can_withdraw(a, who, amount), + Right(a) => >::can_withdraw(a, who, amount), + } + } + fn asset_exists(asset: Self::AssetId) -> bool { + match Criterion::convert(asset) { + Left(a) => >::asset_exists(a), + Right(a) => >::asset_exists(a), + } + } +} + +impl< + Left: fungibles::InspectHold, + Right: fungibles::InspectHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::InspectHold for UnionOf +{ + type Reason = Left::Reason; + + fn reducible_total_balance_on_hold( + asset: Self::AssetId, + who: &AccountId, + force: Fortitude, + ) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => + >::reducible_total_balance_on_hold( + a, who, force, + ), + Right(a) => + >::reducible_total_balance_on_hold( + a, who, force, + ), + } + } + fn hold_available(asset: Self::AssetId, reason: &Self::Reason, who: &AccountId) -> bool { + match Criterion::convert(asset) { + Left(a) => >::hold_available(a, reason, who), + Right(a) => + >::hold_available(a, reason, who), + } + } + fn total_balance_on_hold(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::total_balance_on_hold(a, who), + Right(a) => >::total_balance_on_hold(a, who), + } + } + fn balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + ) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::balance_on_hold(a, reason, who), + Right(a) => + >::balance_on_hold(a, reason, who), + } + } + fn can_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> bool { + match Criterion::convert(asset) { + Left(a) => + >::can_hold(a, reason, who, amount), + Right(a) => + >::can_hold(a, reason, who, amount), + } + } +} + +impl< + Left: fungibles::InspectFreeze, + Right: fungibles::InspectFreeze, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::InspectFreeze for UnionOf +{ + type Id = Left::Id; + fn balance_frozen(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::balance_frozen(a, id, who), + Right(a) => >::balance_frozen(a, id, who), + } + } + fn balance_freezable(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::balance_freezable(a, who), + Right(a) => >::balance_freezable(a, who), + } + } + fn can_freeze(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> bool { + match Criterion::convert(asset) { + Left(a) => >::can_freeze(a, id, who), + Right(a) => >::can_freeze(a, id, who), + } + } +} + +impl< + Left: fungibles::Unbalanced, + Right: fungibles::Unbalanced, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Unbalanced for UnionOf +{ + fn handle_dust(dust: fungibles::Dust) + where + Self: Sized, + { + match Criterion::convert(dust.0) { + Left(a) => + >::handle_dust(fungibles::Dust(a, dust.1)), + Right(a) => + >::handle_dust(fungibles::Dust(a, dust.1)), + } + } + fn write_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + match Criterion::convert(asset) { + Left(a) => >::write_balance(a, who, amount), + Right(a) => >::write_balance(a, who, amount), + } + } + fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) -> () { + match Criterion::convert(asset) { + Left(a) => >::set_total_issuance(a, amount), + Right(a) => >::set_total_issuance(a, amount), + } + } + fn decrease_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::decrease_balance( + a, + who, + amount, + precision, + preservation, + force, + ), + Right(a) => >::decrease_balance( + a, + who, + amount, + precision, + preservation, + force, + ), + } + } + fn increase_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::increase_balance( + a, who, amount, precision, + ), + Right(a) => >::increase_balance( + a, who, amount, precision, + ), + } + } +} + +impl< + Left: fungibles::UnbalancedHold, + Right: fungibles::UnbalancedHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::UnbalancedHold for UnionOf +{ + fn set_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => >::set_balance_on_hold( + a, reason, who, amount, + ), + Right(a) => >::set_balance_on_hold( + a, reason, who, amount, + ), + } + } + fn decrease_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::decrease_balance_on_hold( + a, reason, who, amount, precision, + ), + Right(a) => >::decrease_balance_on_hold( + a, reason, who, amount, precision, + ), + } + } + fn increase_balance_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::decrease_balance_on_hold( + a, reason, who, amount, precision, + ), + Right(a) => >::decrease_balance_on_hold( + a, reason, who, amount, precision, + ), + } + } +} + +impl< + Left: fungibles::Mutate, + Right: fungibles::Mutate, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Mutate for UnionOf +{ + fn mint_into( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::mint_into(a, who, amount), + Right(a) => >::mint_into(a, who, amount), + } + } + fn burn_from( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => + >::burn_from(a, who, amount, precision, force), + Right(a) => + >::burn_from(a, who, amount, precision, force), + } + } + fn shelve( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::shelve(a, who, amount), + Right(a) => >::shelve(a, who, amount), + } + } + fn restore( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::restore(a, who, amount), + Right(a) => >::restore(a, who, amount), + } + } + fn transfer( + asset: Self::AssetId, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::transfer( + a, + source, + dest, + amount, + preservation, + ), + Right(a) => >::transfer( + a, + source, + dest, + amount, + preservation, + ), + } + } + + fn set_balance(asset: Self::AssetId, who: &AccountId, amount: Self::Balance) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::set_balance(a, who, amount), + Right(a) => >::set_balance(a, who, amount), + } + } +} + +impl< + Left: fungibles::MutateHold, + Right: fungibles::MutateHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::MutateHold for UnionOf +{ + fn hold( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => >::hold(a, reason, who, amount), + Right(a) => >::hold(a, reason, who, amount), + } + } + fn release( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::release( + a, reason, who, amount, precision, + ), + Right(a) => >::release( + a, reason, who, amount, precision, + ), + } + } + fn burn_held( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + precision: Precision, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::burn_held( + a, reason, who, amount, precision, force, + ), + Right(a) => >::burn_held( + a, reason, who, amount, precision, force, + ), + } + } + fn transfer_on_hold( + asset: Self::AssetId, + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + mode: Restriction, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::transfer_on_hold( + a, reason, source, dest, amount, precision, mode, force, + ), + Right(a) => >::transfer_on_hold( + a, reason, source, dest, amount, precision, mode, force, + ), + } + } + fn transfer_and_hold( + asset: Self::AssetId, + reason: &Self::Reason, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + match Criterion::convert(asset) { + Left(a) => >::transfer_and_hold( + a, + reason, + source, + dest, + amount, + precision, + preservation, + force, + ), + Right(a) => >::transfer_and_hold( + a, + reason, + source, + dest, + amount, + precision, + preservation, + force, + ), + } + } +} + +impl< + Left: fungibles::MutateFreeze, + Right: fungibles::MutateFreeze, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::MutateFreeze for UnionOf +{ + fn set_freeze( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => >::set_freeze(a, id, who, amount), + Right(a) => + >::set_freeze(a, id, who, amount), + } + } + fn extend_freeze( + asset: Self::AssetId, + id: &Self::Id, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => + >::extend_freeze(a, id, who, amount), + Right(a) => + >::extend_freeze(a, id, who, amount), + } + } + fn thaw(asset: Self::AssetId, id: &Self::Id, who: &AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => >::thaw(a, id, who), + Right(a) => >::thaw(a, id, who), + } + } +} + +pub struct ConvertImbalanceDropHandler< + Left, + Right, + LeftAssetId, + RightAssetId, + Criterion, + AssetKind, + Balance, + AccountId, +>( + sp_std::marker::PhantomData<( + Left, + Right, + LeftAssetId, + RightAssetId, + Criterion, + AssetKind, + Balance, + AccountId, + )>, +); + +impl< + Left: fungibles::HandleImbalanceDrop, + Right: fungibles::HandleImbalanceDrop, + LeftAssetId, + RightAssetId, + Criterion: Convert>, + AssetKind, + Balance, + AccountId, + > fungibles::HandleImbalanceDrop + for ConvertImbalanceDropHandler< + Left, + Right, + LeftAssetId, + RightAssetId, + Criterion, + AssetKind, + Balance, + AccountId, + > +{ + fn handle(asset: AssetKind, amount: Balance) { + match Criterion::convert(asset) { + Left(a) => Left::handle(a, amount), + Right(a) => Right::handle(a, amount), + } + } +} + +impl< + Left: fungibles::Balanced, + Right: fungibles::Balanced, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Balanced for UnionOf +{ + type OnDropDebt = ConvertImbalanceDropHandler< + Left::OnDropDebt, + Right::OnDropDebt, + Left::AssetId, + Right::AssetId, + Criterion, + AssetKind, + Left::Balance, + AccountId, + >; + type OnDropCredit = ConvertImbalanceDropHandler< + Left::OnDropCredit, + Right::OnDropCredit, + Left::AssetId, + Right::AssetId, + Criterion, + AssetKind, + Left::Balance, + AccountId, + >; + + fn deposit( + asset: Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + ) -> Result, DispatchError> { + match Criterion::convert(asset.clone()) { + Left(a) => >::deposit(a, who, value, precision) + .map(|inner_debt| { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt + }), + Right(a) => >::deposit( + a, who, value, precision, + ) + .map(|inner_debt| { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt + }), + } + } + fn issue(asset: Self::AssetId, amount: Self::Balance) -> fungibles::Credit { + match Criterion::convert(asset.clone()) { + Left(a) => { + let inner_credit = >::issue(a, amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }, + Right(a) => { + let inner_credit = >::issue(a, amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }, + } + } + fn pair( + asset: Self::AssetId, + amount: Self::Balance, + ) -> (fungibles::Debt, fungibles::Credit) { + match Criterion::convert(asset.clone()) { + Left(a) => { + let (inner_a, inner_b) = >::pair(a, amount); + let (a, b) = ( + fungibles::Imbalance::new(asset.clone(), inner_a.peek()), + fungibles::Imbalance::new(asset, inner_b.peek()), + ); + fungibles::Imbalance::forget(inner_a); + fungibles::Imbalance::forget(inner_b); + (a, b) + }, + Right(a) => { + let (inner_a, inner_b) = >::pair(a, amount); + let (a, b) = ( + fungibles::Imbalance::new(asset.clone(), inner_a.peek()), + fungibles::Imbalance::new(asset, inner_b.peek()), + ); + fungibles::Imbalance::forget(inner_a); + fungibles::Imbalance::forget(inner_b); + (a, b) + }, + } + } + fn rescind(asset: Self::AssetId, amount: Self::Balance) -> fungibles::Debt { + match Criterion::convert(asset.clone()) { + Left(a) => { + let inner_debt = >::rescind(a, amount); + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt + }, + Right(a) => { + let inner_debt = >::rescind(a, amount); + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + debt + }, + } + } + fn resolve( + who: &AccountId, + credit: fungibles::Credit, + ) -> Result<(), fungibles::Credit> { + let asset = credit.asset(); + match Criterion::convert(asset.clone()) { + Left(a) => { + let inner_credit = fungibles::Imbalance::new(a, credit.peek()); + fungibles::Imbalance::forget(credit); + >::resolve(who, inner_credit).map_err( + |inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }, + ) + }, + Right(a) => { + let inner_credit = fungibles::Imbalance::new(a, credit.peek()); + fungibles::Imbalance::forget(credit); + >::resolve(who, inner_credit).map_err( + |inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }, + ) + }, + } + } + fn settle( + who: &AccountId, + debt: fungibles::Debt, + preservation: Preservation, + ) -> Result, fungibles::Debt> { + let asset = debt.asset(); + match Criterion::convert(asset.clone()) { + Left(a) => { + let inner_debt = fungibles::Imbalance::new(a, debt.peek()); + fungibles::Imbalance::forget(debt); + match >::settle( + who, + inner_debt, + preservation, + ) { + Ok(inner_credit) => { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + Ok(credit) + }, + Err(inner_debt) => { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + Err(debt) + }, + } + }, + Right(a) => { + let inner_debt = fungibles::Imbalance::new(a, debt.peek()); + fungibles::Imbalance::forget(debt); + match >::settle( + who, + inner_debt, + preservation, + ) { + Ok(inner_credit) => { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + Ok(credit) + }, + Err(inner_debt) => { + let debt = fungibles::Imbalance::new(asset, inner_debt.peek()); + fungibles::Imbalance::forget(inner_debt); + Err(debt) + }, + } + }, + } + } + fn withdraw( + asset: Self::AssetId, + who: &AccountId, + value: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result, DispatchError> { + match Criterion::convert(asset.clone()) { + Left(a) => >::withdraw( + a, + who, + value, + precision, + preservation, + force, + ) + .map(|inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }), + Right(a) => >::withdraw( + a, + who, + value, + precision, + preservation, + force, + ) + .map(|inner_credit| { + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + credit + }), + } + } +} + +impl< + Left: fungibles::BalancedHold, + Right: fungibles::BalancedHold, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::BalancedHold for UnionOf +{ + fn slash( + asset: Self::AssetId, + reason: &Self::Reason, + who: &AccountId, + amount: Self::Balance, + ) -> (fungibles::Credit, Self::Balance) { + match Criterion::convert(asset.clone()) { + Left(a) => { + let (inner_credit, amount) = + >::slash(a, reason, who, amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + (credit, amount) + }, + Right(a) => { + let (inner_credit, amount) = + >::slash(a, reason, who, amount); + let credit = fungibles::Imbalance::new(asset, inner_credit.peek()); + fungibles::Imbalance::forget(inner_credit); + (credit, amount) + }, + } + } +} + +impl< + Left: fungibles::Inspect + fungibles::Create, + Right: fungibles::Inspect + fungibles::Create, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > fungibles::Create for UnionOf +{ + fn create( + asset: AssetKind, + admin: AccountId, + is_sufficient: bool, + min_balance: Self::Balance, + ) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => + >::create(a, admin, is_sufficient, min_balance), + Right(a) => >::create( + a, + admin, + is_sufficient, + min_balance, + ), + } + } +} + +impl< + Left: fungibles::Inspect + AccountTouch, + Right: fungibles::Inspect + + AccountTouch< + Right::AssetId, + AccountId, + Balance = >::Balance, + >, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > AccountTouch for UnionOf +{ + type Balance = >::Balance; + + fn deposit_required(asset: AssetKind) -> Self::Balance { + match Criterion::convert(asset) { + Left(a) => >::deposit_required(a), + Right(a) => >::deposit_required(a), + } + } + + fn touch(asset: AssetKind, who: AccountId, depositor: AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => >::touch(a, who, depositor), + Right(a) => + >::touch(a, who, depositor), + } + } +} + +impl< + Left: fungibles::Inspect + ContainsPair, + Right: fungibles::Inspect + + ContainsPair, + Criterion: Convert>, + AssetKind: AssetId, + AccountId, + > ContainsPair for UnionOf +{ + fn contains(asset: &AssetKind, who: &AccountId) -> bool { + match Criterion::convert(asset.clone()) { + Left(a) => >::contains(&a, who), + Right(a) => >::contains(&a, who), + } + } +} From 50cdf8203605fcb884e59d838155ca96b44a98e7 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:24:55 +0200 Subject: [PATCH 43/69] tests for fungible/s sets --- substrate/frame/assets/src/tests.rs | 333 ++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) diff --git a/substrate/frame/assets/src/tests.rs b/substrate/frame/assets/src/tests.rs index f1b116a0f4a0d..10e50136ef65d 100644 --- a/substrate/frame/assets/src/tests.rs +++ b/substrate/frame/assets/src/tests.rs @@ -1775,3 +1775,336 @@ fn asset_destroy_refund_existence_deposit() { assert_eq!(Balances::reserved_balance(&admin), 0); }); } + +mod sets { + use super::*; + use frame_support::{ + parameter_types, + traits::{ + fungible, + fungible::ItemOf, + fungibles, + tokens::{ + fungibles::{ + Balanced as FungiblesBalanced, Create as FungiblesCreate, + Inspect as FungiblesInspect, Mutate as FungiblesMutate, + }, + Fortitude, Precision, Preservation, + }, + }, + }; + use sp_runtime::{traits::ConvertToValue, Either}; + + const FIRST_ASSET: u32 = 0; + const UNKNOWN_ASSET: u32 = 10; + + parameter_types! { + pub const LeftAsset: Either<(), u32> = Either::Left(()); + pub const RightAsset: Either = Either::Right(()); + pub const RightUnitAsset: Either<(), ()> = Either::Right(()); + } + + /// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a + /// single asset class from [`T`] identified by [`FIRST_ASSET`]. + type FirstFungible = ItemOf, u64>; + /// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a + /// single asset class from [`T`] identified by [`UNKNOWN_ASSET`]. + type UnknownFungible = ItemOf, u64>; + /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes + /// the [`FirstFungible`] from the left. + type LeftFungible = + fungible::UnionOf, T, ConvertToValue, (), u64>; + /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes + /// the [`LeftFungible`] from the right. + type RightFungible = fungible::UnionOf< + UnknownFungible, + LeftFungible, + ConvertToValue, + (), + u64, + >; + /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes + /// the [`RightFungible`] from the left. + type LeftFungibles = + fungibles::UnionOf, T, ConvertToValue, (), u64>; + /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes + /// the [`LeftFungibles`] from the right. + /// + /// By using this type, we can navigate through each branch of [`fungible::UnionOf`], + /// [`fungibles::UnionOf`], and [`ItemOf`] to access the underlying `fungibles::*` + /// implementation provided by the pallet. + type First = fungibles::UnionOf, ConvertToValue, (), u64>; + + #[test] + fn deposit_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1 = 0; + let account1 = 1; + let account2 = 2; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::deposit((), &account2, 50, Precision::Exact).unwrap(); + assert_eq!(First::::balance((), &account2), 50); + assert_eq!(First::::total_issuance(()), 100); + + assert_eq!(imb.peek(), 50); + + let (imb1, imb2) = imb.split(30); + assert_eq!(imb1.peek(), 30); + assert_eq!(imb2.peek(), 20); + + drop(imb2); + assert_eq!(First::::total_issuance(()), 120); + + assert!(First::::settle(&account1, imb1, Preservation::Preserve).is_ok()); + assert_eq!(First::::balance((), &account1), 70); + assert_eq!(First::::balance((), &account2), 50); + assert_eq!(First::::total_issuance(()), 120); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); + } + + #[test] + fn issue_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::balance((), &account1), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::issue((), 100); + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(imb.peek(), 100); + + let (imb1, imb2) = imb.split(30); + assert_eq!(imb1.peek(), 30); + assert_eq!(imb2.peek(), 70); + + drop(imb2); + assert_eq!(First::::total_issuance(()), 130); + + assert!(First::::resolve(&account1, imb1).is_ok()); + assert_eq!(First::::balance((), &account1), 130); + assert_eq!(First::::total_issuance(()), 130); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); + } + + #[test] + fn pair_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::balance((), &account1), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let (debt, credit) = First::::pair((), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(debt.peek(), 100); + assert_eq!(credit.peek(), 100); + + let (debt1, debt2) = debt.split(30); + assert_eq!(debt1.peek(), 30); + assert_eq!(debt2.peek(), 70); + + drop(debt2); + assert_eq!(First::::total_issuance(()), 170); + + assert!(First::::settle(&account1, debt1, Preservation::Preserve).is_ok()); + assert_eq!(First::::balance((), &account1), 70); + assert_eq!(First::::total_issuance(()), 170); + + let (credit1, credit2) = credit.split(40); + assert_eq!(credit1.peek(), 40); + assert_eq!(credit2.peek(), 60); + + drop(credit2); + assert_eq!(First::::total_issuance(()), 110); + + assert!(First::::resolve(&account1, credit1).is_ok()); + assert_eq!(First::::balance((), &account1), 110); + assert_eq!(First::::total_issuance(()), 110); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); + } + + #[test] + fn rescind_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::rescind((), 20); + assert_eq!(First::::total_issuance(()), 80); + + assert_eq!(imb.peek(), 20); + + let (imb1, imb2) = imb.split(15); + assert_eq!(imb1.peek(), 15); + assert_eq!(imb2.peek(), 5); + + drop(imb2); + assert_eq!(First::::total_issuance(()), 85); + + assert!(First::::settle(&account1, imb1, Preservation::Preserve).is_ok()); + assert_eq!(First::::balance((), &account1), 85); + assert_eq!(First::::total_issuance(()), 85); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); + } + + #[test] + fn resolve_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + let account2: u64 = 2; + let ed = 11; + + assert_ok!(>::create(asset1, account1, true, ed)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::balance((), &account1), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::issue((), 100); + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(imb.peek(), 100); + + let (imb1, imb2) = imb.split(10); + assert_eq!(imb1.peek(), 10); + assert_eq!(imb2.peek(), 90); + assert_eq!(First::::total_issuance(()), 200); + + // ed requirements not met. + let imb1 = First::::resolve(&account2, imb1).unwrap_err(); + assert_eq!(imb1.peek(), 10); + drop(imb1); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 0); + + // resolve to new account `2`. + assert_ok!(First::::resolve(&account2, imb2)); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 90); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); + } + + #[test] + fn settle_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + let account2: u64 = 2; + let ed = 11; + + assert_ok!(>::create(asset1, account1, true, ed)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + assert_ok!(Assets::mint_into(asset1, &account2, 100)); + + assert_eq!(First::::balance((), &account2), 100); + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::rescind((), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(imb.peek(), 100); + + let (imb1, imb2) = imb.split(10); + assert_eq!(imb1.peek(), 10); + assert_eq!(imb2.peek(), 90); + assert_eq!(First::::total_issuance(()), 100); + + // ed requirements not met. + let imb2 = + First::::settle(&account2, imb2, Preservation::Preserve).unwrap_err(); + assert_eq!(imb2.peek(), 90); + drop(imb2); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 100); + + // settle to account `1`. + assert_ok!(First::::settle(&account2, imb1, Preservation::Preserve)); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 90); + + let imb = First::::rescind((), 85); + assert_eq!(First::::total_issuance(()), 105); + assert_eq!(imb.peek(), 85); + + // settle to account `1` and expect some dust. + let imb = First::::settle(&account2, imb, Preservation::Expendable).unwrap(); + assert_eq!(imb.peek(), 5); + assert_eq!(First::::total_issuance(()), 105); + assert_eq!(First::::balance((), &account2), 0); + + drop(imb); + assert_eq!(First::::total_issuance(()), 100); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); + } + + #[test] + fn withdraw_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1 = 0; + let account1 = 1; + let account2 = 2; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + assert_ok!(Assets::mint_into(asset1, &account2, 100)); + + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::withdraw( + (), + &account2, + 50, + Precision::Exact, + Preservation::Preserve, + Fortitude::Polite, + ) + .unwrap(); + assert_eq!(First::::balance((), &account2), 50); + assert_eq!(First::::total_issuance(()), 200); + + assert_eq!(imb.peek(), 50); + drop(imb); + assert_eq!(First::::total_issuance(()), 150); + assert_eq!(First::::balance((), &account2), 50); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); + } +} From 5fbdc2adb4bab41a5dc024cbf20d349d202cf713 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:25:46 +0200 Subject: [PATCH 44/69] asset conversion --- .../asset-conversion/src/benchmarking.rs | 473 +++---- substrate/frame/asset-conversion/src/lib.rs | 510 +++---- substrate/frame/asset-conversion/src/mock.rs | 42 +- substrate/frame/asset-conversion/src/swap.rs | 32 +- substrate/frame/asset-conversion/src/tests.rs | 1246 +++++++++-------- substrate/frame/asset-conversion/src/types.rs | 276 +--- 6 files changed, 1176 insertions(+), 1403 deletions(-) diff --git a/substrate/frame/asset-conversion/src/benchmarking.rs b/substrate/frame/asset-conversion/src/benchmarking.rs index 628953d0558f7..2892995830bcb 100644 --- a/substrate/frame/asset-conversion/src/benchmarking.rs +++ b/substrate/frame/asset-conversion/src/benchmarking.rs @@ -18,25 +18,48 @@ //! Asset Conversion pallet benchmarking. use super::*; -use frame_benchmarking::{benchmarks, whitelisted_caller}; +use crate::Pallet as AssetConversion; +use frame_benchmarking::{v2::*, whitelisted_caller}; use frame_support::{ assert_ok, traits::{ - fungible::{Inspect as InspectFungible, Mutate as MutateFungible, Unbalanced}, + fungible::NativeOrWithId, fungibles::{Create, Inspect, Mutate}, }, }; use frame_system::RawOrigin as SystemOrigin; use sp_core::Get; -use sp_runtime::traits::{Bounded, StaticLookup}; -use sp_std::{ops::Div, prelude::*}; +use sp_runtime::traits::StaticLookup; +use sp_std::{marker::PhantomData, prelude::*}; -use crate::Pallet as AssetConversion; +/// Benchmark Helper +pub trait BenchmarkHelper { + /// Returns a valid assets pair for the pool creation. + fn create_pair(seed1: u32, seed2: u32) -> (AssetKind, AssetKind); +} + +impl BenchmarkHelper for () +where + AssetKind: From, +{ + fn create_pair(seed1: u32, seed2: u32) -> (AssetKind, AssetKind) { + (seed1.into(), seed2.into()) + } +} + +/// Factory for creating a valid asset pairs with [`NativeOrWithId::Native`] always leading in the +/// pair. +pub struct NativeOrWithIdFactory(PhantomData); +impl + Ord> BenchmarkHelper> + for NativeOrWithIdFactory +{ + fn create_pair(_seed1: u32, seed2: u32) -> (NativeOrWithId, NativeOrWithId) { + (NativeOrWithId::Native, NativeOrWithId::WithId(seed2.into())) + } +} const INITIAL_ASSET_BALANCE: u128 = 1_000_000_000_000; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -type BalanceOf = - <::Currency as InspectFungible<::AccountId>>::Balance; fn get_lp_token_id() -> T::PoolAssetId where @@ -46,37 +69,41 @@ where (next_id - 1).into() } -fn create_asset(asset: &T::MultiAssetId) -> (T::AccountId, AccountIdLookupOf) +fn create_asset(asset: &T::AssetKind) -> (T::AccountId, AccountIdLookupOf) where T::Balance: From, - T::Currency: Unbalanced, T::Assets: Create + Mutate, { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - if let MultiAssetIdConversionResult::Converted(asset_id) = - T::MultiAssetIdConverter::try_convert(asset) - { - T::Currency::set_balance(&caller, BalanceOf::::max_value().div(1000u32.into())); - assert_ok!(T::Assets::create(asset_id.clone(), caller.clone(), true, 1.into())); - assert_ok!(T::Assets::mint_into(asset_id, &caller, INITIAL_ASSET_BALANCE.into())); + if !T::Assets::asset_exists(asset.clone()) { + assert_ok!(T::Assets::create(asset.clone(), caller.clone(), true, 1.into())); } + assert_ok!(T::Assets::mint_into(asset.clone(), &caller, INITIAL_ASSET_BALANCE.into())); + (caller, caller_lookup) } fn create_asset_and_pool( - asset1: &T::MultiAssetId, - asset2: &T::MultiAssetId, + asset1: &T::AssetKind, + asset2: &T::AssetKind, ) -> (T::PoolAssetId, T::AccountId, AccountIdLookupOf) where T::Balance: From, - T::Currency: Unbalanced, T::Assets: Create + Mutate, T::PoolAssetId: Into, { + let fee_asset = T::PoolSetupFeeAsset::get(); + let (_, _) = create_asset::(&fee_asset); let (_, _) = create_asset::(asset1); let (caller, caller_lookup) = create_asset::(asset2); + assert_ok!(T::Assets::mint_into( + fee_asset.clone(), + &caller, + T::PoolSetupFee::get() + T::Assets::minimum_balance(fee_asset) + )); + assert_ok!(AssetConversion::::create_pool( SystemOrigin::Signed(caller.clone()).into(), Box::new(asset1.clone()), @@ -95,65 +122,75 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { assert_eq!(event, &system_event); } -benchmarks! { - where_clause { - where - T::Currency: Unbalanced, - T::Balance: From + Into, - T::Assets: Create + Mutate, - T::PoolAssetId: Into, - } +#[benchmarks(where T::Balance: From + Into, T::Assets: Create + Mutate, T::PoolAssetId: Into,)] +mod benchmarks { + use super::*; - create_pool { - let asset1 = T::MultiAssetIdConverter::get_native(); - let asset2 = T::BenchmarkHelper::multiasset_id(0); + #[benchmark] + fn create_pool() { + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); + let (_, _) = create_asset::(&asset1); let (caller, _) = create_asset::(&asset2); - }: _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone())) - verify { + + assert_ok!(T::Assets::mint_into( + T::PoolSetupFeeAsset::get(), + &caller, + T::PoolSetupFee::get() + T::Assets::minimum_balance(T::PoolSetupFeeAsset::get()) + )); + + #[extrinsic_call] + _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone())); + let lp_token = get_lp_token_id::(); - let pool_id = (asset1.clone(), asset2.clone()); - assert_last_event::(Event::PoolCreated { - creator: caller.clone(), - pool_account: AssetConversion::::get_pool_account(&pool_id), - pool_id, - lp_token, - }.into()); + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2).unwrap(); + let pool_account = T::PoolLocator::address(&pool_id).unwrap(); + assert_last_event::( + Event::PoolCreated { creator: caller.clone(), pool_account, pool_id, lp_token }.into(), + ); } - add_liquidity { - let asset1 = T::MultiAssetIdConverter::get_native(); - let asset2 = T::BenchmarkHelper::multiasset_id(0); + #[benchmark] + fn add_liquidity() { + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); let (lp_token, caller, _) = create_asset_and_pool::(&asset1, &asset2); - let ed: u128 = T::Currency::minimum_balance().into(); + let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); let add_amount = 1000 + ed; - }: _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone()), add_amount.into(), 1000.into(), 0.into(), 0.into(), caller.clone()) - verify { - let pool_id = (asset1.clone(), asset2.clone()); - let lp_minted = AssetConversion::::calc_lp_amount_for_zero_supply(&add_amount.into(), &1000.into()).unwrap().into(); - assert_eq!( - T::PoolAssets::balance(lp_token, &caller), - lp_minted.into() - ); - assert_eq!( - T::Currency::balance(&AssetConversion::::get_pool_account(&pool_id)), - add_amount.into() - ); - assert_eq!( - T::Assets::balance(T::BenchmarkHelper::asset_id(0), &AssetConversion::::get_pool_account(&pool_id)), - 1000.into() + + #[extrinsic_call] + _( + SystemOrigin::Signed(caller.clone()), + Box::new(asset1.clone()), + Box::new(asset2.clone()), + add_amount.into(), + 1000.into(), + 0.into(), + 0.into(), + caller.clone(), ); + + let pool_account = T::PoolLocator::pool_address(&asset1, &asset2).unwrap(); + let lp_minted = + AssetConversion::::calc_lp_amount_for_zero_supply(&add_amount.into(), &1000.into()) + .unwrap() + .into(); + assert_eq!(T::PoolAssets::balance(lp_token, &caller), lp_minted.into()); + assert_eq!(T::Assets::balance(asset1, &pool_account), add_amount.into()); + assert_eq!(T::Assets::balance(asset2, &pool_account), 1000.into()); } - remove_liquidity { - let asset1 = T::MultiAssetIdConverter::get_native(); - let asset2 = T::BenchmarkHelper::multiasset_id(0); + #[benchmark] + fn remove_liquidity() { + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); let (lp_token, caller, _) = create_asset_and_pool::(&asset1, &asset2); - let ed: u128 = T::Currency::minimum_balance().into(); + let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); let add_amount = 100 * ed; - let lp_minted = AssetConversion::::calc_lp_amount_for_zero_supply(&add_amount.into(), &1000.into()).unwrap().into(); + let lp_minted = + AssetConversion::::calc_lp_amount_for_zero_supply(&add_amount.into(), &1000.into()) + .unwrap() + .into(); let remove_lp_amount = lp_minted.checked_div(10).unwrap(); - AssetConversion::::add_liquidity( + assert_ok!(AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), Box::new(asset1.clone()), Box::new(asset2.clone()), @@ -162,213 +199,151 @@ benchmarks! { 0.into(), 0.into(), caller.clone(), - )?; - let total_supply = >::total_issuance(lp_token.clone()); - }: _(SystemOrigin::Signed(caller.clone()), Box::new(asset1), Box::new(asset2), remove_lp_amount.into(), 0.into(), 0.into(), caller.clone()) - verify { - let new_total_supply = >::total_issuance(lp_token.clone()); - assert_eq!( - new_total_supply, - total_supply - remove_lp_amount.into() + )); + let total_supply = + >::total_issuance(lp_token.clone()); + + #[extrinsic_call] + _( + SystemOrigin::Signed(caller.clone()), + Box::new(asset1), + Box::new(asset2), + remove_lp_amount.into(), + 0.into(), + 0.into(), + caller.clone(), ); + + let new_total_supply = + >::total_issuance(lp_token.clone()); + assert_eq!(new_total_supply, total_supply - remove_lp_amount.into()); } - swap_exact_tokens_for_tokens { - let native = T::MultiAssetIdConverter::get_native(); - let asset1 = T::BenchmarkHelper::multiasset_id(1); - let asset2 = T::BenchmarkHelper::multiasset_id(2); - let (_, caller, _) = create_asset_and_pool::(&native, &asset1); - let (_, _) = create_asset::(&asset2); - let ed: u128 = T::Currency::minimum_balance().into(); + #[benchmark] + fn swap_exact_tokens_for_tokens() { + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); + let (_, asset3) = T::BenchmarkHelper::create_pair(1, 2); + let (_, asset4) = T::BenchmarkHelper::create_pair(2, 3); + + let (_, caller, _) = create_asset_and_pool::(&asset1, &asset2); + let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); - AssetConversion::::add_liquidity( + assert_ok!(AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - Box::new(native.clone()), Box::new(asset1.clone()), + Box::new(asset2.clone()), (100 * ed).into(), 200.into(), + 1.into(), 0.into(), + caller.clone(), + )); + + let (_, _, _) = create_asset_and_pool::(&asset2, &asset3); + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset2.clone()), + Box::new(asset3.clone()), + 200.into(), + 2000.into(), + 1.into(), 0.into(), caller.clone(), - )?; - - let path; - let swap_amount; - // if we only allow the native-asset pools, then the worst case scenario would be to swap - // asset1-native-asset2 - if !T::AllowMultiAssetPools::get() { - AssetConversion::::create_pool( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(native.clone()), - Box::new(asset2.clone()) - )?; - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(native.clone()), - Box::new(asset2.clone()), - (500 * ed).into(), - 1000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - path = vec![ - Box::new(asset1.clone()), - Box::new(native.clone()), - Box::new(asset2.clone()) - ]; - swap_amount = 100.into(); - } else { - let asset3 = T::BenchmarkHelper::multiasset_id(3); - AssetConversion::::create_pool( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset1.clone()), - Box::new(asset2.clone()) - )?; - let (_, _) = create_asset::(&asset3); - AssetConversion::::create_pool( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset2.clone()), - Box::new(asset3.clone()) - )?; - - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset1.clone()), - Box::new(asset2.clone()), - 200.into(), - 2000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset2.clone()), - Box::new(asset3.clone()), - 2000.into(), - 2000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - path = vec![ - Box::new(native.clone()), - Box::new(asset1.clone()), - Box::new(asset2.clone()), - Box::new(asset3.clone()) - ]; - swap_amount = ed.into(); - } - let native_balance = T::Currency::balance(&caller); - let asset1_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(1), &caller); - }: _(SystemOrigin::Signed(caller.clone()), path, swap_amount, 1.into(), caller.clone(), false) - verify { - if !T::AllowMultiAssetPools::get() { - let new_asset1_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(1), &caller); - assert_eq!(new_asset1_balance, asset1_balance - 100.into()); - } else { - let new_native_balance = T::Currency::balance(&caller); - assert_eq!(new_native_balance, native_balance - ed.into()); - } + )); + + let (_, _, _) = create_asset_and_pool::(&asset3, &asset4); + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset3.clone()), + Box::new(asset4.clone()), + 2000.into(), + 2000.into(), + 1.into(), + 1.into(), + caller.clone(), + )); + let path = vec![ + Box::new(asset1.clone()), + Box::new(asset2.clone()), + Box::new(asset3.clone()), + Box::new(asset4.clone()), + ]; + + let swap_amount = ed.into(); + let asset1_balance = T::Assets::balance(asset1.clone(), &caller); + + #[extrinsic_call] + _(SystemOrigin::Signed(caller.clone()), path, swap_amount, 1.into(), caller.clone(), false); + + let new_asset1_balance = T::Assets::balance(asset1, &caller); + assert_eq!(new_asset1_balance, asset1_balance - ed.into()); } - swap_tokens_for_exact_tokens { - let native = T::MultiAssetIdConverter::get_native(); - let asset1 = T::BenchmarkHelper::multiasset_id(1); - let asset2 = T::BenchmarkHelper::multiasset_id(2); - let (_, caller, _) = create_asset_and_pool::(&native, &asset1); - let (_, _) = create_asset::(&asset2); - let ed: u128 = T::Currency::minimum_balance().into(); + #[benchmark] + fn swap_tokens_for_exact_tokens() { + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); + let (_, asset3) = T::BenchmarkHelper::create_pair(1, 2); + let (_, asset4) = T::BenchmarkHelper::create_pair(2, 3); - AssetConversion::::add_liquidity( + let (_, caller, _) = create_asset_and_pool::(&asset1, &asset2); + let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); + + assert_ok!(AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), - Box::new(native.clone()), Box::new(asset1.clone()), + Box::new(asset2.clone()), (1000 * ed).into(), 500.into(), + 1.into(), 0.into(), + caller.clone(), + )); + + let (_, _, _) = create_asset_and_pool::(&asset2, &asset3); + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset2.clone()), + Box::new(asset3.clone()), + 2000.into(), + 2000.into(), + 1.into(), 0.into(), caller.clone(), - )?; - - let path; - // if we only allow the native-asset pools, then the worst case scenario would be to swap - // asset1-native-asset2 - if !T::AllowMultiAssetPools::get() { - AssetConversion::::create_pool( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(native.clone()), - Box::new(asset2.clone()) - )?; - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(native.clone()), - Box::new(asset2.clone()), - (500 * ed).into(), - 1000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - path = vec![ - Box::new(asset1.clone()), - Box::new(native.clone()), - Box::new(asset2.clone()) - ]; - } else { - AssetConversion::::create_pool( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset1.clone()), - Box::new(asset2.clone()) - )?; - let asset3 = T::BenchmarkHelper::multiasset_id(3); - let (_, _) = create_asset::(&asset3); - AssetConversion::::create_pool( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset2.clone()), - Box::new(asset3.clone()) - )?; - - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset1.clone()), - Box::new(asset2.clone()), - 2000.into(), - 2000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset2.clone()), - Box::new(asset3.clone()), - 2000.into(), - 2000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - path = vec![ - Box::new(native.clone()), - Box::new(asset1.clone()), - Box::new(asset2.clone()), - Box::new(asset3.clone()) - ]; - } - - let asset2_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(2), &caller); - let asset3_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(3), &caller); - }: _(SystemOrigin::Signed(caller.clone()), path.clone(), 100.into(), (1000 * ed).into(), caller.clone(), false) - verify { - if !T::AllowMultiAssetPools::get() { - let new_asset2_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(2), &caller); - assert_eq!(new_asset2_balance, asset2_balance + 100.into()); - } else { - let new_asset3_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(3), &caller); - assert_eq!(new_asset3_balance, asset3_balance + 100.into()); - } + )); + + let (_, _, _) = create_asset_and_pool::(&asset3, &asset4); + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset3.clone()), + Box::new(asset4.clone()), + 2000.into(), + 2000.into(), + 1.into(), + 0.into(), + caller.clone(), + )); + + let path = vec![ + Box::new(asset1.clone()), + Box::new(asset2.clone()), + Box::new(asset3.clone()), + Box::new(asset4.clone()), + ]; + + let asset4_balance = T::Assets::balance(asset4.clone(), &caller); + + #[extrinsic_call] + _( + SystemOrigin::Signed(caller.clone()), + path.clone(), + 100.into(), + (1000 * ed).into(), + caller.clone(), + false, + ); + + let new_asset4_balance = T::Assets::balance(asset4, &caller); + assert_eq!(new_asset4_balance, asset4_balance + 100.into()); } impl_benchmark_test_suite!(AssetConversion, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index e25725157c32b..6cc73452b250c 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -63,7 +63,8 @@ mod swap; mod tests; mod types; pub mod weights; - +#[cfg(feature = "runtime-benchmarks")] +pub use benchmarking::{BenchmarkHelper, NativeOrWithIdFactory}; pub use pallet::*; pub use swap::*; pub use types::*; @@ -73,18 +74,14 @@ use codec::Codec; use frame_support::{ storage::{with_storage_layer, with_transaction}, traits::{ - fungible::{ - Balanced as BalancedFungible, Credit as CreditFungible, Inspect as InspectFungible, - Mutate as MutateFungible, - }, - fungibles::{Balanced, Create, Credit as CreditFungibles, Inspect, Mutate}, + fungibles::{Balanced, Create, Credit, Inspect, Mutate}, tokens::{ AssetId, Balance, Fortitude::Polite, Precision::Exact, Preservation::{Expendable, Preserve}, }, - AccountTouch, ContainsPair, Imbalance, Incrementable, + AccountTouch, ContainsPair, Incrementable, OnUnbalanced, }, PalletId, }; @@ -94,7 +91,7 @@ use sp_runtime::{ CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, IntegerSquareRoot, MaybeDisplay, One, TrailingZeroInput, Zero, }, - DispatchError, RuntimeDebug, Saturating, TokenError, TransactionOutcome, + DispatchError, Saturating, TokenError, TransactionOutcome, }; use sp_std::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec}; @@ -113,11 +110,6 @@ pub mod pallet { /// Overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Currency type that this works on. - type Currency: InspectFungible - + MutateFungible - + BalancedFungible; - /// The type in which the assets for swapping are measured. type Balance: Balance; @@ -130,30 +122,28 @@ pub mod pallet { + From + TryInto; - /// Identifier for the class of non-native asset. - /// Note: A `From` bound here would prevent `MultiLocation` from being used as an - /// `AssetId`. - type AssetId: AssetId; + /// Type of asset class, sourced from [`Config::Assets`], utilized to offer liquidity to a + /// pool. + type AssetKind: Parameter + MaxEncodedLen; - /// Type that identifies either the native currency or a token class from `Assets`. - /// `Ord` is added because of `get_pool_id`. - /// - /// The pool's `AccountId` is derived from this type. Any changes to the type may - /// necessitate a migration. - type MultiAssetId: AssetId + Ord + From; + /// Registry of assets utilized for providing liquidity to pools. + type Assets: Inspect + + Mutate + + AccountTouch + + ContainsPair + + Balanced; - /// Type to convert an `AssetId` into `MultiAssetId`. - type MultiAssetIdConverter: MultiAssetIdConverter; + /// Liquidity pool identifier. + type PoolId: Parameter + MaxEncodedLen + Ord; - /// `AssetId` to address the lp tokens by. - type PoolAssetId: AssetId + PartialOrd + Incrementable + From; + /// Provides means to resolve the [`Config::PoolId`] and it's `AccountId` from a pair + /// of [`Config::AssetKind`]s. + /// + /// Examples: [`crate::types::WithFirstAsset`], [`crate::types::Ascending`]. + type PoolLocator: PoolLocator; - /// Registry for the assets. - type Assets: Inspect - + Mutate - + AccountTouch - + ContainsPair - + Balanced; + /// Asset class for the lp tokens from [`Self::PoolAssets`]. + type PoolAssetId: AssetId + PartialOrd + Incrementable + From; /// Registry for the lp tokens. Ideally only this pallet should have create permissions on /// the assets. @@ -170,8 +160,12 @@ pub mod pallet { #[pallet::constant] type PoolSetupFee: Get; - /// An account that receives the pool setup fee. - type PoolSetupFeeReceiver: Get; + /// Asset class from [`Config::Assets`] used to pay the [`Config::PoolSetupFee`]. + #[pallet::constant] + type PoolSetupFeeAsset: Get; + + /// Handler for the [`Config::PoolSetupFee`]. + type PoolSetupFeeTarget: OnUnbalanced>; /// A fee to withdraw the liquidity. #[pallet::constant] @@ -189,23 +183,19 @@ pub mod pallet { #[pallet::constant] type PalletId: Get; - /// A setting to allow creating pools with both non-native assets. - #[pallet::constant] - type AllowMultiAssetPools: Get; - /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The benchmarks need a way to create asset ids from u32s. #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper: BenchmarkHelper; + type BenchmarkHelper: BenchmarkHelper; } /// Map from `PoolAssetId` to `PoolInfo`. This establishes whether a pool has been officially /// created rather than people sending tokens directly to a pool's public account. #[pallet::storage] pub type Pools = - StorageMap<_, Blake2_128Concat, PoolIdOf, PoolInfo, OptionQuery>; + StorageMap<_, Blake2_128Concat, T::PoolId, PoolInfo, OptionQuery>; /// Stores the `PoolAssetId` that is going to be used for the next lp token. /// This gets incremented whenever a new lp pool is created. @@ -222,7 +212,7 @@ pub mod pallet { creator: T::AccountId, /// The pool id associated with the pool. Note that the order of the assets may not be /// the same as the order specified in the create pool extrinsic. - pool_id: PoolIdOf, + pool_id: T::PoolId, /// The account ID of the pool. pool_account: T::AccountId, /// The id of the liquidity tokens that will be minted when assets are added to this @@ -237,7 +227,7 @@ pub mod pallet { /// The account that the liquidity tokens were minted to. mint_to: T::AccountId, /// The pool id of the pool that the liquidity was added to. - pool_id: PoolIdOf, + pool_id: T::PoolId, /// The amount of the first asset that was added to the pool. amount1_provided: T::Balance, /// The amount of the second asset that was added to the pool. @@ -255,7 +245,7 @@ pub mod pallet { /// The account that the assets were transferred to. withdraw_to: T::AccountId, /// The pool id that the liquidity was removed from. - pool_id: PoolIdOf, + pool_id: T::PoolId, /// The amount of the first asset that was removed from the pool. amount1: T::Balance, /// The amount of the second asset that was removed from the pool. @@ -296,10 +286,8 @@ pub mod pallet { #[pallet::error] pub enum Error { - /// Provided assets are equal. - EqualAssets, - /// Provided asset is not supported for pool. - UnsupportedAsset, + /// Provided asset pair is not supported for pool. + InvalidAssetPair, /// Pool already exists. PoolExists, /// Desired amount can't be zero. @@ -335,18 +323,12 @@ pub mod pallet { ZeroLiquidity, /// Amount can't be zero. ZeroAmount, - /// Insufficient liquidity in the pool. - InsufficientLiquidity, /// Calculated amount out is less than provided minimum amount. ProvidedMinimumNotSufficientForSwap, /// Provided maximum amount is not sufficient for swap. ProvidedMaximumNotSufficientForSwap, - /// Only pools with native on one side are valid. - PoolMustContainNativeCurrency, /// The provided path must consists of 2 assets at least. InvalidPath, - /// It was not possible to calculate path data. - PathError, /// The provided path must consists of unique assets. NonUniquePath, /// It was not possible to get or increment the Id of the pool. @@ -376,48 +358,33 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::create_pool())] pub fn create_pool( origin: OriginFor, - asset1: Box, - asset2: Box, + asset1: Box, + asset2: Box, ) -> DispatchResult { let sender = ensure_signed(origin)?; - ensure!(asset1 != asset2, Error::::EqualAssets); + ensure!(asset1 != asset2, Error::::InvalidAssetPair); // prepare pool_id - let pool_id = Self::get_pool_id(*asset1, *asset2); + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; ensure!(!Pools::::contains_key(&pool_id), Error::::PoolExists); - let (asset1, asset2) = &pool_id; - if !T::AllowMultiAssetPools::get() && !T::MultiAssetIdConverter::is_native(asset1) { - Err(Error::::PoolMustContainNativeCurrency)?; - } - let pool_account = Self::get_pool_account(&pool_id); + let pool_account = + T::PoolLocator::address(&pool_id).map_err(|_| Error::::InvalidAssetPair)?; frame_system::Pallet::::inc_providers(&pool_account); // pay the setup fee - T::Currency::transfer( - &sender, - &T::PoolSetupFeeReceiver::get(), - T::PoolSetupFee::get(), - Preserve, - )?; + let fee = + Self::withdraw(T::PoolSetupFeeAsset::get(), &sender, T::PoolSetupFee::get(), true)?; + T::PoolSetupFeeTarget::on_unbalanced(fee); - // try to convert both assets - match T::MultiAssetIdConverter::try_convert(asset1) { - MultiAssetIdConversionResult::Converted(asset) => - if !T::Assets::contains(&asset, &pool_account) { - T::Assets::touch(asset, pool_account.clone(), sender.clone())? - }, - MultiAssetIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedAsset)?, - MultiAssetIdConversionResult::Native => (), - } - match T::MultiAssetIdConverter::try_convert(asset2) { - MultiAssetIdConversionResult::Converted(asset) => - if !T::Assets::contains(&asset, &pool_account) { - T::Assets::touch(asset, pool_account.clone(), sender.clone())? - }, - MultiAssetIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedAsset)?, - MultiAssetIdConversionResult::Native => (), - } + if !T::Assets::contains(&asset1, &pool_account) { + T::Assets::touch(*asset1, pool_account.clone(), sender.clone())? + }; + + if !T::Assets::contains(&asset2, &pool_account) { + T::Assets::touch(*asset2, pool_account.clone(), sender.clone())? + }; let lp_token = NextPoolAssetId::::get() .or(T::PoolAssetId::initial_value()) @@ -454,8 +421,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::add_liquidity())] pub fn add_liquidity( origin: OriginFor, - asset1: Box, - asset2: Box, + asset1: Box, + asset2: Box, amount1_desired: T::Balance, amount2_desired: T::Balance, amount1_min: T::Balance, @@ -464,26 +431,20 @@ pub mod pallet { ) -> DispatchResult { let sender = ensure_signed(origin)?; - let pool_id = Self::get_pool_id(*asset1.clone(), *asset2); - // swap params if needed - let (amount1_desired, amount2_desired, amount1_min, amount2_min) = - if pool_id.0 == *asset1 { - (amount1_desired, amount2_desired, amount1_min, amount2_min) - } else { - (amount2_desired, amount1_desired, amount2_min, amount1_min) - }; + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; + ensure!( amount1_desired > Zero::zero() && amount2_desired > Zero::zero(), Error::::WrongDesiredAmount ); - let maybe_pool = Pools::::get(&pool_id); - let pool = maybe_pool.as_ref().ok_or(Error::::PoolNotFound)?; - let pool_account = Self::get_pool_account(&pool_id); + let pool = Pools::::get(&pool_id).ok_or(Error::::PoolNotFound)?; + let pool_account = + T::PoolLocator::address(&pool_id).map_err(|_| Error::::InvalidAssetPair)?; - let (asset1, asset2) = &pool_id; - let reserve1 = Self::get_balance(&pool_account, asset1)?; - let reserve2 = Self::get_balance(&pool_account, asset2)?; + let reserve1 = Self::get_balance(&pool_account, *asset1.clone()); + let reserve2 = Self::get_balance(&pool_account, *asset2.clone()); let amount1: T::Balance; let amount2: T::Balance; @@ -515,13 +476,17 @@ pub mod pallet { } } - Self::validate_minimal_amount(amount1.saturating_add(reserve1), asset1) - .map_err(|_| Error::::AmountOneLessThanMinimal)?; - Self::validate_minimal_amount(amount2.saturating_add(reserve2), asset2) - .map_err(|_| Error::::AmountTwoLessThanMinimal)?; + ensure!( + amount1.saturating_add(reserve1) >= T::Assets::minimum_balance(*asset1.clone()), + Error::::AmountOneLessThanMinimal + ); + ensure!( + amount2.saturating_add(reserve2) >= T::Assets::minimum_balance(*asset2.clone()), + Error::::AmountTwoLessThanMinimal + ); - Self::transfer(asset1, &sender, &pool_account, amount1, true)?; - Self::transfer(asset2, &sender, &pool_account, amount2, true)?; + T::Assets::transfer(*asset1, &sender, &pool_account, amount1, Preserve)?; + T::Assets::transfer(*asset2, &sender, &pool_account, amount2, Preserve)?; let total_supply = T::PoolAssets::total_issuance(pool.lp_token.clone()); @@ -552,7 +517,7 @@ pub mod pallet { pool_id, amount1_provided: amount1, amount2_provided: amount2, - lp_token: pool.lp_token.clone(), + lp_token: pool.lp_token, lp_token_minted: lp_token_amount, }); @@ -566,8 +531,8 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_liquidity())] pub fn remove_liquidity( origin: OriginFor, - asset1: Box, - asset2: Box, + asset1: Box, + asset2: Box, lp_token_burn: T::Balance, amount1_min_receive: T::Balance, amount2_min_receive: T::Balance, @@ -575,23 +540,17 @@ pub mod pallet { ) -> DispatchResult { let sender = ensure_signed(origin)?; - let pool_id = Self::get_pool_id(*asset1.clone(), *asset2); - // swap params if needed - let (amount1_min_receive, amount2_min_receive) = if pool_id.0 == *asset1 { - (amount1_min_receive, amount2_min_receive) - } else { - (amount2_min_receive, amount1_min_receive) - }; - let (asset1, asset2) = pool_id.clone(); + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; ensure!(lp_token_burn > Zero::zero(), Error::::ZeroLiquidity); - let maybe_pool = Pools::::get(&pool_id); - let pool = maybe_pool.as_ref().ok_or(Error::::PoolNotFound)?; + let pool = Pools::::get(&pool_id).ok_or(Error::::PoolNotFound)?; - let pool_account = Self::get_pool_account(&pool_id); - let reserve1 = Self::get_balance(&pool_account, &asset1)?; - let reserve2 = Self::get_balance(&pool_account, &asset2)?; + let pool_account = + T::PoolLocator::address(&pool_id).map_err(|_| Error::::InvalidAssetPair)?; + let reserve1 = Self::get_balance(&pool_account, *asset1.clone()); + let reserve2 = Self::get_balance(&pool_account, *asset2.clone()); let total_supply = T::PoolAssets::total_issuance(pool.lp_token.clone()); let withdrawal_fee_amount = T::LiquidityWithdrawalFee::get() * lp_token_burn; @@ -610,16 +569,20 @@ pub mod pallet { ); let reserve1_left = reserve1.saturating_sub(amount1); let reserve2_left = reserve2.saturating_sub(amount2); - Self::validate_minimal_amount(reserve1_left, &asset1) - .map_err(|_| Error::::ReserveLeftLessThanMinimal)?; - Self::validate_minimal_amount(reserve2_left, &asset2) - .map_err(|_| Error::::ReserveLeftLessThanMinimal)?; + ensure!( + reserve1_left >= T::Assets::minimum_balance(*asset1.clone()), + Error::::ReserveLeftLessThanMinimal + ); + ensure!( + reserve2_left >= T::Assets::minimum_balance(*asset2.clone()), + Error::::ReserveLeftLessThanMinimal + ); // burn the provided lp token amount that includes the fee T::PoolAssets::burn_from(pool.lp_token.clone(), &sender, lp_token_burn, Exact, Polite)?; - Self::transfer(&asset1, &pool_account, &withdraw_to, amount1, false)?; - Self::transfer(&asset2, &pool_account, &withdraw_to, amount2, false)?; + T::Assets::transfer(*asset1, &pool_account, &withdraw_to, amount1, Expendable)?; + T::Assets::transfer(*asset2, &pool_account, &withdraw_to, amount2, Expendable)?; Self::deposit_event(Event::LiquidityRemoved { who: sender, @@ -627,7 +590,7 @@ pub mod pallet { pool_id, amount1, amount2, - lp_token: pool.lp_token.clone(), + lp_token: pool.lp_token, lp_token_burned: lp_token_burn, withdrawal_fee: T::LiquidityWithdrawalFee::get(), }); @@ -645,7 +608,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_exact_tokens_for_tokens())] pub fn swap_exact_tokens_for_tokens( origin: OriginFor, - path: Vec>, + path: Vec>, amount_in: T::Balance, amount_out_min: T::Balance, send_to: T::AccountId, @@ -673,7 +636,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_tokens_for_exact_tokens())] pub fn swap_tokens_for_exact_tokens( origin: OriginFor, - path: Vec>, + path: Vec>, amount_out: T::Balance, amount_in_max: T::Balance, send_to: T::AccountId, @@ -707,7 +670,7 @@ pub mod pallet { /// rollback. pub(crate) fn do_swap_exact_tokens_for_tokens( sender: T::AccountId, - path: Vec, + path: Vec, amount_in: T::Balance, amount_out_min: Option, send_to: T::AccountId, @@ -755,7 +718,7 @@ pub mod pallet { /// rollback. pub(crate) fn do_swap_tokens_for_exact_tokens( sender: T::AccountId, - path: Vec, + path: Vec, amount_out: T::Balance, amount_in_max: Option, send_to: T::AccountId, @@ -801,10 +764,10 @@ pub mod pallet { /// only inside a transactional storage context and an Err result must imply a storage /// rollback. pub(crate) fn do_swap_exact_credit_tokens_for_tokens( - path: Vec, - credit_in: Credit, + path: Vec, + credit_in: CreditOf, amount_out_min: Option, - ) -> Result, (Credit, DispatchError)> { + ) -> Result, (CreditOf, DispatchError)> { let amount_in = credit_in.peek(); let inspect_path = |credit_asset| { ensure!(path.get(0).map_or(false, |a| *a == credit_asset), Error::::InvalidPath); @@ -846,10 +809,10 @@ pub mod pallet { /// only inside a transactional storage context and an Err result must imply a storage /// rollback. pub(crate) fn do_swap_credit_tokens_for_exact_tokens( - path: Vec, - credit_in: Credit, + path: Vec, + credit_in: CreditOf, amount_out: T::Balance, - ) -> Result<(Credit, Credit), (Credit, DispatchError)> { + ) -> Result<(CreditOf, CreditOf), (CreditOf, DispatchError)> { let amount_in_max = credit_in.peek(); let inspect_path = |credit_asset| { ensure!(path.get(0).map_or(false, |a| a == &credit_asset), Error::::InvalidPath); @@ -880,75 +843,6 @@ pub mod pallet { Ok((credit_out, credit_change)) } - /// Transfer an `amount` of `asset_id`, respecting the `keep_alive` requirements. - fn transfer( - asset_id: &T::MultiAssetId, - from: &T::AccountId, - to: &T::AccountId, - amount: T::Balance, - keep_alive: bool, - ) -> Result { - let preservation = match keep_alive { - true => Preserve, - false => Expendable, - }; - match T::MultiAssetIdConverter::try_convert(asset_id) { - MultiAssetIdConversionResult::Converted(asset_id) => - T::Assets::transfer(asset_id, from, to, amount, preservation), - MultiAssetIdConversionResult::Native => - Ok(T::Currency::transfer(from, to, amount, preservation)?), - MultiAssetIdConversionResult::Unsupported(_) => - Err(Error::::UnsupportedAsset.into()), - } - } - - /// The balance of `who` is increased in order to counter `credit`. If the whole of `credit` - /// cannot be countered, then nothing is changed and the original `credit` is returned in an - /// `Err`. - fn resolve(who: &T::AccountId, credit: Credit) -> Result<(), Credit> { - match credit { - Credit::Native(c) => T::Currency::resolve(who, c).map_err(|c| c.into()), - Credit::Asset(c) => T::Assets::resolve(who, c).map_err(|c| c.into()), - } - } - - /// Removes `value` balance of `asset` from `who` account if possible. - fn withdraw( - asset: &T::MultiAssetId, - who: &T::AccountId, - value: T::Balance, - keep_alive: bool, - ) -> Result, DispatchError> { - let preservation = match keep_alive { - true => Preserve, - false => Expendable, - }; - match T::MultiAssetIdConverter::try_convert(asset) { - MultiAssetIdConversionResult::Converted(asset) => { - if preservation == Preserve { - // TODO drop the ensure! when this issue addressed - // https://github.com/paritytech/polkadot-sdk/issues/1698 - let free = - T::Assets::reducible_balance(asset.clone(), who, preservation, Polite); - ensure!(free >= value, TokenError::NotExpendable); - } - T::Assets::withdraw(asset, who, value, Exact, preservation, Polite) - .map(|c| c.into()) - }, - MultiAssetIdConversionResult::Native => { - if preservation == Preserve { - // TODO drop the ensure! when this issue addressed - // https://github.com/paritytech/polkadot-sdk/issues/1698 - let free = T::Currency::reducible_balance(who, preservation, Polite); - ensure!(free >= value, TokenError::NotExpendable); - } - T::Currency::withdraw(who, value, Exact, preservation, Polite).map(|c| c.into()) - }, - MultiAssetIdConversionResult::Unsupported(_) => - Err(Error::::UnsupportedAsset.into()), - } - } - /// Swap assets along the `path`, withdrawing from `sender` and depositing in `send_to`. /// /// Note: It's assumed that the provided `path` is valid. @@ -963,10 +857,10 @@ pub mod pallet { keep_alive: bool, ) -> Result<(), DispatchError> { let (asset_in, amount_in) = path.first().ok_or(Error::::InvalidPath)?; - let credit_in = Self::withdraw(asset_in, sender, *amount_in, keep_alive)?; + let credit_in = Self::withdraw(asset_in.clone(), sender, *amount_in, keep_alive)?; let credit_out = Self::credit_swap(credit_in, path).map_err(|(_, e)| e)?; - Self::resolve(send_to, credit_out).map_err(|_| Error::::BelowMinimum)?; + T::Assets::resolve(send_to, credit_out).map_err(|_| Error::::BelowMinimum)?; Ok(()) } @@ -983,24 +877,29 @@ pub mod pallet { /// only inside a transactional storage context and an Err result must imply a storage /// rollback. fn credit_swap( - credit_in: Credit, + credit_in: CreditOf, path: &BalancePath, - ) -> Result, (Credit, DispatchError)> { - let resolve_path = || -> Result, DispatchError> { + ) -> Result, (CreditOf, DispatchError)> { + let resolve_path = || -> Result, DispatchError> { for pos in 0..=path.len() { if let Some([(asset1, _), (asset2, amount_out)]) = path.get(pos..=pos + 1) { - let pool_from = Self::get_pool_account(&Self::get_pool_id( - asset1.clone(), - asset2.clone(), - )); + let pool_from = T::PoolLocator::pool_address(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; + if let Some((asset3, _)) = path.get(pos + 2) { - let pool_to = Self::get_pool_account(&Self::get_pool_id( + let pool_to = T::PoolLocator::pool_address(&asset2, &asset3) + .map_err(|_| Error::::InvalidAssetPair)?; + + T::Assets::transfer( asset2.clone(), - asset3.clone(), - )); - Self::transfer(asset2, &pool_from, &pool_to, *amount_out, true)?; + &pool_from, + &pool_to, + *amount_out, + Preserve, + )?; } else { - let credit_out = Self::withdraw(asset2, &pool_from, *amount_out, true)?; + let credit_out = + Self::withdraw(asset2.clone(), &pool_from, *amount_out, true)?; return Ok(credit_out) } } @@ -1014,79 +913,57 @@ pub mod pallet { }; let pool_to = if let Some([(asset1, _), (asset2, _)]) = path.get(0..2) { - Self::get_pool_account(&Self::get_pool_id(asset1.clone(), asset2.clone())) + match T::PoolLocator::pool_address(&asset1, &asset2) { + Ok(address) => address, + Err(_) => return Err((credit_in, Error::::InvalidAssetPair.into())), + } } else { return Err((credit_in, Error::::InvalidPath.into())) }; - Self::resolve(&pool_to, credit_in).map_err(|c| (c, Error::::BelowMinimum.into()))?; + T::Assets::resolve(&pool_to, credit_in) + .map_err(|c| (c, Error::::BelowMinimum.into()))?; Ok(credit_out) } - /// The account ID of the pool. - /// - /// This actually does computation. If you need to keep using it, then make sure you cache - /// the value and only call this once. - pub fn get_pool_account(pool_id: &PoolIdOf) -> T::AccountId { - let encoded_pool_id = sp_io::hashing::blake2_256(&Encode::encode(pool_id)[..]); - - Decode::decode(&mut TrailingZeroInput::new(encoded_pool_id.as_ref())) - .expect("infinite length input; no invalid inputs for type; qed") + /// Removes `value` balance of `asset` from `who` account if possible. + fn withdraw( + asset: T::AssetKind, + who: &T::AccountId, + value: T::Balance, + keep_alive: bool, + ) -> Result, DispatchError> { + let preservation = match keep_alive { + true => Preserve, + false => Expendable, + }; + if preservation == Preserve { + // TODO drop the ensure! when this issue addressed + // https://github.com/paritytech/polkadot-sdk/issues/1698 + let free = T::Assets::reducible_balance(asset.clone(), who, preservation, Polite); + ensure!(free >= value, TokenError::NotExpendable); + } + T::Assets::withdraw(asset, who, value, Exact, preservation, Polite) } /// Get the `owner`'s balance of `asset`, which could be the chain's native asset or another /// fungible. Returns a value in the form of an `Balance`. - fn get_balance( - owner: &T::AccountId, - asset: &T::MultiAssetId, - ) -> Result> { - match T::MultiAssetIdConverter::try_convert(asset) { - MultiAssetIdConversionResult::Converted(asset_id) => Ok( - <::Assets>::reducible_balance(asset_id, owner, Expendable, Polite), - ), - MultiAssetIdConversionResult::Native => - Ok(<::Currency>::reducible_balance(owner, Expendable, Polite)), - MultiAssetIdConversionResult::Unsupported(_) => - Err(Error::::UnsupportedAsset.into()), - } - } - - /// Returns a pool id constructed from 2 assets. - /// 1. Native asset should be lower than the other asset ids. - /// 2. Two native or two non-native assets are compared by their `Ord` implementation. - /// - /// We expect deterministic order, so (asset1, asset2) or (asset2, asset1) returns the same - /// result. - pub fn get_pool_id(asset1: T::MultiAssetId, asset2: T::MultiAssetId) -> PoolIdOf { - match ( - T::MultiAssetIdConverter::is_native(&asset1), - T::MultiAssetIdConverter::is_native(&asset2), - ) { - (true, false) => return (asset1, asset2), - (false, true) => return (asset2, asset1), - _ => { - // else we want to be deterministic based on `Ord` implementation - if asset1 <= asset2 { - (asset1, asset2) - } else { - (asset2, asset1) - } - }, - } + fn get_balance(owner: &T::AccountId, asset: T::AssetKind) -> T::Balance { + T::Assets::reducible_balance(asset, owner, Expendable, Polite) } /// Returns the balance of each asset in the pool. /// The tuple result is in the order requested (not necessarily the same as pool order). pub fn get_reserves( - asset1: &T::MultiAssetId, - asset2: &T::MultiAssetId, + asset1: T::AssetKind, + asset2: T::AssetKind, ) -> Result<(T::Balance, T::Balance), Error> { - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + let pool_account = T::PoolLocator::pool_address(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; - let balance1 = Self::get_balance(&pool_account, asset1)?; - let balance2 = Self::get_balance(&pool_account, asset2)?; + let balance1 = Self::get_balance(&pool_account, asset1); + let balance2 = Self::get_balance(&pool_account, asset2); if balance1.is_zero() || balance2.is_zero() { Err(Error::::PoolNotFound)?; @@ -1098,7 +975,7 @@ pub mod pallet { /// Leading to an amount at the end of a `path`, get the required amounts in. pub(crate) fn balance_path_from_amount_out( amount_out: T::Balance, - path: Vec, + path: Vec, ) -> Result, DispatchError> { let mut balance_path: BalancePath = Vec::with_capacity(path.len()); let mut amount_in: T::Balance = amount_out; @@ -1112,7 +989,7 @@ pub mod pallet { break }, }; - let (reserve_in, reserve_out) = Self::get_reserves(asset1, &asset2)?; + let (reserve_in, reserve_out) = Self::get_reserves(asset1.clone(), asset2.clone())?; balance_path.push((asset2, amount_in)); amount_in = Self::get_amount_in(&amount_in, &reserve_in, &reserve_out)?; } @@ -1124,7 +1001,7 @@ pub mod pallet { /// Following an amount into a `path`, get the corresponding amounts out. pub(crate) fn balance_path_from_amount_in( amount_in: T::Balance, - path: Vec, + path: Vec, ) -> Result, DispatchError> { let mut balance_path: BalancePath = Vec::with_capacity(path.len()); let mut amount_out: T::Balance = amount_in; @@ -1138,7 +1015,7 @@ pub mod pallet { break }, }; - let (reserve_in, reserve_out) = Self::get_reserves(&asset1, asset2)?; + let (reserve_in, reserve_out) = Self::get_reserves(asset1.clone(), asset2.clone())?; balance_path.push((asset1, amount_out)); amount_out = Self::get_amount_out(&amount_out, &reserve_in, &reserve_out)?; } @@ -1147,16 +1024,15 @@ pub mod pallet { /// Used by the RPC service to provide current prices. pub fn quote_price_exact_tokens_for_tokens( - asset1: T::MultiAssetId, - asset2: T::MultiAssetId, + asset1: T::AssetKind, + asset2: T::AssetKind, amount: T::Balance, include_fee: bool, ) -> Option { - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + let pool_account = T::PoolLocator::pool_address(&asset1, &asset2).ok()?; - let balance1 = Self::get_balance(&pool_account, &asset1).ok()?; - let balance2 = Self::get_balance(&pool_account, &asset2).ok()?; + let balance1 = Self::get_balance(&pool_account, asset1); + let balance2 = Self::get_balance(&pool_account, asset2); if !balance1.is_zero() { if include_fee { Self::get_amount_out(&amount, &balance1, &balance2).ok() @@ -1170,16 +1046,15 @@ pub mod pallet { /// Used by the RPC service to provide current prices. pub fn quote_price_tokens_for_exact_tokens( - asset1: T::MultiAssetId, - asset2: T::MultiAssetId, + asset1: T::AssetKind, + asset2: T::AssetKind, amount: T::Balance, include_fee: bool, ) -> Option { - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + let pool_account = T::PoolLocator::pool_address(&asset1, &asset2).ok()?; - let balance1 = Self::get_balance(&pool_account, &asset1).ok()?; - let balance2 = Self::get_balance(&pool_account, &asset2).ok()?; + let balance1 = Self::get_balance(&pool_account, asset1); + let balance2 = Self::get_balance(&pool_account, asset2); if !balance1.is_zero() { if include_fee { Self::get_amount_in(&amount, &balance1, &balance2).ok() @@ -1309,36 +1184,18 @@ pub mod pallet { result.try_into().map_err(|_| Error::::Overflow) } - /// Ensure that a `value` meets the minimum balance requirements of an `asset` class. - fn validate_minimal_amount(value: T::Balance, asset: &T::MultiAssetId) -> Result<(), ()> { - if T::MultiAssetIdConverter::is_native(asset) { - let ed = T::Currency::minimum_balance(); - ensure!( - T::HigherPrecisionBalance::from(value) >= T::HigherPrecisionBalance::from(ed), - () - ); - } else { - let MultiAssetIdConversionResult::Converted(asset_id) = - T::MultiAssetIdConverter::try_convert(asset) - else { - return Err(()) - }; - let minimal = T::Assets::minimum_balance(asset_id); - ensure!(value >= minimal, ()); - } - Ok(()) - } - /// Ensure that a path is valid. - fn validate_swap_path(path: &Vec) -> Result<(), DispatchError> { + fn validate_swap_path(path: &Vec) -> Result<(), DispatchError> { ensure!(path.len() >= 2, Error::::InvalidPath); ensure!(path.len() as u32 <= T::MaxSwapPathLength::get(), Error::::InvalidPath); // validate all the pools in the path are unique - let mut pools = BTreeSet::>::new(); + let mut pools = BTreeSet::::new(); for assets_pair in path.windows(2) { if let [asset1, asset2] = assets_pair { - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; + let new_element = pools.insert(pool_id); if !new_element { return Err(Error::::NonUniquePath.into()) @@ -1361,21 +1218,32 @@ pub mod pallet { sp_api::decl_runtime_apis! { /// This runtime api allows people to query the size of the liquidity pools /// and quote prices for swaps. - pub trait AssetConversionApi where + pub trait AssetConversionApi + where Balance: frame_support::traits::tokens::Balance + MaybeDisplay, - AssetId: Codec + AssetId: Codec, { /// Provides a quote for [`Pallet::swap_tokens_for_exact_tokens`]. /// /// Note that the price may have changed by the time the transaction is executed. /// (Use `amount_in_max` to control slippage.) - fn quote_price_tokens_for_exact_tokens(asset1: AssetId, asset2: AssetId, amount: Balance, include_fee: bool) -> Option; + fn quote_price_tokens_for_exact_tokens( + asset1: AssetId, + asset2: AssetId, + amount: Balance, + include_fee: bool, + ) -> Option; /// Provides a quote for [`Pallet::swap_exact_tokens_for_tokens`]. /// /// Note that the price may have changed by the time the transaction is executed. /// (Use `amount_out_min` to control slippage.) - fn quote_price_exact_tokens_for_tokens(asset1: AssetId, asset2: AssetId, amount: Balance, include_fee: bool) -> Option; + fn quote_price_exact_tokens_for_tokens( + asset1: AssetId, + asset2: AssetId, + amount: Balance, + include_fee: bool, + ) -> Option; /// Returns the size of the liquidity pool for the given asset pair. fn get_reserves(asset1: AssetId, asset2: AssetId) -> Option<(Balance, Balance)>; diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 35d5182a3db29..05de1b3d90f7b 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -19,12 +19,17 @@ use super::*; use crate as pallet_asset_conversion; - use frame_support::{ construct_runtime, instances::{Instance1, Instance2}, ord_parameter_types, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64}, + traits::{ + tokens::{ + fungible::{NativeFromLeft, NativeOrWithId, UnionOf}, + imbalance::ResolveAssetTo, + }, + AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, + }, PalletId, }; use frame_system::{EnsureSigned, EnsureSignedBy}; @@ -34,6 +39,7 @@ use sp_runtime::{ traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, BuildStorage, }; +use sp_std::default::Default; type Block = frame_system::mocking::MockBlock; @@ -142,39 +148,39 @@ impl pallet_assets::Config for Test { parameter_types! { pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); - pub storage AllowMultiAssetPools: bool = true; - pub storage LiquidityWithdrawalFee: Permill = Permill::from_percent(0); // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero + pub const Native: NativeOrWithId = NativeOrWithId::Native; + pub storage LiquidityWithdrawalFee: Permill = Permill::from_percent(0); } ord_parameter_types! { pub const AssetConversionOrigin: u128 = AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); } +pub type NativeAndAssets = UnionOf, u128>; +pub type AscendingLocator = Ascending>; +pub type WithFirstAssetLocator = WithFirstAsset>; + impl Config for Test { type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type AssetId = u32; + type Balance = ::Balance; + type HigherPrecisionBalance = sp_core::U256; + type AssetKind = NativeOrWithId; + type Assets = NativeAndAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = Chain; type PoolAssetId = u32; - type Assets = Assets; type PoolAssets = PoolAssets; + type PoolSetupFee = ConstU128<100>; // should be more or equal to the existential deposit + type PoolSetupFeeAsset = Native; + type PoolSetupFeeTarget = ResolveAssetTo; type PalletId = AssetConversionPalletId; type WeightInfo = (); type LPFee = ConstU32<3>; // means 0.3% - type PoolSetupFee = ConstU128<100>; // should be more or equal to the existential deposit - type PoolSetupFeeReceiver = AssetConversionOrigin; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; - type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; type MintMinLiquidity = ConstU128<100>; // 100 is good enough when the main currency has 12 decimals. - - type Balance = ::Balance; - type HigherPrecisionBalance = sp_core::U256; - - type MultiAssetId = NativeOrAssetId; - type MultiAssetIdConverter = NativeOrAssetIdConverter; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + type BenchmarkHelper = NativeOrWithIdFactory; } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index 7f59b8f9b8042..f4f88e3e0695d 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -24,7 +24,7 @@ pub trait Swap { /// Measure units of the asset classes for swapping. type Balance: Balance; /// Kind of assets that are going to be swapped. - type MultiAssetId; + type AssetKind; /// Returns the upper limit on the length of the swap path. fn max_path_len() -> u32; @@ -41,7 +41,7 @@ pub trait Swap { /// This operation is expected to be atomic. fn swap_exact_tokens_for_tokens( sender: AccountId, - path: Vec, + path: Vec, amount_in: Self::Balance, amount_out_min: Option, send_to: AccountId, @@ -60,7 +60,7 @@ pub trait Swap { /// This operation is expected to be atomic. fn swap_tokens_for_exact_tokens( sender: AccountId, - path: Vec, + path: Vec, amount_out: Self::Balance, amount_in_max: Option, send_to: AccountId, @@ -73,7 +73,7 @@ pub trait SwapCredit { /// Measure units of the asset classes for swapping. type Balance: Balance; /// Kind of assets that are going to be swapped. - type MultiAssetId; + type AssetKind; /// Credit implying a negative imbalance in the system that can be placed into an account or /// alter the total supply. type Credit; @@ -90,7 +90,7 @@ pub trait SwapCredit { /// /// This operation is expected to be atomic. fn swap_exact_tokens_for_tokens( - path: Vec, + path: Vec, credit_in: Self::Credit, amount_out_min: Option, ) -> Result; @@ -106,7 +106,7 @@ pub trait SwapCredit { /// /// This operation is expected to be atomic. fn swap_tokens_for_exact_tokens( - path: Vec, + path: Vec, credit_in: Self::Credit, amount_out: Self::Balance, ) -> Result<(Self::Credit, Self::Credit), (Self::Credit, DispatchError)>; @@ -114,7 +114,7 @@ pub trait SwapCredit { impl Swap for Pallet { type Balance = T::Balance; - type MultiAssetId = T::MultiAssetId; + type AssetKind = T::AssetKind; fn max_path_len() -> u32 { T::MaxSwapPathLength::get() @@ -122,7 +122,7 @@ impl Swap for Pallet { fn swap_exact_tokens_for_tokens( sender: T::AccountId, - path: Vec, + path: Vec, amount_in: Self::Balance, amount_out_min: Option, send_to: T::AccountId, @@ -143,7 +143,7 @@ impl Swap for Pallet { fn swap_tokens_for_exact_tokens( sender: T::AccountId, - path: Vec, + path: Vec, amount_out: Self::Balance, amount_in_max: Option, send_to: T::AccountId, @@ -165,18 +165,19 @@ impl Swap for Pallet { impl SwapCredit for Pallet { type Balance = T::Balance; - type MultiAssetId = T::MultiAssetId; - type Credit = Credit; + type AssetKind = T::AssetKind; + type Credit = CreditOf; fn max_path_len() -> u32 { T::MaxSwapPathLength::get() } fn swap_exact_tokens_for_tokens( - path: Vec, + path: Vec, credit_in: Self::Credit, amount_out_min: Option, ) -> Result { + let credit_asset = credit_in.asset(); with_transaction(|| -> TransactionOutcome> { let res = Self::do_swap_exact_credit_tokens_for_tokens(path, credit_in, amount_out_min); match &res { @@ -187,14 +188,15 @@ impl SwapCredit for Pallet { } }) // should never map an error since `with_transaction` above never returns it. - .map_err(|_| (Self::Credit::native_zero(), DispatchError::Corruption))? + .map_err(|_| (Self::Credit::zero(credit_asset), DispatchError::Corruption))? } fn swap_tokens_for_exact_tokens( - path: Vec, + path: Vec, credit_in: Self::Credit, amount_out: Self::Balance, ) -> Result<(Self::Credit, Self::Credit), (Self::Credit, DispatchError)> { + let credit_asset = credit_in.asset(); with_transaction(|| -> TransactionOutcome> { let res = Self::do_swap_credit_tokens_for_exact_tokens(path, credit_in, amount_out); match &res { @@ -205,6 +207,6 @@ impl SwapCredit for Pallet { } }) // should never map an error since `with_transaction` above never returns it. - .map_err(|_| (Self::Credit::native_zero(), DispatchError::Corruption))? + .map_err(|_| (Self::Credit::zero(credit_asset), DispatchError::Corruption))? } } diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index db6aca01dece7..5700622d426be 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -19,7 +19,13 @@ use crate::{mock::*, *}; use frame_support::{ assert_noop, assert_ok, assert_storage_noop, instances::Instance1, - traits::{fungible, fungibles, fungibles::InspectEnumerable, Get}, + traits::{ + fungible, + fungible::{Inspect as FungibleInspect, NativeOrWithId}, + fungibles, + fungibles::{Inspect, InspectEnumerable}, + Get, + }, }; use sp_arithmetic::Permill; use sp_runtime::{DispatchError, TokenError}; @@ -42,18 +48,14 @@ fn events() -> Vec> { result } -fn pools() -> Vec> { +fn pools() -> Vec<::PoolId> { let mut s: Vec<_> = Pools::::iter().map(|x| x.0).collect(); s.sort(); s } -fn assets() -> Vec> { - // if the storage would be public: - // let mut s: Vec<_> = pallet_assets::pallet::Asset::::iter().map(|x| x.0).collect(); - let mut s: Vec<_> = <::Assets>::asset_ids() - .map(|id| NativeOrAssetId::Asset(id)) - .collect(); +fn assets() -> Vec> { + let mut s: Vec<_> = Assets::asset_ids().map(|id| NativeOrWithId::WithId(id)).collect(); s.sort(); s } @@ -64,40 +66,71 @@ fn pool_assets() -> Vec { s } -fn create_tokens(owner: u128, tokens: Vec>) { +fn create_tokens(owner: u128, tokens: Vec>) { create_tokens_with_ed(owner, tokens, 1) } -fn create_tokens_with_ed(owner: u128, tokens: Vec>, ed: u128) { +fn create_tokens_with_ed(owner: u128, tokens: Vec>, ed: u128) { for token_id in tokens { - let MultiAssetIdConversionResult::Converted(asset_id) = - NativeOrAssetIdConverter::try_convert(&token_id) - else { - unreachable!("invalid token") + let asset_id = match token_id { + NativeOrWithId::WithId(id) => id, + _ => unreachable!("invalid token"), }; assert_ok!(Assets::force_create(RuntimeOrigin::root(), asset_id, owner, false, ed)); } } -fn balance(owner: u128, token_id: NativeOrAssetId) -> u128 { - match token_id { - NativeOrAssetId::Native => <::Currency>::free_balance(owner), - NativeOrAssetId::Asset(token_id) => <::Assets>::balance(token_id, owner), - } +fn balance(owner: u128, token_id: NativeOrWithId) -> u128 { + <::Assets>::balance(token_id, &owner) } fn pool_balance(owner: u128, token_id: u32) -> u128 { - <::PoolAssets>::balance(token_id, owner) + <::PoolAssets>::balance(token_id, &owner) } -fn get_ed() -> u128 { - <::Currency>::minimum_balance() +fn get_native_ed() -> u128 { + <::Assets>::minimum_balance(NativeOrWithId::Native) } macro_rules! bvec { - ($( $x:ident ),*) => { + ($($x:expr),+ $(,)?) => ( vec![$( Box::new( $x ), )*] - } + ) +} + +#[test] +fn validate_with_first_asset_pool_id_locator() { + new_test_ext().execute_with(|| { + use NativeOrWithId::{Native, WithId}; + assert_eq!(WithFirstAssetLocator::pool_id(&Native, &WithId(2)), Ok((Native, WithId(2)))); + assert_eq!(WithFirstAssetLocator::pool_id(&WithId(2), &Native), Ok((Native, WithId(2)))); + assert_noop!(WithFirstAssetLocator::pool_id(&Native, &Native), ()); + assert_noop!(WithFirstAssetLocator::pool_id(&WithId(2), &WithId(1)), ()); + }); +} + +#[test] +fn validate_ascending_pool_id_locator() { + new_test_ext().execute_with(|| { + use NativeOrWithId::{Native, WithId}; + assert_eq!(AscendingLocator::pool_id(&Native, &WithId(2)), Ok((Native, WithId(2)))); + assert_eq!(AscendingLocator::pool_id(&WithId(2), &Native), Ok((Native, WithId(2)))); + assert_eq!(AscendingLocator::pool_id(&WithId(2), &WithId(1)), Ok((WithId(1), WithId(2)))); + assert_eq!(AscendingLocator::pool_id(&Native, &Native), Err(())); + assert_eq!(AscendingLocator::pool_id(&WithId(1), &WithId(1)), Err(())); + }); +} + +#[test] +fn validate_native_or_with_id_sorting() { + new_test_ext().execute_with(|| { + use NativeOrWithId::{Native, WithId}; + assert!(WithId(2) > WithId(1)); + assert!(WithId(1) <= WithId(1)); + assert_eq!(WithId(1), WithId(1)); + assert_eq!(Native::, Native::); + assert!(Native < WithId(1)); + }); } #[test] @@ -106,10 +139,11 @@ fn check_pool_accounts_dont_collide() { let mut map = HashSet::new(); for i in 0..1_000_000u32 { - let account = AssetConversion::get_pool_account(&( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(i), - )); + let account: u128 = ::PoolLocator::address(&( + NativeOrWithId::Native, + NativeOrWithId::WithId(i), + )) + .unwrap(); if map.contains(&account) { panic!("Collision at {}", i); } @@ -141,79 +175,67 @@ fn can_create_pool() { let asset_account_deposit: u128 = >::AssetAccountDeposit::get(); let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let pool_id = (token_1, token_2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = (token_1.clone(), token_2.clone()); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); let lp_token = AssetConversion::get_next_pool_asset_id(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 1000)); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_1) + Box::new(token_2.clone()), + Box::new(token_1.clone()) )); let setup_fee = <::PoolSetupFee as Get<::Balance>>::get(); - let pool_account = <::PoolSetupFeeReceiver as Get>::get(); + let pool_account = AssetConversionOrigin::get(); assert_eq!( - balance(user, NativeOrAssetId::Native), + balance(user, NativeOrWithId::Native), 1000 - (setup_fee + asset_account_deposit) ); - assert_eq!(balance(pool_account, NativeOrAssetId::Native), setup_fee); + assert_eq!(balance(pool_account, NativeOrWithId::Native), setup_fee); assert_eq!(lp_token + 1, AssetConversion::get_next_pool_asset_id()); assert_eq!( events(), [Event::::PoolCreated { creator: user, - pool_id, - pool_account: AssetConversion::get_pool_account(&pool_id), + pool_id: pool_id.clone(), + pool_account: ::PoolLocator::address(&pool_id).unwrap(), lp_token }] ); assert_eq!(pools(), vec![pool_id]); - assert_eq!(assets(), vec![token_2]); + assert_eq!(assets(), vec![token_2.clone()]); assert_eq!(pool_assets(), vec![lp_token]); assert_noop!( AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_1) + Box::new(token_1.clone()), + Box::new(token_1.clone()) ), - Error::::EqualAssets + Error::::InvalidAssetPair ); assert_noop!( AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_2) + Box::new(token_2.clone()), + Box::new(token_2.clone()) ), - Error::::EqualAssets + Error::::InvalidAssetPair ); - // validate we can create Asset(1)/Asset(2) pool - let token_1 = NativeOrAssetId::Asset(1); - create_tokens(user, vec![token_1]); + // validate we cannot create WithId(1)/WithId(2) pool + let token_1 = NativeOrWithId::WithId(1); + create_tokens(user, vec![token_1.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - - // validate we can force the first asset to be the Native currency only - AllowMultiAssetPools::set(&false); - let token_1 = NativeOrAssetId::Asset(3); - assert_noop!( - AssetConversion::create_pool( - RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) - ), - Error::::PoolMustContainNativeCurrency - ); }); } @@ -221,16 +243,16 @@ fn can_create_pool() { fn create_same_pool_twice_should_fail() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); let lp_token = AssetConversion::get_next_pool_asset_id(); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_1) + Box::new(token_2.clone()), + Box::new(token_1.clone()) )); let expected_free = lp_token + 1; assert_eq!(expected_free, AssetConversion::get_next_pool_asset_id()); @@ -238,8 +260,8 @@ fn create_same_pool_twice_should_fail() { assert_noop!( AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_1) + Box::new(token_2.clone()), + Box::new(token_1.clone()) ), Error::::PoolExists ); @@ -249,8 +271,8 @@ fn create_same_pool_twice_should_fail() { assert_noop!( AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) ), Error::::PoolExists ); @@ -262,19 +284,19 @@ fn create_same_pool_twice_should_fail() { fn different_pools_should_have_different_lp_tokens() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let token_3 = NativeOrAssetId::Asset(3); - let pool_id_1_2 = (token_1, token_2); - let pool_id_1_3 = (token_1, token_3); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let token_3 = NativeOrWithId::WithId(3); + let pool_id_1_2 = (token_1.clone(), token_2.clone()); + let pool_id_1_3 = (token_1.clone(), token_3.clone()); - create_tokens(user, vec![token_2, token_3]); + create_tokens(user, vec![token_2.clone(), token_3.clone()]); let lp_token2_1 = AssetConversion::get_next_pool_asset_id(); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_1) + Box::new(token_2.clone()), + Box::new(token_1.clone()) )); let lp_token3_1 = AssetConversion::get_next_pool_asset_id(); @@ -282,23 +304,23 @@ fn different_pools_should_have_different_lp_tokens() { events(), [Event::::PoolCreated { creator: user, - pool_id: pool_id_1_2, - pool_account: AssetConversion::get_pool_account(&pool_id_1_2), + pool_id: pool_id_1_2.clone(), + pool_account: ::PoolLocator::address(&pool_id_1_2).unwrap(), lp_token: lp_token2_1 }] ); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_3), - Box::new(token_1) + Box::new(token_3.clone()), + Box::new(token_1.clone()) )); assert_eq!( events(), [Event::::PoolCreated { creator: user, - pool_id: pool_id_1_3, - pool_account: AssetConversion::get_pool_account(&pool_id_1_3), + pool_id: pool_id_1_3.clone(), + pool_account: ::PoolLocator::address(&pool_id_1_3).unwrap(), lp_token: lp_token3_1, }] ); @@ -311,33 +333,33 @@ fn different_pools_should_have_different_lp_tokens() { fn can_add_liquidity() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let token_3 = NativeOrAssetId::Asset(3); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let token_3 = NativeOrWithId::WithId(3); - create_tokens(user, vec![token_2, token_3]); + create_tokens(user, vec![token_2.clone(), token_3.clone()]); let lp_token1 = AssetConversion::get_next_pool_asset_id(); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); let lp_token2 = AssetConversion::get_next_pool_asset_id(); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_3) + Box::new(token_1.clone()), + Box::new(token_3.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 * 2 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 3, user, 1000)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 10, 10000, @@ -345,28 +367,28 @@ fn can_add_liquidity() { user, )); - let pool_id = (token_1, token_2); + let pool_id = (token_1.clone(), token_2.clone()); assert!(events().contains(&Event::::LiquidityAdded { who: user, mint_to: user, - pool_id, + pool_id: pool_id.clone(), amount1_provided: 10000, amount2_provided: 10, lp_token: lp_token1, lp_token_minted: 216, })); - let pallet_account = AssetConversion::get_pool_account(&pool_id); - assert_eq!(balance(pallet_account, token_1), 10000); - assert_eq!(balance(pallet_account, token_2), 10); - assert_eq!(balance(user, token_1), 10000 + ed); - assert_eq!(balance(user, token_2), 1000 - 10); + let pallet_account = ::PoolLocator::address(&pool_id).unwrap(); + assert_eq!(balance(pallet_account, token_1.clone()), 10000); + assert_eq!(balance(pallet_account, token_2.clone()), 10); + assert_eq!(balance(user, token_1.clone()), 10000 + ed); + assert_eq!(balance(user, token_2.clone()), 1000 - 10); assert_eq!(pool_balance(user, lp_token1), 216); // try to pass the non-native - native assets, the result should be the same assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_3), - Box::new(token_1), + Box::new(token_3.clone()), + Box::new(token_1.clone()), 10, 10000, 10, @@ -374,21 +396,21 @@ fn can_add_liquidity() { user, )); - let pool_id = (token_1, token_3); + let pool_id = (token_1.clone(), token_3.clone()); assert!(events().contains(&Event::::LiquidityAdded { who: user, mint_to: user, - pool_id, - amount1_provided: 10000, - amount2_provided: 10, + pool_id: pool_id.clone(), + amount1_provided: 10, + amount2_provided: 10000, lp_token: lp_token2, lp_token_minted: 216, })); - let pallet_account = AssetConversion::get_pool_account(&pool_id); - assert_eq!(balance(pallet_account, token_1), 10000); - assert_eq!(balance(pallet_account, token_3), 10); - assert_eq!(balance(user, token_1), ed); - assert_eq!(balance(user, token_3), 1000 - 10); + let pallet_account = ::PoolLocator::address(&pool_id).unwrap(); + assert_eq!(balance(pallet_account, token_1.clone()), 10000); + assert_eq!(balance(pallet_account, token_3.clone()), 10); + assert_eq!(balance(user, token_1.clone()), ed); + assert_eq!(balance(user, token_3.clone()), 1000 - 10); assert_eq!(pool_balance(user, lp_token2), 216); }); } @@ -397,14 +419,14 @@ fn can_add_liquidity() { fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 1000)); @@ -413,8 +435,8 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { assert_noop!( AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 1, 1, 1, @@ -427,9 +449,9 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { assert_noop!( AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), - get_ed(), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + get_native_ed(), 1, 1, 1, @@ -444,35 +466,37 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { fn add_tiny_liquidity_directly_to_pool_address() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let token_3 = NativeOrAssetId::Asset(3); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let token_3 = NativeOrWithId::WithId(3); - create_tokens(user, vec![token_2, token_3]); + create_tokens(user, vec![token_2.clone(), token_3.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_3) + Box::new(token_1.clone()), + Box::new(token_3.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 * 2 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 3, user, 1000)); - // check we're still able to add the liquidity even when the pool already has some token_1 - let pallet_account = AssetConversion::get_pool_account(&(token_1, token_2)); + // check we're still able to add the liquidity even when the pool already has some + // token_1.clone() + let pallet_account = + ::PoolLocator::address(&(token_1.clone(), token_2.clone())).unwrap(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), pallet_account, 1000)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 10, 10000, @@ -480,13 +504,14 @@ fn add_tiny_liquidity_directly_to_pool_address() { user, )); - // check the same but for token_3 (non-native token) - let pallet_account = AssetConversion::get_pool_account(&(token_1, token_3)); + // check the same but for token_3.clone() (non-native token) + let pallet_account = + ::PoolLocator::address(&(token_1.clone(), token_3.clone())).unwrap(); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, pallet_account, 1)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_3), + Box::new(token_1.clone()), + Box::new(token_3.clone()), 10000, 10, 10000, @@ -500,16 +525,16 @@ fn add_tiny_liquidity_directly_to_pool_address() { fn can_remove_liquidity() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let pool_id = (token_1, token_2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = (token_1.clone(), token_2.clone()); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); let lp_token = AssetConversion::get_next_pool_asset_id(); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); let ed_token_1 = >::minimum_balance(); @@ -517,14 +542,14 @@ fn can_remove_liquidity() { assert_ok!(Balances::force_set_balance( RuntimeOrigin::root(), user, - 10000000000 + ed_token_1 + 10000000000 + ed_token_1.clone() )); - assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 100000 + ed_token_2)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 100000 + ed_token_2.clone())); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 1000000000, 100000, 1000000000, @@ -537,8 +562,8 @@ fn can_remove_liquidity() { assert_ok!(AssetConversion::remove_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), total_lp_received, 0, 0, @@ -548,7 +573,7 @@ fn can_remove_liquidity() { assert!(events().contains(&Event::::LiquidityRemoved { who: user, withdraw_to: user, - pool_id, + pool_id: pool_id.clone(), amount1: 899991000, amount2: 89999, lp_token, @@ -556,13 +581,16 @@ fn can_remove_liquidity() { withdrawal_fee: ::LiquidityWithdrawalFee::get() })); - let pool_account = AssetConversion::get_pool_account(&pool_id); - assert_eq!(balance(pool_account, token_1), 100009000); - assert_eq!(balance(pool_account, token_2), 10001); + let pool_account = ::PoolLocator::address(&pool_id).unwrap(); + assert_eq!(balance(pool_account, token_1.clone()), 100009000); + assert_eq!(balance(pool_account, token_2.clone()), 10001); assert_eq!(pool_balance(pool_account, lp_token), 100); - assert_eq!(balance(user, token_1), 10000000000 - 1000000000 + 899991000 + ed_token_1); - assert_eq!(balance(user, token_2), 89999 + ed_token_2); + assert_eq!( + balance(user, token_1.clone()), + 10000000000 - 1000000000 + 899991000 + ed_token_1.clone() + ); + assert_eq!(balance(user, token_2.clone()), 89999 + ed_token_2.clone()); assert_eq!(pool_balance(user, lp_token), 0); }); } @@ -571,24 +599,28 @@ fn can_remove_liquidity() { fn can_not_redeem_more_lp_tokens_than_were_minted() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); let lp_token = AssetConversion::get_next_pool_asset_id(); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + get_ed())); + assert_ok!(Balances::force_set_balance( + RuntimeOrigin::root(), + user, + 10000 + get_native_ed() + )); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 10, 10000, @@ -602,8 +634,8 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { assert_noop!( AssetConversion::remove_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 216 + 1, // Try and redeem 10 lp tokens while only 9 minted. 0, 0, @@ -618,14 +650,14 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { fn can_quote_price() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); @@ -633,8 +665,8 @@ fn can_quote_price() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 200, 1, @@ -644,8 +676,8 @@ fn can_quote_price() { assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 3000, false, ), @@ -654,8 +686,8 @@ fn can_quote_price() { // including fee so should get less out... assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 3000, true, ), @@ -665,8 +697,8 @@ fn can_quote_price() { // (if the above accidentally exchanged then it would not give same quote as before) assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 3000, false, ), @@ -675,8 +707,8 @@ fn can_quote_price() { // including fee so should get less out... assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 3000, true, ), @@ -686,8 +718,8 @@ fn can_quote_price() { // Check inverse: assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, 60, false, ), @@ -696,8 +728,8 @@ fn can_quote_price() { // including fee so should get less out... assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, 60, true, ), @@ -709,8 +741,8 @@ fn can_quote_price() { // assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 60, false, ), @@ -719,8 +751,8 @@ fn can_quote_price() { // including fee so should need to put more in... assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 60, true, ), @@ -730,8 +762,8 @@ fn can_quote_price() { // (if the above accidentally exchanged then it would not give same quote as before) assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 60, false, ), @@ -740,8 +772,8 @@ fn can_quote_price() { // including fee so should need to put more in... assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), 60, true, ), @@ -751,8 +783,8 @@ fn can_quote_price() { // Check inverse: assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, 3000, false, ), @@ -761,8 +793,8 @@ fn can_quote_price() { // including fee so should need to put more in... assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, 3000, true, ), @@ -776,14 +808,14 @@ fn can_quote_price() { assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, amount_in, false, ) .and_then(|amount| AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), amount, false, )), @@ -791,14 +823,14 @@ fn can_quote_price() { ); assert_eq!( AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), amount_in, false, ) .and_then(|amount| AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, amount, false, )), @@ -807,14 +839,14 @@ fn can_quote_price() { assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, amount_in, false, ) .and_then(|amount| AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), amount, false, )), @@ -822,14 +854,14 @@ fn can_quote_price() { ); assert_eq!( AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(2), + NativeOrWithId::Native, + NativeOrWithId::WithId(2), amount_in, false, ) .and_then(|amount| AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(2), - NativeOrAssetId::Native, + NativeOrWithId::WithId(2), + NativeOrWithId::Native, amount, false, )), @@ -843,14 +875,14 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); @@ -858,8 +890,8 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 200, 1, @@ -870,23 +902,28 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { let amount = 1; let quoted_price = 49; assert_eq!( - AssetConversion::quote_price_exact_tokens_for_tokens(token_2, token_1, amount, true,), + AssetConversion::quote_price_exact_tokens_for_tokens( + token_2.clone(), + token_1.clone(), + amount, + true, + ), Some(quoted_price) ); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, amount)); let prior_dot_balance = 20000; - assert_eq!(prior_dot_balance, balance(user2, token_1)); + assert_eq!(prior_dot_balance, balance(user2, token_1.clone())); assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user2), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], amount, 1, user2, false, )); - assert_eq!(prior_dot_balance + quoted_price, balance(user2, token_1)); + assert_eq!(prior_dot_balance + quoted_price, balance(user2, token_1.clone())); }); } @@ -895,14 +932,14 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 100000)); @@ -910,8 +947,8 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 200, 1, @@ -922,26 +959,31 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { let amount = 49; let quoted_price = 1; assert_eq!( - AssetConversion::quote_price_tokens_for_exact_tokens(token_2, token_1, amount, true,), + AssetConversion::quote_price_tokens_for_exact_tokens( + token_2.clone(), + token_1.clone(), + amount, + true, + ), Some(quoted_price) ); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user2, amount)); let prior_dot_balance = 20000; - assert_eq!(prior_dot_balance, balance(user2, token_1)); + assert_eq!(prior_dot_balance, balance(user2, token_1.clone())); let prior_asset_balance = 49; - assert_eq!(prior_asset_balance, balance(user2, token_2)); + assert_eq!(prior_asset_balance, balance(user2, token_2.clone())); assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user2), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], amount, 1, user2, false, )); - assert_eq!(prior_dot_balance + amount, balance(user2, token_1)); - assert_eq!(prior_asset_balance - quoted_price, balance(user2, token_2)); + assert_eq!(prior_dot_balance + amount, balance(user2, token_1.clone())); + assert_eq!(prior_asset_balance - quoted_price, balance(user2, token_2.clone())); }); } @@ -949,18 +991,18 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { fn can_swap_with_native() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let pool_id = (token_1, token_2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = (token_1.clone(), token_2.clone()); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -969,8 +1011,8 @@ fn can_swap_with_native() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -986,18 +1028,18 @@ fn can_swap_with_native() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], input_amount, 1, user, false, )); - let pallet_account = AssetConversion::get_pool_account(&pool_id); - assert_eq!(balance(user, token_1), expect_receive + ed); - assert_eq!(balance(user, token_2), 1000 - liquidity2 - input_amount); - assert_eq!(balance(pallet_account, token_1), liquidity1 - expect_receive); - assert_eq!(balance(pallet_account, token_2), liquidity2 + input_amount); + let pallet_account = ::PoolLocator::address(&pool_id).unwrap(); + assert_eq!(balance(user, token_1.clone()), expect_receive + ed); + assert_eq!(balance(user, token_2.clone()), 1000 - liquidity2 - input_amount); + assert_eq!(balance(pallet_account, token_1.clone()), liquidity1 - expect_receive); + assert_eq!(balance(pallet_account, token_2.clone()), liquidity2 + input_amount); }); } @@ -1005,13 +1047,13 @@ fn can_swap_with_native() { fn can_swap_with_realistic_values() { new_test_ext().execute_with(|| { let user = 1; - let dot = NativeOrAssetId::Native; - let usd = NativeOrAssetId::Asset(2); - create_tokens(user, vec![usd]); + let dot = NativeOrWithId::Native; + let usd = NativeOrWithId::WithId(2); + create_tokens(user, vec![usd.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(dot), - Box::new(usd) + Box::new(dot.clone()), + Box::new(usd.clone()) )); const UNIT: u128 = 1_000_000_000; @@ -1023,8 +1065,8 @@ fn can_swap_with_realistic_values() { let liquidity_usd = 1_000_000 * UNIT; assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(dot), - Box::new(usd), + Box::new(dot.clone()), + Box::new(usd.clone()), liquidity_dot, liquidity_usd, 1, @@ -1036,7 +1078,7 @@ fn can_swap_with_realistic_values() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![usd, dot], + bvec![usd.clone(), dot.clone()], input_amount, 1, user, @@ -1057,21 +1099,21 @@ fn can_swap_with_realistic_values() { fn can_not_swap_in_pool_with_no_liquidity_added_yet() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); // Check can't swap an empty pool assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], 10, 1, user, @@ -1086,19 +1128,19 @@ fn can_not_swap_in_pool_with_no_liquidity_added_yet() { fn check_no_panic_when_try_swap_close_to_empty_pool() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let pool_id = (token_1, token_2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = (token_1.clone(), token_2.clone()); let lp_token = AssetConversion::get_next_pool_asset_id(); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -1107,8 +1149,8 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -1120,21 +1162,21 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert!(events().contains(&Event::::LiquidityAdded { who: user, mint_to: user, - pool_id, + pool_id: pool_id.clone(), amount1_provided: liquidity1, amount2_provided: liquidity2, lp_token, lp_token_minted, })); - let pallet_account = AssetConversion::get_pool_account(&pool_id); - assert_eq!(balance(pallet_account, token_1), liquidity1); - assert_eq!(balance(pallet_account, token_2), liquidity2); + let pallet_account = ::PoolLocator::address(&pool_id).unwrap(); + assert_eq!(balance(pallet_account, token_1.clone()), liquidity1); + assert_eq!(balance(pallet_account, token_2.clone()), liquidity2); assert_ok!(AssetConversion::remove_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), lp_token_minted, 1, 1, @@ -1143,14 +1185,14 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { // Now, the pool should exist but be almost empty. // Let's try and drain it. - assert_eq!(balance(pallet_account, token_1), 708); - assert_eq!(balance(pallet_account, token_2), 15); + assert_eq!(balance(pallet_account, token_1.clone()), 708); + assert_eq!(balance(pallet_account, token_2.clone()), 15); // validate the reserve should always stay above the ED assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], 708 - ed + 1, // amount_out 500, // amount_in_max user, @@ -1161,15 +1203,15 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], 608, // amount_out 500, // amount_in_max user, false, )); - let token_1_left = balance(pallet_account, token_1); - let token_2_left = balance(pallet_account, token_2); + let token_1_left = balance(pallet_account, token_1.clone()); + let token_2_left = balance(pallet_account, token_2.clone()); assert_eq!(token_1_left, 708 - 608); // The price for the last tokens should be very high @@ -1183,7 +1225,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], token_1_left - 1, // amount_out 1000, // amount_in_max user, @@ -1196,7 +1238,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], token_1_left, // amount_out 1000, // amount_in_max user, @@ -1211,17 +1253,21 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { fn swap_should_not_work_if_too_much_slippage() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + get_ed())); + assert_ok!(Balances::force_set_balance( + RuntimeOrigin::root(), + user, + 10000 + get_native_ed() + )); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); let liquidity1 = 10000; @@ -1229,8 +1275,8 @@ fn swap_should_not_work_if_too_much_slippage() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -1243,7 +1289,7 @@ fn swap_should_not_work_if_too_much_slippage() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], exchange_amount, // amount_in 4000, // amount_out_min user, @@ -1258,32 +1304,32 @@ fn swap_should_not_work_if_too_much_slippage() { fn can_swap_tokens_for_exact_tokens() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let pool_id = (token_1, token_2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = (token_1.clone(), token_2.clone()); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); - let pallet_account = AssetConversion::get_pool_account(&pool_id); - let before1 = balance(pallet_account, token_1) + balance(user, token_1); - let before2 = balance(pallet_account, token_2) + balance(user, token_2); + let pallet_account = ::PoolLocator::address(&pool_id).unwrap(); + let before1 = balance(pallet_account, token_1.clone()) + balance(user, token_1.clone()); + let before2 = balance(pallet_account, token_2.clone()) + balance(user, token_2.clone()); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -1298,23 +1344,29 @@ fn can_swap_tokens_for_exact_tokens() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![token_1.clone(), token_2.clone()], exchange_out, // amount_out 3500, // amount_in_max user, true, )); - assert_eq!(balance(user, token_1), 10000 + ed - expect_in); - assert_eq!(balance(user, token_2), 1000 - liquidity2 + exchange_out); - assert_eq!(balance(pallet_account, token_1), liquidity1 + expect_in); - assert_eq!(balance(pallet_account, token_2), liquidity2 - exchange_out); + assert_eq!(balance(user, token_1.clone()), 10000 + ed - expect_in); + assert_eq!(balance(user, token_2.clone()), 1000 - liquidity2 + exchange_out); + assert_eq!(balance(pallet_account, token_1.clone()), liquidity1 + expect_in); + assert_eq!(balance(pallet_account, token_2.clone()), liquidity2 - exchange_out); // check invariants: // native and asset totals should be preserved. - assert_eq!(before1, balance(pallet_account, token_1) + balance(user, token_1)); - assert_eq!(before2, balance(pallet_account, token_2) + balance(user, token_2)); + assert_eq!( + before1, + balance(pallet_account, token_1.clone()) + balance(user, token_1.clone()) + ); + assert_eq!( + before2, + balance(pallet_account, token_2.clone()) + balance(user, token_2.clone()) + ); }); } @@ -1323,38 +1375,40 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let pool_id = (token_1, token_2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = (token_1.clone(), token_2.clone()); let lp_token = AssetConversion::get_next_pool_asset_id(); - create_tokens(user2, vec![token_2]); + create_tokens(user2, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); let base1 = 10000; let base2 = 1000; assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, base1 + ed)); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, base1 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user2, base2)); - let pallet_account = AssetConversion::get_pool_account(&pool_id); - let before1 = - balance(pallet_account, token_1) + balance(user, token_1) + balance(user2, token_1); - let before2 = - balance(pallet_account, token_2) + balance(user, token_2) + balance(user2, token_2); + let pallet_account = ::PoolLocator::address(&pool_id).unwrap(); + let before1 = balance(pallet_account, token_1.clone()) + + balance(user, token_1.clone()) + + balance(user2, token_1.clone()); + let before2 = balance(pallet_account, token_2.clone()) + + balance(user, token_2.clone()) + + balance(user2, token_2.clone()); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -1362,8 +1416,8 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { user2, )); - assert_eq!(balance(user, token_1), base1 + ed); - assert_eq!(balance(user, token_2), 0); + assert_eq!(balance(user, token_1.clone()), base1 + ed); + assert_eq!(balance(user, token_2.clone()), 0); let exchange_out = 50; let expect_in = AssetConversion::get_amount_in(&exchange_out, &liquidity1, &liquidity2) @@ -1372,28 +1426,32 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![token_1.clone(), token_2.clone()], exchange_out, // amount_out 3500, // amount_in_max user, true, )); - assert_eq!(balance(user, token_1), base1 + ed - expect_in); - assert_eq!(balance(pallet_account, token_1), liquidity1 + expect_in); - assert_eq!(balance(user, token_2), exchange_out); - assert_eq!(balance(pallet_account, token_2), liquidity2 - exchange_out); + assert_eq!(balance(user, token_1.clone()), base1 + ed - expect_in); + assert_eq!(balance(pallet_account, token_1.clone()), liquidity1 + expect_in); + assert_eq!(balance(user, token_2.clone()), exchange_out); + assert_eq!(balance(pallet_account, token_2.clone()), liquidity2 - exchange_out); // check invariants: // native and asset totals should be preserved. assert_eq!( before1, - balance(pallet_account, token_1) + balance(user, token_1) + balance(user2, token_1) + balance(pallet_account, token_1.clone()) + + balance(user, token_1.clone()) + + balance(user2, token_1.clone()) ); assert_eq!( before2, - balance(pallet_account, token_2) + balance(user, token_2) + balance(user2, token_2) + balance(pallet_account, token_2.clone()) + + balance(user, token_2.clone()) + + balance(user2, token_2.clone()) ); let lp_token_minted = pool_balance(user2, lp_token); @@ -1401,8 +1459,8 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(AssetConversion::remove_liquidity( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), lp_token_minted, 0, 0, @@ -1416,17 +1474,17 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user2, vec![token_2]); + create_tokens(user2, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 101)); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 10000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user2, 1000)); @@ -1434,8 +1492,8 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 200, 1, @@ -1446,7 +1504,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![token_1.clone(), token_2.clone()], 1, // amount_out 101, // amount_in_max user, @@ -1458,7 +1516,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![token_1.clone(), token_2.clone()], 51, // amount_in 1, // amount_out_min user, @@ -1470,7 +1528,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], 51, // amount_out 2, // amount_in_max user, @@ -1482,7 +1540,7 @@ fn swap_when_existential_deposit_would_cause_reaping_but_keep_alive_set() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![token_2.clone(), token_1.clone()], 2, // amount_in 1, // amount_out_min user, @@ -1498,29 +1556,29 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let token_3 = NativeOrAssetId::Asset(3); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let token_3 = NativeOrWithId::WithId(3); let ed_assets = 100; - create_tokens_with_ed(user2, vec![token_2, token_3], ed_assets); + create_tokens_with_ed(user2, vec![token_2.clone(), token_3.clone()], ed_assets); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_3) + Box::new(token_1.clone()), + Box::new(token_3.clone()) )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user2), - Box::new(token_2), - Box::new(token_3) + Box::new(token_2.clone()), + Box::new(token_3.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user2, 20000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user2), 2, user2, 400 + ed_assets)); @@ -1531,8 +1589,8 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 200, 1, @@ -1542,8 +1600,8 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - Box::new(token_1), - Box::new(token_3), + Box::new(token_1.clone()), + Box::new(token_3.clone()), 200, 10000, 1, @@ -1553,8 +1611,8 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user2), - Box::new(token_2), - Box::new(token_3), + Box::new(token_2.clone()), + Box::new(token_3.clone()), 200, 10000, 1, @@ -1566,7 +1624,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![token_1.clone(), token_2.clone()], 110, // amount_out 20000, // amount_in_max user, @@ -1579,7 +1637,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![token_1.clone(), token_2.clone()], 15000, // amount_in 110, // amount_out_min user, @@ -1592,7 +1650,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_3, token_1], + bvec![token_3.clone(), token_1.clone()], 110, // amount_out 20000, // amount_in_max user, @@ -1605,7 +1663,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_3, token_1], + bvec![token_3.clone(), token_1.clone()], 15000, // amount_in 110, // amount_out_min user, @@ -1617,7 +1675,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { // causes an account removal for native token 1 locate in the middle of a swap path let amount_in = AssetConversion::balance_path_from_amount_out( 110, - vec![token_3, token_1].try_into().unwrap(), + vec![token_3.clone(), token_1.clone()].try_into().unwrap(), ) .unwrap() .first() @@ -1627,7 +1685,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_3, token_1, token_2], + bvec![token_3.clone(), token_1.clone(), token_2.clone()], amount_in, // amount_in 1, // amount_out_min user, @@ -1639,7 +1697,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { // causes an account removal for asset token 2 locate in the middle of a swap path let amount_in = AssetConversion::balance_path_from_amount_out( 110, - vec![token_1, token_2].try_into().unwrap(), + vec![token_1.clone(), token_2.clone()].try_into().unwrap(), ) .unwrap() .first() @@ -1649,7 +1707,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3], + bvec![token_1.clone(), token_2.clone(), token_3.clone()], amount_in, // amount_in 1, // amount_out_min user, @@ -1664,17 +1722,21 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + get_ed())); + assert_ok!(Balances::force_set_balance( + RuntimeOrigin::root(), + user, + 20000 + get_native_ed() + )); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); let liquidity1 = 10000; @@ -1682,8 +1744,8 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -1696,7 +1758,7 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { assert_noop!( AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![token_1.clone(), token_2.clone()], exchange_out, // amount_out 50, // amount_in_max just greater than slippage. user, @@ -1711,23 +1773,23 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { fn swap_exact_tokens_for_tokens_in_multi_hops() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let token_3 = NativeOrAssetId::Asset(3); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let token_3 = NativeOrWithId::WithId(3); - create_tokens(user, vec![token_2, token_3]); + create_tokens(user, vec![token_2.clone(), token_3.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_3) + Box::new(token_2.clone()), + Box::new(token_3.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); let base1 = 10000; let base2 = 10000; assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, base1 * 2 + ed)); @@ -1740,8 +1802,8 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -1750,8 +1812,8 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { )); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_3), + Box::new(token_2.clone()), + Box::new(token_3.clone()), liquidity2, liquidity3, 1, @@ -1770,7 +1832,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1], + bvec![token_1.clone()], input_amount, 80, user, @@ -1782,7 +1844,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3, token_2], + bvec![token_1.clone(), token_2.clone(), token_3.clone(), token_2.clone()], input_amount, 80, user, @@ -1793,24 +1855,24 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3], + bvec![token_1.clone(), token_2.clone(), token_3.clone()], input_amount, // amount_in 80, // amount_out_min user, true, )); - let pool_id1 = (token_1, token_2); - let pool_id2 = (token_2, token_3); - let pallet_account1 = AssetConversion::get_pool_account(&pool_id1); - let pallet_account2 = AssetConversion::get_pool_account(&pool_id2); + let pool_id1 = (token_1.clone(), token_2.clone()); + let pool_id2 = (token_2.clone(), token_3.clone()); + let pallet_account1 = ::PoolLocator::address(&pool_id1).unwrap(); + let pallet_account2 = ::PoolLocator::address(&pool_id2).unwrap(); - assert_eq!(balance(user, token_1), base1 + ed - input_amount); - assert_eq!(balance(pallet_account1, token_1), liquidity1 + input_amount); - assert_eq!(balance(pallet_account1, token_2), liquidity2 - expect_out2); - assert_eq!(balance(pallet_account2, token_2), liquidity2 + expect_out2); - assert_eq!(balance(pallet_account2, token_3), liquidity3 - expect_out3); - assert_eq!(balance(user, token_3), 10000 - liquidity3 + expect_out3); + assert_eq!(balance(user, token_1.clone()), base1 + ed - input_amount); + assert_eq!(balance(pallet_account1, token_1.clone()), liquidity1 + input_amount); + assert_eq!(balance(pallet_account1, token_2.clone()), liquidity2 - expect_out2); + assert_eq!(balance(pallet_account2, token_2.clone()), liquidity2 + expect_out2); + assert_eq!(balance(pallet_account2, token_3.clone()), liquidity3 - expect_out3); + assert_eq!(balance(user, token_3.clone()), 10000 - liquidity3 + expect_out3); }); } @@ -1818,23 +1880,23 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { fn swap_tokens_for_exact_tokens_in_multi_hops() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let token_3 = NativeOrAssetId::Asset(3); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let token_3 = NativeOrWithId::WithId(3); - create_tokens(user, vec![token_2, token_3]); + create_tokens(user, vec![token_2.clone(), token_3.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_3) + Box::new(token_2.clone()), + Box::new(token_3.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); let base1 = 10000; let base2 = 10000; assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, base1 * 2 + ed)); @@ -1847,8 +1909,8 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -1857,8 +1919,8 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { )); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_2), - Box::new(token_3), + Box::new(token_2.clone()), + Box::new(token_3.clone()), liquidity2, liquidity3, 1, @@ -1876,24 +1938,24 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { assert_ok!(AssetConversion::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2, token_3], + bvec![token_1.clone(), token_2.clone(), token_3.clone()], exchange_out3, // amount_out 1000, // amount_in_max user, true, )); - let pool_id1 = (token_1, token_2); - let pool_id2 = (token_2, token_3); - let pallet_account1 = AssetConversion::get_pool_account(&pool_id1); - let pallet_account2 = AssetConversion::get_pool_account(&pool_id2); + let pool_id1 = (token_1.clone(), token_2.clone()); + let pool_id2 = (token_2.clone(), token_3.clone()); + let pallet_account1 = ::PoolLocator::address(&pool_id1).unwrap(); + let pallet_account2 = ::PoolLocator::address(&pool_id2).unwrap(); - assert_eq!(balance(user, token_1), base1 + ed - expect_in1); - assert_eq!(balance(pallet_account1, token_1), liquidity1 + expect_in1); - assert_eq!(balance(pallet_account1, token_2), liquidity2 - expect_in2); - assert_eq!(balance(pallet_account2, token_2), liquidity2 + expect_in2); - assert_eq!(balance(pallet_account2, token_3), liquidity3 - exchange_out3); - assert_eq!(balance(user, token_3), 10000 - liquidity3 + exchange_out3); + assert_eq!(balance(user, token_1.clone()), base1 + ed - expect_in1); + assert_eq!(balance(pallet_account1, token_1.clone()), liquidity1 + expect_in1); + assert_eq!(balance(pallet_account1, token_2.clone()), liquidity2 - expect_in2); + assert_eq!(balance(pallet_account2, token_2.clone()), liquidity2 + expect_in2); + assert_eq!(balance(pallet_account2, token_3.clone()), liquidity3 - exchange_out3); + assert_eq!(balance(user, token_3.clone()), 10000 - liquidity3 + exchange_out3); }); } @@ -1901,10 +1963,10 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { fn can_not_swap_same_asset() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Asset(1); - let token_2 = NativeOrAssetId::Native; + let token_1 = NativeOrWithId::WithId(1); + let token_2 = NativeOrWithId::Native; - create_tokens(user, vec![token_1]); + create_tokens(user, vec![token_1.clone()]); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 1, user, 1000)); let liquidity1 = 1000; @@ -1912,60 +1974,44 @@ fn can_not_swap_same_asset() { assert_noop!( AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_1), + Box::new(token_1.clone()), + Box::new(token_1.clone()), liquidity1, liquidity2, 1, 1, user, ), - Error::::PoolNotFound + Error::::InvalidAssetPair ); let exchange_amount = 10; assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_1], + bvec![token_1.clone(), token_1.clone()], exchange_amount, 1, user, true, ), - Error::::PoolNotFound + Error::::InvalidAssetPair ); assert_noop!( AssetConversion::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_2], + bvec![token_2.clone(), token_2.clone()], exchange_amount, 1, user, true, ), - Error::::PoolNotFound + Error::::InvalidAssetPair ); }); } -#[test] -fn validate_pool_id_sorting() { - new_test_ext().execute_with(|| { - use crate::NativeOrAssetId::{Asset, Native}; - assert_eq!(AssetConversion::get_pool_id(Native, Asset(2)), (Native, Asset(2))); - assert_eq!(AssetConversion::get_pool_id(Asset(2), Native), (Native, Asset(2))); - assert_eq!(AssetConversion::get_pool_id(Native, Native), (Native, Native)); - assert_eq!(AssetConversion::get_pool_id(Asset(2), Asset(1)), (Asset(1), Asset(2))); - assert!(Asset(2) > Asset(1)); - assert!(Asset(1) <= Asset(1)); - assert_eq!(Asset(1), Asset(1)); - assert_eq!(Native::, Native::); - assert!(Native < Asset(1)); - }); -} - #[test] fn cannot_block_pool_creation() { new_test_ext().execute_with(|| { @@ -1974,16 +2020,16 @@ fn cannot_block_pool_creation() { // User 2 is the attacker let attacker = 2; - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), attacker, 10000 + ed)); - // The target pool the user wants to create is Native <=> Asset(2) - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + // The target pool the user wants to create is Native <=> WithId(2) + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); // Attacker computes the still non-existing pool account for the target pair let pool_account = - AssetConversion::get_pool_account(&AssetConversion::get_pool_id(token_2, token_1)); + ::PoolLocator::address(&(token_1.clone(), token_2.clone())).unwrap(); // And transfers the ED to that pool account assert_ok!(Balances::transfer_allow_death( RuntimeOrigin::signed(attacker), @@ -1992,21 +2038,21 @@ fn cannot_block_pool_creation() { )); // Then, the attacker creates 14 tokens and sends one of each to the pool account for i in 10..25 { - create_tokens(attacker, vec![NativeOrAssetId::Asset(i)]); + create_tokens(attacker, vec![NativeOrWithId::WithId(i)]); assert_ok!(Assets::mint(RuntimeOrigin::signed(attacker), i, attacker, 1000)); assert_ok!(Assets::transfer(RuntimeOrigin::signed(attacker), i, pool_account, 1)); } // User can still create the pool - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - // User has to transfer one Asset(2) token to the pool account (otherwise add_liquidity will - // fail with `AssetTwoDepositDidNotMeetMinimum`) + // User has to transfer one WithId(2) token to the pool account (otherwise add_liquidity + // will fail with `AssetTwoDepositDidNotMeetMinimum`) assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 10000)); assert_ok!(Assets::transfer(RuntimeOrigin::signed(user), 2, pool_account, 1)); @@ -2014,8 +2060,8 @@ fn cannot_block_pool_creation() { // add_liquidity shouldn't fail because of the number of consumers assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), 10000, 100, 10000, @@ -2030,24 +2076,24 @@ fn swap_transactional() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); - let token_3 = NativeOrAssetId::Asset(3); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let token_3 = NativeOrWithId::WithId(3); let asset_ed = 150; - create_tokens_with_ed(user, vec![token_2, token_3], asset_ed); + create_tokens_with_ed(user, vec![token_2.clone(), token_3.clone()], asset_ed); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_3) + Box::new(token_1.clone()), + Box::new(token_3.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 3, user, 1000)); @@ -2061,8 +2107,8 @@ fn swap_transactional() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -2072,8 +2118,8 @@ fn swap_transactional() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_3), + Box::new(token_1.clone()), + Box::new(token_3.clone()), liquidity1, liquidity2, 1, @@ -2081,8 +2127,10 @@ fn swap_transactional() { user, )); - let pool_1 = AssetConversion::get_pool_account(&(token_1, token_2)); - let pool_2 = AssetConversion::get_pool_account(&(token_1, token_3)); + let pool_1 = + ::PoolLocator::address(&(token_1.clone(), token_2.clone())).unwrap(); + let pool_2 = + ::PoolLocator::address(&(token_1.clone(), token_3.clone())).unwrap(); assert_eq!(Balances::balance(&pool_1), liquidity1); assert_eq!(Assets::balance(2, &pool_1), liquidity2); @@ -2093,7 +2141,7 @@ fn swap_transactional() { let expected_out = liquidity2 - asset_ed + 1; let amount_in = AssetConversion::balance_path_from_amount_out( expected_out, - vec![token_2, token_1, token_3].try_into().unwrap(), + vec![token_2.clone(), token_1.clone(), token_3.clone()].try_into().unwrap(), ) .unwrap() .first() @@ -2101,42 +2149,42 @@ fn swap_transactional() { .unwrap(); // swap credit with `swap_tokens_for_exact_tokens` transactional - let credit_in = Assets::issue(2, amount_in); - let credit_in_err_expected = Assets::issue(2, amount_in); + let credit_in = NativeAndAssets::issue(token_2.clone(), amount_in); + let credit_in_err_expected = NativeAndAssets::issue(token_2.clone(), amount_in); // avoiding drop of any credit, to assert any storage mutation from an actual call. let error; assert_storage_noop!( error = >::swap_tokens_for_exact_tokens( - vec![token_2, token_1, token_3], - credit_in.into(), + vec![token_2.clone(), token_1.clone(), token_3.clone()], + credit_in, expected_out, ) .unwrap_err() ); - assert_eq!(error, (credit_in_err_expected.into(), TokenError::NotExpendable.into())); + assert_eq!(error, (credit_in_err_expected, TokenError::NotExpendable.into())); // swap credit with `swap_exact_tokens_for_tokens` transactional - let credit_in = Assets::issue(2, amount_in); - let credit_in_err_expected = Assets::issue(2, amount_in); + let credit_in = NativeAndAssets::issue(token_2.clone(), amount_in); + let credit_in_err_expected = NativeAndAssets::issue(token_2.clone(), amount_in); // avoiding drop of any credit, to assert any storage mutation from an actual call. let error; assert_storage_noop!( error = >::swap_exact_tokens_for_tokens( - vec![token_2, token_1, token_3], - credit_in.into(), + vec![token_2.clone(), token_1.clone(), token_3.clone()], + credit_in, Some(expected_out), ) .unwrap_err() ); - assert_eq!(error, (credit_in_err_expected.into(), TokenError::NotExpendable.into())); + assert_eq!(error, (credit_in_err_expected, TokenError::NotExpendable.into())); // swap with `swap_exact_tokens_for_tokens` transactional assert_noop!( >::swap_exact_tokens_for_tokens( user2, - vec![token_2, token_1, token_3], - amount_in.into(), - Some(expected_out.into()), + vec![token_2.clone(), token_1.clone(), token_3.clone()], + amount_in, + Some(expected_out), user2, true, ), @@ -2147,9 +2195,9 @@ fn swap_transactional() { assert_noop!( >::swap_tokens_for_exact_tokens( user2, - vec![token_2, token_1, token_3], - expected_out.into(), - Some(amount_in.into()), + vec![token_2.clone(), token_1.clone(), token_3.clone()], + expected_out, + Some(amount_in), user2, true, ), @@ -2167,17 +2215,17 @@ fn swap_transactional() { fn swap_credit_returns_change() { new_test_ext().execute_with(|| { let user = 1; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -2186,8 +2234,8 @@ fn swap_credit_returns_change() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -2195,21 +2243,22 @@ fn swap_credit_returns_change() { user, )); - let expected_change = Balances::issue(100); - let expected_credit_out = Assets::issue(2, 20); + let expected_change = NativeAndAssets::issue(token_1.clone(), 100); + let expected_credit_out = NativeAndAssets::issue(token_2.clone(), 20); let amount_in_max = AssetConversion::get_amount_in(&expected_credit_out.peek(), &liquidity1, &liquidity2) .unwrap(); - let credit_in = Balances::issue(amount_in_max + expected_change.peek()); + let credit_in = + NativeAndAssets::issue(token_1.clone(), amount_in_max + expected_change.peek()); assert_ok!( >::swap_tokens_for_exact_tokens( - vec![token_1, token_2], - credit_in.into(), + vec![token_1.clone(), token_2.clone()], + credit_in, expected_credit_out.peek(), ), - (expected_credit_out.into(), expected_change.into()) + (expected_credit_out, expected_change) ); }) } @@ -2219,17 +2268,17 @@ fn swap_credit_insufficient_amount_bounds() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -2241,8 +2290,8 @@ fn swap_credit_insufficient_amount_bounds() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -2255,11 +2304,11 @@ fn swap_credit_insufficient_amount_bounds() { let amount_in = AssetConversion::get_amount_in(&(amount_out_min - 1), &liquidity2, &liquidity1) .unwrap(); - let credit_in = Balances::issue(amount_in); - let expected_credit_in = Balances::issue(amount_in); + let credit_in = NativeAndAssets::issue(token_1.clone(), amount_in); + let expected_credit_in = NativeAndAssets::issue(token_1.clone(), amount_in); let error = >::swap_exact_tokens_for_tokens( - vec![token_1, token_2], - credit_in.into(), + vec![token_1.clone(), token_2.clone()], + credit_in, Some(amount_out_min), ) .unwrap_err(); @@ -2272,17 +2321,17 @@ fn swap_credit_insufficient_amount_bounds() { let amount_out = 20; let amount_in_max = AssetConversion::get_amount_in(&(amount_out - 1), &liquidity2, &liquidity1).unwrap(); - let credit_in = Balances::issue(amount_in_max); - let expected_credit_in = Balances::issue(amount_in_max); + let credit_in = NativeAndAssets::issue(token_1.clone(), amount_in_max); + let expected_credit_in = NativeAndAssets::issue(token_1.clone(), amount_in_max); let error = >::swap_tokens_for_exact_tokens( - vec![token_1, token_2], - credit_in.into(), + vec![token_1.clone(), token_2.clone()], + credit_in, amount_out, ) .unwrap_err(); assert_eq!( error, - (expected_credit_in.into(), Error::::ProvidedMaximumNotSufficientForSwap.into()) + (expected_credit_in, Error::::ProvidedMaximumNotSufficientForSwap.into()) ); }) } @@ -2292,17 +2341,17 @@ fn swap_credit_zero_amount() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -2314,8 +2363,8 @@ fn swap_credit_zero_amount() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -2324,10 +2373,10 @@ fn swap_credit_zero_amount() { )); // swap with zero credit fails for `swap_exact_tokens_for_tokens` - let credit_in = Credit::native_zero(); - let expected_credit_in = Credit::native_zero(); + let credit_in = CreditOf::::zero(token_1.clone()); + let expected_credit_in = CreditOf::::zero(token_1.clone()); let error = >::swap_exact_tokens_for_tokens( - vec![token_1, token_2], + vec![token_1.clone(), token_2.clone()], credit_in, None, ) @@ -2335,10 +2384,10 @@ fn swap_credit_zero_amount() { assert_eq!(error, (expected_credit_in, Error::::ZeroAmount.into())); // swap with zero credit fails for `swap_tokens_for_exact_tokens` - let credit_in = Credit::native_zero(); - let expected_credit_in = Credit::native_zero(); + let credit_in = CreditOf::::zero(token_1.clone()); + let expected_credit_in = CreditOf::::zero(token_1.clone()); let error = >::swap_tokens_for_exact_tokens( - vec![token_1, token_2], + vec![token_1.clone(), token_2.clone()], credit_in, 10, ) @@ -2346,26 +2395,26 @@ fn swap_credit_zero_amount() { assert_eq!(error, (expected_credit_in, Error::::ZeroAmount.into())); // swap with zero amount_out_min fails for `swap_exact_tokens_for_tokens` - let credit_in = Balances::issue(10); - let expected_credit_in = Balances::issue(10); + let credit_in = NativeAndAssets::issue(token_1.clone(), 10); + let expected_credit_in = NativeAndAssets::issue(token_1.clone(), 10); let error = >::swap_exact_tokens_for_tokens( - vec![token_1, token_2], - credit_in.into(), + vec![token_1.clone(), token_2.clone()], + credit_in, Some(0), ) .unwrap_err(); - assert_eq!(error, (expected_credit_in.into(), Error::::ZeroAmount.into())); + assert_eq!(error, (expected_credit_in, Error::::ZeroAmount.into())); // swap with zero amount_out fails with `swap_tokens_for_exact_tokens` fails - let credit_in = Balances::issue(10); - let expected_credit_in = Balances::issue(10); + let credit_in = NativeAndAssets::issue(token_1.clone(), 10); + let expected_credit_in = NativeAndAssets::issue(token_1.clone(), 10); let error = >::swap_tokens_for_exact_tokens( - vec![token_1, token_2], - credit_in.into(), + vec![token_1.clone(), token_2.clone()], + credit_in, 0, ) .unwrap_err(); - assert_eq!(error, (expected_credit_in.into(), Error::::ZeroAmount.into())); + assert_eq!(error, (expected_credit_in, Error::::ZeroAmount.into())); }); } @@ -2374,17 +2423,17 @@ fn swap_credit_invalid_path() { new_test_ext().execute_with(|| { let user = 1; let user2 = 2; - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(2); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); - create_tokens(user, vec![token_2]); + create_tokens(user, vec![token_2.clone()]); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); - let ed = get_ed(); + let ed = get_native_ed(); assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 20000 + ed)); assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); @@ -2396,8 +2445,8 @@ fn swap_credit_invalid_path() { assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), - Box::new(token_1), - Box::new(token_2), + Box::new(token_1.clone()), + Box::new(token_2.clone()), liquidity1, liquidity2, 1, @@ -2406,47 +2455,44 @@ fn swap_credit_invalid_path() { )); // swap with credit_in.asset different from path[0] asset fails - let credit_in = Balances::issue(10); - let expected_credit_in = Balances::issue(10); + let credit_in = NativeAndAssets::issue(token_1.clone(), 10); + let expected_credit_in = NativeAndAssets::issue(token_1.clone(), 10); let error = >::swap_exact_tokens_for_tokens( - vec![token_2, token_1], - credit_in.into(), + vec![token_2.clone(), token_1.clone()], + credit_in, None, ) .unwrap_err(); - assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + assert_eq!(error, (expected_credit_in, Error::::InvalidPath.into())); // swap with credit_in.asset different from path[0] asset fails - let credit_in = Assets::issue(2, 10); - let expected_credit_in = Assets::issue(2, 10); + let credit_in = NativeAndAssets::issue(token_2.clone(), 10); + let expected_credit_in = NativeAndAssets::issue(token_2.clone(), 10); let error = >::swap_tokens_for_exact_tokens( - vec![token_1, token_2], - credit_in.into(), + vec![token_1.clone(), token_2.clone()], + credit_in, 10, ) .unwrap_err(); - assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + assert_eq!(error, (expected_credit_in, Error::::InvalidPath.into())); // swap with path.len < 2 fails - let credit_in = Balances::issue(10); - let expected_credit_in = Balances::issue(10); + let credit_in = NativeAndAssets::issue(token_1.clone(), 10); + let expected_credit_in = NativeAndAssets::issue(token_1.clone(), 10); let error = >::swap_exact_tokens_for_tokens( - vec![token_2], - credit_in.into(), + vec![token_2.clone()], + credit_in, None, ) .unwrap_err(); - assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + assert_eq!(error, (expected_credit_in, Error::::InvalidPath.into())); // swap with path.len < 2 fails - let credit_in = Assets::issue(2, 10); - let expected_credit_in = Assets::issue(2, 10); - let error = >::swap_tokens_for_exact_tokens( - vec![], - credit_in.into(), - 10, - ) - .unwrap_err(); - assert_eq!(error, (expected_credit_in.into(), Error::::InvalidPath.into())); + let credit_in = NativeAndAssets::issue(token_2.clone(), 10); + let expected_credit_in = NativeAndAssets::issue(token_2.clone(), 10); + let error = + >::swap_tokens_for_exact_tokens(vec![], credit_in, 10) + .unwrap_err(); + assert_eq!(error, (expected_credit_in, Error::::InvalidPath.into())); }); } diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index d5ad8f590653c..049a028be9ca7 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -16,16 +16,9 @@ // limitations under the License. use super::*; - use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_std::{cmp::Ordering, marker::PhantomData}; - -/// Pool ID. -/// -/// The pool's `AccountId` is derived from this type. Any changes to the type may necessitate a -/// migration. -pub(super) type PoolIdOf = (::MultiAssetId, ::MultiAssetId); +use sp_std::marker::PhantomData; /// Represents a swap path with associated asset amounts indicating how much of the asset needs to /// be deposited to get the following asset's amount withdrawn (this is inclusive of fees). @@ -35,7 +28,10 @@ pub(super) type PoolIdOf = (::MultiAssetId, ::Multi /// 1. `asset(asset1, amount_in)` take from `user` and move to the pool(asset1, asset2); /// 2. `asset(asset2, amount_out2)` transfer from pool(asset1, asset2) to pool(asset2, asset3); /// 3. `asset(asset3, amount_out3)` move from pool(asset2, asset3) to `user`. -pub(super) type BalancePath = Vec<(::MultiAssetId, ::Balance)>; +pub(super) type BalancePath = Vec<(::AssetKind, ::Balance)>; + +/// Credit of [Config::Assets]. +pub type CreditOf = Credit<::AccountId, ::Assets>; /// Stores the lp_token asset id a particular pool has been assigned. #[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)] @@ -44,214 +40,94 @@ pub struct PoolInfo { pub lp_token: PoolAssetId, } -/// A trait that converts between a MultiAssetId and either the native currency or an AssetId. -pub trait MultiAssetIdConverter { - /// Returns the MultiAssetId representing the native currency of the chain. - fn get_native() -> MultiAssetId; - - /// Returns true if the given MultiAssetId is the native currency. - fn is_native(asset: &MultiAssetId) -> bool; - - /// If it's not native, returns the AssetId for the given MultiAssetId. - fn try_convert(asset: &MultiAssetId) -> MultiAssetIdConversionResult; -} - -/// Result of `MultiAssetIdConverter::try_convert`. -#[cfg_attr(feature = "std", derive(PartialEq, Debug))] -pub enum MultiAssetIdConversionResult { - /// Input asset is successfully converted. Means that converted asset is supported. - Converted(AssetId), - /// Means that input asset is the chain's native asset, if it has one, so no conversion (see - /// `MultiAssetIdConverter::get_native`). - Native, - /// Means input asset is not supported for pool. - Unsupported(MultiAssetId), -} - -/// Benchmark Helper -#[cfg(feature = "runtime-benchmarks")] -pub trait BenchmarkHelper { - /// Returns an `AssetId` from a given integer. - fn asset_id(asset_id: u32) -> AssetId; - - /// Returns a `MultiAssetId` from a given integer. - fn multiasset_id(asset_id: u32) -> MultiAssetId; -} - -#[cfg(feature = "runtime-benchmarks")] -impl BenchmarkHelper for () -where - AssetId: From, - MultiAssetId: From, -{ - fn asset_id(asset_id: u32) -> AssetId { - asset_id.into() - } - - fn multiasset_id(asset_id: u32) -> MultiAssetId { - asset_id.into() +/// Provides means to resolve the `PoolId` and `AccountId` from a pair of assets. +/// +/// Resulting `PoolId` remains consistent whether the asset pair is presented as (asset1, asset2) +/// or (asset2, asset1). The derived `AccountId` may serve as an address for liquidity provider +/// tokens. +pub trait PoolLocator { + /// Retrieves the account address associated with a valid `PoolId`. + fn address(id: &PoolId) -> Result; + /// Identifies the `PoolId` for a given pair of assets. + /// + /// Returns an error if the asset pair isn't supported. + fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result; + /// Retrieves the account address associated with a given asset pair. + /// + /// Returns an error if the asset pair isn't supported. + fn pool_address(asset1: &AssetKind, asset2: &AssetKind) -> Result { + if let Ok(id) = Self::pool_id(asset1, asset2) { + Self::address(&id) + } else { + Err(()) + } } } -/// An implementation of MultiAssetId that can be either Native or an asset. -#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Copy, Debug)] -pub enum NativeOrAssetId +/// Pool locator that mandates the inclusion of the specified `FirstAsset` in every asset pair. +/// +/// The `PoolId` is represented as a tuple of `AssetKind`s with `FirstAsset` always positioned as +/// the first element. +pub struct WithFirstAsset( + PhantomData<(FirstAsset, AccountId, AssetKind)>, +); +impl PoolLocator + for WithFirstAsset where - AssetId: Ord, + AssetKind: PartialEq + Clone + Encode, + AccountId: Decode, + FirstAsset: Get, { - /// Native asset. For example, on the Polkadot Asset Hub this would be DOT. - #[default] - Native, - /// A non-native asset id. - Asset(AssetId), -} - -impl From for NativeOrAssetId { - fn from(asset: AssetId) -> Self { - Self::Asset(asset) - } -} - -impl Ord for NativeOrAssetId { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (Self::Native, Self::Native) => Ordering::Equal, - (Self::Native, Self::Asset(_)) => Ordering::Less, - (Self::Asset(_), Self::Native) => Ordering::Greater, - (Self::Asset(id1), Self::Asset(id2)) => ::cmp(id1, id2), + fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { + let first = FirstAsset::get(); + match true { + _ if asset1 == asset2 => Err(()), + _ if first == *asset1 => Ok((first, asset2.clone())), + _ if first == *asset2 => Ok((first, asset1.clone())), + _ => Err(()), } } -} -impl PartialOrd for NativeOrAssetId { - fn partial_cmp(&self, other: &Self) -> Option { - Some(::cmp(self, other)) - } -} -impl PartialEq for NativeOrAssetId { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal + fn address(id: &(AssetKind, AssetKind)) -> Result { + let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); + Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| ()) } } -impl Eq for NativeOrAssetId {} - -/// Converts between a MultiAssetId and an AssetId (or the native currency). -pub struct NativeOrAssetIdConverter { - _phantom: PhantomData, -} -impl MultiAssetIdConverter, AssetId> - for NativeOrAssetIdConverter +/// Pool locator where the `PoolId` is a tuple of `AssetKind`s arranged in ascending order. +pub struct Ascending(PhantomData<(AccountId, AssetKind)>); +impl PoolLocator + for Ascending +where + AssetKind: PartialOrd + Clone + Encode, + AccountId: Decode, { - fn get_native() -> NativeOrAssetId { - NativeOrAssetId::Native - } - - fn is_native(asset: &NativeOrAssetId) -> bool { - *asset == Self::get_native() - } - - fn try_convert( - asset: &NativeOrAssetId, - ) -> MultiAssetIdConversionResult, AssetId> { - match asset { - NativeOrAssetId::Asset(asset) => MultiAssetIdConversionResult::Converted(asset.clone()), - NativeOrAssetId::Native => MultiAssetIdConversionResult::Native, - } - } -} - -/// Credit of [Config::Currency]. -/// -/// Implies a negative imbalance in the system that can be placed into an account or alter the total -/// supply. -pub type NativeCredit = - CreditFungible<::AccountId, ::Currency>; - -/// Credit (aka negative imbalance) of [Config::Assets]. -/// -/// Implies a negative imbalance in the system that can be placed into an account or alter the total -/// supply. -pub type AssetCredit = - CreditFungibles<::AccountId, ::Assets>; - -/// Credit that can be either [`NativeCredit`] or [`AssetCredit`]. -/// -/// Implies a negative imbalance in the system that can be placed into an account or alter the total -/// supply. -#[derive(RuntimeDebug, Eq, PartialEq)] -pub enum Credit { - /// Native credit. - Native(NativeCredit), - /// Asset credit. - Asset(AssetCredit), -} - -impl From> for Credit { - fn from(value: NativeCredit) -> Self { - Credit::Native(value) - } -} - -impl From> for Credit { - fn from(value: AssetCredit) -> Self { - Credit::Asset(value) - } -} - -impl TryInto> for Credit { - type Error = (); - fn try_into(self) -> Result, ()> { - match self { - Credit::Native(c) => Ok(c), + fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { + match true { + _ if asset1 > asset2 => Ok((asset2.clone(), asset1.clone())), + _ if asset1 < asset2 => Ok((asset1.clone(), asset2.clone())), _ => Err(()), } } -} - -impl TryInto> for Credit { - type Error = (); - fn try_into(self) -> Result, ()> { - match self { - Credit::Asset(c) => Ok(c), - _ => Err(()), - } + fn address(id: &(AssetKind, AssetKind)) -> Result { + let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); + Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| ()) } } -impl Credit { - /// Create zero native credit. - pub fn native_zero() -> Self { - NativeCredit::::zero().into() - } - - /// Amount of `self`. - pub fn peek(&self) -> T::Balance { - match self { - Credit::Native(c) => c.peek(), - Credit::Asset(c) => c.peek(), - } - } - - /// Asset class of `self`. - pub fn asset(&self) -> T::MultiAssetId { - match self { - Credit::Native(_) => T::MultiAssetIdConverter::get_native(), - Credit::Asset(c) => c.asset().into(), - } +/// Pool locator that chains the `First` and `Second` implementations of [`PoolLocator`]. +/// +/// If the `First` implementation fails, it falls back to the `Second`. +pub struct Chain(PhantomData<(First, Second)>); +impl PoolLocator + for Chain +where + First: PoolLocator, + Second: PoolLocator, +{ + fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { + First::pool_id(asset1, asset2).or(Second::pool_id(asset1, asset2)) } - - /// Consume `self` and return two independent instances; the first is guaranteed to be at most - /// `amount` and the second will be the remainder. - pub fn split(self, amount: T::Balance) -> (Self, Self) { - match self { - Credit::Native(c) => { - let (left, right) = c.split(amount); - (left.into(), right.into()) - }, - Credit::Asset(c) => { - let (left, right) = c.split(amount); - (left.into(), right.into()) - }, - } + fn address(id: &(AssetKind, AssetKind)) -> Result { + First::address(id).or(Second::address(id)) } } From f49074443d4242bbed268e2d252cfb9e41444bad Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:26:08 +0200 Subject: [PATCH 45/69] asset conversion tx payment --- .../asset-conversion-tx-payment/src/lib.rs | 1 - .../asset-conversion-tx-payment/src/mock.rs | 43 ++++++++++--------- .../src/payment.rs | 17 ++++---- .../asset-conversion-tx-payment/src/tests.rs | 43 +++++++++---------- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs index 04a71e2ff4260..ed0ed56e6e074 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/lib.rs @@ -69,7 +69,6 @@ mod tests; mod payment; use frame_support::traits::tokens::AssetId; -use pallet_asset_conversion::MultiAssetIdConverter; pub use payment::*; /// Type aliases used for interaction with `OnChargeTransaction`. diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index 2a18b620edefd..373ecef27efc5 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -16,20 +16,25 @@ use super::*; use crate as pallet_asset_conversion_tx_payment; -use codec; use frame_support::{ dispatch::DispatchClass, instances::Instance2, ord_parameter_types, pallet_prelude::*, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU32, ConstU64, ConstU8, Imbalance, OnUnbalanced}, + traits::{ + tokens::{ + fungible::{NativeFromLeft, NativeOrWithId, UnionOf}, + imbalance::ResolveAssetTo, + }, + AsEnsureOriginWithArg, ConstU32, ConstU64, ConstU8, Imbalance, OnUnbalanced, + }, weights::{Weight, WeightToFee as WeightToFeeT}, PalletId, }; use frame_system as system; use frame_system::{EnsureRoot, EnsureSignedBy}; -use pallet_asset_conversion::{NativeOrAssetId, NativeOrAssetIdConverter}; +use pallet_asset_conversion::{Ascending, Chain, WithFirstAsset}; use pallet_transaction_payment::CurrencyAdapter; use sp_core::H256; use sp_runtime::{ @@ -223,10 +228,9 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); - pub storage AllowMultiAssetPools: bool = false; - // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero pub storage LiquidityWithdrawalFee: Permill = Permill::from_percent(0); pub const MaxSwapPathLength: u32 = 4; + pub const Native: NativeOrWithId = NativeOrWithId::Native; } ord_parameter_types! { @@ -235,27 +239,26 @@ ord_parameter_types! { impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type AssetId = u32; + type Balance = Balance; + type HigherPrecisionBalance = u128; + type AssetKind = NativeOrWithId; + type Assets = UnionOf, AccountId>; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = Chain< + WithFirstAsset>, + Ascending>, + >; type PoolAssetId = u32; - type Assets = Assets; type PoolAssets = PoolAssets; + type PoolSetupFee = ConstU64<100>; // should be more or equal to the existential deposit + type PoolSetupFeeAsset = Native; + type PoolSetupFeeTarget = ResolveAssetTo; type PalletId = AssetConversionPalletId; - type WeightInfo = (); type LPFee = ConstU32<3>; // means 0.3% - type PoolSetupFee = ConstU64<100>; // should be more or equal to the existential deposit - type PoolSetupFeeReceiver = AssetConversionOrigin; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; - type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = MaxSwapPathLength; type MintMinLiquidity = ConstU64<100>; // 100 is good enough when the main currency has 12 decimals. - - type Balance = u64; - type HigherPrecisionBalance = u128; - - type MultiAssetId = NativeOrAssetId; - type MultiAssetIdConverter = NativeOrAssetIdConverter; - + type WeightInfo = (); pallet_asset_conversion::runtime_benchmarks_enabled! { type BenchmarkHelper = (); } @@ -264,5 +267,5 @@ impl pallet_asset_conversion::Config for Runtime { impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; - type OnChargeAssetTransaction = AssetConversionAdapter; + type OnChargeAssetTransaction = AssetConversionAdapter; } diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs index ccea9e55bbed2..f2f2c57bb376d 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs @@ -24,7 +24,7 @@ use frame_support::{ }; use pallet_asset_conversion::Swap; use sp_runtime::{ - traits::{DispatchInfoOf, PostDispatchInfoOf, Zero}, + traits::{DispatchInfoOf, Get, PostDispatchInfoOf, Zero}, transaction_validity::InvalidTransaction, Saturating, }; @@ -76,16 +76,17 @@ pub trait OnChargeAssetTransaction { /// Implements the asset transaction for a balance to asset converter (implementing [`Swap`]). /// /// The converter is given the complete fee in terms of the asset used for the transaction. -pub struct AssetConversionAdapter(PhantomData<(C, CON)>); +pub struct AssetConversionAdapter(PhantomData<(C, CON, N)>); /// Default implementation for a runtime instantiating this pallet, an asset to native swapper. -impl OnChargeAssetTransaction for AssetConversionAdapter +impl OnChargeAssetTransaction for AssetConversionAdapter where + N: Get, T: Config, C: Inspect<::AccountId>, - CON: Swap, MultiAssetId = T::MultiAssetId>, + CON: Swap, AssetKind = T::AssetKind>, BalanceOf: Into>, - T::MultiAssetId: From>, + T::AssetKind: From>, BalanceOf: IsType<::AccountId>>::Balance>, { type Balance = BalanceOf; @@ -116,7 +117,7 @@ where let asset_consumed = CON::swap_tokens_for_exact_tokens( who.clone(), - vec![asset_id.into(), T::MultiAssetIdConverter::get_native()], + vec![asset_id.into(), N::get()], native_asset_required, None, who.clone(), @@ -168,8 +169,8 @@ where match CON::swap_exact_tokens_for_tokens( who.clone(), // we already deposited the native to `who` vec![ - T::MultiAssetIdConverter::get_native(), // we provide the native - asset_id.into(), // we want asset_id back + N::get(), // we provide the native + asset_id.into(), // we want asset_id back ], swap_back, // amount of the native asset to convert to `asset_id` None, // no minimum amount back diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs index d50a051642358..62faed269d377 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/tests.rs @@ -20,14 +20,13 @@ use frame_support::{ dispatch::{DispatchInfo, PostDispatchInfo}, pallet_prelude::*, traits::{ - fungible::Inspect, + fungible::{Inspect, NativeOrWithId}, fungibles::{Inspect as FungiblesInspect, Mutate}, }, weights::Weight, }; use frame_system as system; use mock::{ExtrinsicBaseWeight, *}; -use pallet_asset_conversion::NativeOrAssetId; use pallet_balances::Call as BalancesCall; use sp_runtime::{traits::StaticLookup, BuildStorage}; @@ -127,12 +126,12 @@ fn setup_lp(asset_id: u32, balance_factor: u64) { 10_000 * balance_factor + ed_asset )); - let token_1 = NativeOrAssetId::Native; - let token_2 = NativeOrAssetId::Asset(asset_id); + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(asset_id); assert_ok!(AssetConversion::create_pool( RuntimeOrigin::signed(lp_provider), - Box::new(token_1), - Box::new(token_2) + Box::new(token_1.clone()), + Box::new(token_2.clone()) )); assert_ok!(AssetConversion::add_liquidity( @@ -228,8 +227,8 @@ fn transaction_payment_in_asset_possible() { let fee_in_native = base_weight + tx_weight + len as u64; let input_quote = AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(asset_id), - NativeOrAssetId::Native, + NativeOrWithId::WithId(asset_id), + NativeOrWithId::Native, fee_in_native, true, ); @@ -337,8 +336,8 @@ fn transaction_payment_without_fee() { let len = 10; let fee_in_native = base_weight + weight + len as u64; let input_quote = AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(asset_id), - NativeOrAssetId::Native, + NativeOrWithId::WithId(asset_id), + NativeOrWithId::Native, fee_in_native, true, ); @@ -355,8 +354,8 @@ fn transaction_payment_without_fee() { assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); let refund = AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(asset_id), + NativeOrWithId::Native, + NativeOrWithId::WithId(asset_id), fee_in_native, true, ) @@ -412,8 +411,8 @@ fn asset_transaction_payment_with_tip_and_refund() { let len = 10; let fee_in_native = base_weight + weight + len as u64 + tip; let input_quote = AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(asset_id), - NativeOrAssetId::Native, + NativeOrWithId::WithId(asset_id), + NativeOrWithId::Native, fee_in_native, true, ); @@ -428,8 +427,8 @@ fn asset_transaction_payment_with_tip_and_refund() { let final_weight = 50; let expected_fee = fee_in_native - final_weight - tip; let expected_token_refund = AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(asset_id), + NativeOrWithId::Native, + NativeOrWithId::WithId(asset_id), fee_in_native - expected_fee - tip, true, ) @@ -493,8 +492,8 @@ fn payment_from_account_with_only_assets() { let fee_in_native = base_weight + weight + len as u64; let ed = Balances::minimum_balance(); let fee_in_asset = AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(asset_id), - NativeOrAssetId::Native, + NativeOrWithId::WithId(asset_id), + NativeOrWithId::Native, fee_in_native + ed, true, ) @@ -509,8 +508,8 @@ fn payment_from_account_with_only_assets() { assert_eq!(Assets::balance(asset_id, caller), balance - fee_in_asset); let refund = AssetConversion::quote_price_exact_tokens_for_tokens( - NativeOrAssetId::Native, - NativeOrAssetId::Asset(asset_id), + NativeOrWithId::Native, + NativeOrWithId::WithId(asset_id), ed, true, ) @@ -585,8 +584,8 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { // validate even a small fee gets converted to asset. let fee_in_native = base_weight + weight + len as u64; let fee_in_asset = AssetConversion::quote_price_tokens_for_exact_tokens( - NativeOrAssetId::Asset(asset_id), - NativeOrAssetId::Native, + NativeOrWithId::WithId(asset_id), + NativeOrWithId::Native, fee_in_native, true, ) From 45d450d97902f7836cbd4b340e56d6388562fadc Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:27:00 +0200 Subject: [PATCH 46/69] substrate test runtime --- substrate/bin/node/runtime/src/lib.rs | 54 ++++++++++++++++----------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 1d4caed8b4942..245dbae0f8c68 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -36,8 +36,13 @@ use frame_support::{ pallet_prelude::Get, parameter_types, traits::{ - fungible::{Balanced, Credit, HoldConsideration, ItemOf}, - tokens::{nonfungibles_v2::Inspect, pay::PayAssetFromAccount, GetSalary, PayFromAccount}, + fungible::{ + Balanced, Credit, HoldConsideration, ItemOf, NativeFromLeft, NativeOrWithId, UnionOf, + }, + tokens::{ + imbalance::ResolveAssetTo, nonfungibles_v2::Inspect, pay::PayAssetFromAccount, + GetSalary, PayFromAccount, + }, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Contains, Currency, EitherOfDiverse, EqualPrivilegeOnly, Imbalance, InsideBoth, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, OnUnbalanced, @@ -57,7 +62,7 @@ use frame_system::{ }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce}; -use pallet_asset_conversion::{NativeOrAssetId, NativeOrAssetIdConverter}; +use pallet_asset_conversion::{Ascending, Chain, WithFirstAsset}; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600}; use pallet_election_provider_multi_phase::{GeometricDepositBase, SolutionAccuracyOf}; use pallet_identity::simple::IdentityInfo; @@ -565,8 +570,11 @@ impl pallet_asset_tx_payment::Config for Runtime { impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; - type OnChargeAssetTransaction = - pallet_asset_conversion_tx_payment::AssetConversionAdapter; + type OnChargeAssetTransaction = pallet_asset_conversion_tx_payment::AssetConversionAdapter< + Balances, + AssetConversion, + Native, + >; } parameter_types! { @@ -1636,32 +1644,34 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); - pub AllowMultiAssetPools: bool = true; pub const PoolSetupFee: Balance = 1 * DOLLARS; // should be more or equal to the existential deposit pub const MintMinLiquidity: Balance = 100; // 100 is good enough when the main currency has 10-12 decimals. - pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero. + pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); + pub const Native: NativeOrWithId = NativeOrWithId::Native; } impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type HigherPrecisionBalance = sp_core::U256; - type Assets = Assets; type Balance = u128; - type PoolAssets = PoolAssets; - type AssetId = >::AssetId; - type MultiAssetId = NativeOrAssetId; + type HigherPrecisionBalance = sp_core::U256; + type AssetKind = NativeOrWithId; + type Assets = UnionOf, AccountId>; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = Chain< + WithFirstAsset>, + Ascending>, + >; type PoolAssetId = >::AssetId; + type PoolAssets = PoolAssets; + type PoolSetupFee = PoolSetupFee; + type PoolSetupFeeAsset = Native; + type PoolSetupFeeTarget = ResolveAssetTo; type PalletId = AssetConversionPalletId; type LPFee = ConstU32<3>; // means 0.3% - type PoolSetupFee = PoolSetupFee; - type PoolSetupFeeReceiver = AssetConversionOrigin; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type WeightInfo = pallet_asset_conversion::weights::SubstrateWeight; - type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; type MintMinLiquidity = MintMinLiquidity; - type MultiAssetIdConverter = NativeOrAssetIdConverter; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } @@ -2562,19 +2572,19 @@ impl_runtime_apis! { impl pallet_asset_conversion::AssetConversionApi< Block, Balance, - NativeOrAssetId + NativeOrWithId > for Runtime { - fn quote_price_exact_tokens_for_tokens(asset1: NativeOrAssetId, asset2: NativeOrAssetId, amount: Balance, include_fee: bool) -> Option { + fn quote_price_exact_tokens_for_tokens(asset1: NativeOrWithId, asset2: NativeOrWithId, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_exact_tokens_for_tokens(asset1, asset2, amount, include_fee) } - fn quote_price_tokens_for_exact_tokens(asset1: NativeOrAssetId, asset2: NativeOrAssetId, amount: Balance, include_fee: bool) -> Option { + fn quote_price_tokens_for_exact_tokens(asset1: NativeOrWithId, asset2: NativeOrWithId, amount: Balance, include_fee: bool) -> Option { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } - fn get_reserves(asset1: NativeOrAssetId, asset2: NativeOrAssetId) -> Option<(Balance, Balance)> { - AssetConversion::get_reserves(&asset1, &asset2).ok() + fn get_reserves(asset1: NativeOrWithId, asset2: NativeOrWithId) -> Option<(Balance, Balance)> { + AssetConversion::get_reserves(asset1, asset2).ok() } } From baac8e505258728dbbd69bc7b1b443e185a7459b Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:27:33 +0200 Subject: [PATCH 47/69] asset hub common impls --- .../runtimes/assets/common/src/benchmarks.rs | 42 ++ .../runtimes/assets/common/src/lib.rs | 2 + .../common/src/local_and_foreign_assets.rs | 466 ++---------------- 3 files changed, 72 insertions(+), 438 deletions(-) create mode 100644 cumulus/parachains/runtimes/assets/common/src/benchmarks.rs diff --git a/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs b/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs new file mode 100644 index 0000000000000..ed1379695317c --- /dev/null +++ b/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs @@ -0,0 +1,42 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use cumulus_primitives_core::ParaId; +use sp_runtime::traits::Get; +use sp_std::marker::PhantomData; +use xcm::latest::prelude::*; + +/// Creates asset pairs for liquidity pools with `Target` always being the first asset. +pub struct AssetPairFactory( + PhantomData<(Target, SelfParaId, PalletId)>, +); +impl, SelfParaId: Get, PalletId: Get> + pallet_asset_conversion::BenchmarkHelper + for AssetPairFactory +{ + fn create_pair(_seed1: u32, seed2: u32) -> (MultiLocation, MultiLocation) { + ( + Target::get(), + MultiLocation::new( + 1, + X3( + Parachain(SelfParaId::get().into()), + PalletInstance(PalletId::get() as u8), + GeneralIndex(seed2.into()), + ), + ), + ) + } +} diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index f45c3289aab49..15327f51b2a99 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -15,6 +15,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarks; pub mod foreign_creators; pub mod fungible_conversion; pub mod local_and_foreign_assets; diff --git a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs index f9f935dab8225..7dd497797eaa5 100644 --- a/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs +++ b/cumulus/parachains/runtimes/assets/common/src/local_and_foreign_assets.rs @@ -13,48 +13,42 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::traits::{ - fungibles::{Balanced, Create, HandleImbalanceDrop, Inspect, Mutate, Unbalanced}, - tokens::{ - DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence, - }, - AccountTouch, Contains, ContainsPair, Get, PalletInfoAccess, +use frame_support::traits::Get; +use sp_runtime::{ + traits::{Convert, MaybeEquivalence}, + Either, + Either::{Left, Right}, }; -use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter}; -use parachains_common::AccountId; -use sp_runtime::{traits::MaybeEquivalence, DispatchError, DispatchResult}; use sp_std::marker::PhantomData; use xcm::latest::MultiLocation; -pub struct MultiLocationConverter, MultiLocationMatcher> { - _phantom: PhantomData<(NativeAssetLocation, MultiLocationMatcher)>, +/// Converts a given [`MultiLocation`] to [`Either::Left`] when equal to `Target`, or +/// [`Either::Right`] otherwise. +/// +/// Suitable for use as a `Criterion` with [`frame_support::traits::tokens::fungible::UnionOf`]. +pub struct TargetFromLeft(PhantomData); +impl> Convert> + for TargetFromLeft +{ + fn convert(l: MultiLocation) -> Either<(), MultiLocation> { + Target::get().eq(&l).then(|| Left(())).map_or(Right(l), |n| n) + } } -impl MultiAssetIdConverter - for MultiLocationConverter +/// Converts a given [`MultiLocation`] to [`Either::Left`] based on the `Equivalence` criteria. +/// Returns [`Either::Right`] if not equivalent. +/// +/// Suitable for use as a `Criterion` with [`frame_support::traits::tokens::fungibles::UnionOf`]. +pub struct LocalFromLeft(PhantomData<(Equivalence, AssetId)>); +impl Convert> + for LocalFromLeft where - NativeAssetLocation: Get, - MultiLocationMatcher: Contains, + Equivalence: MaybeEquivalence, { - fn get_native() -> MultiLocation { - NativeAssetLocation::get() - } - - fn is_native(asset_id: &MultiLocation) -> bool { - *asset_id == Self::get_native() - } - - fn try_convert( - asset_id: &MultiLocation, - ) -> MultiAssetIdConversionResult { - if Self::is_native(asset_id) { - return MultiAssetIdConversionResult::Native - } - - if MultiLocationMatcher::contains(asset_id) { - MultiAssetIdConversionResult::Converted(*asset_id) - } else { - MultiAssetIdConversionResult::Unsupported(*asset_id) + fn convert(l: MultiLocation) -> Either { + match Equivalence::convert(&l) { + Some(id) => Left(id), + None => Right(l), } } } @@ -63,407 +57,3 @@ pub trait MatchesLocalAndForeignAssetsMultiLocation { fn is_local(location: &MultiLocation) -> bool; fn is_foreign(location: &MultiLocation) -> bool; } - -pub struct LocalAndForeignAssets { - _phantom: PhantomData<(Assets, LocalAssetIdConverter, ForeignAssets)>, -} - -impl Unbalanced - for LocalAndForeignAssets -where - Assets: Inspect - + Unbalanced - + Balanced - + PalletInfoAccess, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: Inspect - + Unbalanced - + Balanced, -{ - fn handle_dust(dust: frame_support::traits::fungibles::Dust) { - let credit = dust.into_credit(); - - if let Some(asset) = LocalAssetIdConverter::convert(&credit.asset()) { - Assets::handle_raw_dust(asset, credit.peek()); - } else { - ForeignAssets::handle_raw_dust(credit.asset(), credit.peek()); - } - - // As we have already handled the dust, we must stop credit's drop from happening: - sp_std::mem::forget(credit); - } - - fn write_balance( - asset: >::AssetId, - who: &AccountId, - amount: >::Balance, - ) -> Result>::Balance>, DispatchError> { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::write_balance(asset, who, amount) - } else { - ForeignAssets::write_balance(asset, who, amount) - } - } - - /// Set the total issuance of `asset` to `amount`. - fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::set_total_issuance(asset, amount) - } else { - ForeignAssets::set_total_issuance(asset, amount) - } - } - - fn decrease_balance( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - precision: Precision, - preservation: Preservation, - force: Fortitude, - ) -> Result { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::decrease_balance(asset, who, amount, precision, preservation, force) - } else { - ForeignAssets::decrease_balance(asset, who, amount, precision, preservation, force) - } - } - - fn increase_balance( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - precision: Precision, - ) -> Result { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::increase_balance(asset, who, amount, precision) - } else { - ForeignAssets::increase_balance(asset, who, amount, precision) - } - } -} - -impl Inspect - for LocalAndForeignAssets -where - Assets: Inspect, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: Inspect, -{ - type AssetId = MultiLocation; - type Balance = u128; - - /// The total amount of issuance in the system. - fn total_issuance(asset: Self::AssetId) -> Self::Balance { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::total_issuance(asset) - } else { - ForeignAssets::total_issuance(asset) - } - } - - /// The minimum balance any single account may have. - fn minimum_balance(asset: Self::AssetId) -> Self::Balance { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::minimum_balance(asset) - } else { - ForeignAssets::minimum_balance(asset) - } - } - - fn total_balance( - asset: >::AssetId, - account: &AccountId, - ) -> >::Balance { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::total_balance(asset, account) - } else { - ForeignAssets::total_balance(asset, account) - } - } - - /// Get the `asset` balance of `who`. - fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::balance(asset, who) - } else { - ForeignAssets::balance(asset, who) - } - } - - /// Get the maximum amount of `asset` that `who` can withdraw/transfer successfully. - fn reducible_balance( - asset: Self::AssetId, - who: &AccountId, - presevation: Preservation, - fortitude: Fortitude, - ) -> Self::Balance { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::reducible_balance(asset, who, presevation, fortitude) - } else { - ForeignAssets::reducible_balance(asset, who, presevation, fortitude) - } - } - - /// Returns `true` if the `asset` balance of `who` may be increased by `amount`. - /// - /// - `asset`: The asset that should be deposited. - /// - `who`: The account of which the balance should be increased by `amount`. - /// - `amount`: How much should the balance be increased? - /// - `mint`: Will `amount` be minted to deposit it into `account`? - fn can_deposit( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - mint: Provenance, - ) -> DepositConsequence { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::can_deposit(asset, who, amount, mint) - } else { - ForeignAssets::can_deposit(asset, who, amount, mint) - } - } - - /// Returns `Failed` if the `asset` balance of `who` may not be decreased by `amount`, otherwise - /// the consequence. - fn can_withdraw( - asset: Self::AssetId, - who: &AccountId, - amount: Self::Balance, - ) -> WithdrawConsequence { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::can_withdraw(asset, who, amount) - } else { - ForeignAssets::can_withdraw(asset, who, amount) - } - } - - /// Returns `true` if an `asset` exists. - fn asset_exists(asset: Self::AssetId) -> bool { - if let Some(asset) = LocalAssetIdConverter::convert(&asset) { - Assets::asset_exists(asset) - } else { - ForeignAssets::asset_exists(asset) - } - } -} - -impl Mutate - for LocalAndForeignAssets -where - Assets: Mutate - + Inspect - + Balanced - + PalletInfoAccess, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: Mutate - + Inspect - + Balanced, -{ - /// Transfer funds from one account into another. - fn transfer( - asset: MultiLocation, - source: &AccountId, - dest: &AccountId, - amount: Self::Balance, - keep_alive: Preservation, - ) -> Result { - if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) { - Assets::transfer(asset_id, source, dest, amount, keep_alive) - } else { - ForeignAssets::transfer(asset, source, dest, amount, keep_alive) - } - } -} - -impl Create - for LocalAndForeignAssets -where - Assets: Create + Inspect, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: Create + Inspect, -{ - /// Create a new fungible asset. - fn create( - asset_id: Self::AssetId, - admin: AccountId, - is_sufficient: bool, - min_balance: Self::Balance, - ) -> DispatchResult { - if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) { - Assets::create(asset_id, admin, is_sufficient, min_balance) - } else { - ForeignAssets::create(asset_id, admin, is_sufficient, min_balance) - } - } -} - -impl AccountTouch - for LocalAndForeignAssets -where - Assets: AccountTouch, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: AccountTouch, -{ - type Balance = u128; - - fn deposit_required( - asset_id: MultiLocation, - ) -> >::Balance { - if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) { - Assets::deposit_required(asset_id) - } else { - ForeignAssets::deposit_required(asset_id) - } - } - - fn touch( - asset_id: MultiLocation, - who: AccountId, - depositor: AccountId, - ) -> Result<(), DispatchError> { - if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) { - Assets::touch(asset_id, who, depositor) - } else { - ForeignAssets::touch(asset_id, who, depositor) - } - } -} - -/// Implements [`ContainsPair`] trait for a pair of asset and account IDs. -impl ContainsPair - for LocalAndForeignAssets -where - Assets: PalletInfoAccess + ContainsPair, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: ContainsPair, -{ - /// Check if an account with the given asset ID and account address exists. - fn contains(asset_id: &MultiLocation, who: &AccountId) -> bool { - if let Some(asset_id) = LocalAssetIdConverter::convert(asset_id) { - Assets::contains(&asset_id, &who) - } else { - ForeignAssets::contains(&asset_id, &who) - } - } -} - -impl Balanced - for LocalAndForeignAssets -where - Assets: - Balanced + Inspect + PalletInfoAccess, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: - Balanced + Inspect, -{ - type OnDropDebt = DebtDropIndirection; - type OnDropCredit = CreditDropIndirection; -} - -pub struct DebtDropIndirection { - _phantom: PhantomData>, -} - -impl HandleImbalanceDrop - for DebtDropIndirection -where - Assets: Balanced + Inspect, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: - Balanced + Inspect, -{ - fn handle(asset: MultiLocation, amount: u128) { - if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) { - Assets::OnDropDebt::handle(asset_id, amount); - } else { - ForeignAssets::OnDropDebt::handle(asset, amount); - } - } -} - -pub struct CreditDropIndirection { - _phantom: PhantomData>, -} - -impl HandleImbalanceDrop - for CreditDropIndirection -where - Assets: Balanced + Inspect, - LocalAssetIdConverter: MaybeEquivalence, - ForeignAssets: - Balanced + Inspect, -{ - fn handle(asset: MultiLocation, amount: u128) { - if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) { - Assets::OnDropCredit::handle(asset_id, amount); - } else { - ForeignAssets::OnDropCredit::handle(asset, amount); - } - } -} - -#[cfg(test)] -mod tests { - use crate::{ - local_and_foreign_assets::MultiLocationConverter, AssetIdForPoolAssetsConvert, - AssetIdForTrustBackedAssetsConvert, - }; - use frame_support::traits::EverythingBut; - use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter}; - use sp_runtime::traits::MaybeEquivalence; - use xcm::latest::prelude::*; - use xcm_builder::StartsWith; - - #[test] - fn test_multi_location_converter_works() { - frame_support::parameter_types! { - pub const WestendLocation: MultiLocation = MultiLocation::parent(); - pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(50_u8).into(); - pub PoolAssetsPalletLocation: MultiLocation = PalletInstance(55_u8).into(); - } - - type C = MultiLocationConverter< - WestendLocation, - EverythingBut>, - >; - - let native_asset = WestendLocation::get(); - let local_asset = - AssetIdForTrustBackedAssetsConvert::::convert_back( - &123, - ) - .unwrap(); - let pool_asset = - AssetIdForPoolAssetsConvert::::convert_back(&456).unwrap(); - let foreign_asset1 = MultiLocation { parents: 1, interior: X1(Parachain(2222)) }; - let foreign_asset2 = MultiLocation { - parents: 2, - interior: X2(GlobalConsensus(ByGenesis([1; 32])), Parachain(2222)), - }; - - assert!(C::is_native(&native_asset)); - assert!(!C::is_native(&local_asset)); - assert!(!C::is_native(&pool_asset)); - assert!(!C::is_native(&foreign_asset1)); - assert!(!C::is_native(&foreign_asset2)); - - assert_eq!(C::try_convert(&native_asset), MultiAssetIdConversionResult::Native); - assert_eq!( - C::try_convert(&local_asset), - MultiAssetIdConversionResult::Converted(local_asset) - ); - assert_eq!( - C::try_convert(&pool_asset), - MultiAssetIdConversionResult::Unsupported(pool_asset) - ); - assert_eq!( - C::try_convert(&foreign_asset1), - MultiAssetIdConversionResult::Converted(foreign_asset1) - ); - assert_eq!( - C::try_convert(&foreign_asset2), - MultiAssetIdConversionResult::Converted(foreign_asset2) - ); - } -} From c4eb5148dc89dcb505c0a59ba8d8b065c2186c56 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:34:26 +0200 Subject: [PATCH 48/69] asset hub runtimes --- .../assets/asset-hub-kusama/src/lib.rs | 68 ++++--- .../assets/asset-hub-kusama/src/xcm_config.rs | 33 +-- .../assets/asset-hub-rococo/src/lib.rs | 73 ++++--- .../assets/asset-hub-rococo/src/xcm_config.rs | 33 +-- .../assets/asset-hub-westend/src/lib.rs | 189 ++++-------------- .../asset-hub-westend/src/xcm_config.rs | 34 +--- .../assets/asset-hub-westend/tests/tests.rs | 5 +- 7 files changed, 126 insertions(+), 309 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index a1ee0e4df71c0..583fdd359a0a7 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -29,7 +29,7 @@ pub mod xcm_config; use assets_common::{ foreign_creators::ForeignCreators, - local_and_foreign_assets::{LocalAndForeignAssets, MultiLocationConverter}, + local_and_foreign_assets::{LocalFromLeft, TargetFromLeft}, matching::FromSiblingParachain, AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId, }; @@ -57,8 +57,8 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, ord_parameter_types, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, - InstanceFilter, + fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, + ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -93,10 +93,7 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; -use crate::xcm_config::{ - ForeignCreatorsSovereignAccountOf, LocalAndForeignAssetsMultiLocationMatcher, - TrustBackedAssetsPalletLocation, -}; +use crate::xcm_config::{ForeignCreatorsSovereignAccountOf, TrustBackedAssetsPalletLocation}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; impl_opaque_keys! { @@ -292,8 +289,6 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); - pub const AllowMultiAssetPools: bool = false; - // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); } @@ -328,35 +323,50 @@ impl pallet_assets::Config for Runtime { type BenchmarkHelper = (); } +/// Union fungibles implementation for `Assets`` and `ForeignAssets`. +pub type LocalAndForeignAssets = fungibles::UnionOf< + Assets, + ForeignAssets, + LocalFromLeft< + AssetIdForTrustBackedAssetsConvert, + AssetIdForTrustBackedAssets, + >, + MultiLocation, + AccountId, +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; - type Currency = Balances; - type AssetId = MultiLocation; - type Assets = LocalAndForeignAssets< - Assets, - AssetIdForTrustBackedAssetsConvert, - ForeignAssets, + type AssetKind = MultiLocation; + type Assets = fungible::UnionOf< + Balances, + LocalAndForeignAssets, + TargetFromLeft, + Self::AssetKind, + Self::AccountId, >; - type PoolAssets = PoolAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = + pallet_asset_conversion::WithFirstAsset; type PoolAssetId = u32; + type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam - type PoolSetupFeeReceiver = AssetConversionOrigin; - // should be non-zero if `AllowMultiAssetPools` is true, otherwise can be zero. + type PoolSetupFeeAsset = KsmLocation; + type PoolSetupFeeTarget = ResolveAssetTo; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; type PalletId = AssetConversionPalletId; - type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; - type MultiAssetId = MultiLocation; - type MultiAssetIdConverter = - MultiLocationConverter; type MintMinLiquidity = ConstU128<100>; type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = - crate::xcm_config::BenchmarkMultiLocationConverter>; + type BenchmarkHelper = assets_common::benchmarks::AssetPairFactory< + KsmLocation, + parachain_info::Pallet, + xcm_config::AssetsPalletIndex, + >; } parameter_types! { @@ -715,12 +725,8 @@ impl pallet_collator_selection::Config for Runtime { impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Fungibles = LocalAndForeignAssets< - Assets, - AssetIdForTrustBackedAssetsConvert, - ForeignAssets, - >; - type OnChargeAssetTransaction = AssetConversionAdapter; + type Fungibles = LocalAndForeignAssets; + type OnChargeAssetTransaction = AssetConversionAdapter; } parameter_types! { @@ -1042,7 +1048,7 @@ impl_runtime_apis! { AssetConversion::quote_price_tokens_for_exact_tokens(asset1, asset2, amount, include_fee) } fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> { - AssetConversion::get_reserves(&asset1, &asset2).ok() + AssetConversion::get_reserves(asset1, asset2).ok() } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs index 13da81fe59123..5047fbe1e1703 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/xcm_config.rs @@ -49,9 +49,6 @@ use xcm_builder::{ }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; -#[cfg(feature = "runtime-benchmarks")] -use {cumulus_primitives_core::ParaId, sp_core::Get}; - parameter_types! { pub const KsmLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: Option = Some(NetworkId::Kusama); @@ -59,8 +56,8 @@ parameter_types! { pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap(); - pub TrustBackedAssetsPalletLocation: MultiLocation = - PalletInstance(::index() as u8).into(); + pub AssetsPalletIndex: u32 = ::index() as u32; + pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(AssetsPalletIndex::get() as u8).into(); pub ForeignAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: MultiLocation = @@ -612,29 +609,3 @@ impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { MultiLocation { parents: 1, interior: X1(Parachain(id)) } } } - -#[cfg(feature = "runtime-benchmarks")] -pub struct BenchmarkMultiLocationConverter { - _phantom: sp_std::marker::PhantomData, -} - -#[cfg(feature = "runtime-benchmarks")] -impl pallet_asset_conversion::BenchmarkHelper - for BenchmarkMultiLocationConverter -where - SelfParaId: Get, -{ - fn asset_id(asset_id: u32) -> MultiLocation { - MultiLocation { - parents: 1, - interior: X3( - Parachain(SelfParaId::get().into()), - PalletInstance(::index() as u8), - GeneralIndex(asset_id.into()), - ), - } - } - fn multiasset_id(asset_id: u32) -> MultiLocation { - Self::asset_id(asset_id) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 1d18296cb6aa4..dcfc41c79620c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -35,7 +35,7 @@ pub mod xcm_config; use assets_common::{ foreign_creators::ForeignCreators, - local_and_foreign_assets::{LocalAndForeignAssets, MultiLocationConverter}, + local_and_foreign_assets::{LocalFromLeft, TargetFromLeft}, matching::FromSiblingParachain, AssetIdForTrustBackedAssetsConvert, MultiLocationForAssetId, }; @@ -60,8 +60,8 @@ use frame_support::{ dispatch::DispatchClass, ord_parameter_types, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, - Equals, InstanceFilter, + fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, + ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -83,8 +83,9 @@ use parachains_common::{ use sp_runtime::RuntimeDebug; use xcm::opaque::v3::MultiLocation; use xcm_config::{ - ForeignAssetsConvertedConcreteId, GovernanceLocation, PoolAssetsConvertedConcreteId, - TokenLocation, TrustBackedAssetsConvertedConcreteId, XcmConfig, + ForeignAssetsConvertedConcreteId, ForeignCreatorsSovereignAccountOf, GovernanceLocation, + PoolAssetsConvertedConcreteId, TokenLocation, TrustBackedAssetsConvertedConcreteId, + TrustBackedAssetsPalletLocation, XcmConfig, }; #[cfg(any(feature = "std", test))] @@ -96,10 +97,6 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use xcm::latest::prelude::*; use xcm_executor::XcmExecutor; -use crate::xcm_config::{ - ForeignCreatorsSovereignAccountOf, LocalAndForeignAssetsMultiLocationMatcher, - TrustBackedAssetsPalletLocation, -}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; /// Enum for handling differences in the runtime configuration for `AssetHubRococo` vs. @@ -298,8 +295,6 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); - pub const AllowMultiAssetPools: bool = false; - // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); } @@ -334,35 +329,50 @@ impl pallet_assets::Config for Runtime { type BenchmarkHelper = (); } +/// Union fungibles implementation for `Assets`` and `ForeignAssets`. +pub type LocalAndForeignAssets = fungibles::UnionOf< + Assets, + ForeignAssets, + LocalFromLeft< + AssetIdForTrustBackedAssetsConvert, + AssetIdForTrustBackedAssets, + >, + MultiLocation, + AccountId, +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; - type Currency = Balances; - type AssetId = MultiLocation; - type Assets = LocalAndForeignAssets< - Assets, - AssetIdForTrustBackedAssetsConvert, - ForeignAssets, + type AssetKind = MultiLocation; + type Assets = fungible::UnionOf< + Balances, + LocalAndForeignAssets, + TargetFromLeft, + Self::AssetKind, + Self::AccountId, >; - type PoolAssets = PoolAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = + pallet_asset_conversion::WithFirstAsset; type PoolAssetId = u32; + type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam - type PoolSetupFeeReceiver = AssetConversionOrigin; - // should be non-zero if `AllowMultiAssetPools` is true, otherwise can be zero. + type PoolSetupFeeAsset = TokenLocation; + type PoolSetupFeeTarget = ResolveAssetTo; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; type PalletId = AssetConversionPalletId; - type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; - type MultiAssetId = MultiLocation; - type MultiAssetIdConverter = - MultiLocationConverter; type MintMinLiquidity = ConstU128<100>; type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = - crate::xcm_config::BenchmarkMultiLocationConverter>; + type BenchmarkHelper = assets_common::benchmarks::AssetPairFactory< + TokenLocation, + parachain_info::Pallet, + xcm_config::AssetsPalletIndex, + >; } parameter_types! { @@ -727,12 +737,9 @@ impl pallet_collator_selection::Config for Runtime { impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Fungibles = LocalAndForeignAssets< - Assets, - AssetIdForTrustBackedAssetsConvert, - ForeignAssets, - >; - type OnChargeAssetTransaction = AssetConversionAdapter; + type Fungibles = LocalAndForeignAssets; + type OnChargeAssetTransaction = + AssetConversionAdapter; } parameter_types! { @@ -1123,7 +1130,7 @@ impl_runtime_apis! { } fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> { - AssetConversion::get_reserves(&asset1, &asset2).ok() + AssetConversion::get_reserves(asset1, asset2).ok() } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index b88de9efb09c0..19319c89c875e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -57,9 +57,6 @@ use xcm_builder::{ }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; -#[cfg(feature = "runtime-benchmarks")] -use cumulus_primitives_core::ParaId; - parameter_types! { pub storage Flavor: RuntimeFlavor = RuntimeFlavor::default(); pub const TokenLocation: MultiLocation = MultiLocation::parent(); @@ -67,8 +64,8 @@ parameter_types! { pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap(); - pub TrustBackedAssetsPalletLocation: MultiLocation = - PalletInstance(::index() as u8).into(); + pub AssetsPalletIndex: u32 = ::index() as u32; + pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(AssetsPalletIndex::get() as u8).into(); pub ForeignAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: MultiLocation = @@ -718,32 +715,6 @@ impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { } } -#[cfg(feature = "runtime-benchmarks")] -pub struct BenchmarkMultiLocationConverter { - _phantom: sp_std::marker::PhantomData, -} - -#[cfg(feature = "runtime-benchmarks")] -impl pallet_asset_conversion::BenchmarkHelper - for BenchmarkMultiLocationConverter -where - SelfParaId: Get, -{ - fn asset_id(asset_id: u32) -> MultiLocation { - MultiLocation { - parents: 1, - interior: X3( - Parachain(SelfParaId::get().into()), - PalletInstance(::index() as u8), - GeneralIndex(asset_id.into()), - ), - } - } - fn multiasset_id(asset_id: u32) -> MultiLocation { - Self::asset_id(asset_id) - } -} - /// All configuration related to bridging pub mod bridging { use super::*; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 01d327c7c5930..8f7518ee6bf36 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -27,11 +27,8 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); mod weights; pub mod xcm_config; -use crate::xcm_config::{ - LocalAndForeignAssetsMultiLocationMatcher, TrustBackedAssetsPalletLocation, -}; use assets_common::{ - local_and_foreign_assets::{LocalAndForeignAssets, MultiLocationConverter}, + local_and_foreign_assets::{LocalFromLeft, TargetFromLeft}, AssetIdForTrustBackedAssetsConvert, }; use codec::{Decode, Encode, MaxEncodedLen}; @@ -42,8 +39,9 @@ use frame_support::{ genesis_builder_helper::{build_config, create_default_config}, ord_parameter_types, parameter_types, traits::{ - tokens::nonfungibles_v2::Inspect, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, - ConstU64, ConstU8, InstanceFilter, + fungible, fungibles, + tokens::{imbalance::ResolveAssetTo, nonfungibles_v2::Inspect}, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, InstanceFilter, }, weights::{ConstantMultiplier, Weight}, BoundedVec, PalletId, @@ -77,8 +75,8 @@ use sp_version::RuntimeVersion; use xcm::opaque::v3::MultiLocation; use xcm_config::{ ForeignAssetsConvertedConcreteId, PoolAssetsConvertedConcreteId, - TrustBackedAssetsConvertedConcreteId, WestendLocation, XcmConfig, - XcmOriginToTransactDispatchOrigin, + TrustBackedAssetsConvertedConcreteId, TrustBackedAssetsPalletLocation, WestendLocation, + XcmConfig, XcmOriginToTransactDispatchOrigin, }; #[cfg(any(feature = "std", test))] @@ -269,8 +267,6 @@ impl pallet_assets::Config for Runtime { parameter_types! { pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); - pub const AllowMultiAssetPools: bool = false; - // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); } @@ -304,34 +300,50 @@ impl pallet_assets::Config for Runtime { type BenchmarkHelper = (); } +/// Union fungibles implementation for `Assets`` and `ForeignAssets`. +pub type LocalAndForeignAssets = fungibles::UnionOf< + Assets, + ForeignAssets, + LocalFromLeft< + AssetIdForTrustBackedAssetsConvert, + AssetIdForTrustBackedAssets, + >, + MultiLocation, + AccountId, +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type HigherPrecisionBalance = sp_core::U256; - type Currency = Balances; - type AssetId = MultiLocation; - type Assets = LocalAndForeignAssets< - Assets, - AssetIdForTrustBackedAssetsConvert, - ForeignAssets, + type AssetKind = MultiLocation; + type Assets = fungible::UnionOf< + Balances, + LocalAndForeignAssets, + TargetFromLeft, + Self::AssetKind, + Self::AccountId, >; - type PoolAssets = PoolAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = + pallet_asset_conversion::WithFirstAsset; type PoolAssetId = u32; + type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam - type PoolSetupFeeReceiver = AssetConversionOrigin; - type LiquidityWithdrawalFee = LiquidityWithdrawalFee; // should be non-zero if AllowMultiAssetPools is true, otherwise can be zero. + type PoolSetupFeeAsset = WestendLocation; + type PoolSetupFeeTarget = ResolveAssetTo; + type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; type PalletId = AssetConversionPalletId; - type AllowMultiAssetPools = AllowMultiAssetPools; type MaxSwapPathLength = ConstU32<4>; - type MultiAssetId = MultiLocation; - type MultiAssetIdConverter = - MultiLocationConverter; type MintMinLiquidity = ConstU128<100>; type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = - crate::xcm_config::BenchmarkMultiLocationConverter>; + type BenchmarkHelper = assets_common::benchmarks::AssetPairFactory< + WestendLocation, + parachain_info::Pallet, + xcm_config::AssetsPalletIndex, + >; } parameter_types! { @@ -690,12 +702,9 @@ impl pallet_collator_selection::Config for Runtime { impl pallet_asset_conversion_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Fungibles = LocalAndForeignAssets< - Assets, - AssetIdForTrustBackedAssetsConvert, - ForeignAssets, - >; - type OnChargeAssetTransaction = AssetConversionAdapter; + type Fungibles = LocalAndForeignAssets; + type OnChargeAssetTransaction = + AssetConversionAdapter; } parameter_types! { @@ -871,8 +880,6 @@ pub type Migrations = ( // unreleased pallet_collator_selection::migration::v1::MigrateToV1, // unreleased - migrations::NativeAssetParents0ToParents1Migration, - // unreleased pallet_multisig::migrations::v1::MigrateToV1, // unreleased InitStorageVersions, @@ -1106,7 +1113,7 @@ impl_runtime_apis! { } fn get_reserves(asset1: MultiLocation, asset2: MultiLocation) -> Option<(Balance, Balance)> { - AssetConversion::get_reserves(&asset1, &asset2).ok() + AssetConversion::get_reserves(asset1, asset2).ok() } } @@ -1435,117 +1442,3 @@ cumulus_pallet_parachain_system::register_validate_block! { Runtime = Runtime, BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, } - -pub mod migrations { - use super::*; - use frame_support::{ - pallet_prelude::Get, - traits::{ - fungibles::{Inspect, Mutate}, - tokens::Preservation, - OnRuntimeUpgrade, OriginTrait, - }, - }; - use parachains_common::impls::AccountIdOf; - use sp_runtime::{traits::StaticLookup, Saturating}; - - /// Temporary migration because of bug with native asset, it can be removed once applied on - /// `AssetHubWestend`. Migrates pools with `MultiLocation { parents: 0, interior: Here }` to - /// `MultiLocation { parents: 1, interior: Here }` - pub struct NativeAssetParents0ToParents1Migration(sp_std::marker::PhantomData); - impl< - T: pallet_asset_conversion::Config, - > OnRuntimeUpgrade for NativeAssetParents0ToParents1Migration - where - ::PoolAssetId: Into, - AccountIdOf: Into<[u8; 32]>, - ::AccountId: - Into<<::RuntimeOrigin as OriginTrait>::AccountId>, - <::Lookup as StaticLookup>::Source: - From<::AccountId>, - sp_runtime::AccountId32: From<::AccountId>, - { - fn on_runtime_upgrade() -> Weight { - let invalid_native_asset = MultiLocation { parents: 0, interior: Here }; - let valid_native_asset = WestendLocation::get(); - - let mut reads: u64 = 1; - let mut writes: u64 = 0; - - // migrate pools with invalid native asset - let pools = pallet_asset_conversion::Pools::::iter().collect::>(); - reads.saturating_accrue(1); - for (old_pool_id, pool_info) in pools { - let old_pool_account = - pallet_asset_conversion::Pallet::::get_pool_account(&old_pool_id); - reads.saturating_accrue(1); - let pool_asset_id = pool_info.lp_token.clone(); - if old_pool_id.0 != invalid_native_asset { - // skip, if ok - continue - } - - // fix new account - let new_pool_id = pallet_asset_conversion::Pallet::::get_pool_id( - valid_native_asset, - old_pool_id.1, - ); - let new_pool_account = - pallet_asset_conversion::Pallet::::get_pool_account(&new_pool_id); - frame_system::Pallet::::inc_providers(&new_pool_account); - reads.saturating_accrue(2); - writes.saturating_accrue(1); - - // move currency - let _ = Balances::transfer_all( - RuntimeOrigin::signed(sp_runtime::AccountId32::from(old_pool_account.clone())), - sp_runtime::AccountId32::from(new_pool_account.clone()).into(), - false, - ); - reads.saturating_accrue(2); - writes.saturating_accrue(2); - - // move LP token - let _ = T::PoolAssets::transfer( - pool_asset_id.clone(), - &old_pool_account, - &new_pool_account, - T::PoolAssets::balance(pool_asset_id.clone(), &old_pool_account), - Preservation::Expendable, - ); - reads.saturating_accrue(1); - writes.saturating_accrue(2); - - // change the ownership of LP token - let _ = pallet_assets::Pallet::::transfer_ownership( - RuntimeOrigin::signed(sp_runtime::AccountId32::from(old_pool_account.clone())), - pool_asset_id.into(), - sp_runtime::AccountId32::from(new_pool_account.clone()).into(), - ); - reads.saturating_accrue(1); - writes.saturating_accrue(2); - - // move LocalOrForeignAssets - let _ = T::Assets::transfer( - old_pool_id.1, - &old_pool_account, - &new_pool_account, - T::Assets::balance(old_pool_id.1, &old_pool_account), - Preservation::Expendable, - ); - reads.saturating_accrue(1); - writes.saturating_accrue(2); - - // dec providers for old account - let _ = frame_system::Pallet::::dec_providers(&old_pool_account); - writes.saturating_accrue(1); - - // change pool key - pallet_asset_conversion::Pools::::insert(new_pool_id, pool_info); - pallet_asset_conversion::Pools::::remove(old_pool_id); - } - - T::DbWeight::get().reads_writes(reads, writes) - } - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 0b108e3c022b3..7ef53179c54b5 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -56,9 +56,6 @@ use xcm_builder::{ }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; -#[cfg(feature = "runtime-benchmarks")] -use {cumulus_primitives_core::ParaId, sp_core::Get}; - parameter_types! { pub const WestendLocation: MultiLocation = MultiLocation::parent(); pub const RelayNetwork: Option = Some(NetworkId::Westend); @@ -66,8 +63,8 @@ parameter_types! { pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(ParachainInfo::parachain_id().into())); pub UniversalLocationNetworkId: NetworkId = UniversalLocation::get().global_consensus().unwrap(); - pub TrustBackedAssetsPalletLocation: MultiLocation = - PalletInstance(::index() as u8).into(); + pub AssetsPalletIndex: u32 = ::index() as u32; + pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(AssetsPalletIndex::get() as u8).into(); pub ForeignAssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: MultiLocation = @@ -649,30 +646,3 @@ impl pallet_assets::BenchmarkHelper for XcmBenchmarkHelper { MultiLocation { parents: 1, interior: X1(Parachain(id)) } } } - -#[cfg(feature = "runtime-benchmarks")] -pub struct BenchmarkMultiLocationConverter { - _phantom: sp_std::marker::PhantomData, -} - -#[cfg(feature = "runtime-benchmarks")] -impl pallet_asset_conversion::BenchmarkHelper - for BenchmarkMultiLocationConverter -where - SelfParaId: Get, -{ - fn asset_id(asset_id: u32) -> MultiLocation { - MultiLocation { - parents: 1, - interior: X3( - Parachain(SelfParaId::get().into()), - PalletInstance(::index() as u8), - GeneralIndex(asset_id.into()), - ), - } - } - - fn multiasset_id(asset_id: u32) -> MultiLocation { - Self::asset_id(asset_id) - } -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs index 599ff90e254aa..8a1f92b0ca12a 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -27,9 +27,8 @@ use asset_hub_westend_runtime::{ }; pub use asset_hub_westend_runtime::{ xcm_config::{CheckingAccount, TrustBackedAssetsPalletLocation, XcmConfig}, - AllowMultiAssetPools, AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, - ForeignAssetsInstance, ParachainSystem, Runtime, SessionKeys, System, - TrustBackedAssetsInstance, + AssetDeposit, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, + ParachainSystem, Runtime, SessionKeys, System, TrustBackedAssetsInstance, }; use asset_test_utils::{CollatorSessionKeys, ExtBuilder, XcmReceivedFrom}; use codec::{Decode, DecodeLimit, Encode}; From d28ffeaf8975cde403711b4b5a4e26de3373724d Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 16:34:46 +0200 Subject: [PATCH 49/69] asset hub emulated tests --- .../emulated/assets/asset-hub-rococo/src/tests/swap.rs | 2 +- .../emulated/assets/asset-hub-westend/src/tests/swap.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs index b16667eaeaecb..21162d60bf260 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-rococo/src/tests/swap.rs @@ -355,7 +355,7 @@ fn cannot_create_pool_from_pool_assets() { Box::new(asset_native), Box::new(asset_one), ), - Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset")) + Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown")) ); }); } diff --git a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs index feb30fa0347e1..1c59b2696bf5f 100644 --- a/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs +++ b/cumulus/parachains/integration-tests/emulated/assets/asset-hub-westend/src/tests/swap.rs @@ -341,7 +341,7 @@ fn cannot_create_pool_from_pool_assets() { Box::new(asset_native), Box::new(asset_one), ), - Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("UnsupportedAsset")) + Err(DispatchError::Module(ModuleError{index: _, error: _, message})) => assert_eq!(message, Some("Unknown")) ); }); } From d255301880a0a9f830aac5dde02c83d364acc6d9 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 18:54:13 +0200 Subject: [PATCH 50/69] clippy fixes --- substrate/frame/asset-conversion/src/lib.rs | 20 ++++++++++---------- substrate/frame/asset-conversion/src/swap.rs | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 6cc73452b250c..041877139c202 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -770,7 +770,7 @@ pub mod pallet { ) -> Result, (CreditOf, DispatchError)> { let amount_in = credit_in.peek(); let inspect_path = |credit_asset| { - ensure!(path.get(0).map_or(false, |a| *a == credit_asset), Error::::InvalidPath); + ensure!(path.first().map_or(false, |a| *a == credit_asset), Error::::InvalidPath); ensure!(!amount_in.is_zero(), Error::::ZeroAmount); ensure!(amount_out_min.map_or(true, |a| !a.is_zero()), Error::::ZeroAmount); @@ -815,7 +815,7 @@ pub mod pallet { ) -> Result<(CreditOf, CreditOf), (CreditOf, DispatchError)> { let amount_in_max = credit_in.peek(); let inspect_path = |credit_asset| { - ensure!(path.get(0).map_or(false, |a| a == &credit_asset), Error::::InvalidPath); + ensure!(path.first().map_or(false, |a| a == &credit_asset), Error::::InvalidPath); ensure!(amount_in_max > Zero::zero(), Error::::ZeroAmount); ensure!(amount_out > Zero::zero(), Error::::ZeroAmount); @@ -883,11 +883,11 @@ pub mod pallet { let resolve_path = || -> Result, DispatchError> { for pos in 0..=path.len() { if let Some([(asset1, _), (asset2, amount_out)]) = path.get(pos..=pos + 1) { - let pool_from = T::PoolLocator::pool_address(&asset1, &asset2) + let pool_from = T::PoolLocator::pool_address(asset1, asset2) .map_err(|_| Error::::InvalidAssetPair)?; if let Some((asset3, _)) = path.get(pos + 2) { - let pool_to = T::PoolLocator::pool_address(&asset2, &asset3) + let pool_to = T::PoolLocator::pool_address(asset2, asset3) .map_err(|_| Error::::InvalidAssetPair)?; T::Assets::transfer( @@ -904,7 +904,7 @@ pub mod pallet { } } } - return Err(Error::::InvalidPath.into()) + Err(Error::::InvalidPath.into()) }; let credit_out = match resolve_path() { @@ -913,7 +913,7 @@ pub mod pallet { }; let pool_to = if let Some([(asset1, _), (asset2, _)]) = path.get(0..2) { - match T::PoolLocator::pool_address(&asset1, &asset2) { + match T::PoolLocator::pool_address(asset1, asset2) { Ok(address) => address, Err(_) => return Err((credit_in, Error::::InvalidAssetPair.into())), } @@ -1121,7 +1121,7 @@ pub mod pallet { let reserve_out = T::HigherPrecisionBalance::from(*reserve_out); if reserve_in.is_zero() || reserve_out.is_zero() { - return Err(Error::::ZeroLiquidity.into()) + return Err(Error::::ZeroLiquidity) } let amount_in_with_fee = amount_in @@ -1156,11 +1156,11 @@ pub mod pallet { let reserve_out = T::HigherPrecisionBalance::from(*reserve_out); if reserve_in.is_zero() || reserve_out.is_zero() { - Err(Error::::ZeroLiquidity.into())? + Err(Error::::ZeroLiquidity)? } if amount_out >= reserve_out { - Err(Error::::AmountOutTooHigh.into())? + Err(Error::::AmountOutTooHigh)? } let numerator = reserve_in @@ -1193,7 +1193,7 @@ pub mod pallet { let mut pools = BTreeSet::::new(); for assets_pair in path.windows(2) { if let [asset1, asset2] = assets_pair { - let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + let pool_id = T::PoolLocator::pool_id(asset1, asset2) .map_err(|_| Error::::InvalidAssetPair)?; let new_element = pools.insert(pool_id); diff --git a/substrate/frame/asset-conversion/src/swap.rs b/substrate/frame/asset-conversion/src/swap.rs index f4f88e3e0695d..a6154e2941476 100644 --- a/substrate/frame/asset-conversion/src/swap.rs +++ b/substrate/frame/asset-conversion/src/swap.rs @@ -138,7 +138,7 @@ impl Swap for Pallet { keep_alive, ) })?; - Ok(amount_out.into()) + Ok(amount_out) } fn swap_tokens_for_exact_tokens( @@ -159,7 +159,7 @@ impl Swap for Pallet { keep_alive, ) })?; - Ok(amount_in.into()) + Ok(amount_in) } } From 4ec7496fa2632385b08fae860fcf28a523a7b5de Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 25 Oct 2023 19:02:17 +0200 Subject: [PATCH 51/69] clippy fixes --- substrate/frame/asset-conversion/src/tests.rs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 5700622d426be..32423435cbb7c 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -85,7 +85,7 @@ fn balance(owner: u128, token_id: NativeOrWithId) -> u128 { } fn pool_balance(owner: u128, token_id: u32) -> u128 { - <::PoolAssets>::balance(token_id, &owner) + <::PoolAssets>::balance(token_id, owner) } fn get_native_ed() -> u128 { @@ -542,9 +542,9 @@ fn can_remove_liquidity() { assert_ok!(Balances::force_set_balance( RuntimeOrigin::root(), user, - 10000000000 + ed_token_1.clone() + 10000000000 + ed_token_1 )); - assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 100000 + ed_token_2.clone())); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 100000 + ed_token_2)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), @@ -588,9 +588,9 @@ fn can_remove_liquidity() { assert_eq!( balance(user, token_1.clone()), - 10000000000 - 1000000000 + 899991000 + ed_token_1.clone() + 10000000000 - 1000000000 + 899991000 + ed_token_1 ); - assert_eq!(balance(user, token_2.clone()), 89999 + ed_token_2.clone()); + assert_eq!(balance(user, token_2.clone()), 89999 + ed_token_2); assert_eq!(pool_balance(user, lp_token), 0); }); } @@ -1675,7 +1675,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { // causes an account removal for native token 1 locate in the middle of a swap path let amount_in = AssetConversion::balance_path_from_amount_out( 110, - vec![token_3.clone(), token_1.clone()].try_into().unwrap(), + vec![token_3.clone(), token_1.clone()], ) .unwrap() .first() @@ -1697,7 +1697,7 @@ fn swap_when_existential_deposit_would_cause_reaping_pool_account() { // causes an account removal for asset token 2 locate in the middle of a swap path let amount_in = AssetConversion::balance_path_from_amount_out( 110, - vec![token_1.clone(), token_2.clone()].try_into().unwrap(), + vec![token_1.clone(), token_2.clone()], ) .unwrap() .first() @@ -2133,15 +2133,15 @@ fn swap_transactional() { ::PoolLocator::address(&(token_1.clone(), token_3.clone())).unwrap(); assert_eq!(Balances::balance(&pool_1), liquidity1); - assert_eq!(Assets::balance(2, &pool_1), liquidity2); + assert_eq!(Assets::balance(2, pool_1), liquidity2); assert_eq!(Balances::balance(&pool_2), liquidity1); - assert_eq!(Assets::balance(3, &pool_2), liquidity2); + assert_eq!(Assets::balance(3, pool_2), liquidity2); // the amount that would cause a transfer from the last pool in the path to fail let expected_out = liquidity2 - asset_ed + 1; let amount_in = AssetConversion::balance_path_from_amount_out( expected_out, - vec![token_2.clone(), token_1.clone(), token_3.clone()].try_into().unwrap(), + vec![token_2.clone(), token_1.clone(), token_3.clone()], ) .unwrap() .first() @@ -2205,9 +2205,9 @@ fn swap_transactional() { ); assert_eq!(Balances::balance(&pool_1), liquidity1); - assert_eq!(Assets::balance(2, &pool_1), liquidity2); + assert_eq!(Assets::balance(2, pool_1), liquidity2); assert_eq!(Balances::balance(&pool_2), liquidity1); - assert_eq!(Assets::balance(3, &pool_2), liquidity2); + assert_eq!(Assets::balance(3, pool_2), liquidity2); }) } @@ -2314,7 +2314,7 @@ fn swap_credit_insufficient_amount_bounds() { .unwrap_err(); assert_eq!( error, - (expected_credit_in.into(), Error::::ProvidedMinimumNotSufficientForSwap.into()) + (expected_credit_in, Error::::ProvidedMinimumNotSufficientForSwap.into()) ); // provided `credit_in` is not sufficient to swap for desired `amount_out` From 2ce50712e389fd3fb68735e072b3ce14aec7c345 Mon Sep 17 00:00:00 2001 From: Muharem Date: Thu, 26 Oct 2023 12:40:25 +0200 Subject: [PATCH 52/69] Apply suggestions from code review Co-authored-by: Liam Aharon --- .../frame/support/src/traits/tokens/fungible/union_of.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 0ba8cc28d83c6..8b46f0cb522d8 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -34,7 +34,7 @@ use sp_runtime::{ }; use sp_std::cmp::Ordering; -/// The `NativeOrWithId` enum classifies an asset as either `Native`` to the current chain or as an +/// The `NativeOrWithId` enum classifies an asset as either `Native` to the current chain or as an /// asset with a specific ID. #[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Debug)] pub enum NativeOrWithId @@ -95,7 +95,7 @@ impl Convert, Either<(), AssetId>> for Nat /// - `Left` is `fungible::*` implementation that is incorporated into the resulting union. /// - `Right` is `fungibles::*` implementation that is incorporated into the resulting union. /// - `Criterion` determines whether the `AssetKind` belongs to the `Left` or `Right` set. -/// - `AssetKind` is a superset type encompassing asset kinds from `Left`` and `Right` sets. +/// - `AssetKind` is a superset type encompassing asset kinds from `Left` and `Right` sets. /// - `AccountId` is an account identifier type. pub struct UnionOf( sp_std::marker::PhantomData<(Left, Right, Criterion, AssetKind, AccountId)>, From c60fa97ff7b2f7aab35f93ed7e42937b203a68b8 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 26 Oct 2023 13:12:36 +0200 Subject: [PATCH 53/69] fixes --- .../frame/support/src/traits/tokens/fungible/union_of.rs | 7 ++++--- .../frame/support/src/traits/tokens/fungibles/union_of.rs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 8b46f0cb522d8..43a6bae928484 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -31,12 +31,13 @@ use sp_runtime::{ traits::Convert, DispatchError, DispatchResult, Either, Either::{Left, Right}, + RuntimeDebug, }; use sp_std::cmp::Ordering; /// The `NativeOrWithId` enum classifies an asset as either `Native` to the current chain or as an /// asset with a specific ID. -#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Debug)] +#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, RuntimeDebug)] pub enum NativeOrWithId where AssetId: Ord, @@ -407,10 +408,10 @@ impl< precision: Precision, ) -> Result { match Criterion::convert(asset) { - Left(()) => >::decrease_balance_on_hold( + Left(()) => >::increase_balance_on_hold( reason, who, amount, precision, ), - Right(a) => >::decrease_balance_on_hold( + Right(a) => >::increase_balance_on_hold( a, reason, who, amount, precision, ), } diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index eb6927553d496..6b093f1f6cc55 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -355,10 +355,10 @@ impl< precision: Precision, ) -> Result { match Criterion::convert(asset) { - Left(a) => >::decrease_balance_on_hold( + Left(a) => >::increase_balance_on_hold( a, reason, who, amount, precision, ), - Right(a) => >::decrease_balance_on_hold( + Right(a) => >::increase_balance_on_hold( a, reason, who, amount, precision, ), } From 3b187eb747958203982854e7215185e0ee915eff Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 26 Oct 2023 13:17:40 +0200 Subject: [PATCH 54/69] derive Eq --- substrate/frame/support/src/traits/tokens/fungible/union_of.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 43a6bae928484..3fad47afddd3a 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -37,7 +37,7 @@ use sp_std::cmp::Ordering; /// The `NativeOrWithId` enum classifies an asset as either `Native` to the current chain or as an /// asset with a specific ID. -#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, RuntimeDebug)] +#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, RuntimeDebug, Eq)] pub enum NativeOrWithId where AssetId: Ord, @@ -75,7 +75,6 @@ impl PartialEq for NativeOrWithId { self.cmp(other) == Ordering::Equal } } -impl Eq for NativeOrWithId {} /// Criterion for [`UnionOf`] where a set for [`NativeOrWithId::Native`] asset located from the left /// and for [`NativeOrWithId::WithId`] from the right. From 03bec01f1687cd1fc2d72a876c584500622c2160 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 26 Oct 2023 13:27:52 +0200 Subject: [PATCH 55/69] update bounds --- substrate/frame/asset-conversion/src/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 049a028be9ca7..fd6d41a55b613 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -74,7 +74,7 @@ pub struct WithFirstAsset( impl PoolLocator for WithFirstAsset where - AssetKind: PartialEq + Clone + Encode, + AssetKind: Eq + Clone + Encode, AccountId: Decode, FirstAsset: Get, { @@ -98,7 +98,7 @@ pub struct Ascending(PhantomData<(AccountId, AssetKind)>); impl PoolLocator for Ascending where - AssetKind: PartialOrd + Clone + Encode, + AssetKind: Ord + Clone + Encode, AccountId: Decode, { fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { From 51c6dfc26ef3bdb3e0bacc249691e90d25d88072 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 30 Oct 2023 15:23:33 +0100 Subject: [PATCH 56/69] benchmarks --- .../assets/asset-hub-kusama/src/lib.rs | 2 +- .../src/weights/pallet_asset_conversion.rs | 224 ++++++++--- .../assets/asset-hub-rococo/src/lib.rs | 2 +- .../src/weights/pallet_asset_conversion.rs | 224 ++++++++--- .../assets/asset-hub-westend/src/lib.rs | 2 +- .../src/weights/pallet_asset_conversion.rs | 228 ++++++++--- .../runtimes/assets/common/src/benchmarks.rs | 24 +- .../asset-conversion/src/benchmarking.rs | 376 +++++++++--------- substrate/frame/asset-conversion/src/lib.rs | 18 +- substrate/frame/asset-conversion/src/mock.rs | 2 +- .../frame/asset-conversion/src/weights.rs | 232 ++++++----- 11 files changed, 846 insertions(+), 488 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs index 583fdd359a0a7..a8fb78e3059ef 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/lib.rs @@ -358,7 +358,7 @@ impl pallet_asset_conversion::Config for Runtime { type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; type PalletId = AssetConversionPalletId; - type MaxSwapPathLength = ConstU32<4>; + type MaxSwapPathLength = ConstU32<3>; type MintMinLiquidity = ConstU128<100>; type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs index 702f3743a7203..54a458de51aef 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs @@ -17,42 +17,48 @@ //! Autogenerated weights for `pallet_asset_conversion` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-30, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: `1024` // Executed Command: -// target/production/polkadot-parachain +// ./target/debug/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 +// --chain=asset-hub-kusama-dev +// --steps=20 +// --repeat=2 +// --pallet=pallet-asset-conversion // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/cumulus/.git/.artifacts/bench.json -// --pallet=pallet_asset_conversion -// --chain=asset-hub-kusama-dev -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-kusama/src/weights/ +// --output=./cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::Weight}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions for `pallet_asset_conversion`. -pub struct WeightInfo(PhantomData); -impl pallet_asset_conversion::WeightInfo for WeightInfo { +/// Weight functions needed for `pallet_asset_conversion`. +pub trait WeightInfo { + fn create_pool() -> Weight; + fn add_liquidity() -> Weight; + fn remove_liquidity() -> Weight; + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; +} + +/// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) - /// Storage: `System::Account` (r:2 w:1) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:1 w:1) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) @@ -66,22 +72,21 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `480` - // Estimated: `6196` - // Minimum execution time: 88_484_000 picoseconds. - Weight::from_parts(92_964_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `408` + // Estimated: `4689` + // Minimum execution time: 909_000_000 picoseconds. + Weight::from_parts(944_000_000, 4689) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Asset` (r:1 w:1) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:2 w:2) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Account` (r:2 w:2) @@ -90,35 +95,138 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo // Proof Size summary in bytes: // Measured: `1117` // Estimated: `7404` - // Minimum execution time: 153_015_000 picoseconds. - Weight::from_parts(157_018_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) + // Minimum execution time: 1_629_000_000 picoseconds. + Weight::from_parts(1_766_000_000, 7404) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn remove_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1106` + // Estimated: `7404` + // Minimum execution time: 1_431_000_000 picoseconds. + Weight::from_parts(1_517_000_000, 7404) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 3]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 922_000_000 picoseconds. + Weight::from_parts(954_000_000, 7404) + // Standard Error: 15_697_849 + .saturating_add(Weight::from_parts(39_602_040, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 3]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±73)` + // Minimum execution time: 929_000_000 picoseconds. + Weight::from_parts(947_000_000, 7404) + // Standard Error: 15_496_079 + .saturating_add(Weight::from_parts(41_295_918, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `AssetConversion::Pools` (r:1 w:1) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) + /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn create_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `408` + // Estimated: `4689` + // Minimum execution time: 909_000_000 picoseconds. + Weight::from_parts(944_000_000, 4689) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn add_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1117` + // Estimated: `7404` + // Minimum execution time: 1_629_000_000 picoseconds. + Weight::from_parts(1_766_000_000, 7404) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Asset` (r:1 w:1) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:2 w:2) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) /// Storage: `PoolAssets::Account` (r:1 w:1) /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn remove_liquidity() -> Weight { // Proof Size summary in bytes: // Measured: `1106` // Estimated: `7404` - // Minimum execution time: 141_726_000 picoseconds. - Weight::from_parts(147_865_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) + // Minimum execution time: 1_431_000_000 picoseconds. + Weight::from_parts(1_517_000_000, 7404) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `ForeignAssets::Asset` (r:2 w:2) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) @@ -126,15 +234,18 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn swap_exact_tokens_for_tokens() -> Weight { + /// The range of component `n` is `[2, 3]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1148` - // Estimated: `13818` - // Minimum execution time: 168_619_000 picoseconds. - Weight::from_parts(174_283_000, 0) - .saturating_add(Weight::from_parts(0, 13818)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 922_000_000 picoseconds. + Weight::from_parts(954_000_000, 7404) + // Standard Error: 15_697_849 + .saturating_add(Weight::from_parts(39_602_040, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -142,14 +253,17 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:4 w:4) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - fn swap_tokens_for_exact_tokens() -> Weight { + /// The range of component `n` is `[2, 3]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1148` - // Estimated: `13818` - // Minimum execution time: 171_565_000 picoseconds. - Weight::from_parts(173_702_000, 0) - .saturating_add(Weight::from_parts(0, 13818)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±73)` + // Minimum execution time: 929_000_000 picoseconds. + Weight::from_parts(947_000_000, 7404) + // Standard Error: 15_496_079 + .saturating_add(Weight::from_parts(41_295_918, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index dcfc41c79620c..004cc9b232831 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -364,7 +364,7 @@ impl pallet_asset_conversion::Config for Runtime { type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; type PalletId = AssetConversionPalletId; - type MaxSwapPathLength = ConstU32<4>; + type MaxSwapPathLength = ConstU32<3>; type MintMinLiquidity = ConstU128<100>; type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs index 4514fbfa8763a..a416c6947ce2e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs @@ -17,42 +17,48 @@ //! Autogenerated weights for `pallet_asset_conversion` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-30, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: `1024` // Executed Command: -// target/production/polkadot-parachain +// ./target/debug/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 +// --chain=asset-hub-rococo-dev +// --steps=20 +// --repeat=2 +// --pallet=pallet-asset-conversion // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/cumulus/.git/.artifacts/bench.json -// --pallet=pallet_asset_conversion -// --chain=asset-hub-rococo-dev -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::Weight}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions for `pallet_asset_conversion`. -pub struct WeightInfo(PhantomData); -impl pallet_asset_conversion::WeightInfo for WeightInfo { +/// Weight functions needed for `pallet_asset_conversion`. +pub trait WeightInfo { + fn create_pool() -> Weight; + fn add_liquidity() -> Weight; + fn remove_liquidity() -> Weight; + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; +} + +/// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) - /// Storage: `System::Account` (r:2 w:1) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:1 w:1) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) @@ -66,22 +72,21 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `480` - // Estimated: `6196` - // Minimum execution time: 88_484_000 picoseconds. - Weight::from_parts(92_964_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `408` + // Estimated: `4689` + // Minimum execution time: 917_000_000 picoseconds. + Weight::from_parts(989_000_000, 4689) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Asset` (r:1 w:1) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:2 w:2) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Account` (r:2 w:2) @@ -90,35 +95,138 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo // Proof Size summary in bytes: // Measured: `1117` // Estimated: `7404` - // Minimum execution time: 153_015_000 picoseconds. - Weight::from_parts(157_018_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) + // Minimum execution time: 1_622_000_000 picoseconds. + Weight::from_parts(1_639_000_000, 7404) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn remove_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1106` + // Estimated: `7404` + // Minimum execution time: 1_496_000_000 picoseconds. + Weight::from_parts(1_497_000_000, 7404) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 3]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 925_000_000 picoseconds. + Weight::from_parts(947_000_000, 7404) + // Standard Error: 15_819_119 + .saturating_add(Weight::from_parts(38_448_979, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 3]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±73)` + // Minimum execution time: 913_000_000 picoseconds. + Weight::from_parts(945_000_000, 7404) + // Standard Error: 17_010_580 + .saturating_add(Weight::from_parts(43_326_530, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `AssetConversion::Pools` (r:1 w:1) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) + /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn create_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `408` + // Estimated: `4689` + // Minimum execution time: 917_000_000 picoseconds. + Weight::from_parts(989_000_000, 4689) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn add_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1117` + // Estimated: `7404` + // Minimum execution time: 1_622_000_000 picoseconds. + Weight::from_parts(1_639_000_000, 7404) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Asset` (r:1 w:1) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:2 w:2) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) /// Storage: `PoolAssets::Account` (r:1 w:1) /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn remove_liquidity() -> Weight { // Proof Size summary in bytes: // Measured: `1106` // Estimated: `7404` - // Minimum execution time: 141_726_000 picoseconds. - Weight::from_parts(147_865_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) + // Minimum execution time: 1_496_000_000 picoseconds. + Weight::from_parts(1_497_000_000, 7404) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `ForeignAssets::Asset` (r:2 w:2) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) @@ -126,15 +234,18 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn swap_exact_tokens_for_tokens() -> Weight { + /// The range of component `n` is `[2, 3]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1148` - // Estimated: `13818` - // Minimum execution time: 168_619_000 picoseconds. - Weight::from_parts(174_283_000, 0) - .saturating_add(Weight::from_parts(0, 13818)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 925_000_000 picoseconds. + Weight::from_parts(947_000_000, 7404) + // Standard Error: 15_819_119 + .saturating_add(Weight::from_parts(38_448_979, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -142,14 +253,17 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:4 w:4) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - fn swap_tokens_for_exact_tokens() -> Weight { + /// The range of component `n` is `[2, 3]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1148` - // Estimated: `13818` - // Minimum execution time: 171_565_000 picoseconds. - Weight::from_parts(173_702_000, 0) - .saturating_add(Weight::from_parts(0, 13818)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±73)` + // Minimum execution time: 913_000_000 picoseconds. + Weight::from_parts(945_000_000, 7404) + // Standard Error: 17_010_580 + .saturating_add(Weight::from_parts(43_326_530, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 8f7518ee6bf36..fe9bb3dd99e06 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -335,7 +335,7 @@ impl pallet_asset_conversion::Config for Runtime { type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type LPFee = ConstU32<3>; type PalletId = AssetConversionPalletId; - type MaxSwapPathLength = ConstU32<4>; + type MaxSwapPathLength = ConstU32<3>; type MintMinLiquidity = ConstU128<100>; type WeightInfo = weights::pallet_asset_conversion::WeightInfo; #[cfg(feature = "runtime-benchmarks")] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs index 2f39df6540304..87c22abfcf571 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs @@ -17,44 +17,48 @@ //! Autogenerated weights for `pallet_asset_conversion` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-30, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/polkadot-parachain +// ./target/debug/polkadot-parachain // benchmark // pallet // --chain=asset-hub-westend-dev -// --wasm-execution=compiled -// --pallet=pallet_asset_conversion -// --no-storage-info -// --no-median-slopes -// --no-min-squares +// --steps=20 +// --repeat=2 +// --pallet=pallet-asset-conversion // --extrinsic=* -// --steps=50 -// --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::Weight}; +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions for `pallet_asset_conversion`. -pub struct WeightInfo(PhantomData); -impl pallet_asset_conversion::WeightInfo for WeightInfo { +/// Weight functions needed for `pallet_asset_conversion`. +pub trait WeightInfo { + fn create_pool() -> Weight; + fn add_liquidity() -> Weight; + fn remove_liquidity() -> Weight; + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; +} + +/// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x76a2c49709deec21d9c05f96c1f47351` (r:1 w:0) - /// Storage: `System::Account` (r:2 w:1) + /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:1 w:1) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) @@ -68,22 +72,21 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `480` - // Estimated: `6196` - // Minimum execution time: 90_011_000 picoseconds. - Weight::from_parts(92_372_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + // Measured: `408` + // Estimated: `4689` + // Minimum execution time: 904_000_000 picoseconds. + Weight::from_parts(938_000_000, 4689) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Asset` (r:1 w:1) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:2 w:2) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Account` (r:2 w:2) @@ -92,35 +95,138 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo // Proof Size summary in bytes: // Measured: `1117` // Estimated: `7404` - // Minimum execution time: 153_484_000 picoseconds. - Weight::from_parts(155_465_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(7)) + // Minimum execution time: 1_613_000_000 picoseconds. + Weight::from_parts(1_923_000_000, 7404) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn remove_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1106` + // Estimated: `7404` + // Minimum execution time: 1_479_000_000 picoseconds. + Weight::from_parts(1_559_000_000, 7404) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 3]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 920_000_000 picoseconds. + Weight::from_parts(950_000_000, 7404) + // Standard Error: 18_279_661 + .saturating_add(Weight::from_parts(47_071_428, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) + } + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:2 w:2) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:4 w:4) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 3]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 932_000_000 picoseconds. + Weight::from_parts(944_000_000, 7404) + // Standard Error: 14_264_382 + .saturating_add(Weight::from_parts(41_938_775, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `AssetConversion::Pools` (r:1 w:1) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:1 w:1) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) + /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:1 w:1) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn create_pool() -> Weight { + // Proof Size summary in bytes: + // Measured: `408` + // Estimated: `4689` + // Minimum execution time: 904_000_000 picoseconds. + Weight::from_parts(938_000_000, 4689) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + fn add_liquidity() -> Weight { + // Proof Size summary in bytes: + // Measured: `1117` + // Estimated: `7404` + // Minimum execution time: 1_613_000_000 picoseconds. + Weight::from_parts(1_923_000_000, 7404) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Asset` (r:1 w:1) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:2 w:2) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x2433d831722b1f4aeb1666953f1c0e77` (r:1 w:0) /// Storage: `PoolAssets::Account` (r:1 w:1) /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn remove_liquidity() -> Weight { // Proof Size summary in bytes: // Measured: `1106` // Estimated: `7404` - // Minimum execution time: 141_326_000 picoseconds. - Weight::from_parts(143_882_000, 0) - .saturating_add(Weight::from_parts(0, 7404)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) + // Minimum execution time: 1_479_000_000 picoseconds. + Weight::from_parts(1_559_000_000, 7404) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `ForeignAssets::Asset` (r:2 w:2) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) @@ -128,15 +234,18 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn swap_exact_tokens_for_tokens() -> Weight { + /// The range of component `n` is `[2, 3]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1148` - // Estimated: `13818` - // Minimum execution time: 168_556_000 picoseconds. - Weight::from_parts(170_313_000, 0) - .saturating_add(Weight::from_parts(0, 13818)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 920_000_000 picoseconds. + Weight::from_parts(950_000_000, 7404) + // Standard Error: 18_279_661 + .saturating_add(Weight::from_parts(47_071_428, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) @@ -144,14 +253,17 @@ impl pallet_asset_conversion::WeightInfo for WeightInfo /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) /// Storage: `ForeignAssets::Account` (r:4 w:4) /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - fn swap_tokens_for_exact_tokens() -> Weight { + /// The range of component `n` is `[2, 3]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1148` - // Estimated: `13818` - // Minimum execution time: 167_704_000 picoseconds. - Weight::from_parts(170_034_000, 0) - .saturating_add(Weight::from_parts(0, 13818)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `0 + n * (557 ±0)` + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 932_000_000 picoseconds. + Weight::from_parts(944_000_000, 7404) + // Standard Error: 14_264_382 + .saturating_add(Weight::from_parts(41_938_775, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) + .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } } diff --git a/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs b/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs index ed1379695317c..344cb5ca33684 100644 --- a/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs +++ b/cumulus/parachains/runtimes/assets/common/src/benchmarks.rs @@ -26,17 +26,19 @@ impl, SelfParaId: Get, PalletId: Get> pallet_asset_conversion::BenchmarkHelper for AssetPairFactory { - fn create_pair(_seed1: u32, seed2: u32) -> (MultiLocation, MultiLocation) { - ( - Target::get(), - MultiLocation::new( - 1, - X3( - Parachain(SelfParaId::get().into()), - PalletInstance(PalletId::get() as u8), - GeneralIndex(seed2.into()), - ), + fn create_pair(seed1: u32, seed2: u32) -> (MultiLocation, MultiLocation) { + let with_id = MultiLocation::new( + 1, + X3( + Parachain(SelfParaId::get().into()), + PalletInstance(PalletId::get() as u8), + GeneralIndex(seed2.into()), ), - ) + ); + if seed1 % 2 == 0 { + (with_id, Target::get()) + } else { + (Target::get(), with_id) + } } } diff --git a/substrate/frame/asset-conversion/src/benchmarking.rs b/substrate/frame/asset-conversion/src/benchmarking.rs index 2892995830bcb..f0e02c802ad8e 100644 --- a/substrate/frame/asset-conversion/src/benchmarking.rs +++ b/substrate/frame/asset-conversion/src/benchmarking.rs @@ -29,12 +29,14 @@ use frame_support::{ }; use frame_system::RawOrigin as SystemOrigin; use sp_core::Get; -use sp_runtime::traits::StaticLookup; use sp_std::{marker::PhantomData, prelude::*}; /// Benchmark Helper pub trait BenchmarkHelper { /// Returns a valid assets pair for the pool creation. + /// + /// When a specific asset, such as the native asset, is required in every pool, it should be + /// returned for each odd-numbered seed. fn create_pair(seed1: u32, seed2: u32) -> (AssetKind, AssetKind); } @@ -53,65 +55,105 @@ pub struct NativeOrWithIdFactory(PhantomData); impl + Ord> BenchmarkHelper> for NativeOrWithIdFactory { - fn create_pair(_seed1: u32, seed2: u32) -> (NativeOrWithId, NativeOrWithId) { - (NativeOrWithId::Native, NativeOrWithId::WithId(seed2.into())) + fn create_pair(seed1: u32, seed2: u32) -> (NativeOrWithId, NativeOrWithId) { + if seed1 % 2 == 0 { + (NativeOrWithId::WithId(seed2.into()), NativeOrWithId::Native) + } else { + (NativeOrWithId::Native, NativeOrWithId::WithId(seed2.into())) + } } } -const INITIAL_ASSET_BALANCE: u128 = 1_000_000_000_000; -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; - -fn get_lp_token_id() -> T::PoolAssetId +/// Provides a pair of amounts expected to serve as sufficient initial liquidity for a pool. +fn valid_liquidity_amount(ed1: T::Balance, ed2: T::Balance) -> (T::Balance, T::Balance) where - T::PoolAssetId: Into, + T::Assets: Inspect, { - let next_id: u32 = AssetConversion::::get_next_pool_asset_id().into(); - (next_id - 1).into() + let l = + ed1.max(ed2) + T::MintMinLiquidity::get() + T::MintMinLiquidity::get() + T::Balance::one(); + (l, l) } -fn create_asset(asset: &T::AssetKind) -> (T::AccountId, AccountIdLookupOf) +/// Create the `asset` and mint the `amount` for the `caller`. +fn create_asset(caller: &T::AccountId, asset: &T::AssetKind, amount: T::Balance) where - T::Balance: From, T::Assets: Create + Mutate, { - let caller: T::AccountId = whitelisted_caller(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); if !T::Assets::asset_exists(asset.clone()) { - assert_ok!(T::Assets::create(asset.clone(), caller.clone(), true, 1.into())); + assert_ok!(T::Assets::create(asset.clone(), caller.clone(), true, T::Balance::one())); } - assert_ok!(T::Assets::mint_into(asset.clone(), &caller, INITIAL_ASSET_BALANCE.into())); - - (caller, caller_lookup) + assert_ok!(T::Assets::mint_into( + asset.clone(), + &caller, + amount + T::Assets::minimum_balance(asset.clone()) + )); } -fn create_asset_and_pool( - asset1: &T::AssetKind, - asset2: &T::AssetKind, -) -> (T::PoolAssetId, T::AccountId, AccountIdLookupOf) +/// Create the designated fee asset for pool creation. +fn create_fee_asset(caller: &T::AccountId) where - T::Balance: From, T::Assets: Create + Mutate, - T::PoolAssetId: Into, { let fee_asset = T::PoolSetupFeeAsset::get(); - let (_, _) = create_asset::(&fee_asset); - let (_, _) = create_asset::(asset1); - let (caller, caller_lookup) = create_asset::(asset2); - + if !T::Assets::asset_exists(fee_asset.clone()) { + assert_ok!(T::Assets::create(fee_asset.clone(), caller.clone(), true, T::Balance::one())); + } assert_ok!(T::Assets::mint_into( fee_asset.clone(), &caller, - T::PoolSetupFee::get() + T::Assets::minimum_balance(fee_asset) + T::Assets::minimum_balance(fee_asset) + )); +} + +/// Mint the fee asset for the `caller` sufficient to cover the fee for creating a new pool. +fn mint_setup_fee_asset( + caller: &T::AccountId, + asset1: &T::AssetKind, + asset2: &T::AssetKind, + lp_token: &T::PoolAssetId, +) where + T::Assets: Create + Mutate, +{ + assert_ok!(T::Assets::mint_into( + T::PoolSetupFeeAsset::get(), + &caller, + T::PoolSetupFee::get() + + T::Assets::deposit_required(asset1.clone()) + + T::Assets::deposit_required(asset2.clone()) + + T::PoolAssets::deposit_required(lp_token.clone()) )); +} + +/// Creates a pool for a given asset pair. +/// +/// This action mints the necessary amounts of the given assets for the `caller` to provide initial +/// liquidity. It returns the LP token ID along with a pair of amounts sufficient for the pool's +/// initial liquidity. +fn create_asset_and_pool( + caller: &T::AccountId, + asset1: &T::AssetKind, + asset2: &T::AssetKind, +) -> (T::PoolAssetId, T::Balance, T::Balance) +where + T::Assets: Create + Mutate, +{ + let (liquidity1, liquidity2) = valid_liquidity_amount::( + T::Assets::minimum_balance(asset1.clone()), + T::Assets::minimum_balance(asset2.clone()), + ); + create_asset::(caller, asset1, liquidity1); + create_asset::(caller, asset2, liquidity2); + let lp_token = AssetConversion::::get_next_pool_asset_id(); + + mint_setup_fee_asset::(caller, asset1, asset2, &lp_token); assert_ok!(AssetConversion::::create_pool( SystemOrigin::Signed(caller.clone()).into(), Box::new(asset1.clone()), Box::new(asset2.clone()) )); - let lp_token = get_lp_token_id::(); - (lp_token, caller, caller_lookup) + (lp_token, liquidity1, liquidity2) } fn assert_last_event(generic_event: ::RuntimeEvent) { @@ -122,82 +164,79 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { assert_eq!(event, &system_event); } -#[benchmarks(where T::Balance: From + Into, T::Assets: Create + Mutate, T::PoolAssetId: Into,)] +#[benchmarks(where T::Assets: Create + Mutate, T::PoolAssetId: Into,)] mod benchmarks { use super::*; #[benchmark] fn create_pool() { + let caller: T::AccountId = whitelisted_caller(); let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); - let (_, _) = create_asset::(&asset1); - let (caller, _) = create_asset::(&asset2); + create_asset::(&caller, &asset1, T::Assets::minimum_balance(asset1.clone())); + create_asset::(&caller, &asset2, T::Assets::minimum_balance(asset2.clone())); - assert_ok!(T::Assets::mint_into( - T::PoolSetupFeeAsset::get(), - &caller, - T::PoolSetupFee::get() + T::Assets::minimum_balance(T::PoolSetupFeeAsset::get()) - )); + let lp_token = AssetConversion::::get_next_pool_asset_id(); + create_fee_asset::(&caller); + mint_setup_fee_asset::(&caller, &asset1, &asset2, &lp_token); #[extrinsic_call] _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone())); - let lp_token = get_lp_token_id::(); let pool_id = T::PoolLocator::pool_id(&asset1, &asset2).unwrap(); let pool_account = T::PoolLocator::address(&pool_id).unwrap(); assert_last_event::( - Event::PoolCreated { creator: caller.clone(), pool_account, pool_id, lp_token }.into(), + Event::PoolCreated { creator: caller, pool_account, pool_id, lp_token }.into(), ); } #[benchmark] fn add_liquidity() { + let caller: T::AccountId = whitelisted_caller(); let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); - let (lp_token, caller, _) = create_asset_and_pool::(&asset1, &asset2); - let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); - let add_amount = 1000 + ed; + + create_fee_asset::(&caller); + let (lp_token, liquidity1, liquidity2) = + create_asset_and_pool::(&caller, &asset1, &asset2); #[extrinsic_call] _( SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone()), - add_amount.into(), - 1000.into(), - 0.into(), - 0.into(), + liquidity1, + liquidity2, + T::Balance::one(), + T::Balance::zero(), caller.clone(), ); let pool_account = T::PoolLocator::pool_address(&asset1, &asset2).unwrap(); let lp_minted = - AssetConversion::::calc_lp_amount_for_zero_supply(&add_amount.into(), &1000.into()) - .unwrap() - .into(); - assert_eq!(T::PoolAssets::balance(lp_token, &caller), lp_minted.into()); - assert_eq!(T::Assets::balance(asset1, &pool_account), add_amount.into()); - assert_eq!(T::Assets::balance(asset2, &pool_account), 1000.into()); + AssetConversion::::calc_lp_amount_for_zero_supply(&liquidity1, &liquidity2).unwrap(); + assert_eq!(T::PoolAssets::balance(lp_token, &caller), lp_minted); + assert_eq!(T::Assets::balance(asset1, &pool_account), liquidity1); + assert_eq!(T::Assets::balance(asset2, &pool_account), liquidity2); } #[benchmark] fn remove_liquidity() { + let caller: T::AccountId = whitelisted_caller(); let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); - let (lp_token, caller, _) = create_asset_and_pool::(&asset1, &asset2); - let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); - let add_amount = 100 * ed; - let lp_minted = - AssetConversion::::calc_lp_amount_for_zero_supply(&add_amount.into(), &1000.into()) - .unwrap() - .into(); - let remove_lp_amount = lp_minted.checked_div(10).unwrap(); + + create_fee_asset::(&caller); + let (lp_token, liquidity1, liquidity2) = + create_asset_and_pool::(&caller, &asset1, &asset2); + + let remove_lp_amount = T::Balance::one(); assert_ok!(AssetConversion::::add_liquidity( SystemOrigin::Signed(caller.clone()).into(), Box::new(asset1.clone()), Box::new(asset2.clone()), - add_amount.into(), - 1000.into(), - 0.into(), - 0.into(), + liquidity1, + liquidity2, + T::Balance::one(), + T::Balance::zero(), caller.clone(), )); let total_supply = @@ -208,142 +247,115 @@ mod benchmarks { SystemOrigin::Signed(caller.clone()), Box::new(asset1), Box::new(asset2), - remove_lp_amount.into(), - 0.into(), - 0.into(), + remove_lp_amount, + T::Balance::zero(), + T::Balance::zero(), caller.clone(), ); - let new_total_supply = - >::total_issuance(lp_token.clone()); - assert_eq!(new_total_supply, total_supply - remove_lp_amount.into()); + let new_total_supply = >::total_issuance(lp_token); + assert_eq!(new_total_supply, total_supply - remove_lp_amount); } #[benchmark] - fn swap_exact_tokens_for_tokens() { - let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); - let (_, asset3) = T::BenchmarkHelper::create_pair(1, 2); - let (_, asset4) = T::BenchmarkHelper::create_pair(2, 3); - - let (_, caller, _) = create_asset_and_pool::(&asset1, &asset2); - let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); - - assert_ok!(AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset1.clone()), - Box::new(asset2.clone()), - (100 * ed).into(), - 200.into(), - 1.into(), - 0.into(), - caller.clone(), - )); - - let (_, _, _) = create_asset_and_pool::(&asset2, &asset3); - assert_ok!(AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset2.clone()), - Box::new(asset3.clone()), - 200.into(), - 2000.into(), - 1.into(), - 0.into(), - caller.clone(), - )); - - let (_, _, _) = create_asset_and_pool::(&asset3, &asset4); - assert_ok!(AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset3.clone()), - Box::new(asset4.clone()), - 2000.into(), - 2000.into(), - 1.into(), - 1.into(), - caller.clone(), + fn swap_exact_tokens_for_tokens(n: Linear<2, { T::MaxSwapPathLength::get() }>) { + let mut swap_amount = T::Balance::one(); + let mut path = vec![]; + + let caller: T::AccountId = whitelisted_caller(); + create_fee_asset::(&caller); + for n in 1..n { + let (asset1, asset2) = T::BenchmarkHelper::create_pair(n - 1, n); + swap_amount = swap_amount + T::Balance::one(); + if path.len() == 0 { + path = vec![Box::new(asset1.clone()), Box::new(asset2.clone())]; + } else { + path.push(Box::new(asset2.clone())); + } + + let (_, liquidity1, liquidity2) = create_asset_and_pool::(&caller, &asset1, &asset2); + + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()), + liquidity1, + liquidity2, + T::Balance::one(), + T::Balance::zero(), + caller.clone(), + )); + } + + let asset_in = *path.first().unwrap().clone(); + assert_ok!(T::Assets::mint_into( + asset_in.clone(), + &caller, + swap_amount + T::Balance::one() )); - let path = vec![ - Box::new(asset1.clone()), - Box::new(asset2.clone()), - Box::new(asset3.clone()), - Box::new(asset4.clone()), - ]; - - let swap_amount = ed.into(); - let asset1_balance = T::Assets::balance(asset1.clone(), &caller); + let init_caller_balance = T::Assets::balance(asset_in.clone(), &caller); #[extrinsic_call] - _(SystemOrigin::Signed(caller.clone()), path, swap_amount, 1.into(), caller.clone(), false); + _( + SystemOrigin::Signed(caller.clone()), + path, + swap_amount, + T::Balance::one(), + caller.clone(), + true, + ); - let new_asset1_balance = T::Assets::balance(asset1, &caller); - assert_eq!(new_asset1_balance, asset1_balance - ed.into()); + let actual_balance = T::Assets::balance(asset_in, &caller); + assert_eq!(actual_balance, init_caller_balance - swap_amount); } #[benchmark] - fn swap_tokens_for_exact_tokens() { - let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); - let (_, asset3) = T::BenchmarkHelper::create_pair(1, 2); - let (_, asset4) = T::BenchmarkHelper::create_pair(2, 3); - - let (_, caller, _) = create_asset_and_pool::(&asset1, &asset2); - let ed: u128 = T::Assets::minimum_balance(asset1.clone()).into(); - - assert_ok!(AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset1.clone()), - Box::new(asset2.clone()), - (1000 * ed).into(), - 500.into(), - 1.into(), - 0.into(), - caller.clone(), - )); - - let (_, _, _) = create_asset_and_pool::(&asset2, &asset3); - assert_ok!(AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset2.clone()), - Box::new(asset3.clone()), - 2000.into(), - 2000.into(), - 1.into(), - 0.into(), - caller.clone(), - )); - - let (_, _, _) = create_asset_and_pool::(&asset3, &asset4); - assert_ok!(AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - Box::new(asset3.clone()), - Box::new(asset4.clone()), - 2000.into(), - 2000.into(), - 1.into(), - 0.into(), - caller.clone(), - )); - - let path = vec![ - Box::new(asset1.clone()), - Box::new(asset2.clone()), - Box::new(asset3.clone()), - Box::new(asset4.clone()), - ]; - - let asset4_balance = T::Assets::balance(asset4.clone(), &caller); + fn swap_tokens_for_exact_tokens(n: Linear<2, { T::MaxSwapPathLength::get() }>) { + let mut max_swap_amount = T::Balance::one(); + let mut path = vec![]; + + let caller: T::AccountId = whitelisted_caller(); + create_fee_asset::(&caller); + for n in 1..n { + let (asset1, asset2) = T::BenchmarkHelper::create_pair(n - 1, n); + max_swap_amount = max_swap_amount + T::Balance::one() + T::Balance::one(); + if path.len() == 0 { + path = vec![Box::new(asset1.clone()), Box::new(asset2.clone())]; + } else { + path.push(Box::new(asset2.clone())); + } + + let (_, liquidity1, liquidity2) = create_asset_and_pool::(&caller, &asset1, &asset2); + + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()), + liquidity1, + liquidity2, + T::Balance::one(), + T::Balance::zero(), + caller.clone(), + )); + } + + let asset_in = *path.first().unwrap().clone(); + let asset_out = *path.last().unwrap().clone(); + assert_ok!(T::Assets::mint_into(asset_in, &caller, max_swap_amount)); + let init_caller_balance = T::Assets::balance(asset_out.clone(), &caller); #[extrinsic_call] _( SystemOrigin::Signed(caller.clone()), - path.clone(), - 100.into(), - (1000 * ed).into(), + path, + T::Balance::one(), + max_swap_amount, caller.clone(), - false, + true, ); - let new_asset4_balance = T::Assets::balance(asset4, &caller); - assert_eq!(new_asset4_balance, asset4_balance + 100.into()); + let actual_balance = T::Assets::balance(asset_out, &caller); + assert_eq!(actual_balance, init_caller_balance + T::Balance::one()); } impl_benchmark_test_suite!(AssetConversion, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 041877139c202..7f4a8e21c4b30 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -129,7 +129,7 @@ pub mod pallet { /// Registry of assets utilized for providing liquidity to pools. type Assets: Inspect + Mutate - + AccountTouch + + AccountTouch + ContainsPair + Balanced; @@ -150,7 +150,7 @@ pub mod pallet { type PoolAssets: Inspect + Create + Mutate - + AccountTouch; + + AccountTouch; /// A % the liquidity providers will take of every swap. Represents 10ths of a percent. #[pallet::constant] @@ -605,7 +605,7 @@ pub mod pallet { /// [`AssetConversionApi::quote_price_exact_tokens_for_tokens`] runtime call can be called /// for a quote. #[pallet::call_index(3)] - #[pallet::weight(T::WeightInfo::swap_exact_tokens_for_tokens())] + #[pallet::weight(T::WeightInfo::swap_exact_tokens_for_tokens(path.len() as u32))] pub fn swap_exact_tokens_for_tokens( origin: OriginFor, path: Vec>, @@ -633,7 +633,7 @@ pub mod pallet { /// [`AssetConversionApi::quote_price_tokens_for_exact_tokens`] runtime call can be called /// for a quote. #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::swap_tokens_for_exact_tokens())] + #[pallet::weight(T::WeightInfo::swap_tokens_for_exact_tokens(path.len() as u32))] pub fn swap_tokens_for_exact_tokens( origin: OriginFor, path: Vec>, @@ -770,7 +770,10 @@ pub mod pallet { ) -> Result, (CreditOf, DispatchError)> { let amount_in = credit_in.peek(); let inspect_path = |credit_asset| { - ensure!(path.first().map_or(false, |a| *a == credit_asset), Error::::InvalidPath); + ensure!( + path.first().map_or(false, |a| *a == credit_asset), + Error::::InvalidPath + ); ensure!(!amount_in.is_zero(), Error::::ZeroAmount); ensure!(amount_out_min.map_or(true, |a| !a.is_zero()), Error::::ZeroAmount); @@ -815,7 +818,10 @@ pub mod pallet { ) -> Result<(CreditOf, CreditOf), (CreditOf, DispatchError)> { let amount_in_max = credit_in.peek(); let inspect_path = |credit_asset| { - ensure!(path.first().map_or(false, |a| a == &credit_asset), Error::::InvalidPath); + ensure!( + path.first().map_or(false, |a| a == &credit_asset), + Error::::InvalidPath + ); ensure!(amount_in_max > Zero::zero(), Error::::ZeroAmount); ensure!(amount_out > Zero::zero(), Error::::ZeroAmount); diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 05de1b3d90f7b..377cbc314e193 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -180,7 +180,7 @@ impl Config for Test { type MaxSwapPathLength = ConstU32<4>; type MintMinLiquidity = ConstU128<100>; // 100 is good enough when the main currency has 12 decimals. #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = NativeOrWithIdFactory; + type BenchmarkHelper = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/substrate/frame/asset-conversion/src/weights.rs b/substrate/frame/asset-conversion/src/weights.rs index 550878ba0be96..a0e687f7a4168 100644 --- a/substrate/frame/asset-conversion/src/weights.rs +++ b/substrate/frame/asset-conversion/src/weights.rs @@ -15,29 +15,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated weights for pallet_asset_conversion +//! Autogenerated weights for `pallet_asset_conversion` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-30, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-gghbxkbs-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// target/production/substrate +// ./target/debug/substrate-node // benchmark // pallet -// --steps=50 -// --repeat=20 +// --chain=dev +// --steps=5 +// --repeat=2 +// --pallet=pallet-asset-conversion // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_asset_conversion -// --chain=dev -// --header=./HEADER-APACHE2 -// --output=./frame/asset-conversion/src/weights.rs -// --template=./.maintain/frame-weight-template.hbs +// --output=./substrate/frame/asset-conversion/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,25 +45,25 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_asset_conversion. +/// Weight functions needed for `pallet_asset_conversion`. pub trait WeightInfo { fn create_pool() -> Weight; fn add_liquidity() -> Weight; fn remove_liquidity() -> Weight; - fn swap_exact_tokens_for_tokens() -> Weight; - fn swap_tokens_for_exact_tokens() -> Weight; + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; } -/// Weights for pallet_asset_conversion using the Substrate node and recommended hardware. +/// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) + /// Storage: `Assets::Account` (r:2 w:2) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -75,20 +73,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `729` - // Estimated: `6196` - // Minimum execution time: 131_688_000 picoseconds. - Weight::from_parts(134_092_000, 6196) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(8_u64)) + // Measured: `1081` + // Estimated: `6360` + // Minimum execution time: 1_576_000_000 picoseconds. + Weight::from_parts(1_668_000_000, 6360) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(10_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) + /// Storage: `Assets::Account` (r:4 w:4) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) @@ -96,20 +92,18 @@ impl WeightInfo for SubstrateWeight { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn add_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1382` - // Estimated: `6208` - // Minimum execution time: 157_310_000 picoseconds. - Weight::from_parts(161_547_000, 6208) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Measured: `1761` + // Estimated: `11426` + // Minimum execution time: 1_636_000_000 picoseconds. + Weight::from_parts(1_894_000_000, 11426) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) + /// Storage: `Assets::Account` (r:4 w:4) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) @@ -117,42 +111,46 @@ impl WeightInfo for SubstrateWeight { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn remove_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1371` - // Estimated: `6208` - // Minimum execution time: 142_769_000 picoseconds. - Weight::from_parts(145_139_000, 6208) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `1750` + // Estimated: `11426` + // Minimum execution time: 1_507_000_000 picoseconds. + Weight::from_parts(1_524_000_000, 11426) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:3 w:3) + /// Storage: `Assets::Asset` (r:4 w:4) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:6 w:6) + /// Storage: `Assets::Account` (r:8 w:8) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn swap_exact_tokens_for_tokens() -> Weight { + /// The range of component `n` is `[2, 4]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1738` - // Estimated: `16644` - // Minimum execution time: 213_186_000 picoseconds. - Weight::from_parts(217_471_000, 16644) - .saturating_add(T::DbWeight::get().reads(10_u64)) - .saturating_add(T::DbWeight::get().writes(10_u64)) + // Measured: `0 + n * (522 ±0)` + // Estimated: `990 + n * (5218 ±0)` + // Minimum execution time: 937_000_000 picoseconds. + Weight::from_parts(941_000_000, 990) + // Standard Error: 40_863_477 + .saturating_add(Weight::from_parts(205_862_068, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) } - /// Storage: `Assets::Asset` (r:3 w:3) + /// Storage: `Assets::Asset` (r:4 w:4) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:6 w:6) + /// Storage: `Assets::Account` (r:8 w:8) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn swap_tokens_for_exact_tokens() -> Weight { + /// The range of component `n` is `[2, 4]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1738` - // Estimated: `16644` - // Minimum execution time: 213_793_000 picoseconds. - Weight::from_parts(218_584_000, 16644) - .saturating_add(T::DbWeight::get().reads(10_u64)) - .saturating_add(T::DbWeight::get().writes(10_u64)) + // Measured: `0 + n * (522 ±0)` + // Estimated: `990 + n * (5218 ±0)` + // Minimum execution time: 935_000_000 picoseconds. + Weight::from_parts(947_000_000, 990) + // Standard Error: 46_904_620 + .saturating_add(Weight::from_parts(218_275_862, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) } } @@ -162,9 +160,9 @@ impl WeightInfo for () { /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:1 w:1) + /// Storage: `Assets::Account` (r:2 w:2) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -174,20 +172,18 @@ impl WeightInfo for () { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn create_pool() -> Weight { // Proof Size summary in bytes: - // Measured: `729` - // Estimated: `6196` - // Minimum execution time: 131_688_000 picoseconds. - Weight::from_parts(134_092_000, 6196) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(8_u64)) + // Measured: `1081` + // Estimated: `6360` + // Minimum execution time: 1_576_000_000 picoseconds. + Weight::from_parts(1_668_000_000, 6360) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(10_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) + /// Storage: `Assets::Account` (r:4 w:4) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) @@ -195,20 +191,18 @@ impl WeightInfo for () { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn add_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1382` - // Estimated: `6208` - // Minimum execution time: 157_310_000 picoseconds. - Weight::from_parts(161_547_000, 6208) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Measured: `1761` + // Estimated: `11426` + // Minimum execution time: 1_636_000_000 picoseconds. + Weight::from_parts(1_894_000_000, 11426) + .saturating_add(RocksDbWeight::get().reads(10_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:1 w:1) + /// Storage: `Assets::Asset` (r:2 w:2) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:2 w:2) + /// Storage: `Assets::Account` (r:4 w:4) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `PoolAssets::Asset` (r:1 w:1) /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) @@ -216,41 +210,45 @@ impl WeightInfo for () { /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) fn remove_liquidity() -> Weight { // Proof Size summary in bytes: - // Measured: `1371` - // Estimated: `6208` - // Minimum execution time: 142_769_000 picoseconds. - Weight::from_parts(145_139_000, 6208) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `1750` + // Estimated: `11426` + // Minimum execution time: 1_507_000_000 picoseconds. + Weight::from_parts(1_524_000_000, 11426) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:3 w:3) + /// Storage: `Assets::Asset` (r:4 w:4) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:6 w:6) + /// Storage: `Assets::Account` (r:8 w:8) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn swap_exact_tokens_for_tokens() -> Weight { + /// The range of component `n` is `[2, 4]`. + fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1738` - // Estimated: `16644` - // Minimum execution time: 213_186_000 picoseconds. - Weight::from_parts(217_471_000, 16644) - .saturating_add(RocksDbWeight::get().reads(10_u64)) - .saturating_add(RocksDbWeight::get().writes(10_u64)) + // Measured: `0 + n * (522 ±0)` + // Estimated: `990 + n * (5218 ±0)` + // Minimum execution time: 937_000_000 picoseconds. + Weight::from_parts(941_000_000, 990) + // Standard Error: 40_863_477 + .saturating_add(Weight::from_parts(205_862_068, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) } - /// Storage: `Assets::Asset` (r:3 w:3) + /// Storage: `Assets::Asset` (r:4 w:4) /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:6 w:6) + /// Storage: `Assets::Account` (r:8 w:8) /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn swap_tokens_for_exact_tokens() -> Weight { + /// The range of component `n` is `[2, 4]`. + fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1738` - // Estimated: `16644` - // Minimum execution time: 213_793_000 picoseconds. - Weight::from_parts(218_584_000, 16644) - .saturating_add(RocksDbWeight::get().reads(10_u64)) - .saturating_add(RocksDbWeight::get().writes(10_u64)) + // Measured: `0 + n * (522 ±0)` + // Estimated: `990 + n * (5218 ±0)` + // Minimum execution time: 935_000_000 picoseconds. + Weight::from_parts(947_000_000, 990) + // Standard Error: 46_904_620 + .saturating_add(Weight::from_parts(218_275_862, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 5218).saturating_mul(n.into())) } } From 1a9c5f3cb9d424851b9032b42061bd4a37e53708 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 30 Oct 2023 15:31:55 +0100 Subject: [PATCH 57/69] weights --- .../src/weights/pallet_asset_conversion.rs | 182 ++++------------- .../src/weights/pallet_asset_conversion.rs | 182 ++++------------- .../src/weights/pallet_asset_conversion.rs | 184 ++++-------------- 3 files changed, 106 insertions(+), 442 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs index 54a458de51aef..ac58bc22e8ab3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs @@ -20,7 +20,7 @@ //! DATE: 2023-10-30, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `cob`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: `1024` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-kusama-dev")`, DB CACHE: 1024 // Executed Command: // ./target/debug/polkadot-parachain @@ -34,28 +34,18 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./cumulus/parachains/runtimes/assets/asset-hub-kusama/src/weights/pallet_asset_conversion.rs -// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_asset_conversion`. -pub trait WeightInfo { - fn create_pool() -> Weight; - fn add_liquidity() -> Weight; - fn remove_liquidity() -> Weight; - fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; - fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; -} - -/// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { +/// Weight functions for `pallet_asset_conversion`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion::WeightInfo for WeightInfo { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -74,10 +64,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `408` // Estimated: `4689` - // Minimum execution time: 909_000_000 picoseconds. - Weight::from_parts(944_000_000, 4689) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 905_000_000 picoseconds. + Weight::from_parts(928_000_000, 0) + .saturating_add(Weight::from_parts(0, 4689)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) @@ -95,10 +86,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1117` // Estimated: `7404` - // Minimum execution time: 1_629_000_000 picoseconds. - Weight::from_parts(1_766_000_000, 7404) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 1_628_000_000 picoseconds. + Weight::from_parts(1_799_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) @@ -116,10 +108,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1106` // Estimated: `7404` - // Minimum execution time: 1_431_000_000 picoseconds. - Weight::from_parts(1_517_000_000, 7404) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 1_567_000_000 picoseconds. + Weight::from_parts(1_616_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `ForeignAssets::Asset` (r:2 w:2) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) @@ -131,13 +124,14 @@ impl WeightInfo for SubstrateWeight { fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 922_000_000 picoseconds. - Weight::from_parts(954_000_000, 7404) - // Standard Error: 15_697_849 - .saturating_add(Weight::from_parts(39_602_040, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Estimated: `7404 + n * (393 ±92)` + // Minimum execution time: 940_000_000 picoseconds. + Weight::from_parts(959_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + // Standard Error: 17_639_773 + .saturating_add(Weight::from_parts(45_724_489, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } /// Storage: `System::Account` (r:2 w:2) @@ -148,122 +142,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) /// The range of component `n` is `[2, 3]`. fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±73)` - // Minimum execution time: 929_000_000 picoseconds. - Weight::from_parts(947_000_000, 7404) - // Standard Error: 15_496_079 - .saturating_add(Weight::from_parts(41_295_918, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - /// Storage: `AssetConversion::Pools` (r:1 w:1) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:1 w:1) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) - /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:1 w:1) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn create_pool() -> Weight { - // Proof Size summary in bytes: - // Measured: `408` - // Estimated: `4689` - // Minimum execution time: 909_000_000 picoseconds. - Weight::from_parts(944_000_000, 4689) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) - } - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:2 w:2) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn add_liquidity() -> Weight { - // Proof Size summary in bytes: - // Measured: `1117` - // Estimated: `7404` - // Minimum execution time: 1_629_000_000 picoseconds. - Weight::from_parts(1_766_000_000, 7404) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) - } - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:1 w:1) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn remove_liquidity() -> Weight { - // Proof Size summary in bytes: - // Measured: `1106` - // Estimated: `7404` - // Minimum execution time: 1_431_000_000 picoseconds. - Weight::from_parts(1_517_000_000, 7404) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - } - /// Storage: `ForeignAssets::Asset` (r:2 w:2) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:4 w:4) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `n` is `[2, 3]`. - fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (557 ±0)` // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 922_000_000 picoseconds. - Weight::from_parts(954_000_000, 7404) - // Standard Error: 15_697_849 - .saturating_add(Weight::from_parts(39_602_040, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) - } - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:2 w:2) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:4 w:4) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// The range of component `n` is `[2, 3]`. - fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±73)` - // Minimum execution time: 929_000_000 picoseconds. - Weight::from_parts(947_000_000, 7404) - // Standard Error: 15_496_079 - .saturating_add(Weight::from_parts(41_295_918, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 928_000_000 picoseconds. + Weight::from_parts(956_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + // Standard Error: 16_273_167 + .saturating_add(Weight::from_parts(42_867_346, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs index a416c6947ce2e..0486932d1d6e4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs @@ -20,7 +20,7 @@ //! DATE: 2023-10-30, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `cob`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: `1024` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 // Executed Command: // ./target/debug/polkadot-parachain @@ -34,28 +34,18 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion.rs -// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_asset_conversion`. -pub trait WeightInfo { - fn create_pool() -> Weight; - fn add_liquidity() -> Weight; - fn remove_liquidity() -> Weight; - fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; - fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; -} - -/// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { +/// Weight functions for `pallet_asset_conversion`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion::WeightInfo for WeightInfo { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -74,10 +64,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `408` // Estimated: `4689` - // Minimum execution time: 917_000_000 picoseconds. - Weight::from_parts(989_000_000, 4689) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 906_000_000 picoseconds. + Weight::from_parts(945_000_000, 0) + .saturating_add(Weight::from_parts(0, 4689)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) @@ -95,10 +86,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1117` // Estimated: `7404` - // Minimum execution time: 1_622_000_000 picoseconds. - Weight::from_parts(1_639_000_000, 7404) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 1_609_000_000 picoseconds. + Weight::from_parts(1_631_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) @@ -116,10 +108,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1106` // Estimated: `7404` - // Minimum execution time: 1_496_000_000 picoseconds. - Weight::from_parts(1_497_000_000, 7404) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 1_480_000_000 picoseconds. + Weight::from_parts(1_506_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `ForeignAssets::Asset` (r:2 w:2) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) @@ -129,122 +122,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[2, 3]`. fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 925_000_000 picoseconds. - Weight::from_parts(947_000_000, 7404) - // Standard Error: 15_819_119 - .saturating_add(Weight::from_parts(38_448_979, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) - } - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:2 w:2) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:4 w:4) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// The range of component `n` is `[2, 3]`. - fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (557 ±0)` // Estimated: `7404 + n * (393 ±73)` - // Minimum execution time: 913_000_000 picoseconds. - Weight::from_parts(945_000_000, 7404) - // Standard Error: 17_010_580 - .saturating_add(Weight::from_parts(43_326_530, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - /// Storage: `AssetConversion::Pools` (r:1 w:1) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:1 w:1) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) - /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:1 w:1) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn create_pool() -> Weight { - // Proof Size summary in bytes: - // Measured: `408` - // Estimated: `4689` - // Minimum execution time: 917_000_000 picoseconds. - Weight::from_parts(989_000_000, 4689) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) - } - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:2 w:2) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn add_liquidity() -> Weight { - // Proof Size summary in bytes: - // Measured: `1117` - // Estimated: `7404` - // Minimum execution time: 1_622_000_000 picoseconds. - Weight::from_parts(1_639_000_000, 7404) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) - } - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:1 w:1) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn remove_liquidity() -> Weight { - // Proof Size summary in bytes: - // Measured: `1106` - // Estimated: `7404` - // Minimum execution time: 1_496_000_000 picoseconds. - Weight::from_parts(1_497_000_000, 7404) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - } - /// Storage: `ForeignAssets::Asset` (r:2 w:2) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:4 w:4) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `n` is `[2, 3]`. - fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 925_000_000 picoseconds. - Weight::from_parts(947_000_000, 7404) - // Standard Error: 15_819_119 - .saturating_add(Weight::from_parts(38_448_979, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 933_000_000 picoseconds. + Weight::from_parts(950_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + // Standard Error: 18_792_550 + .saturating_add(Weight::from_parts(46_683_673, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } /// Storage: `System::Account` (r:2 w:2) @@ -257,13 +144,14 @@ impl WeightInfo for () { fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±73)` - // Minimum execution time: 913_000_000 picoseconds. - Weight::from_parts(945_000_000, 7404) - // Standard Error: 17_010_580 - .saturating_add(Weight::from_parts(43_326_530, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Estimated: `7404 + n * (393 ±180)` + // Minimum execution time: 936_000_000 picoseconds. + Weight::from_parts(954_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + // Standard Error: 15_942_881 + .saturating_add(Weight::from_parts(39_755_102, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs index 87c22abfcf571..344d990cad238 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs @@ -20,7 +20,7 @@ //! DATE: 2023-10-30, STEPS: `20`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `cob`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: `1024` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: // ./target/debug/polkadot-parachain @@ -34,135 +34,18 @@ // --wasm-execution=compiled // --heap-pages=4096 // --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion.rs -// --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions needed for `pallet_asset_conversion`. -pub trait WeightInfo { - fn create_pool() -> Weight; - fn add_liquidity() -> Weight; - fn remove_liquidity() -> Weight; - fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight; - fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight; -} - -/// Weights for `pallet_asset_conversion` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `AssetConversion::Pools` (r:1 w:1) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:1 w:1) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `AssetConversion::NextPoolAssetId` (r:1 w:1) - /// Proof: `AssetConversion::NextPoolAssetId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:1 w:1) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn create_pool() -> Weight { - // Proof Size summary in bytes: - // Measured: `408` - // Estimated: `4689` - // Minimum execution time: 904_000_000 picoseconds. - Weight::from_parts(938_000_000, 4689) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) - } - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:2 w:2) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn add_liquidity() -> Weight { - // Proof Size summary in bytes: - // Measured: `1117` - // Estimated: `7404` - // Minimum execution time: 1_613_000_000 picoseconds. - Weight::from_parts(1_923_000_000, 7404) - .saturating_add(T::DbWeight::get().reads(8_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) - } - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:1 w:1) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:2 w:2) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:1 w:1) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - fn remove_liquidity() -> Weight { - // Proof Size summary in bytes: - // Measured: `1106` - // Estimated: `7404` - // Minimum execution time: 1_479_000_000 picoseconds. - Weight::from_parts(1_559_000_000, 7404) - .saturating_add(T::DbWeight::get().reads(7_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) - } - /// Storage: `ForeignAssets::Asset` (r:2 w:2) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:4 w:4) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// The range of component `n` is `[2, 3]`. - fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 920_000_000 picoseconds. - Weight::from_parts(950_000_000, 7404) - // Standard Error: 18_279_661 - .saturating_add(Weight::from_parts(47_071_428, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) - } - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Asset` (r:2 w:2) - /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) - /// Storage: `ForeignAssets::Account` (r:4 w:4) - /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) - /// The range of component `n` is `[2, 3]`. - fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 932_000_000 picoseconds. - Weight::from_parts(944_000_000, 7404) - // Standard Error: 14_264_382 - .saturating_add(Weight::from_parts(41_938_775, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { +/// Weight functions for `pallet_asset_conversion`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion::WeightInfo for WeightInfo { /// Storage: `AssetConversion::Pools` (r:1 w:1) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -181,10 +64,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `408` // Estimated: `4689` - // Minimum execution time: 904_000_000 picoseconds. - Weight::from_parts(938_000_000, 4689) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Minimum execution time: 922_000_000 picoseconds. + Weight::from_parts(1_102_000_000, 0) + .saturating_add(Weight::from_parts(0, 4689)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) @@ -202,10 +86,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1117` // Estimated: `7404` - // Minimum execution time: 1_613_000_000 picoseconds. - Weight::from_parts(1_923_000_000, 7404) - .saturating_add(RocksDbWeight::get().reads(8_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Minimum execution time: 1_597_000_000 picoseconds. + Weight::from_parts(1_655_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `AssetConversion::Pools` (r:1 w:0) /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) @@ -223,10 +108,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1106` // Estimated: `7404` - // Minimum execution time: 1_479_000_000 picoseconds. - Weight::from_parts(1_559_000_000, 7404) - .saturating_add(RocksDbWeight::get().reads(7_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 1_500_000_000 picoseconds. + Weight::from_parts(1_633_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `ForeignAssets::Asset` (r:2 w:2) /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) @@ -238,13 +124,14 @@ impl WeightInfo for () { fn swap_exact_tokens_for_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 920_000_000 picoseconds. - Weight::from_parts(950_000_000, 7404) - // Standard Error: 18_279_661 - .saturating_add(Weight::from_parts(47_071_428, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Estimated: `7404 + n * (393 ±92)` + // Minimum execution time: 930_000_000 picoseconds. + Weight::from_parts(960_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + // Standard Error: 17_993_720 + .saturating_add(Weight::from_parts(41_959_183, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } /// Storage: `System::Account` (r:2 w:2) @@ -257,13 +144,14 @@ impl WeightInfo for () { fn swap_tokens_for_exact_tokens(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (557 ±0)` - // Estimated: `7404 + n * (393 ±180)` - // Minimum execution time: 932_000_000 picoseconds. - Weight::from_parts(944_000_000, 7404) - // Standard Error: 14_264_382 - .saturating_add(Weight::from_parts(41_938_775, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Estimated: `7404 + n * (393 ±92)` + // Minimum execution time: 940_000_000 picoseconds. + Weight::from_parts(956_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + // Standard Error: 15_746_647 + .saturating_add(Weight::from_parts(39_193_877, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 393).saturating_mul(n.into())) } } From e0f1d0aa2c9c825fd5665d8eaf57247b48dad08a Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 30 Oct 2023 15:44:04 +0100 Subject: [PATCH 58/69] remove inc_providers on pool creation --- substrate/frame/asset-conversion/src/lib.rs | 1 - substrate/frame/asset-conversion/src/tests.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 7f4a8e21c4b30..6a00e59ac4529 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -371,7 +371,6 @@ pub mod pallet { let pool_account = T::PoolLocator::address(&pool_id).map_err(|_| Error::::InvalidAssetPair)?; - frame_system::Pallet::::inc_providers(&pool_account); // pay the setup fee let fee = diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 32423435cbb7c..95f8c7412f69f 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -507,7 +507,6 @@ fn add_tiny_liquidity_directly_to_pool_address() { // check the same but for token_3.clone() (non-native token) let pallet_account = ::PoolLocator::address(&(token_1.clone(), token_3.clone())).unwrap(); - assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, pallet_account, 1)); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), Box::new(token_1.clone()), From 78332d74eb1ac1a7cbc9dd0d54e1a8ed51bb710c Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 30 Oct 2023 17:04:35 +0100 Subject: [PATCH 59/69] remove unused var --- substrate/frame/asset-conversion/src/tests.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index 95f8c7412f69f..e69d14fcb3c40 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -505,8 +505,6 @@ fn add_tiny_liquidity_directly_to_pool_address() { )); // check the same but for token_3.clone() (non-native token) - let pallet_account = - ::PoolLocator::address(&(token_1.clone(), token_3.clone())).unwrap(); assert_ok!(AssetConversion::add_liquidity( RuntimeOrigin::signed(user), Box::new(token_1.clone()), From 3f59637721267c92bf54c59a84e677b10b107142 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 31 Oct 2023 13:48:39 +0100 Subject: [PATCH 60/69] account touch --- substrate/frame/asset-conversion/src/lib.rs | 6 ++--- substrate/frame/assets/src/lib.rs | 12 ++++++++-- substrate/frame/balances/src/impl_fungible.rs | 24 +++++++++++++++---- substrate/frame/support/src/traits/misc.rs | 16 +++++++++---- .../src/traits/tokens/fungible/union_of.rs | 15 ++++++++---- .../src/traits/tokens/fungibles/union_of.rs | 9 ++++++- 6 files changed, 64 insertions(+), 18 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 6a00e59ac4529..7f90ecce6f8d2 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -378,11 +378,11 @@ pub mod pallet { T::PoolSetupFeeTarget::on_unbalanced(fee); if !T::Assets::contains(&asset1, &pool_account) { - T::Assets::touch(*asset1, pool_account.clone(), sender.clone())? + T::Assets::touch(*asset1, &pool_account, &sender)? }; if !T::Assets::contains(&asset2, &pool_account) { - T::Assets::touch(*asset2, pool_account.clone(), sender.clone())? + T::Assets::touch(*asset2, &pool_account, &sender)? }; let lp_token = NextPoolAssetId::::get() @@ -392,7 +392,7 @@ pub mod pallet { NextPoolAssetId::::set(Some(next_lp_token_id)); T::PoolAssets::create(lp_token.clone(), pool_account.clone(), false, 1u32.into())?; - T::PoolAssets::touch(lp_token.clone(), pool_account.clone(), sender.clone())?; + T::PoolAssets::touch(lp_token.clone(), &pool_account, &sender)?; let pool_info = PoolInfo { lp_token: lp_token.clone() }; Pools::::insert(pool_id.clone(), pool_info); diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 79e4fe3001872..62d2b27908821 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -1648,8 +1648,16 @@ pub mod pallet { T::AssetAccountDeposit::get() } - fn touch(asset: T::AssetId, who: T::AccountId, depositor: T::AccountId) -> DispatchResult { - Self::do_touch(asset, who, depositor, false) + fn should_touch(_: T::AssetId, _: &T::AccountId) -> bool { + true + } + + fn touch( + asset: T::AssetId, + who: &T::AccountId, + depositor: &T::AccountId, + ) -> DispatchResult { + Self::do_touch(asset, who.clone(), depositor.clone(), false) } } diff --git a/substrate/frame/balances/src/impl_fungible.rs b/substrate/frame/balances/src/impl_fungible.rs index fc8c2d71f256e..6737727e0a297 100644 --- a/substrate/frame/balances/src/impl_fungible.rs +++ b/substrate/frame/balances/src/impl_fungible.rs @@ -17,10 +17,13 @@ //! Implementation of `fungible` traits for Balances pallet. use super::*; -use frame_support::traits::tokens::{ - Fortitude, - Preservation::{self, Preserve, Protect}, - Provenance::{self, Minted}, +use frame_support::traits::{ + tokens::{ + Fortitude, + Preservation::{self, Preserve, Protect}, + Provenance::{self, Minted}, + }, + AccountTouch, }; impl, I: 'static> fungible::Inspect for Pallet { @@ -356,3 +359,16 @@ impl, I: 'static> fungible::Balanced for Pallet } impl, I: 'static> fungible::BalancedHold for Pallet {} + +impl, I: 'static> AccountTouch<(), T::AccountId> for Pallet { + type Balance = T::Balance; + fn deposit_required(_: ()) -> Self::Balance { + Self::Balance::zero() + } + fn should_touch(_: (), _: &T::AccountId) -> bool { + false + } + fn touch(_: (), _: &T::AccountId, _: &T::AccountId) -> DispatchResult { + Ok(()) + } +} diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index 45a3bba9b3a60..a60dbd716c054 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -1170,17 +1170,25 @@ impl PreimageRecipient for () { fn unnote_preimage(_: &Hash) {} } -/// Trait for creating an asset account with a deposit taken from a designated depositor specified -/// by the client. +/// Trait for touching/creating an asset account with a deposit taken from a designated depositor +/// specified by the client. +/// +/// Ensures that transfers to the touched account will succeed without being denied by the system's +/// account existence requirements. For example, this is particularly useful for the account +/// creation of non-sufficient assets when its system account may not have the free consumer +/// reference required for it. pub trait AccountTouch { /// The type for currency units of the deposit. type Balance; - /// The deposit amount of a native currency required for creating an account of the `asset`. + /// The deposit amount of a native currency required for touching an account of the `asset`. fn deposit_required(asset: AssetId) -> Self::Balance; + /// Checks if an account for a given asset should be touched. + fn should_touch(asset: AssetId, who: &AccountId) -> bool; + /// Create an account for `who` of the `asset` with a deposit taken from the `depositor`. - fn touch(asset: AssetId, who: AccountId, depositor: AccountId) -> DispatchResult; + fn touch(asset: AssetId, who: &AccountId, depositor: &AccountId) -> DispatchResult; } #[cfg(test)] diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 3fad47afddd3a..fb9d722e6575c 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -954,7 +954,8 @@ impl< } impl< - Left: fungible::Inspect, + Left: fungible::Inspect + + AccountTouch<(), AccountId, Balance = >::Balance>, Right: fungibles::Inspect + AccountTouch< Right::AssetId, @@ -975,10 +976,16 @@ impl< } } - fn touch(asset: AssetKind, who: AccountId, depositor: AccountId) -> DispatchResult { + fn should_touch(asset: AssetKind, who: &AccountId) -> bool { match Criterion::convert(asset) { - // no-op for `Left` since `AccountTouch` trait is not defined within `fungible::*`. - Left(()) => Ok(()), + Left(()) => >::should_touch((), who), + Right(a) => >::should_touch(a, who), + } + } + + fn touch(asset: AssetKind, who: &AccountId, depositor: &AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => >::touch((), who, depositor), Right(a) => >::touch(a, who, depositor), } diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index 6b093f1f6cc55..c7bd3a0fe2d98 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -959,7 +959,14 @@ impl< } } - fn touch(asset: AssetKind, who: AccountId, depositor: AccountId) -> DispatchResult { + fn should_touch(asset: AssetKind, who: &AccountId) -> bool { + match Criterion::convert(asset) { + Left(a) => >::should_touch(a, who), + Right(a) => >::should_touch(a, who), + } + } + + fn touch(asset: AssetKind, who: &AccountId, depositor: &AccountId) -> DispatchResult { match Criterion::convert(asset) { Left(a) => >::touch(a, who, depositor), Right(a) => From 9ea208deea331f9540004c05cfec299325819ca4 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 31 Oct 2023 13:50:16 +0100 Subject: [PATCH 61/69] remove conrain pair from union_of --- .../src/traits/tokens/fungible/union_of.rs | 21 +------------------ .../src/traits/tokens/fungibles/union_of.rs | 19 +---------------- 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index fb9d722e6575c..cad677b0f27fb 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -24,7 +24,7 @@ use frame_support::traits::{ fungible, fungibles, AssetId, DepositConsequence, Fortitude, Imbalance as ImbalanceT, Precision, Preservation, Provenance, Restriction, WithdrawConsequence, }, - AccountTouch, ContainsPair, + AccountTouch, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -991,22 +991,3 @@ impl< } } } - -impl< - Left: fungible::Inspect, - Right: fungibles::Inspect - + ContainsPair, - Criterion: Convert>, - AssetKind: AssetId, - AccountId, - > ContainsPair for UnionOf -{ - fn contains(asset: &AssetKind, who: &AccountId) -> bool { - match Criterion::convert(asset.clone()) { - Left(()) => - >::total_balance(who) >= - >::minimum_balance(), - Right(a) => >::contains(&a, who), - } - } -} diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index c7bd3a0fe2d98..d74c1b3604131 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -22,7 +22,7 @@ use frame_support::traits::{ fungibles, AssetId, DepositConsequence, Fortitude, Precision, Preservation, Provenance, Restriction, WithdrawConsequence, }, - AccountTouch, ContainsPair, + AccountTouch, }; use sp_runtime::{ traits::Convert, @@ -974,20 +974,3 @@ impl< } } } - -impl< - Left: fungibles::Inspect + ContainsPair, - Right: fungibles::Inspect - + ContainsPair, - Criterion: Convert>, - AssetKind: AssetId, - AccountId, - > ContainsPair for UnionOf -{ - fn contains(asset: &AssetKind, who: &AccountId) -> bool { - match Criterion::convert(asset.clone()) { - Left(a) => >::contains(&a, who), - Right(a) => >::contains(&a, who), - } - } -} From d87a80ed7bd87ae1d9a8b03258ac020c76a22571 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 31 Oct 2023 13:57:12 +0100 Subject: [PATCH 62/69] should touch --- substrate/frame/asset-conversion/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 7f90ecce6f8d2..f0695678fbddf 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -81,7 +81,7 @@ use frame_support::{ Precision::Exact, Preservation::{Expendable, Preserve}, }, - AccountTouch, ContainsPair, Incrementable, OnUnbalanced, + AccountTouch, Incrementable, OnUnbalanced, }, PalletId, }; @@ -130,7 +130,6 @@ pub mod pallet { type Assets: Inspect + Mutate + AccountTouch - + ContainsPair + Balanced; /// Liquidity pool identifier. @@ -377,11 +376,11 @@ pub mod pallet { Self::withdraw(T::PoolSetupFeeAsset::get(), &sender, T::PoolSetupFee::get(), true)?; T::PoolSetupFeeTarget::on_unbalanced(fee); - if !T::Assets::contains(&asset1, &pool_account) { + if T::Assets::should_touch(*asset1.clone(), &pool_account) { T::Assets::touch(*asset1, &pool_account, &sender)? }; - if !T::Assets::contains(&asset2, &pool_account) { + if T::Assets::should_touch(*asset2.clone(), &pool_account) { T::Assets::touch(*asset2, &pool_account, &sender)? }; From 55917ddfdb79851b38f699ed5b6757f02a3f5e2f Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 31 Oct 2023 14:08:58 +0100 Subject: [PATCH 63/69] touch doc --- substrate/frame/support/src/traits/misc.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index a60dbd716c054..dffa55dab4b80 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -1173,10 +1173,11 @@ impl PreimageRecipient for () { /// Trait for touching/creating an asset account with a deposit taken from a designated depositor /// specified by the client. /// -/// Ensures that transfers to the touched account will succeed without being denied by the system's -/// account existence requirements. For example, this is particularly useful for the account -/// creation of non-sufficient assets when its system account may not have the free consumer -/// reference required for it. +/// Ensures that transfers to the touched account will succeed without being denied by the account +/// existence requirements. For example, this is particularly useful for the account creation of +/// non-sufficient assets when its system account may not have the free consumer reference required +/// for it. If there is no risk of failing to meet those requirements, the touch operation can be a +/// no-op, as is common for native assets. pub trait AccountTouch { /// The type for currency units of the deposit. type Balance; From 4673656c9b28dbb633f5ef799b20f29005c733f4 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 2 Nov 2023 10:35:49 +0100 Subject: [PATCH 64/69] docs --- substrate/frame/support/src/traits/tokens/fungible/union_of.rs | 2 +- substrate/frame/support/src/traits/tokens/fungibles/union_of.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index cad677b0f27fb..e375540b6c3fa 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -91,7 +91,7 @@ impl Convert, Either<(), AssetId>> for Nat /// Type to combine some `fungible::*` and `fungibles::*` implementations into one union /// `fungibles::*` implementation. /// -/// ### Generic Parameters: +/// ### Parameters: /// - `Left` is `fungible::*` implementation that is incorporated into the resulting union. /// - `Right` is `fungibles::*` implementation that is incorporated into the resulting union. /// - `Criterion` determines whether the `AssetKind` belongs to the `Left` or `Right` set. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index d74c1b3604131..b43e4dc956625 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -32,7 +32,7 @@ use sp_runtime::{ /// Type to combine two `fungibles::*` implementations into one union `fungibles::*` implementation. /// -/// ### Generic Parameters: +/// ### Parameters: /// - `Left` is `fungibles::*` implementation that is incorporated into the resulting union. /// - `Right` is `fungibles::*` implementation that is incorporated into the resulting union. /// - `Criterion` determines whether the `AssetKind` belongs to the `Left` or `Right` set. From 701c4f6135bcaf836c8327ad5d7717b35ab37079 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 2 Nov 2023 10:44:51 +0100 Subject: [PATCH 65/69] docs --- substrate/frame/support/src/traits/misc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index dffa55dab4b80..a4b167ea7406f 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -1185,7 +1185,7 @@ pub trait AccountTouch { /// The deposit amount of a native currency required for touching an account of the `asset`. fn deposit_required(asset: AssetId) -> Self::Balance; - /// Checks if an account for a given asset should be touched. + /// Check if an account for a given asset should be touched to meet the existence requirements. fn should_touch(asset: AssetId, who: &AccountId) -> bool; /// Create an account for `who` of the `asset` with a deposit taken from the `depositor`. From 8d5e5fe96f6ae04d25997252677eb20a5cc47371 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 2 Nov 2023 15:52:50 +0100 Subject: [PATCH 66/69] should_touch for pallet-assets --- substrate/frame/assets/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 62d2b27908821..b77f9097990a8 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -1648,8 +1648,8 @@ pub mod pallet { T::AssetAccountDeposit::get() } - fn should_touch(_: T::AssetId, _: &T::AccountId) -> bool { - true + fn should_touch(asset: T::AssetId, who: &T::AccountId) -> bool { + !Account::::contains_key(asset, who) } fn touch( From 05562672b65ada717a8b21e0b8eaea0c85fe093d Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 2 Nov 2023 16:03:06 +0100 Subject: [PATCH 67/69] move set tests into a separete file --- substrate/frame/assets/src/tests.rs | 335 +--------------------- substrate/frame/assets/src/tests/sets.rs | 346 +++++++++++++++++++++++ 2 files changed, 348 insertions(+), 333 deletions(-) create mode 100644 substrate/frame/assets/src/tests/sets.rs diff --git a/substrate/frame/assets/src/tests.rs b/substrate/frame/assets/src/tests.rs index 10e50136ef65d..e09648a51eccd 100644 --- a/substrate/frame/assets/src/tests.rs +++ b/substrate/frame/assets/src/tests.rs @@ -28,6 +28,8 @@ use pallet_balances::Error as BalancesError; use sp_io::storage; use sp_runtime::{traits::ConvertInto, TokenError}; +mod sets; + fn asset_ids() -> Vec { let mut s: Vec<_> = Assets::asset_ids().collect(); s.sort(); @@ -1775,336 +1777,3 @@ fn asset_destroy_refund_existence_deposit() { assert_eq!(Balances::reserved_balance(&admin), 0); }); } - -mod sets { - use super::*; - use frame_support::{ - parameter_types, - traits::{ - fungible, - fungible::ItemOf, - fungibles, - tokens::{ - fungibles::{ - Balanced as FungiblesBalanced, Create as FungiblesCreate, - Inspect as FungiblesInspect, Mutate as FungiblesMutate, - }, - Fortitude, Precision, Preservation, - }, - }, - }; - use sp_runtime::{traits::ConvertToValue, Either}; - - const FIRST_ASSET: u32 = 0; - const UNKNOWN_ASSET: u32 = 10; - - parameter_types! { - pub const LeftAsset: Either<(), u32> = Either::Left(()); - pub const RightAsset: Either = Either::Right(()); - pub const RightUnitAsset: Either<(), ()> = Either::Right(()); - } - - /// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a - /// single asset class from [`T`] identified by [`FIRST_ASSET`]. - type FirstFungible = ItemOf, u64>; - /// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a - /// single asset class from [`T`] identified by [`UNKNOWN_ASSET`]. - type UnknownFungible = ItemOf, u64>; - /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes - /// the [`FirstFungible`] from the left. - type LeftFungible = - fungible::UnionOf, T, ConvertToValue, (), u64>; - /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes - /// the [`LeftFungible`] from the right. - type RightFungible = fungible::UnionOf< - UnknownFungible, - LeftFungible, - ConvertToValue, - (), - u64, - >; - /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes - /// the [`RightFungible`] from the left. - type LeftFungibles = - fungibles::UnionOf, T, ConvertToValue, (), u64>; - /// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes - /// the [`LeftFungibles`] from the right. - /// - /// By using this type, we can navigate through each branch of [`fungible::UnionOf`], - /// [`fungibles::UnionOf`], and [`ItemOf`] to access the underlying `fungibles::*` - /// implementation provided by the pallet. - type First = fungibles::UnionOf, ConvertToValue, (), u64>; - - #[test] - fn deposit_from_set_types_works() { - new_test_ext().execute_with(|| { - let asset1 = 0; - let account1 = 1; - let account2 = 2; - - assert_ok!(>::create(asset1, account1, true, 1)); - assert_ok!(Assets::mint_into(asset1, &account1, 100)); - - assert_eq!(First::::total_issuance(()), 100); - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - - let imb = First::::deposit((), &account2, 50, Precision::Exact).unwrap(); - assert_eq!(First::::balance((), &account2), 50); - assert_eq!(First::::total_issuance(()), 100); - - assert_eq!(imb.peek(), 50); - - let (imb1, imb2) = imb.split(30); - assert_eq!(imb1.peek(), 30); - assert_eq!(imb2.peek(), 20); - - drop(imb2); - assert_eq!(First::::total_issuance(()), 120); - - assert!(First::::settle(&account1, imb1, Preservation::Preserve).is_ok()); - assert_eq!(First::::balance((), &account1), 70); - assert_eq!(First::::balance((), &account2), 50); - assert_eq!(First::::total_issuance(()), 120); - - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - }); - } - - #[test] - fn issue_from_set_types_works() { - new_test_ext().execute_with(|| { - let asset1: u32 = 0; - let account1: u64 = 1; - - assert_ok!(>::create(asset1, account1, true, 1)); - assert_ok!(Assets::mint_into(asset1, &account1, 100)); - - assert_eq!(First::::balance((), &account1), 100); - assert_eq!(First::::total_issuance(()), 100); - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - - let imb = First::::issue((), 100); - assert_eq!(First::::total_issuance(()), 200); - assert_eq!(imb.peek(), 100); - - let (imb1, imb2) = imb.split(30); - assert_eq!(imb1.peek(), 30); - assert_eq!(imb2.peek(), 70); - - drop(imb2); - assert_eq!(First::::total_issuance(()), 130); - - assert!(First::::resolve(&account1, imb1).is_ok()); - assert_eq!(First::::balance((), &account1), 130); - assert_eq!(First::::total_issuance(()), 130); - - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - }); - } - - #[test] - fn pair_from_set_types_works() { - new_test_ext().execute_with(|| { - let asset1: u32 = 0; - let account1: u64 = 1; - - assert_ok!(>::create(asset1, account1, true, 1)); - assert_ok!(Assets::mint_into(asset1, &account1, 100)); - - assert_eq!(First::::balance((), &account1), 100); - assert_eq!(First::::total_issuance(()), 100); - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - - let (debt, credit) = First::::pair((), 100); - assert_eq!(First::::total_issuance(()), 100); - assert_eq!(debt.peek(), 100); - assert_eq!(credit.peek(), 100); - - let (debt1, debt2) = debt.split(30); - assert_eq!(debt1.peek(), 30); - assert_eq!(debt2.peek(), 70); - - drop(debt2); - assert_eq!(First::::total_issuance(()), 170); - - assert!(First::::settle(&account1, debt1, Preservation::Preserve).is_ok()); - assert_eq!(First::::balance((), &account1), 70); - assert_eq!(First::::total_issuance(()), 170); - - let (credit1, credit2) = credit.split(40); - assert_eq!(credit1.peek(), 40); - assert_eq!(credit2.peek(), 60); - - drop(credit2); - assert_eq!(First::::total_issuance(()), 110); - - assert!(First::::resolve(&account1, credit1).is_ok()); - assert_eq!(First::::balance((), &account1), 110); - assert_eq!(First::::total_issuance(()), 110); - - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - }); - } - - #[test] - fn rescind_from_set_types_works() { - new_test_ext().execute_with(|| { - let asset1: u32 = 0; - let account1: u64 = 1; - - assert_ok!(>::create(asset1, account1, true, 1)); - assert_ok!(Assets::mint_into(asset1, &account1, 100)); - - assert_eq!(First::::total_issuance(()), 100); - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - - let imb = First::::rescind((), 20); - assert_eq!(First::::total_issuance(()), 80); - - assert_eq!(imb.peek(), 20); - - let (imb1, imb2) = imb.split(15); - assert_eq!(imb1.peek(), 15); - assert_eq!(imb2.peek(), 5); - - drop(imb2); - assert_eq!(First::::total_issuance(()), 85); - - assert!(First::::settle(&account1, imb1, Preservation::Preserve).is_ok()); - assert_eq!(First::::balance((), &account1), 85); - assert_eq!(First::::total_issuance(()), 85); - - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - }); - } - - #[test] - fn resolve_from_set_types_works() { - new_test_ext().execute_with(|| { - let asset1: u32 = 0; - let account1: u64 = 1; - let account2: u64 = 2; - let ed = 11; - - assert_ok!(>::create(asset1, account1, true, ed)); - assert_ok!(Assets::mint_into(asset1, &account1, 100)); - - assert_eq!(First::::balance((), &account1), 100); - assert_eq!(First::::total_issuance(()), 100); - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - - let imb = First::::issue((), 100); - assert_eq!(First::::total_issuance(()), 200); - assert_eq!(imb.peek(), 100); - - let (imb1, imb2) = imb.split(10); - assert_eq!(imb1.peek(), 10); - assert_eq!(imb2.peek(), 90); - assert_eq!(First::::total_issuance(()), 200); - - // ed requirements not met. - let imb1 = First::::resolve(&account2, imb1).unwrap_err(); - assert_eq!(imb1.peek(), 10); - drop(imb1); - assert_eq!(First::::total_issuance(()), 190); - assert_eq!(First::::balance((), &account2), 0); - - // resolve to new account `2`. - assert_ok!(First::::resolve(&account2, imb2)); - assert_eq!(First::::total_issuance(()), 190); - assert_eq!(First::::balance((), &account2), 90); - - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - }); - } - - #[test] - fn settle_from_set_types_works() { - new_test_ext().execute_with(|| { - let asset1: u32 = 0; - let account1: u64 = 1; - let account2: u64 = 2; - let ed = 11; - - assert_ok!(>::create(asset1, account1, true, ed)); - assert_ok!(Assets::mint_into(asset1, &account1, 100)); - assert_ok!(Assets::mint_into(asset1, &account2, 100)); - - assert_eq!(First::::balance((), &account2), 100); - assert_eq!(First::::total_issuance(()), 200); - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - - let imb = First::::rescind((), 100); - assert_eq!(First::::total_issuance(()), 100); - assert_eq!(imb.peek(), 100); - - let (imb1, imb2) = imb.split(10); - assert_eq!(imb1.peek(), 10); - assert_eq!(imb2.peek(), 90); - assert_eq!(First::::total_issuance(()), 100); - - // ed requirements not met. - let imb2 = - First::::settle(&account2, imb2, Preservation::Preserve).unwrap_err(); - assert_eq!(imb2.peek(), 90); - drop(imb2); - assert_eq!(First::::total_issuance(()), 190); - assert_eq!(First::::balance((), &account2), 100); - - // settle to account `1`. - assert_ok!(First::::settle(&account2, imb1, Preservation::Preserve)); - assert_eq!(First::::total_issuance(()), 190); - assert_eq!(First::::balance((), &account2), 90); - - let imb = First::::rescind((), 85); - assert_eq!(First::::total_issuance(()), 105); - assert_eq!(imb.peek(), 85); - - // settle to account `1` and expect some dust. - let imb = First::::settle(&account2, imb, Preservation::Expendable).unwrap(); - assert_eq!(imb.peek(), 5); - assert_eq!(First::::total_issuance(()), 105); - assert_eq!(First::::balance((), &account2), 0); - - drop(imb); - assert_eq!(First::::total_issuance(()), 100); - - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - }); - } - - #[test] - fn withdraw_from_set_types_works() { - new_test_ext().execute_with(|| { - let asset1 = 0; - let account1 = 1; - let account2 = 2; - - assert_ok!(>::create(asset1, account1, true, 1)); - assert_ok!(Assets::mint_into(asset1, &account1, 100)); - assert_ok!(Assets::mint_into(asset1, &account2, 100)); - - assert_eq!(First::::total_issuance(()), 200); - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - - let imb = First::::withdraw( - (), - &account2, - 50, - Precision::Exact, - Preservation::Preserve, - Fortitude::Polite, - ) - .unwrap(); - assert_eq!(First::::balance((), &account2), 50); - assert_eq!(First::::total_issuance(()), 200); - - assert_eq!(imb.peek(), 50); - drop(imb); - assert_eq!(First::::total_issuance(()), 150); - assert_eq!(First::::balance((), &account2), 50); - - assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); - }); - } -} diff --git a/substrate/frame/assets/src/tests/sets.rs b/substrate/frame/assets/src/tests/sets.rs new file mode 100644 index 0000000000000..bdff5175185f9 --- /dev/null +++ b/substrate/frame/assets/src/tests/sets.rs @@ -0,0 +1,346 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for [`ItemOf`], [`fungible::UnionOf`] and [`fungibles::UnionOf`] set types. + +use super::*; +use frame_support::{ + parameter_types, + traits::{ + fungible, + fungible::ItemOf, + fungibles, + tokens::{ + fungibles::{ + Balanced as FungiblesBalanced, Create as FungiblesCreate, + Inspect as FungiblesInspect, Mutate as FungiblesMutate, + }, + Fortitude, Precision, Preservation, + }, + }, +}; +use sp_runtime::{traits::ConvertToValue, Either}; + +const FIRST_ASSET: u32 = 0; +const UNKNOWN_ASSET: u32 = 10; + +parameter_types! { + pub const LeftAsset: Either<(), u32> = Either::Left(()); + pub const RightAsset: Either = Either::Right(()); + pub const RightUnitAsset: Either<(), ()> = Either::Right(()); +} + +/// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a +/// single asset class from [`T`] identified by [`FIRST_ASSET`]. +type FirstFungible = ItemOf, u64>; + +/// Implementation of the `fungible` traits through the [`ItemOf`] type, specifically for a +/// single asset class from [`T`] identified by [`UNKNOWN_ASSET`]. +type UnknownFungible = ItemOf, u64>; + +/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes +/// the [`FirstFungible`] from the left. +type LeftFungible = fungible::UnionOf, T, ConvertToValue, (), u64>; + +/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes +/// the [`LeftFungible`] from the right. +type RightFungible = + fungible::UnionOf, LeftFungible, ConvertToValue, (), u64>; + +/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes +/// the [`RightFungible`] from the left. +type LeftFungibles = fungibles::UnionOf, T, ConvertToValue, (), u64>; + +/// Implementation of `fungibles` traits using [`fungibles::UnionOf`] that exclusively utilizes +/// the [`LeftFungibles`] from the right. +/// +/// By using this type, we can navigate through each branch of [`fungible::UnionOf`], +/// [`fungibles::UnionOf`], and [`ItemOf`] to access the underlying `fungibles::*` +/// implementation provided by the pallet. +type First = fungibles::UnionOf, ConvertToValue, (), u64>; + +#[test] +fn deposit_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1 = 0; + let account1 = 1; + let account2 = 2; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::deposit((), &account2, 50, Precision::Exact).unwrap(); + assert_eq!(First::::balance((), &account2), 50); + assert_eq!(First::::total_issuance(()), 100); + + assert_eq!(imb.peek(), 50); + + let (imb1, imb2) = imb.split(30); + assert_eq!(imb1.peek(), 30); + assert_eq!(imb2.peek(), 20); + + drop(imb2); + assert_eq!(First::::total_issuance(()), 120); + + assert!(First::::settle(&account1, imb1, Preservation::Preserve).is_ok()); + assert_eq!(First::::balance((), &account1), 70); + assert_eq!(First::::balance((), &account2), 50); + assert_eq!(First::::total_issuance(()), 120); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); +} + +#[test] +fn issue_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::balance((), &account1), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::issue((), 100); + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(imb.peek(), 100); + + let (imb1, imb2) = imb.split(30); + assert_eq!(imb1.peek(), 30); + assert_eq!(imb2.peek(), 70); + + drop(imb2); + assert_eq!(First::::total_issuance(()), 130); + + assert!(First::::resolve(&account1, imb1).is_ok()); + assert_eq!(First::::balance((), &account1), 130); + assert_eq!(First::::total_issuance(()), 130); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); +} + +#[test] +fn pair_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::balance((), &account1), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let (debt, credit) = First::::pair((), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(debt.peek(), 100); + assert_eq!(credit.peek(), 100); + + let (debt1, debt2) = debt.split(30); + assert_eq!(debt1.peek(), 30); + assert_eq!(debt2.peek(), 70); + + drop(debt2); + assert_eq!(First::::total_issuance(()), 170); + + assert!(First::::settle(&account1, debt1, Preservation::Preserve).is_ok()); + assert_eq!(First::::balance((), &account1), 70); + assert_eq!(First::::total_issuance(()), 170); + + let (credit1, credit2) = credit.split(40); + assert_eq!(credit1.peek(), 40); + assert_eq!(credit2.peek(), 60); + + drop(credit2); + assert_eq!(First::::total_issuance(()), 110); + + assert!(First::::resolve(&account1, credit1).is_ok()); + assert_eq!(First::::balance((), &account1), 110); + assert_eq!(First::::total_issuance(()), 110); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); +} + +#[test] +fn rescind_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::rescind((), 20); + assert_eq!(First::::total_issuance(()), 80); + + assert_eq!(imb.peek(), 20); + + let (imb1, imb2) = imb.split(15); + assert_eq!(imb1.peek(), 15); + assert_eq!(imb2.peek(), 5); + + drop(imb2); + assert_eq!(First::::total_issuance(()), 85); + + assert!(First::::settle(&account1, imb1, Preservation::Preserve).is_ok()); + assert_eq!(First::::balance((), &account1), 85); + assert_eq!(First::::total_issuance(()), 85); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); +} + +#[test] +fn resolve_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + let account2: u64 = 2; + let ed = 11; + + assert_ok!(>::create(asset1, account1, true, ed)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + + assert_eq!(First::::balance((), &account1), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::issue((), 100); + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(imb.peek(), 100); + + let (imb1, imb2) = imb.split(10); + assert_eq!(imb1.peek(), 10); + assert_eq!(imb2.peek(), 90); + assert_eq!(First::::total_issuance(()), 200); + + // ed requirements not met. + let imb1 = First::::resolve(&account2, imb1).unwrap_err(); + assert_eq!(imb1.peek(), 10); + drop(imb1); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 0); + + // resolve to new account `2`. + assert_ok!(First::::resolve(&account2, imb2)); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 90); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); +} + +#[test] +fn settle_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1: u32 = 0; + let account1: u64 = 1; + let account2: u64 = 2; + let ed = 11; + + assert_ok!(>::create(asset1, account1, true, ed)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + assert_ok!(Assets::mint_into(asset1, &account2, 100)); + + assert_eq!(First::::balance((), &account2), 100); + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::rescind((), 100); + assert_eq!(First::::total_issuance(()), 100); + assert_eq!(imb.peek(), 100); + + let (imb1, imb2) = imb.split(10); + assert_eq!(imb1.peek(), 10); + assert_eq!(imb2.peek(), 90); + assert_eq!(First::::total_issuance(()), 100); + + // ed requirements not met. + let imb2 = First::::settle(&account2, imb2, Preservation::Preserve).unwrap_err(); + assert_eq!(imb2.peek(), 90); + drop(imb2); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 100); + + // settle to account `1`. + assert_ok!(First::::settle(&account2, imb1, Preservation::Preserve)); + assert_eq!(First::::total_issuance(()), 190); + assert_eq!(First::::balance((), &account2), 90); + + let imb = First::::rescind((), 85); + assert_eq!(First::::total_issuance(()), 105); + assert_eq!(imb.peek(), 85); + + // settle to account `1` and expect some dust. + let imb = First::::settle(&account2, imb, Preservation::Expendable).unwrap(); + assert_eq!(imb.peek(), 5); + assert_eq!(First::::total_issuance(()), 105); + assert_eq!(First::::balance((), &account2), 0); + + drop(imb); + assert_eq!(First::::total_issuance(()), 100); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); +} + +#[test] +fn withdraw_from_set_types_works() { + new_test_ext().execute_with(|| { + let asset1 = 0; + let account1 = 1; + let account2 = 2; + + assert_ok!(>::create(asset1, account1, true, 1)); + assert_ok!(Assets::mint_into(asset1, &account1, 100)); + assert_ok!(Assets::mint_into(asset1, &account2, 100)); + + assert_eq!(First::::total_issuance(()), 200); + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + + let imb = First::::withdraw( + (), + &account2, + 50, + Precision::Exact, + Preservation::Preserve, + Fortitude::Polite, + ) + .unwrap(); + assert_eq!(First::::balance((), &account2), 50); + assert_eq!(First::::total_issuance(()), 200); + + assert_eq!(imb.peek(), 50); + drop(imb); + assert_eq!(First::::total_issuance(()), 150); + assert_eq!(First::::balance((), &account2), 50); + + assert_eq!(First::::total_issuance(()), Assets::total_issuance(asset1)); + }); +} From fb451cbd7c6d7efd1cf9610ac3f484128c66ee04 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 2 Nov 2023 16:38:13 +0100 Subject: [PATCH 68/69] should_touch for pallet-assets --- substrate/frame/assets/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index b77f9097990a8..5f2449ee6d381 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -1649,7 +1649,11 @@ pub mod pallet { } fn should_touch(asset: T::AssetId, who: &T::AccountId) -> bool { - !Account::::contains_key(asset, who) + match Asset::::get(&asset) { + Some(info) if info.is_sufficient => false, + Some(_) => !Account::::contains_key(asset, who), + _ => true, + } } fn touch( From 524d6f0c821bd21147cdeb7c37298ea2c9533496 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 19 Dec 2023 17:06:31 +0100 Subject: [PATCH 69/69] prdoc --- prdoc/pr_2031.prdoc | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 prdoc/pr_2031.prdoc diff --git a/prdoc/pr_2031.prdoc b/prdoc/pr_2031.prdoc new file mode 100644 index 0000000000000..fc2695df52e1b --- /dev/null +++ b/prdoc/pr_2031.prdoc @@ -0,0 +1,29 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "pallet-asset-conversion: Decoupling Native Currency Dependancy" + +doc: + - audience: Runtime Dev + description: | + Decoupling Pallet from the Concept of Native Currency + + Currently, the pallet used to intrinsically linked with the concept of native currency, requiring users to provide implementations of the `fungible::*` and `fungibles::*` traits to interact with native and non native assets. This incapsulates some non-related to the pallet complexity and makes it less adaptable in contexts where the native currency concept is absent. + + With this PR, the dependence on `fungible::*` for liquidity-supplying assets has been removed. Instead, the native and non-native currencies' handling is now overseen by a single type that implements the `fungibles::*` traits. To simplify this integration, types have been introduced to facilitate the creation of a union between `fungible::*` and `fungibles::*` implementations, producing a unified `fungibles::*` type. + + One of the reasons driving these changes is the ambition to create a more user-friendly API for the `SwapCredit` implementation. Given that it interacts with two distinct credit types from `fungible` and `fungibles`, a unified type was introduced. Clients now manage potential conversion failures for those credit types. In certain contexts, it's vital to guarantee that operations are fail-safe, like in this impl - [PR](https://github.com/paritytech/polkadot-sdk/pull/1845), place in [code](https://github.com/paritytech/polkadot-sdk/blob/20b85a5fada8f55c98ba831964f5866ffeadf4da/cumulus/primitives/utility/src/lib.rs#L429). + + Additional Updates: + - abstracted the pool ID and its account derivation logic via trait bounds, along with common implementation offerings; + - removed `inc_providers` on a pool creation for the pool account; + - benchmarks: + -- swap complexity is N, not const; + -- removed `From + Into` bound from `T::Balance`; + -- removed swap/liquidity/.. amount constants, resolve them dynamically based on pallet configuration; + -- migrated to v2 API; + - `OnUnbalanced` handler for the pool creation fee, replacing direct transfers to a specified account ID; + - renamed `MultiAssetId` to `AssetKind` aligning with naming across frame crates; + +crates: + - name: pallet-asset-conversion