diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f5c03b3ca..8e0e7e3ee 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,8 +63,6 @@ jobs: -p serai-primitives \ -p serai-coins-primitives \ -p serai-coins-pallet \ - -p serai-liquidity-tokens-pallet \ - -p serai-dex-primitives \ -p serai-dex-pallet \ -p serai-validator-sets-primitives \ -p serai-validator-sets-pallet \ diff --git a/Cargo.lock b/Cargo.lock index 96372980f..8653f9fe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7535,7 +7535,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "serai-coins-primitives", - "serai-dex-primitives", "serai-primitives", "sp-core", "sp-runtime", @@ -7626,8 +7625,6 @@ dependencies = [ "parity-scale-codec", "scale-info", "serai-coins-pallet", - "serai-dex-primitives", - "serai-liquidity-tokens-pallet", "serai-primitives", "sp-api", "sp-arithmetic", @@ -7637,19 +7634,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "serai-dex-primitives" -version = "0.1.0" -dependencies = [ - "frame-benchmarking", - "frame-support", - "parity-scale-codec", - "scale-info", - "serai-primitives", - "sp-runtime", - "sp-std", -] - [[package]] name = "serai-docker-tests" version = "0.1.0" @@ -7719,20 +7703,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "serai-liquidity-tokens-pallet" -version = "0.1.0" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "scale-info", - "serai-dex-primitives", - "serai-primitives", - "sp-core", - "sp-std", -] - [[package]] name = "serai-message-queue" version = "0.1.0" @@ -7947,9 +7917,7 @@ dependencies = [ "scale-info", "serai-coins-pallet", "serai-dex-pallet", - "serai-dex-primitives", "serai-in-instructions-pallet", - "serai-liquidity-tokens-pallet", "serai-primitives", "serai-signals-pallet", "serai-validator-sets-pallet", diff --git a/coordinator/src/substrate/mod.rs b/coordinator/src/substrate/mod.rs index 6f314d915..78bdfd26c 100644 --- a/coordinator/src/substrate/mod.rs +++ b/coordinator/src/substrate/mod.rs @@ -208,8 +208,8 @@ async fn handle_batch_and_burns( } } - for burn in serai.coins().burn_events().await? { - if let CoinsEvent::Burn { from: _, instruction } = burn { + for burn in serai.coins().burn_with_instruction_events().await? { + if let CoinsEvent::BurnWithInstruction { from: _, instruction } = burn { let network = instruction.balance.coin.network(); network_had_event(&mut burns, &mut batches, network); diff --git a/deny.toml b/deny.toml index 76a88efdf..72ffdf033 100644 --- a/deny.toml +++ b/deny.toml @@ -54,8 +54,6 @@ exceptions = [ { allow = ["AGPL-3.0"], name = "serai-coordinator" }, { allow = ["AGPL-3.0"], name = "serai-coins-pallet" }, - { allow = ["AGPL-3.0"], name = "serai-liquidity-tokens-pallet" }, - { allow = ["AGPL-3.0"], name = "serai-dex-primitives" }, { allow = ["AGPL-3.0"], name = "serai-dex-pallet" }, { allow = ["AGPL-3.0"], name = "serai-in-instructions-pallet" }, diff --git a/substrate/client/src/serai/coins.rs b/substrate/client/src/serai/coins.rs index b197aedd2..b73f0e7d9 100644 --- a/substrate/client/src/serai/coins.rs +++ b/substrate/client/src/serai/coins.rs @@ -24,8 +24,8 @@ impl<'a> SeraiCoins<'a> { self.0.events::(|event| matches!(event, CoinsEvent::Mint { .. })).await } - pub async fn burn_events(&self) -> Result, SeraiError> { - self.0.events::(|event| matches!(event, CoinsEvent::Burn { .. })).await + pub async fn burn_with_instruction_events(&self) -> Result, SeraiError> { + self.0.events::(|event| matches!(event, CoinsEvent::BurnWithInstruction { .. })).await } pub async fn coin_supply(&self, coin: Coin) -> Result { @@ -64,7 +64,15 @@ impl<'a> SeraiCoins<'a> { ) } - pub fn burn(instruction: OutInstructionWithBalance) -> Payload> { - Payload::new(PALLET, "burn", scale_composite(coins::Call::::burn { instruction })) + pub fn burn(balance: Balance) -> Payload> { + Payload::new(PALLET, "burn", scale_composite(coins::Call::::burn { balance })) + } + + pub fn burn_with_instruction(instruction: OutInstructionWithBalance) -> Payload> { + Payload::new( + PALLET, + "burn_with_instruction", + scale_composite(coins::Call::::burn_with_instruction { instruction }), + ) } } diff --git a/substrate/client/src/serai/dex.rs b/substrate/client/src/serai/dex.rs index 698fecfbe..1b1f15f8a 100644 --- a/substrate/client/src/serai/dex.rs +++ b/substrate/client/src/serai/dex.rs @@ -31,12 +31,11 @@ impl<'a> SeraiDex<'a> { PALLET, "add_liquidity", scale_composite(dex::Call::::add_liquidity { - coin1: coin, - coin2: Coin::Serai, - amount1_desired: coin_amount.0, - amount2_desired: sri_amount.0, - amount1_min: min_coin_amount.0, - amount2_min: min_sri_amount.0, + coin, + coin_desired: coin_amount.0, + sri_desired: sri_amount.0, + coin_min: min_coin_amount.0, + sri_min: min_sri_amount.0, mint_to: address.into(), }), ) diff --git a/substrate/client/tests/burn.rs b/substrate/client/tests/burn.rs index cfdf943a3..456dc131d 100644 --- a/substrate/client/tests/burn.rs +++ b/substrate/client/tests/burn.rs @@ -93,7 +93,7 @@ serai_test!( &serai .sign( &PairSigner::new(pair), - &SeraiCoins::burn(instruction.clone()), + &SeraiCoins::burn_with_instruction(instruction.clone()), 0, BaseExtrinsicParamsBuilder::new(), ) @@ -102,8 +102,8 @@ serai_test!( .await; let serai = serai.as_of(block).coins(); - let events = serai.burn_events().await.unwrap(); - assert_eq!(events, vec![CoinsEvent::Burn { from: address.into(), instruction }]); + let events = serai.burn_with_instruction_events().await.unwrap(); + assert_eq!(events, vec![CoinsEvent::BurnWithInstruction { from: address.into(), instruction }]); assert_eq!(serai.coin_supply(coin).await.unwrap(), Amount(0)); assert_eq!(serai.coin_balance(coin, address).await.unwrap(), Amount(0)); }) diff --git a/substrate/client/tests/dex.rs b/substrate/client/tests/dex.rs index 6e52763cb..fc576db0c 100644 --- a/substrate/client/tests/dex.rs +++ b/substrate/client/tests/dex.rs @@ -36,24 +36,24 @@ serai_test!( events, vec![ DexEvent::PoolCreated { - pool_id: (Coin::Serai, Coin::Bitcoin), - pool_account: PublicKey::from_raw(blake2_256(&(Coin::Serai, Coin::Bitcoin).encode())), - lp_token: 0, + pool_id: Coin::Bitcoin, + pool_account: PublicKey::from_raw(blake2_256(&Coin::Bitcoin.encode())), + lp_token: Coin::Bitcoin, }, DexEvent::PoolCreated { - pool_id: (Coin::Serai, Coin::Ether), - pool_account: PublicKey::from_raw(blake2_256(&(Coin::Serai, Coin::Ether).encode())), - lp_token: 1, + pool_id: Coin::Ether, + pool_account: PublicKey::from_raw(blake2_256(&Coin::Ether.encode())), + lp_token: Coin::Ether, }, DexEvent::PoolCreated { - pool_id: (Coin::Serai, Coin::Dai), - pool_account: PublicKey::from_raw(blake2_256(&(Coin::Serai, Coin::Dai).encode())), - lp_token: 2, + pool_id: Coin::Dai, + pool_account: PublicKey::from_raw(blake2_256(&Coin::Dai.encode())), + lp_token: Coin::Dai, }, DexEvent::PoolCreated { - pool_id: (Coin::Serai, Coin::Monero), - pool_account: PublicKey::from_raw(blake2_256(&(Coin::Serai, Coin::Monero).encode())), - lp_token: 3, + pool_id: Coin::Monero, + pool_account: PublicKey::from_raw(blake2_256(&Coin::Monero.encode())), + lp_token: Coin::Monero, }, ] ); @@ -93,10 +93,10 @@ serai_test!( vec![DexEvent::LiquidityAdded { who: pair.public(), mint_to: pair.public(), - pool_id: (Coin::Serai, Coin::Monero), - amount1_provided: coin_amount.0, - amount2_provided: sri_amount.0, - lp_token: 3, + pool_id: Coin::Monero, + coin_amount: coin_amount.0, + sri_amount: sri_amount.0, + lp_token: Coin::Monero, lp_token_minted: 49_999999990000 }] ); @@ -277,10 +277,10 @@ serai_test!( vec![DexEvent::LiquidityAdded { who: IN_INSTRUCTION_EXECUTOR.into(), mint_to: pair.public(), - pool_id: (Coin::Serai, Coin::Bitcoin), - amount1_provided: 6_947_918_403_646, - amount2_provided: 10_000_000_000_000, // half of sent amount - lp_token: 0, + pool_id: Coin::Bitcoin, + coin_amount: 10_000_000_000_000, // half of sent amount + sri_amount: 6_947_918_403_646, + lp_token: Coin::Bitcoin, lp_token_minted: 8333333333332 }] ); diff --git a/substrate/coins/pallet/Cargo.toml b/substrate/coins/pallet/Cargo.toml index cafe2f6c4..1936b4008 100644 --- a/substrate/coins/pallet/Cargo.toml +++ b/substrate/coins/pallet/Cargo.toml @@ -24,8 +24,6 @@ sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false } -dex-primitives = { package = "serai-dex-primitives", path = "../../dex/primitives", default-features = false } - serai-primitives = { path = "../../primitives", default-features = false } coins-primitives = { package = "serai-coins-primitives", path = "../primitives", default-features = false } @@ -40,8 +38,6 @@ std = [ "pallet-transaction-payment/std", - "dex-primitives/std", - "serai-primitives/std", "coins-primitives/std", ] diff --git a/substrate/coins/pallet/src/lib.rs b/substrate/coins/pallet/src/lib.rs index 433c2bd7f..71b924ef7 100644 --- a/substrate/coins/pallet/src/lib.rs +++ b/substrate/coins/pallet/src/lib.rs @@ -2,7 +2,7 @@ #[frame_support::pallet] pub mod pallet { - use sp_std::vec::Vec; + use sp_std::{vec::Vec, any::TypeId}; use sp_core::sr25519::Public; use sp_runtime::{ traits::{DispatchInfoOf, PostDispatchInfoOf}, @@ -14,80 +14,82 @@ pub mod pallet { use pallet_transaction_payment::{Config as TpConfig, OnChargeTransaction}; - use dex_primitives::{Currency, Coins as CoinsTrait}; - use serai_primitives::*; pub use coins_primitives as primitives; use primitives::*; + type LiquidityTokensInstance = crate::Instance1; + #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::genesis_config] #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] - pub struct GenesisConfig { + pub struct GenesisConfig, I: 'static = ()> { pub accounts: Vec<(T::AccountId, Balance)>, + pub _ignore: PhantomData, } - impl Default for GenesisConfig { + impl, I: 'static> Default for GenesisConfig { fn default() -> Self { - GenesisConfig { accounts: Default::default() } + GenesisConfig { accounts: Default::default(), _ignore: Default::default() } } } #[pallet::error] - pub enum Error { + pub enum Error { AmountOverflowed, NotEnoughCoins, - SriBurnNotAllowed, + BurnWithInstructionNotAllowed, } #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { Mint { to: Public, balance: Balance }, - Burn { from: Public, instruction: OutInstructionWithBalance }, - SriBurn { from: Public, amount: Amount }, + Burn { from: Public, balance: Balance }, + BurnWithInstruction { from: Public, instruction: OutInstructionWithBalance }, Transfer { from: Public, to: Public, balance: Balance }, } #[pallet::pallet] - pub struct Pallet(PhantomData); + pub struct Pallet(_); /// The amount of coins each account has. // Identity is used as the second key's hasher due to it being a non-manipulatable fixed-space // ID. #[pallet::storage] #[pallet::getter(fn balances)] - pub type Balances = + pub type Balances, I: 'static = ()> = StorageDoubleMap<_, Blake2_128Concat, Public, Identity, Coin, SubstrateAmount, ValueQuery>; /// The total supply of each coin. // We use Identity type here again due to reasons stated in the Balances Storage. #[pallet::storage] #[pallet::getter(fn supply)] - pub type Supply = StorageMap<_, Identity, Coin, SubstrateAmount, ValueQuery>; + pub type Supply, I: 'static = ()> = + StorageMap<_, Identity, Coin, SubstrateAmount, ValueQuery>; #[pallet::genesis_build] - impl BuildGenesisConfig for GenesisConfig { + impl, I: 'static> BuildGenesisConfig for GenesisConfig { fn build(&self) { // initialize the supply of the coins // TODO: Don't use COINS yet GenesisConfig so we can safely expand COINS for c in &COINS { - Supply::::set(c, 0); + Supply::::set(c, 0); } // initialize the genesis accounts for (account, balance) in &self.accounts { - Pallet::::mint(*account, *balance).unwrap(); + Pallet::::mint(*account, *balance).unwrap(); } } } #[pallet::hooks] - impl Hooks> for Pallet { + impl, I: 'static> Hooks> for Pallet { fn on_initialize(_: BlockNumberFor) -> Weight { // burn the fees collected previous block let coin = Coin::Serai; @@ -95,66 +97,66 @@ pub mod pallet { // we can unwrap, we are not burning more then what we have // If this errors, it'll halt the runtime however (due to being called at the start of every // block), requiring extra care when reviewing - Self::burn_sri(FEE_ACCOUNT.into(), amount).unwrap(); + Self::burn_internal(FEE_ACCOUNT.into(), Balance { coin, amount }).unwrap(); Weight::zero() // TODO } } - impl Pallet { + impl, I: 'static> Pallet { /// Returns the balance of a given account for `coin`. pub fn balance(of: Public, coin: Coin) -> Amount { Amount(Self::balances(of, coin)) } - fn decrease_balance_internal(from: Public, balance: Balance) -> Result<(), Error> { + fn decrease_balance_internal(from: Public, balance: Balance) -> Result<(), Error> { let coin = &balance.coin; // sub amount from account let new_amount = Self::balances(from, coin) .checked_sub(balance.amount.0) - .ok_or(Error::::NotEnoughCoins)?; + .ok_or(Error::::NotEnoughCoins)?; // save if new_amount == 0 { - Balances::::remove(from, coin); + Balances::::remove(from, coin); } else { - Balances::::set(from, coin, new_amount); + Balances::::set(from, coin, new_amount); } Ok(()) } - fn increase_balance_internal(to: Public, balance: Balance) -> Result<(), Error> { + fn increase_balance_internal(to: Public, balance: Balance) -> Result<(), Error> { let coin = &balance.coin; // sub amount from account let new_amount = Self::balances(to, coin) .checked_add(balance.amount.0) - .ok_or(Error::::AmountOverflowed)?; + .ok_or(Error::::AmountOverflowed)?; // save - Balances::::set(to, coin, new_amount); + Balances::::set(to, coin, new_amount); Ok(()) } /// Mint `balance` to the given account. /// /// Errors if any amount overflows. - pub fn mint(to: Public, balance: Balance) -> Result<(), Error> { + pub fn mint(to: Public, balance: Balance) -> Result<(), Error> { // update the balance Self::increase_balance_internal(to, balance)?; // update the supply let new_supply = Self::supply(balance.coin) .checked_add(balance.amount.0) - .ok_or(Error::::AmountOverflowed)?; - Supply::::set(balance.coin, new_supply); + .ok_or(Error::::AmountOverflowed)?; + Supply::::set(balance.coin, new_supply); Self::deposit_event(Event::Mint { to, balance }); Ok(()) } - // Burn `balance` from the specified account. - fn burn_internal(from: Public, balance: Balance) -> Result<(), Error> { + /// Burn `balance` from the specified account. + fn burn_internal(from: Public, balance: Balance) -> Result<(), Error> { // don't waste time if amount == 0 if balance.amount.0 == 0 { return Ok(()); @@ -165,31 +167,17 @@ pub mod pallet { // update the supply let new_supply = Self::supply(balance.coin).checked_sub(balance.amount.0).unwrap(); - Supply::::set(balance.coin, new_supply); - - Ok(()) - } + Supply::::set(balance.coin, new_supply); - pub fn burn_sri(from: Public, amount: Amount) -> Result<(), Error> { - Self::burn_internal(from, Balance { coin: Coin::Serai, amount })?; - Self::deposit_event(Event::SriBurn { from, amount }); - Ok(()) - } - - pub fn burn_non_sri( - from: Public, - instruction: OutInstructionWithBalance, - ) -> Result<(), Error> { - if instruction.balance.coin == Coin::Serai { - Err(Error::::SriBurnNotAllowed)?; - } - Self::burn_internal(from, instruction.balance)?; - Self::deposit_event(Event::Burn { from, instruction }); Ok(()) } /// Transfer `balance` from `from` to `to`. - pub fn transfer_internal(from: Public, to: Public, balance: Balance) -> Result<(), Error> { + pub fn transfer_internal( + from: Public, + to: Public, + balance: Balance, + ) -> Result<(), Error> { // update balances of accounts Self::decrease_balance_internal(from, balance)?; Self::increase_balance_internal(to, balance)?; @@ -199,7 +187,7 @@ pub mod pallet { } #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { #[pallet::call_index(0)] #[pallet::weight((0, DispatchClass::Normal))] // TODO pub fn transfer(origin: OriginFor, to: Public, balance: Balance) -> DispatchResult { @@ -208,77 +196,35 @@ pub mod pallet { Ok(()) } + /// Burn `balance` from the caller. #[pallet::call_index(1)] #[pallet::weight((0, DispatchClass::Normal))] // TODO - pub fn burn(origin: OriginFor, instruction: OutInstructionWithBalance) -> DispatchResult { + pub fn burn(origin: OriginFor, balance: Balance) -> DispatchResult { let from = ensure_signed(origin)?; - Self::burn_non_sri(from, instruction)?; + Self::burn_internal(from, balance)?; + Self::deposit_event(Event::Burn { from, balance }); Ok(()) } - } - - impl Currency for Pallet { - type Balance = SubstrateAmount; - - fn balance(of: &Public) -> Self::Balance { - Self::balance(*of, Coin::Serai).0 - } - - /// TODO: make sure of coin precision here. - fn minimum_balance() -> Self::Balance { - 1 - } - fn transfer( - from: &Public, - to: &Public, - amount: Self::Balance, - ) -> Result { - let balance = Balance { coin: Coin::Serai, amount: Amount(amount) }; - Self::transfer_internal(*from, *to, balance)?; - Ok(amount) - } - - fn mint(to: &Public, amount: Self::Balance) -> Result { - Self::mint(*to, Balance { coin: Coin::native(), amount: Amount(amount) })?; - Ok(amount) - } - } - - // TODO: Have DEX implement for Coins, not Coins implement for Coins - impl CoinsTrait for Pallet { - type Balance = SubstrateAmount; - type CoinId = Coin; - - // TODO: Swap the order of these arguments - fn balance(coin: Self::CoinId, of: &Public) -> Self::Balance { - Self::balance(*of, coin).0 - } - - fn minimum_balance(_: Self::CoinId) -> Self::Balance { - 1 - } - - // TODO: Move coin next to amount - fn transfer( - coin: Self::CoinId, - from: &Public, - to: &Public, - amount: Self::Balance, - ) -> Result { - let balance = Balance { coin, amount: Amount(amount) }; - Self::transfer_internal(*from, *to, balance)?; - Ok(amount) - } + /// Burn `balance` with `OutInstructionWithBalance` from the caller. + /// Errors if called for SRI or Instance1 instance of this pallet. + #[pallet::call_index(2)] + #[pallet::weight((0, DispatchClass::Normal))] // TODO + pub fn burn_with_instruction( + origin: OriginFor, + instruction: OutInstructionWithBalance, + ) -> DispatchResult { + if instruction.balance.coin == Coin::Serai { + Err(Error::::BurnWithInstructionNotAllowed)?; + } + if TypeId::of::() == TypeId::of::() { + Err(Error::::BurnWithInstructionNotAllowed)?; + } - // TODO: Move coin next to amount - fn mint( - coin: Self::CoinId, - to: &Public, - amount: Self::Balance, - ) -> Result { - Self::mint(*to, Balance { coin, amount: Amount(amount) })?; - Ok(amount) + let from = ensure_signed(origin)?; + Self::burn_internal(from, instruction.balance)?; + Self::deposit_event(Event::BurnWithInstruction { from, instruction }); + Ok(()) } } diff --git a/substrate/dex/pallet/Cargo.toml b/substrate/dex/pallet/Cargo.toml index cff31531c..2dcd461c4 100644 --- a/substrate/dex/pallet/Cargo.toml +++ b/substrate/dex/pallet/Cargo.toml @@ -26,14 +26,10 @@ frame-system = { git = "https://github.com/serai-dex/substrate", default-feature frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } frame-benchmarking = { git = "https://github.com/serai-dex/substrate", default-features = false, optional = true } -dex-primitives = { package = "serai-dex-primitives", path = "../primitives", default-features = false } +coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false } -[dev-dependencies] serai-primitives = { path = "../../primitives", default-features = false } -coins-pallet = { package = "serai-coins-pallet", path = "../../coins/pallet", default-features = false } -liquidity-tokens-pallet = { package = "serai-liquidity-tokens-pallet", path = "../../liquidity-tokens/pallet", default-features = false } - [features] default = ["std"] std = [ @@ -49,14 +45,11 @@ std = [ "serai-primitives/std", - "dex-primitives/std", - "frame-system/std", "frame-support/std", "frame-benchmarking?/std", "coins-pallet/std", - "liquidity-tokens-pallet/std", ] runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", @@ -64,8 +57,6 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", - - "dex-primitives/runtime-benchmarks", ] try-runtime = [ "sp-runtime/try-runtime", diff --git a/substrate/dex/pallet/src/benchmarking.rs b/substrate/dex/pallet/src/benchmarking.rs index 372c9df8d..4fe301f61 100644 --- a/substrate/dex/pallet/src/benchmarking.rs +++ b/substrate/dex/pallet/src/benchmarking.rs @@ -24,247 +24,206 @@ use super::*; use frame_benchmarking::{benchmarks, whitelisted_caller}; use frame_support::{assert_ok, storage::bounded_vec::BoundedVec}; use frame_system::RawOrigin as SystemOrigin; -use sp_runtime::traits::{Bounded, StaticLookup}; + +use sp_runtime::traits::StaticLookup; use sp_std::{ops::Div, prelude::*}; +use serai_primitives::{Amount, Balance}; + use crate::Pallet as Dex; +use coins_pallet::Pallet as Coins; const INITIAL_COIN_BALANCE: u64 = 1_000_000_000; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; -fn get_lp_token_id() -> T::PoolCoinId -where - T::PoolCoinId: Into, -{ - let next_id: u32 = Dex::::get_next_pool_coin_id().into(); - (next_id - 1).into() -} +type LiquidityTokens = coins_pallet::Pallet; -fn create_coin(coin: &T::MultiCoinId) -> (T::AccountId, AccountIdLookupOf) -where - T::CoinBalance: From, - T::Currency: Currency, - T::Coins: Coins, -{ +fn create_coin(coin: &Coin) -> (T::AccountId, AccountIdLookupOf) { let caller: T::AccountId = whitelisted_caller(); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - if let MultiCoinIdConversionResult::Converted(coin_id) = - T::MultiCoinIdConverter::try_convert(coin) - { - assert_ok!(T::Currency::mint(&caller, BalanceOf::::max_value().div(1000u32.into()))); - assert_ok!(T::Coins::mint(coin_id, &caller, INITIAL_COIN_BALANCE.into())); - } + let caller_lookup = T::Lookup::unlookup(caller); + assert_ok!(Coins::::mint( + caller, + Balance { coin: Coin::native(), amount: Amount(SubstrateAmount::max_value().div(1000u64)) } + )); + assert_ok!(Coins::::mint( + caller, + Balance { coin: *coin, amount: Amount(INITIAL_COIN_BALANCE) } + )); (caller, caller_lookup) } fn create_coin_and_pool( - coin1: &T::MultiCoinId, - coin2: &T::MultiCoinId, -) -> (T::PoolCoinId, T::AccountId, AccountIdLookupOf) -where - T::CoinBalance: From, - T::Currency: Currency, - T::Coins: Coins, - T::PoolCoinId: Into, -{ - assert_eq!(coin1, &T::MultiCoinIdConverter::get_native()); - - let (caller, caller_lookup) = create_coin::(coin2); + coin: &Coin, +) -> (PoolCoinId, T::AccountId, AccountIdLookupOf) { + let (caller, caller_lookup) = create_coin::(coin); + assert_ok!(Dex::::create_pool(*coin)); - assert_ok!(Dex::::create_pool(coin2.clone())); - let lp_token = get_lp_token_id::(); - - (lp_token, caller, caller_lookup) + (*coin, caller, caller_lookup) } benchmarks! { - where_clause { - where - T::CoinBalance: From + Into, - T::Currency: Currency, - T::Balance: From + Into, - T::Coins: Coins, - T::PoolCoinId: Into, - } - add_liquidity { - let coin1 = T::MultiCoinIdConverter::get_native(); - let coin2: T::MultiCoinId = T::BenchmarkHelper::coin_id(0).into(); - let (lp_token, caller, _) = create_coin_and_pool::(&coin1, &coin2); - let ed: u64 = T::Currency::minimum_balance().into(); - let add_amount = 1000 + ed; + let coin1 = Coin::native(); + let coin2 = Coin::Bitcoin; + let (lp_token, caller, _) = create_coin_and_pool::(&coin2); + let add_amount: u64 = 1000; }: _( - SystemOrigin::Signed(caller.clone()), - coin1.clone(), - coin2.clone(), - add_amount.into(), - 1000.into(), - 0.into(), - 0.into(), - caller.clone() + SystemOrigin::Signed(caller), + coin2, + 1000u64, + add_amount, + 0u64, + 0u64, + caller ) verify { - let pool_id = (coin1.clone(), coin2.clone()); + let pool_id = Dex::::get_pool_id(coin1, coin2).unwrap(); let lp_minted = Dex::::calc_lp_amount_for_zero_supply( - &add_amount.into(), - &1000.into() - ).unwrap().into(); + add_amount, + 1000u64, + ).unwrap(); assert_eq!( - T::PoolCoins::balance(lp_token, &caller), - lp_minted.into() + LiquidityTokens::::balance(caller, lp_token).0, + lp_minted ); assert_eq!( - T::Currency::balance(&Dex::::get_pool_account(&pool_id)), - add_amount.into() + Coins::::balance(Dex::::get_pool_account(pool_id), Coin::native()).0, + add_amount ); assert_eq!( - T::Coins::balance( - T::BenchmarkHelper::coin_id(0), - &Dex::::get_pool_account(&pool_id) - ), - 1000.into() + Coins::::balance( + Dex::::get_pool_account(pool_id), + Coin::Bitcoin, + ).0, + 1000 ); } remove_liquidity { - let coin1 = T::MultiCoinIdConverter::get_native(); - let coin2: T::MultiCoinId = T::BenchmarkHelper::coin_id(0).into(); - let (lp_token, caller, _) = create_coin_and_pool::(&coin1, &coin2); - let ed: u64 = T::Currency::minimum_balance().into(); - let add_amount = 100 * ed; + let coin1 = Coin::native(); + let coin2 = Coin::Monero; + let (lp_token, caller, _) = create_coin_and_pool::(&coin2); + let add_amount: u64 = 100; let lp_minted = Dex::::calc_lp_amount_for_zero_supply( - &add_amount.into(), - &1000.into() - ).unwrap().into(); - let remove_lp_amount = lp_minted.checked_div(10).unwrap(); + add_amount, + 1000u64 + ).unwrap(); + let remove_lp_amount: u64 = lp_minted.checked_div(10).unwrap(); Dex::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - coin1.clone(), - coin2.clone(), - add_amount.into(), - 1000.into(), - 0.into(), - 0.into(), - caller.clone(), + SystemOrigin::Signed(caller).into(), + coin2, + 1000u64, + add_amount, + 0u64, + 0u64, + caller, )?; - let total_supply = - >::total_issuance(lp_token.clone()); + let total_supply = LiquidityTokens::::supply(lp_token); }: _( - SystemOrigin::Signed(caller.clone()), - coin1, + SystemOrigin::Signed(caller), coin2, - remove_lp_amount.into(), - 0.into(), - 0.into(), - caller.clone() + remove_lp_amount, + 0u64, + 0u64, + caller ) verify { - let new_total_supply = - >::total_issuance(lp_token.clone()); + let new_total_supply = LiquidityTokens::::supply(lp_token); assert_eq!( new_total_supply, - total_supply - remove_lp_amount.into() + total_supply - remove_lp_amount ); } swap_exact_tokens_for_tokens { - let native = T::MultiCoinIdConverter::get_native(); - let coin1: T::MultiCoinId = T::BenchmarkHelper::coin_id(1).into(); - let coin2: T::MultiCoinId = T::BenchmarkHelper::coin_id(2).into(); - let (_, caller, _) = create_coin_and_pool::(&native, &coin1); + let native = Coin::native(); + let coin1 = Coin::Bitcoin; + let coin2 = Coin::Ether; + let (_, caller, _) = create_coin_and_pool::(&coin1); let (_, _) = create_coin::(&coin2); - let ed: u64 = T::Currency::minimum_balance().into(); - let ed_bump = 2u64; Dex::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - coin1.clone(), - // TODO: this call otherwise fails with `InsufficientLiquidityMinted`. - // might be again related to their expectance on ed being > 1. - (100 * (ed + ed_bump)).into(), - 200.into(), - 0.into(), - 0.into(), - caller.clone(), + SystemOrigin::Signed(caller).into(), + coin1, + 200u64, + // TODO: this call otherwise fails with `InsufficientLiquidityMinted` if we don't multiply + // with 3. Might be again related to their expectance on ed being > 1. + 100 * 3, + 0u64, + 0u64, + caller, )?; - let swap_amount = 100.into(); + let swap_amount = 100u64; // since we only allow the native-coin pools, then the worst case scenario would be to swap // coin1-native-coin2 - Dex::::create_pool(coin2.clone())?; + Dex::::create_pool(coin2)?; Dex::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - coin2.clone(), - (500 * ed).into(), - 1000.into(), - 0.into(), - 0.into(), - caller.clone(), + SystemOrigin::Signed(caller).into(), + coin2, + 1000u64, + 500, + 0u64, + 0u64, + caller, )?; - let path = vec![coin1.clone(), native.clone(), coin2.clone()]; + let path = vec![coin1, native, coin2]; let path = BoundedVec::<_, T::MaxSwapPathLength>::try_from(path).unwrap(); - let native_balance = T::Currency::balance(&caller); - let coin1_balance = T::Coins::balance(T::BenchmarkHelper::coin_id(1), &caller); - }: _(SystemOrigin::Signed(caller.clone()), path, swap_amount, 1.into(), caller.clone()) + let native_balance = Coins::::balance(caller, native).0; + let coin1_balance = Coins::::balance(caller, Coin::Bitcoin).0; + }: _(SystemOrigin::Signed(caller), path, swap_amount, 1u64, caller) verify { let ed_bump = 2u64; - let new_coin1_balance = T::Coins::balance(T::BenchmarkHelper::coin_id(1), &caller); - assert_eq!(new_coin1_balance, coin1_balance - 100.into()); + let new_coin1_balance = Coins::::balance(caller, Coin::Bitcoin).0; + assert_eq!(new_coin1_balance, coin1_balance - 100u64); } swap_tokens_for_exact_tokens { - let native = T::MultiCoinIdConverter::get_native(); - let coin1: T::MultiCoinId = T::BenchmarkHelper::coin_id(1).into(); - let coin2: T::MultiCoinId = T::BenchmarkHelper::coin_id(2).into(); - let (_, caller, _) = create_coin_and_pool::(&native, &coin1); + let native = Coin::native(); + let coin1 = Coin::Bitcoin; + let coin2 = Coin::Ether; + let (_, caller, _) = create_coin_and_pool::(&coin1); let (_, _) = create_coin::(&coin2); - let ed: u64 = T::Currency::minimum_balance().into(); Dex::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - coin1.clone(), - (1000 * ed).into(), - 500.into(), - 0.into(), - 0.into(), - caller.clone(), + SystemOrigin::Signed(caller).into(), + coin1, + 500u64, + 1000, + 0u64, + 0u64, + caller, )?; // since we only allow the native-coin pools, then the worst case scenario would be to swap // coin1-native-coin2 - Dex::::create_pool(coin2.clone())?; + Dex::::create_pool(coin2)?; Dex::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - coin2.clone(), - (500 * ed).into(), - 1000.into(), - 0.into(), - 0.into(), - caller.clone(), + SystemOrigin::Signed(caller).into(), + coin2, + 1000u64, + 500, + 0u64, + 0u64, + caller, )?; - let path = vec![coin1.clone(), native.clone(), coin2.clone()]; + let path = vec![coin1, native, coin2]; let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap(); - let coin2_balance = T::Coins::balance(T::BenchmarkHelper::coin_id(2), &caller); + let coin2_balance = Coins::::balance(caller, Coin::Ether).0; }: _( - SystemOrigin::Signed(caller.clone()), + SystemOrigin::Signed(caller), path.clone(), - 100.into(), - (1000 * ed).into(), - caller.clone() + 100u64, + 1000, + caller ) verify { - let new_coin2_balance = T::Coins::balance(T::BenchmarkHelper::coin_id(2), &caller); - assert_eq!(new_coin2_balance, coin2_balance + 100.into()); + let new_coin2_balance = Coins::::balance(caller, Coin::Ether).0; + assert_eq!(new_coin2_balance, coin2_balance + 100u64); } impl_benchmark_test_suite!(Dex, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/dex/pallet/src/lib.rs b/substrate/dex/pallet/src/lib.rs index 5f808da21..553903bdf 100644 --- a/substrate/dex/pallet/src/lib.rs +++ b/substrate/dex/pallet/src/lib.rs @@ -64,11 +64,12 @@ //! (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}; +use frame_support::traits::DefensiveOption; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +mod types; pub mod weights; #[cfg(test)] @@ -77,106 +78,68 @@ mod tests; #[cfg(test)] mod mock; -use codec::Codec; -use frame_support::{ - ensure, - traits::tokens::{AssetId as CoinId, Balance}, -}; +use frame_support::ensure; use frame_system::{ - ensure_signed, pallet_prelude::{BlockNumberFor, OriginFor}, + ensure_signed, }; + pub use pallet::*; -use sp_arithmetic::traits::Unsigned; -use sp_runtime::{ - traits::{ - CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Ensure, MaybeDisplay, TrailingZeroInput, - }, - DispatchError, -}; + +use sp_runtime::{traits::TrailingZeroInput, DispatchError}; + +use serai_primitives::{Coin, SubstrateAmount}; + use sp_std::prelude::*; -use dex_primitives::*; +pub use types::*; pub use weights::WeightInfo; #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::{pallet_prelude::*, BoundedBTreeSet}; - use sp_runtime::{ - traits::{IntegerSquareRoot, One, Zero}, - Saturating, - }; + + use sp_core::sr25519::Public; + use sp_runtime::traits::IntegerSquareRoot; + + use coins_pallet::{Pallet as CoinsPallet, Config as CoinsConfig}; + + use serai_primitives::{Coin, Amount, Balance, SubstrateAmount}; /// Pool ID. /// /// The pool's `AccountId` is derived from this type. Any changes to the type may necessitate a /// migration. - pub type PoolIdOf = (::MultiCoinId, ::MultiCoinId); + pub type PoolId = Coin; + + /// Liquidity token id is the same as pool id. + pub type PoolCoinId = Coin; + + /// LiquidityTokens Pallet as an instance of coins pallet. + pub type LiquidityTokens = coins_pallet::Pallet; + + /// A type used for amount conversions. + pub type HigherPrecisionBalance = u128; #[pallet::pallet] pub struct Pallet(_); #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: + frame_system::Config + + CoinsConfig + + coins_pallet::Config + { /// Overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Currency type that this works on. - type Currency: Currency; - - /// The `Currency::Balance` type of the native currency. - type Balance: Balance; - - /// The type used to describe the amount of fractions converted into coins. - type CoinBalance: Balance; - - /// A type used for conversions between `Balance` and `CoinBalance`. - type HigherPrecisionBalance: IntegerSquareRoot - + One - + Ensure - + Unsigned - + From - + From - + From - + TryInto - + TryInto; - - /// Identifier for the class of non-native coin. - /// Note: A `From` bound here would prevent `MultiLocation` from being used as an - /// `CoinId`. - type CoinId: frame_support::Serialize + sp_runtime::DeserializeOwned + CoinId; - - /// Type that identifies either the native currency or a token class from `Coins`. - /// `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 MultiCoinId: Ord + CoinId + From; - - /// Type to convert an `CoinId` into `MultiCoinId`. - type MultiCoinIdConverter: MultiCoinIdConverter; - - /// `CoinId` to address the lp tokens by. - type PoolCoinId: CoinId + PartialOrd + Incrementable + From; - - /// Registry for the coins. - type Coins: Coins; - - /// Registry for the lp tokens. Ideally only this pallet should have create permissions on - /// the coins. - type PoolCoins: LiquidityTokens< - Self::AccountId, - CoinId = Self::PoolCoinId, - Balance = Self::CoinBalance, - >; - /// A % the liquidity providers will take of every swap. Represents 10ths of a percent. #[pallet::constant] type LPFee: Get; /// 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] @@ -184,22 +147,12 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - - /// The benchmarks need a way to create coin ids from u32s. - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper: BenchmarkHelper; } /// Map from `PoolCoinId` 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>; - - /// Stores the `PoolCoinId` that is going to be used for the next lp token. - /// This gets incremented whenever a new lp pool is created. - #[pallet::storage] - pub type NextPoolCoinId = StorageValue<_, T::PoolCoinId, OptionQuery>; + pub type Pools = StorageMap<_, Blake2_128Concat, PoolId, PoolInfo, OptionQuery>; // Pallet's events. #[pallet::event] @@ -209,12 +162,12 @@ pub mod pallet { PoolCreated { /// The pool id associated with the pool. Note that the order of the coins may not be /// the same as the order specified in the create pool extrinsic. - pool_id: PoolIdOf, + pool_id: PoolId, /// The account ID of the pool. pool_account: T::AccountId, /// The id of the liquidity tokens that will be minted when coins are added to this /// pool. - lp_token: T::PoolCoinId, + lp_token: PoolCoinId, }, /// A successful call of the `AddLiquidity` extrinsic will create this event. @@ -224,15 +177,15 @@ 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, - /// The amount of the first coin that was added to the pool. - amount1_provided: T::CoinBalance, - /// The amount of the second coin that was added to the pool. - amount2_provided: T::CoinBalance, + pool_id: PoolId, + /// The amount of the coin that was added to the pool. + coin_amount: SubstrateAmount, + /// The amount of the SRI that was added to the pool. + sri_amount: SubstrateAmount, /// The id of the lp token that was minted. - lp_token: T::PoolCoinId, + lp_token: PoolCoinId, /// The amount of lp tokens that were minted of that id. - lp_token_minted: T::CoinBalance, + lp_token_minted: SubstrateAmount, }, /// A successful call of the `RemoveLiquidity` extrinsic will create this event. @@ -242,15 +195,15 @@ pub mod pallet { /// The account that the coins were transferred to. withdraw_to: T::AccountId, /// The pool id that the liquidity was removed from. - pool_id: PoolIdOf, + pool_id: PoolId, /// The amount of the first coin that was removed from the pool. - amount1: T::CoinBalance, + coin_amount: SubstrateAmount, /// The amount of the second coin that was removed from the pool. - amount2: T::CoinBalance, + sri_amount: SubstrateAmount, /// The id of the lp token that was burned. - lp_token: T::PoolCoinId, + lp_token: PoolCoinId, /// The amount of lp tokens that were burned of that id. - lp_token_burned: T::CoinBalance, + lp_token_burned: SubstrateAmount, }, /// Coins have been converted from one to another. Both `SwapExactTokenForToken` /// and `SwapTokenForExactToken` will generate this event. @@ -260,23 +213,12 @@ pub mod pallet { /// The account that the coins were transferred to. send_to: T::AccountId, /// The route of coin ids that the swap went through. - /// E.g. A -> Dot -> B - path: BoundedVec, + /// E.g. A -> SRI -> B + path: BoundedVec, /// The amount of the first coin that was swapped. - amount_in: T::CoinBalance, + amount_in: SubstrateAmount, /// The amount of the second coin that was received. - amount_out: T::CoinBalance, - }, - /// An amount has been transferred from one account to another. - Transfer { - /// The account that the coins were transferred from. - from: T::AccountId, - /// The account that the coins were transferred to. - to: T::AccountId, - /// The coin that was transferred. - coin: T::MultiCoinId, - /// The amount of the coin that was transferred. - amount: T::CoinBalance, + amount_out: SubstrateAmount, }, } @@ -284,12 +226,14 @@ pub mod pallet { #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] pub struct GenesisConfig { /// Pools to create at launch. - pub pools: Vec, + pub pools: Vec, + /// field just to have T. + pub _ignore: PhantomData, } impl Default for GenesisConfig { fn default() -> Self { - GenesisConfig { pools: Default::default() } + GenesisConfig { pools: Default::default(), _ignore: Default::default() } } } @@ -297,7 +241,7 @@ pub mod pallet { impl BuildGenesisConfig for GenesisConfig { fn build(&self) { for coin in &self.pools { - Pallet::::create_pool(coin.clone().into()).unwrap(); + Pallet::::create_pool(*coin).unwrap(); } } } @@ -313,27 +257,27 @@ pub mod pallet { /// Desired amount can't be zero. WrongDesiredAmount, /// Provided amount should be greater than or equal to the existential deposit/coin's - /// minimal amount. - AmountOneLessThanMinimal, + /// minimum amount. + CoinAmountLessThanMinimum, /// Provided amount should be greater than or equal to the existential deposit/coin's - /// minimal amount. - AmountTwoLessThanMinimal, + /// minimum amount. + SriAmountLessThanMinimum, /// Reserve needs to always be greater than or equal to the existential deposit/coin's - /// minimal amount. - ReserveLeftLessThanMinimal, + /// minimum amount. + ReserveLeftLessThanMinimum, /// Desired amount can't be equal to the pool reserve. AmountOutTooHigh, /// The pool doesn't exist. PoolNotFound, /// An overflow happened. Overflow, - /// The minimal amount requirement for the first token in the pair wasn't met. + /// The minimum amount requirement for the first token in the pair wasn't met. CoinOneDepositDidNotMeetMinimum, - /// The minimal amount requirement for the second token in the pair wasn't met. + /// The minimum amount requirement for the second token in the pair wasn't met. CoinTwoDepositDidNotMeetMinimum, - /// The minimal amount requirement for the first token in the pair wasn't met. + /// The minimum amount requirement for the first token in the pair wasn't met. CoinOneWithdrawalDidNotMeetMinimum, - /// The minimal amount requirement for the second token in the pair wasn't met. + /// The minimum amount requirement for the second token in the pair wasn't met. CoinTwoWithdrawalDidNotMeetMinimum, /// Optimal calculated amount is less than desired. OptimalAmountLessThanDesired, @@ -377,34 +321,26 @@ pub mod pallet { /// (the id of which is returned in the `Event::PoolCreated` event). /// /// Once a pool is created, someone may [`Pallet::add_liquidity`] to it. - pub(crate) fn create_pool(coin2: T::MultiCoinId) -> DispatchResult { - let coin1 = T::MultiCoinIdConverter::get_native(); - ensure!(coin1 != coin2, Error::::EqualCoins); + pub(crate) fn create_pool(coin: Coin) -> DispatchResult { + ensure!(coin != Coin::Serai, Error::::EqualCoins); // prepare pool_id - let pool_id = Self::get_pool_id(coin1, coin2); - ensure!(!Pools::::contains_key(&pool_id), Error::::PoolExists); + let pool_id = Self::get_pool_id(coin, Coin::Serai).unwrap(); + ensure!(!Pools::::contains_key(pool_id), Error::::PoolExists); - let pool_account = Self::get_pool_account(&pool_id); + let pool_account = Self::get_pool_account(pool_id); frame_system::Pallet::::inc_providers(&pool_account); - let lp_token = NextPoolCoinId::::get() - .or(T::PoolCoinId::initial_value()) - .ok_or(Error::::IncorrectPoolCoinId)?; - let next_lp_token_id = lp_token.increment().ok_or(Error::::IncorrectPoolCoinId)?; - NextPoolCoinId::::set(Some(next_lp_token_id)); - - let pool_info = PoolInfo { lp_token: lp_token.clone() }; - Pools::::insert(pool_id.clone(), pool_info); + let pool_info = PoolInfo { lp_token: coin }; + Pools::::insert(pool_id, pool_info); - Self::deposit_event(Event::PoolCreated { pool_id, pool_account, lp_token }); + Self::deposit_event(Event::PoolCreated { pool_id, pool_account, lp_token: coin }); Ok(()) } } /// Pallet's callable functions. - // TODO: For all of these calls, limit one of these to always be Coin::Serai #[pallet::call] impl Pallet { /// Provide liquidity into the pool of `coin1` and `coin2`. @@ -421,74 +357,69 @@ pub mod pallet { #[allow(clippy::too_many_arguments)] pub fn add_liquidity( origin: OriginFor, - coin1: T::MultiCoinId, - coin2: T::MultiCoinId, - amount1_desired: T::CoinBalance, - amount2_desired: T::CoinBalance, - amount1_min: T::CoinBalance, - amount2_min: T::CoinBalance, + coin: Coin, + coin_desired: SubstrateAmount, + sri_desired: SubstrateAmount, + coin_min: SubstrateAmount, + sri_min: SubstrateAmount, mint_to: T::AccountId, ) -> DispatchResult { let sender = ensure_signed(origin)?; + ensure!((sri_desired > 0) && (coin_desired > 0), Error::::WrongDesiredAmount); + ensure!(coin != Coin::Serai, Error::::EqualCoins); - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); - // swap params if needed - let (amount1_desired, amount2_desired, amount1_min, amount2_min) = if pool_id.0 == coin1 { - (amount1_desired, amount2_desired, amount1_min, amount2_min) - } else { - (amount2_desired, amount1_desired, amount2_min, amount1_min) - }; - ensure!( - amount1_desired > Zero::zero() && amount2_desired > Zero::zero(), - Error::::WrongDesiredAmount - ); + let pool_id = Self::get_pool_id(coin, Coin::Serai).unwrap(); - let maybe_pool = Pools::::get(&pool_id); + 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_account = Self::get_pool_account(pool_id); - let (coin1, coin2) = &pool_id; - let reserve1 = Self::get_balance(&pool_account, coin1)?; - let reserve2 = Self::get_balance(&pool_account, coin2)?; + let sri_reserve = Self::get_balance(&pool_account, Coin::Serai); + let coin_reserve = Self::get_balance(&pool_account, coin); - let amount1: T::CoinBalance; - let amount2: T::CoinBalance; - if reserve1.is_zero() || reserve2.is_zero() { - amount1 = amount1_desired; - amount2 = amount2_desired; + let sri_amount: SubstrateAmount; + let coin_amount: SubstrateAmount; + if (sri_reserve == 0) || (coin_reserve == 0) { + sri_amount = sri_desired; + coin_amount = coin_desired; } else { - let amount2_optimal = Self::quote(&amount1_desired, &reserve1, &reserve2)?; + let coin_optimal = Self::quote(sri_desired, sri_reserve, coin_reserve)?; - if amount2_optimal <= amount2_desired { - ensure!(amount2_optimal >= amount2_min, Error::::CoinTwoDepositDidNotMeetMinimum); - amount1 = amount1_desired; - amount2 = amount2_optimal; + if coin_optimal <= coin_desired { + ensure!(coin_optimal >= coin_min, Error::::CoinTwoDepositDidNotMeetMinimum); + sri_amount = sri_desired; + coin_amount = coin_optimal; } else { - let amount1_optimal = Self::quote(&amount2_desired, &reserve2, &reserve1)?; - ensure!(amount1_optimal <= amount1_desired, Error::::OptimalAmountLessThanDesired); - ensure!(amount1_optimal >= amount1_min, Error::::CoinOneDepositDidNotMeetMinimum); - amount1 = amount1_optimal; - amount2 = amount2_desired; + let sri_optimal = Self::quote(coin_desired, coin_reserve, sri_reserve)?; + ensure!(sri_optimal <= sri_desired, Error::::OptimalAmountLessThanDesired); + ensure!(sri_optimal >= sri_min, Error::::CoinOneDepositDidNotMeetMinimum); + sri_amount = sri_optimal; + coin_amount = coin_desired; } } - Self::validate_minimal_amount(amount1.saturating_add(reserve1), coin1) - .map_err(|_| Error::::AmountOneLessThanMinimal)?; - Self::validate_minimal_amount(amount2.saturating_add(reserve2), coin2) - .map_err(|_| Error::::AmountTwoLessThanMinimal)?; + ensure!(sri_amount.saturating_add(sri_reserve) >= 1, Error::::SriAmountLessThanMinimum); + ensure!(coin_amount.saturating_add(coin_reserve) >= 1, Error::::CoinAmountLessThanMinimum); - Self::transfer(coin1, &sender, &pool_account, amount1)?; - Self::transfer(coin2, &sender, &pool_account, amount2)?; + Self::transfer( + &sender, + &pool_account, + Balance { coin: Coin::Serai, amount: Amount(sri_amount) }, + )?; + Self::transfer(&sender, &pool_account, Balance { coin, amount: Amount(coin_amount) })?; - let total_supply = T::PoolCoins::total_issuance(pool.lp_token.clone()); + let total_supply = LiquidityTokens::::supply(coin); - let lp_token_amount: T::CoinBalance; - if total_supply.is_zero() { - lp_token_amount = Self::calc_lp_amount_for_zero_supply(&amount1, &amount2)?; - T::PoolCoins::mint_into(pool.lp_token.clone(), &pool_account, T::MintMinLiquidity::get())?; + let lp_token_amount: SubstrateAmount; + if total_supply == 0 { + lp_token_amount = Self::calc_lp_amount_for_zero_supply(sri_amount, coin_amount)?; + LiquidityTokens::::mint( + pool_account, + Balance { coin, amount: Amount(T::MintMinLiquidity::get()) }, + )?; } else { - let side1 = Self::mul_div(&amount1, &total_supply, &reserve1)?; - let side2 = Self::mul_div(&amount2, &total_supply, &reserve2)?; + let side1 = Self::mul_div(sri_amount, total_supply, sri_reserve)?; + let side2 = Self::mul_div(coin_amount, total_supply, coin_reserve)?; lp_token_amount = side1.min(side2); } @@ -497,15 +428,15 @@ pub mod pallet { Error::::InsufficientLiquidityMinted ); - T::PoolCoins::mint_into(pool.lp_token.clone(), &mint_to, lp_token_amount)?; + LiquidityTokens::::mint(mint_to, Balance { coin, amount: Amount(lp_token_amount) })?; Self::deposit_event(Event::LiquidityAdded { who: sender, mint_to, pool_id, - amount1_provided: amount1, - amount2_provided: amount2, - lp_token: pool.lp_token.clone(), + coin_amount, + sri_amount, + lp_token: pool.lp_token, lp_token_minted: lp_token_amount, }); @@ -519,67 +450,62 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_liquidity())] pub fn remove_liquidity( origin: OriginFor, - coin1: T::MultiCoinId, - coin2: T::MultiCoinId, - lp_token_burn: T::CoinBalance, - amount1_min_receive: T::CoinBalance, - amount2_min_receive: T::CoinBalance, + coin: Coin, + lp_token_burn: SubstrateAmount, + coin_min_receive: SubstrateAmount, + sri_min_receive: SubstrateAmount, withdraw_to: T::AccountId, ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); - // swap params if needed - let (amount1_min_receive, amount2_min_receive) = if pool_id.0 == coin1 { - (amount1_min_receive, amount2_min_receive) - } else { - (amount2_min_receive, amount1_min_receive) - }; - let (coin1, coin2) = pool_id.clone(); + let sender = ensure_signed(origin.clone())?; + ensure!(coin != Coin::Serai, Error::::EqualCoins); - ensure!(lp_token_burn > Zero::zero(), Error::::ZeroLiquidity); + let pool_id = Self::get_pool_id(coin, Coin::Serai).unwrap(); + ensure!(lp_token_burn > 0, Error::::ZeroLiquidity); - let maybe_pool = Pools::::get(&pool_id); + 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 reserve1 = Self::get_balance(&pool_account, &coin1)?; - let reserve2 = Self::get_balance(&pool_account, &coin2)?; + let pool_account = Self::get_pool_account(pool_id); + let sri_reserve = Self::get_balance(&pool_account, Coin::Serai); + let coin_reserve = Self::get_balance(&pool_account, coin); - let total_supply = T::PoolCoins::total_issuance(pool.lp_token.clone()); + let total_supply = LiquidityTokens::::supply(coin); let lp_redeem_amount = lp_token_burn; - let amount1 = Self::mul_div(&lp_redeem_amount, &reserve1, &total_supply)?; - let amount2 = Self::mul_div(&lp_redeem_amount, &reserve2, &total_supply)?; + let sri_amount = Self::mul_div(lp_redeem_amount, sri_reserve, total_supply)?; + let coin_amount = Self::mul_div(lp_redeem_amount, coin_reserve, total_supply)?; ensure!( - !amount1.is_zero() && amount1 >= amount1_min_receive, + (sri_amount != 0) && (sri_amount >= sri_min_receive), Error::::CoinOneWithdrawalDidNotMeetMinimum ); ensure!( - !amount2.is_zero() && amount2 >= amount2_min_receive, + (coin_amount != 0) && (coin_amount >= coin_min_receive), Error::::CoinTwoWithdrawalDidNotMeetMinimum ); - let reserve1_left = reserve1.saturating_sub(amount1); - let reserve2_left = reserve2.saturating_sub(amount2); - Self::validate_minimal_amount(reserve1_left, &coin1) - .map_err(|_| Error::::ReserveLeftLessThanMinimal)?; - Self::validate_minimal_amount(reserve2_left, &coin2) - .map_err(|_| Error::::ReserveLeftLessThanMinimal)?; + let sri_reserve_left = sri_reserve.saturating_sub(sri_amount); + let coin_reserve_left = coin_reserve.saturating_sub(coin_amount); + + ensure!(sri_reserve_left >= 1, Error::::ReserveLeftLessThanMinimum); + ensure!(coin_reserve_left >= 1, Error::::ReserveLeftLessThanMinimum); // burn the provided lp token amount that includes the fee - T::PoolCoins::burn_from(pool.lp_token.clone(), &sender, lp_token_burn)?; + LiquidityTokens::::burn(origin, Balance { coin, amount: Amount(lp_token_burn) })?; - Self::transfer(&coin1, &pool_account, &withdraw_to, amount1)?; - Self::transfer(&coin2, &pool_account, &withdraw_to, amount2)?; + Self::transfer( + &pool_account, + &withdraw_to, + Balance { coin: Coin::Serai, amount: Amount(sri_amount) }, + )?; + Self::transfer(&pool_account, &withdraw_to, Balance { coin, amount: Amount(coin_amount) })?; Self::deposit_event(Event::LiquidityRemoved { who: sender, withdraw_to, pool_id, - amount1, - amount2, - lp_token: pool.lp_token.clone(), + coin_amount, + sri_amount, + lp_token: pool.lp_token, lp_token_burned: lp_token_burn, }); @@ -596,9 +522,9 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_exact_tokens_for_tokens())] pub fn swap_exact_tokens_for_tokens( origin: OriginFor, - path: BoundedVec, - amount_in: T::CoinBalance, - amount_out_min: T::CoinBalance, + path: BoundedVec, + amount_in: SubstrateAmount, + amount_out_min: SubstrateAmount, send_to: T::AccountId, ) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -622,9 +548,9 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::swap_tokens_for_exact_tokens())] pub fn swap_tokens_for_exact_tokens( origin: OriginFor, - path: BoundedVec, - amount_out: T::CoinBalance, - amount_in_max: T::CoinBalance, + path: BoundedVec, + amount_out: SubstrateAmount, + amount_in_max: SubstrateAmount, send_to: T::AccountId, ) -> DispatchResult { let sender = ensure_signed(origin)?; @@ -649,19 +575,19 @@ pub mod pallet { /// If successful, returns the amount of `path[1]` acquired for the `amount_in`. pub fn do_swap_exact_tokens_for_tokens( sender: T::AccountId, - path: BoundedVec, - amount_in: T::CoinBalance, - amount_out_min: Option, + path: BoundedVec, + amount_in: SubstrateAmount, + amount_out_min: Option, send_to: T::AccountId, - ) -> Result { - ensure!(amount_in > Zero::zero(), Error::::ZeroAmount); + ) -> Result { + ensure!(amount_in > 0, Error::::ZeroAmount); if let Some(amount_out_min) = amount_out_min { - ensure!(amount_out_min > Zero::zero(), Error::::ZeroAmount); + ensure!(amount_out_min > 0, Error::::ZeroAmount); } Self::validate_swap_path(&path)?; - let amounts = Self::get_amounts_out(&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")?; @@ -682,19 +608,19 @@ pub mod pallet { /// If successful returns the amount of the `path[0]` taken to provide `path[1]`. pub fn do_swap_tokens_for_exact_tokens( sender: T::AccountId, - path: BoundedVec, - amount_out: T::CoinBalance, - amount_in_max: Option, + path: BoundedVec, + amount_out: SubstrateAmount, + amount_in_max: Option, send_to: T::AccountId, - ) -> Result { - ensure!(amount_out > Zero::zero(), Error::::ZeroAmount); + ) -> Result { + ensure!(amount_out > 0, Error::::ZeroAmount); if let Some(amount_in_max) = amount_in_max { - ensure!(amount_in_max > Zero::zero(), Error::::ZeroAmount); + ensure!(amount_in_max > 0, Error::::ZeroAmount); } Self::validate_swap_path(&path)?; - let amounts = Self::get_amounts_in(&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")?; @@ -708,97 +634,70 @@ pub mod pallet { /// Transfer an `amount` of `coin_id`. fn transfer( - coin_id: &T::MultiCoinId, from: &T::AccountId, to: &T::AccountId, - amount: T::CoinBalance, - ) -> Result { - let result = match T::MultiCoinIdConverter::try_convert(coin_id) { - MultiCoinIdConversionResult::Converted(coin_id) => { - T::Coins::transfer(coin_id, from, to, amount) - } - MultiCoinIdConversionResult::Native => { - let amount = Self::convert_coin_balance_to_native_balance(amount)?; - Ok(Self::convert_native_balance_to_coin_balance(T::Currency::transfer( - from, to, amount, - )?)?) - } - MultiCoinIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedCoin.into()), - }; - - if result.is_ok() { - Self::deposit_event(Event::Transfer { - from: from.clone(), - to: to.clone(), - coin: (*coin_id).clone(), - amount, - }); - } - result - } - - /// Convert a `Balance` type to an `CoinBalance`. - pub(crate) fn convert_native_balance_to_coin_balance( - amount: T::Balance, - ) -> Result> { - T::HigherPrecisionBalance::from(amount).try_into().map_err(|_| Error::::Overflow) - } - - /// Convert an `CoinBalance` type to a `Balance`. - pub(crate) fn convert_coin_balance_to_native_balance( - amount: T::CoinBalance, - ) -> Result> { - T::HigherPrecisionBalance::from(amount).try_into().map_err(|_| Error::::Overflow) + balance: Balance, + ) -> Result { + CoinsPallet::::transfer_internal(*from, *to, balance)?; + Ok(balance.amount) } - /// Convert a `HigherPrecisionBalance` type to an `CoinBalance`. + /// Convert a `HigherPrecisionBalance` type to an `SubstrateAmount`. pub(crate) fn convert_hpb_to_coin_balance( - amount: T::HigherPrecisionBalance, - ) -> Result> { + amount: HigherPrecisionBalance, + ) -> Result> { amount.try_into().map_err(|_| Error::::Overflow) } /// Swap coins along a `path`, depositing in `send_to`. pub(crate) fn do_swap( sender: T::AccountId, - amounts: &Vec, - path: BoundedVec, + amounts: &Vec, + path: BoundedVec, send_to: T::AccountId, ) -> Result<(), DispatchError> { ensure!(amounts.len() > 1, Error::::CorrespondenceError); if let Some([coin1, coin2]) = &path.get(0 .. 2) { - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + let pool_id = Self::get_pool_id(*coin1, *coin2)?; + 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(coin1, &sender, &pool_account, *first_amount)?; + Self::transfer( + &sender, + &pool_account, + Balance { coin: *coin1, amount: Amount(*first_amount) }, + )?; let mut i = 0; let path_len = path.len() as u32; + #[allow(clippy::explicit_counter_loop)] for coins_pair in path.windows(2) { if let [coin1, coin2] = coins_pair { - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + let pool_id = Self::get_pool_id(*coin1, *coin2)?; + 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 coin3 = path.get((i + 2) as usize).ok_or(Error::::PathError)?; - Self::get_pool_account(&Self::get_pool_id(coin2.clone(), coin3.clone())) + Self::get_pool_account(Self::get_pool_id(*coin2, *coin3)?) } else { - send_to.clone() + send_to }; - let reserve = Self::get_balance(&pool_account, coin2)?; + let reserve = Self::get_balance(&pool_account, *coin2); let reserve_left = reserve.saturating_sub(*amount_out); - Self::validate_minimal_amount(reserve_left, coin2) - .map_err(|_| Error::::ReserveLeftLessThanMinimal)?; + ensure!(reserve_left >= 1, Error::::ReserveLeftLessThanMinimum); - Self::transfer(coin2, &pool_account, &to, *amount_out)?; + Self::transfer( + &pool_account, + &to, + Balance { coin: *coin2, amount: Amount(*amount_out) }, + )?; } - i.saturating_inc(); + i += 1; } Self::deposit_event(Event::SwapExecuted { who: sender, @@ -817,65 +716,45 @@ pub mod pallet { /// /// 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)[..]); + pub fn get_pool_account(pool_id: PoolId) -> 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") } /// Get the `owner`'s balance of `coin`, which could be the chain's native coin or another - /// fungible. Returns a value in the form of an `CoinBalance`. - fn get_balance( - owner: &T::AccountId, - coin: &T::MultiCoinId, - ) -> Result> { - match T::MultiCoinIdConverter::try_convert(coin) { - MultiCoinIdConversionResult::Converted(coin_id) => { - Ok(<::Coins>::balance(coin_id, owner)) - } - MultiCoinIdConversionResult::Native => { - Self::convert_native_balance_to_coin_balance(<::Currency>::balance(owner)) - } - MultiCoinIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedCoin), - } + /// fungible. Returns a value in the form of an `Amount`. + fn get_balance(owner: &T::AccountId, coin: Coin) -> SubstrateAmount { + CoinsPallet::::balance(*owner, coin).0 } /// Returns a pool id constructed from 2 coins. - /// 1. Native coin should be lower than the other coin ids. - /// 2. Two native or two non-native coins are compared by their `Ord` implementation. - /// /// We expect deterministic order, so (coin1, coin2) or (coin2, coin1) returns the same - /// result. - pub fn get_pool_id(coin1: T::MultiCoinId, coin2: T::MultiCoinId) -> PoolIdOf { - match (T::MultiCoinIdConverter::is_native(&coin1), T::MultiCoinIdConverter::is_native(&coin2)) - { - (true, false) => (coin1, coin2), - (false, true) => (coin2, coin1), - _ => { - // else we want to be deterministic based on `Ord` implementation - if coin1 <= coin2 { - (coin1, coin2) - } else { - (coin2, coin1) - } - } + /// result. Coins have to be different and one of them should be Coin::Serai. + pub fn get_pool_id(coin1: Coin, coin2: Coin) -> Result> { + ensure!((coin1 == Coin::Serai) || (coin2 == Coin::Serai), Error::::PoolNotFound); + ensure!(coin1 != coin2, Error::::EqualCoins); + if coin1 == Coin::Serai { + Ok(coin2) + } else { + Ok(coin1) } } /// Returns the balance of each coin in the pool. /// The tuple result is in the order requested (not necessarily the same as pool order). pub fn get_reserves( - coin1: &T::MultiCoinId, - coin2: &T::MultiCoinId, - ) -> Result<(T::CoinBalance, T::CoinBalance), Error> { - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + coin1: &Coin, + coin2: &Coin, + ) -> Result<(SubstrateAmount, SubstrateAmount), Error> { + let pool_id = Self::get_pool_id(*coin1, *coin2)?; + let pool_account = Self::get_pool_account(pool_id); - let balance1 = Self::get_balance(&pool_account, coin1)?; - let balance2 = Self::get_balance(&pool_account, coin2)?; + let balance1 = Self::get_balance(&pool_account, *coin1); + let balance2 = Self::get_balance(&pool_account, *coin2); - if balance1.is_zero() || balance2.is_zero() { + if (balance1 == 0) || (balance2 == 0) { Err(Error::::PoolNotFound)?; } @@ -884,16 +763,16 @@ 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::CoinBalance, - path: &BoundedVec, - ) -> Result, DispatchError> { - let mut amounts: Vec = vec![*amount_out]; + amount_out: SubstrateAmount, + path: &BoundedVec, + ) -> Result, DispatchError> { + let mut amounts: Vec = vec![amount_out]; for coins_pair in path.windows(2).rev() { if let [coin1, coin2] = coins_pair { let (reserve_in, reserve_out) = Self::get_reserves(coin1, coin2)?; 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)?; + let amount_in = Self::get_amount_in(*prev_amount, reserve_in, reserve_out)?; amounts.push(amount_in); } } @@ -904,16 +783,16 @@ pub mod pallet { /// Following an amount into a `path`, get the corresponding amounts out. pub(crate) fn get_amounts_out( - amount_in: &T::CoinBalance, - path: &BoundedVec, - ) -> Result, DispatchError> { - let mut amounts: Vec = vec![*amount_in]; + amount_in: SubstrateAmount, + path: &BoundedVec, + ) -> Result, DispatchError> { + let mut amounts: Vec = vec![amount_in]; for coins_pair in path.windows(2) { if let [coin1, coin2] = coins_pair { let (reserve_in, reserve_out) = Self::get_reserves(coin1, coin2)?; 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)?; + let amount_out = Self::get_amount_out(*prev_amount, reserve_in, reserve_out)?; amounts.push(amount_out); } } @@ -923,21 +802,21 @@ pub mod pallet { /// Used by the RPC service to provide current prices. pub fn quote_price_exact_tokens_for_tokens( - coin1: T::MultiCoinId, - coin2: T::MultiCoinId, - amount: T::CoinBalance, + coin1: Coin, + coin2: Coin, + amount: SubstrateAmount, include_fee: bool, - ) -> Option { - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + ) -> Option { + let pool_id = Self::get_pool_id(coin1, coin2).ok()?; + let pool_account = Self::get_pool_account(pool_id); - let balance1 = Self::get_balance(&pool_account, &coin1).ok()?; - let balance2 = Self::get_balance(&pool_account, &coin2).ok()?; - if !balance1.is_zero() { + let balance1 = Self::get_balance(&pool_account, coin1); + let balance2 = Self::get_balance(&pool_account, coin2); + if balance1 != 0 { if include_fee { - Self::get_amount_out(&amount, &balance1, &balance2).ok() + Self::get_amount_out(amount, balance1, balance2).ok() } else { - Self::quote(&amount, &balance1, &balance2).ok() + Self::quote(amount, balance1, balance2).ok() } } else { None @@ -946,21 +825,21 @@ pub mod pallet { /// Used by the RPC service to provide current prices. pub fn quote_price_tokens_for_exact_tokens( - coin1: T::MultiCoinId, - coin2: T::MultiCoinId, - amount: T::CoinBalance, + coin1: Coin, + coin2: Coin, + amount: SubstrateAmount, include_fee: bool, - ) -> Option { - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); - let pool_account = Self::get_pool_account(&pool_id); + ) -> Option { + let pool_id = Self::get_pool_id(coin1, coin2).ok()?; + let pool_account = Self::get_pool_account(pool_id); - let balance1 = Self::get_balance(&pool_account, &coin1).ok()?; - let balance2 = Self::get_balance(&pool_account, &coin2).ok()?; - if !balance1.is_zero() { + let balance1 = Self::get_balance(&pool_account, coin1); + let balance2 = Self::get_balance(&pool_account, coin2); + if balance1 != 0 { if include_fee { - Self::get_amount_in(&amount, &balance1, &balance2).ok() + Self::get_amount_in(amount, balance1, balance2).ok() } else { - Self::quote(&amount, &balance2, &balance1).ok() + Self::quote(amount, balance2, balance1).ok() } } else { None @@ -969,45 +848,42 @@ pub mod pallet { /// Calculates the optimal amount from the reserves. pub fn quote( - amount: &T::CoinBalance, - reserve1: &T::CoinBalance, - reserve2: &T::CoinBalance, - ) -> Result> { + amount: SubstrateAmount, + reserve1: SubstrateAmount, + reserve2: SubstrateAmount, + ) -> Result> { // amount * reserve2 / reserve1 Self::mul_div(amount, reserve2, reserve1) } pub(super) fn calc_lp_amount_for_zero_supply( - amount1: &T::CoinBalance, - amount2: &T::CoinBalance, - ) -> Result> { - let amount1 = T::HigherPrecisionBalance::from(*amount1); - let amount2 = T::HigherPrecisionBalance::from(*amount2); + amount1: SubstrateAmount, + amount2: SubstrateAmount, + ) -> Result> { + let amount1 = HigherPrecisionBalance::from(amount1); + let amount2 = HigherPrecisionBalance::from(amount2); let result = amount1 - .checked_mul(&amount2) + .checked_mul(amount2) .ok_or(Error::::Overflow)? .integer_sqrt() - .checked_sub(&T::MintMinLiquidity::get().into()) + .checked_sub(T::MintMinLiquidity::get().into()) .ok_or(Error::::InsufficientLiquidityMinted)?; result.try_into().map_err(|_| Error::::Overflow) } fn mul_div( - a: &T::CoinBalance, - b: &T::CoinBalance, - c: &T::CoinBalance, - ) -> Result> { - let a = T::HigherPrecisionBalance::from(*a); - let b = T::HigherPrecisionBalance::from(*b); - let c = T::HigherPrecisionBalance::from(*c); - - let result = a - .checked_mul(&b) - .ok_or(Error::::Overflow)? - .checked_div(&c) - .ok_or(Error::::Overflow)?; + a: SubstrateAmount, + b: SubstrateAmount, + c: SubstrateAmount, + ) -> Result> { + let a = HigherPrecisionBalance::from(a); + let b = HigherPrecisionBalance::from(b); + let c = HigherPrecisionBalance::from(c); + + let result = + a.checked_mul(b).ok_or(Error::::Overflow)?.checked_div(c).ok_or(Error::::Overflow)?; result.try_into().map_err(|_| Error::::Overflow) } @@ -1017,31 +893,33 @@ pub mod pallet { /// Given an input amount of an coin and pair reserves, returns the maximum output amount /// of the other coin. pub fn get_amount_out( - amount_in: &T::CoinBalance, - reserve_in: &T::CoinBalance, - reserve_out: &T::CoinBalance, - ) -> 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); - - if reserve_in.is_zero() || reserve_out.is_zero() { + amount_in: SubstrateAmount, + reserve_in: SubstrateAmount, + reserve_out: SubstrateAmount, + ) -> Result> { + let amount_in = HigherPrecisionBalance::from(amount_in); + let reserve_in = HigherPrecisionBalance::from(reserve_in); + let reserve_out = HigherPrecisionBalance::from(reserve_out); + + if (reserve_in == 0) || (reserve_out == 0) { return Err(Error::::ZeroLiquidity); } let amount_in_with_fee = amount_in - .checked_mul(&(T::HigherPrecisionBalance::from(1000u32) - (T::LPFee::get().into()))) + .checked_mul( + HigherPrecisionBalance::from(1000u32) - HigherPrecisionBalance::from(T::LPFee::get()), + ) .ok_or(Error::::Overflow)?; - let numerator = amount_in_with_fee.checked_mul(&reserve_out).ok_or(Error::::Overflow)?; + let numerator = amount_in_with_fee.checked_mul(reserve_out).ok_or(Error::::Overflow)?; let denominator = reserve_in - .checked_mul(&1000u32.into()) + .checked_mul(1000u32.into()) .ok_or(Error::::Overflow)? - .checked_add(&amount_in_with_fee) + .checked_add(amount_in_with_fee) .ok_or(Error::::Overflow)?; - let result = numerator.checked_div(&denominator).ok_or(Error::::Overflow)?; + let result = numerator.checked_div(denominator).ok_or(Error::::Overflow)?; result.try_into().map_err(|_| Error::::Overflow) } @@ -1051,15 +929,15 @@ pub mod pallet { /// Given an output amount of an coin and pair reserves, returns a required input amount /// of the other coin. pub fn get_amount_in( - amount_out: &T::CoinBalance, - reserve_in: &T::CoinBalance, - reserve_out: &T::CoinBalance, - ) -> 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); - - if reserve_in.is_zero() || reserve_out.is_zero() { + amount_out: SubstrateAmount, + reserve_in: SubstrateAmount, + reserve_out: SubstrateAmount, + ) -> Result> { + let amount_out = HigherPrecisionBalance::from(amount_out); + let reserve_in = HigherPrecisionBalance::from(reserve_in); + let reserve_out = HigherPrecisionBalance::from(reserve_out); + + if (reserve_in == 0) || (reserve_out == 0) { Err(Error::::ZeroLiquidity)? } @@ -1068,54 +946,39 @@ pub mod pallet { } let numerator = reserve_in - .checked_mul(&amount_out) + .checked_mul(amount_out) .ok_or(Error::::Overflow)? - .checked_mul(&1000u32.into()) + .checked_mul(1000u32.into()) .ok_or(Error::::Overflow)?; let denominator = reserve_out - .checked_sub(&amount_out) + .checked_sub(amount_out) .ok_or(Error::::Overflow)? - .checked_mul(&(T::HigherPrecisionBalance::from(1000u32) - T::LPFee::get().into())) + .checked_mul( + HigherPrecisionBalance::from(1000u32) - HigherPrecisionBalance::from(T::LPFee::get()), + ) .ok_or(Error::::Overflow)?; let result = numerator - .checked_div(&denominator) + .checked_div(denominator) .ok_or(Error::::Overflow)? - .checked_add(&One::one()) + .checked_add(1) .ok_or(Error::::Overflow)?; result.try_into().map_err(|_| Error::::Overflow) } - /// Ensure that a `value` meets the minimum balance requirements of an `coin` class. - fn validate_minimal_amount(value: T::CoinBalance, coin: &T::MultiCoinId) -> Result<(), ()> { - if T::MultiCoinIdConverter::is_native(coin) { - let ed = T::Currency::minimum_balance(); - ensure!(T::HigherPrecisionBalance::from(value) >= T::HigherPrecisionBalance::from(ed), ()); - } else { - let MultiCoinIdConversionResult::Converted(coin_id) = - T::MultiCoinIdConverter::try_convert(coin) - else { - return Err(()); - }; - let minimal = T::Coins::minimum_balance(coin_id); - ensure!(value >= minimal, ()); - } - Ok(()) - } - /// Ensure that a path is valid. fn validate_swap_path( - path: &BoundedVec, + path: &BoundedVec, ) -> Result<(), DispatchError> { ensure!(path.len() >= 2, Error::::InvalidPath); // validate all the pools in the path are unique - let mut pools = BoundedBTreeSet::, T::MaxSwapPathLength>::new(); + let mut pools = BoundedBTreeSet::::new(); for coins_pair in path.windows(2) { if let [coin1, coin2] = coins_pair { - let pool_id = Self::get_pool_id(coin1.clone(), coin2.clone()); + let pool_id = Self::get_pool_id(*coin1, *coin2)?; let new_element = pools.try_insert(pool_id).map_err(|_| Error::::Overflow)?; if !new_element { return Err(Error::::NonUniquePath.into()); @@ -1124,25 +987,17 @@ pub mod pallet { } Ok(()) } - - /// Returns the next pool coin id for benchmark purposes only. - #[cfg(any(test, feature = "runtime-benchmarks"))] - pub fn get_next_pool_coin_id() -> T::PoolCoinId { - NextPoolCoinId::::get() - .or(T::PoolCoinId::initial_value()) - .expect("Next pool coin ID can not be None") - } } } -impl Swap for Pallet { +impl Swap for Pallet { fn swap_exact_tokens_for_tokens( sender: T::AccountId, - path: Vec, - amount_in: T::HigherPrecisionBalance, - amount_out_min: Option, + path: Vec, + amount_in: HigherPrecisionBalance, + amount_out_min: Option, send_to: T::AccountId, - ) -> Result { + ) -> Result { let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_out_min = amount_out_min.map(Self::convert_hpb_to_coin_balance).transpose()?; let amount_out = Self::do_swap_exact_tokens_for_tokens( @@ -1157,11 +1012,11 @@ impl Swap fo fn swap_tokens_for_exact_tokens( sender: T::AccountId, - path: Vec, - amount_out: T::HigherPrecisionBalance, - amount_in_max: Option, + path: Vec, + amount_out: HigherPrecisionBalance, + amount_in_max: Option, send_to: T::AccountId, - ) -> Result { + ) -> Result { let path = path.try_into().map_err(|_| Error::::PathError)?; let amount_in_max = amount_in_max.map(Self::convert_hpb_to_coin_balance).transpose()?; let amount_in = Self::do_swap_tokens_for_exact_tokens( @@ -1178,35 +1033,31 @@ impl Swap fo 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 DexApi where - Balance: Codec + MaybeDisplay, - CoinBalance: frame_support::traits::tokens::Balance, - CoinId: Codec - { + pub trait DexApi { /// 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( - coin1: CoinId, - coin2: CoinId, - amount: CoinBalance, + coin1: Coin, + coin2: Coin, + amount: SubstrateAmount, include_fee: bool - ) -> Option; + ) -> 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( - coin1: CoinId, - coin2: CoinId, - amount: CoinBalance, + coin1: Coin, + coin2: Coin, + amount: SubstrateAmount, include_fee: bool - ) -> Option; + ) -> Option; /// Returns the size of the liquidity pool for the given coin pair. - fn get_reserves(coin1: CoinId, coin2: CoinId) -> Option<(Balance, Balance)>; + fn get_reserves(coin1: Coin, coin2: Coin) -> Option<(SubstrateAmount, SubstrateAmount)>; } } diff --git a/substrate/dex/pallet/src/mock.rs b/substrate/dex/pallet/src/mock.rs index 2376b6e10..9bc302746 100644 --- a/substrate/dex/pallet/src/mock.rs +++ b/substrate/dex/pallet/src/mock.rs @@ -37,7 +37,6 @@ use sp_runtime::{ use serai_primitives::{Coin, Balance, Amount, system_address}; pub use coins_pallet as coins; -pub use liquidity_tokens_pallet as liquidity_tokens; type Block = frame_system::mocking::MockBlock; @@ -46,7 +45,7 @@ construct_runtime!( { System: frame_system, CoinsPallet: coins, - LiquidityTokens: liquidity_tokens, + LiquidityTokens: coins::::{Pallet, Call, Storage, Event}, Dex: dex, } ); @@ -81,54 +80,18 @@ impl coins::Config for Test { type RuntimeEvent = RuntimeEvent; } -impl liquidity_tokens::Config for Test { +impl coins::Config for Test { type RuntimeEvent = RuntimeEvent; } -pub struct CoinConverter; -impl MultiCoinIdConverter for CoinConverter { - /// Returns the MultiCoinId representing the native currency of the chain. - fn get_native() -> Coin { - Coin::Serai - } - - /// Returns true if the given MultiCoinId is the native currency. - fn is_native(coin: &Coin) -> bool { - coin.is_native() - } - - /// If it's not native, returns the CoinId for the given MultiCoinId. - fn try_convert(coin: &Coin) -> MultiCoinIdConversionResult { - if coin.is_native() { - MultiCoinIdConversionResult::Native - } else { - MultiCoinIdConversionResult::Converted(*coin) - } - } -} - impl Config for Test { type RuntimeEvent = RuntimeEvent; - type Currency = CoinsPallet; - type CoinBalance = u64; - type CoinId = Coin; - type PoolCoinId = u32; - type Coins = CoinsPallet; - type PoolCoins = LiquidityTokens; + type WeightInfo = (); type LPFee = ConstU32<3>; // means 0.3% type MaxSwapPathLength = ConstU32<4>; // 100 is good enough when the main currency has 12 decimals. type MintMinLiquidity = ConstU64<100>; - - type Balance = u64; - type HigherPrecisionBalance = u128; - - type MultiCoinId = Coin; - type MultiCoinIdConverter = CoinConverter; - - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { @@ -145,6 +108,7 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { .into_iter() .map(|a| (a, Balance { coin: Coin::Serai, amount: Amount(1 << 60) })) .collect(), + _ignore: Default::default(), } .assimilate_storage(&mut t) .unwrap(); diff --git a/substrate/dex/pallet/src/tests.rs b/substrate/dex/pallet/src/tests.rs index 4b13dc26f..522b65902 100644 --- a/substrate/dex/pallet/src/tests.rs +++ b/substrate/dex/pallet/src/tests.rs @@ -22,9 +22,13 @@ use crate::{mock::*, *}; use frame_support::{assert_noop, assert_ok}; pub use coins_pallet as coins; -pub use dex_primitives as primitives; -use serai_primitives::{*, Balance}; +use coins::Pallet as CoinsPallet; + +use serai_primitives::*; + +type LiquidityTokens = coins_pallet::Pallet; +type LiquidityTokensError = coins_pallet::Error; fn events() -> Vec> { let result = System::events() @@ -38,7 +42,7 @@ fn events() -> Vec> { result } -fn pools() -> Vec> { +fn pools() -> Vec { let mut s: Vec<_> = Pools::::iter().map(|x| x.0).collect(); s.sort(); s @@ -49,15 +53,11 @@ fn coins() -> Vec { } fn balance(owner: PublicKey, coin: Coin) -> u64 { - <::Currency>::balance(owner, coin).0 -} - -fn pool_balance(owner: PublicKey, token_id: u32) -> u64 { - <::PoolCoins>::balance(token_id, owner) + CoinsPallet::::balance(owner, coin).0 } -fn get_ed() -> u64 { - as primitives::Currency>::minimum_balance() +fn pool_balance(owner: PublicKey, token_id: Coin) -> u64 { + LiquidityTokens::::balance(owner, token_id).0 } macro_rules! bvec { @@ -72,7 +72,7 @@ fn check_pool_accounts_dont_collide() { let mut map = HashSet::new(); for coin in coins() { - let account = Dex::get_pool_account(&(Coin::native(), coin)); + let account = Dex::get_pool_account(coin); if map.contains(&account) { panic!("Collision at {:?}", coin); } @@ -83,12 +83,12 @@ fn check_pool_accounts_dont_collide() { #[test] fn check_max_numbers() { new_test_ext().execute_with(|| { - assert_eq!(Dex::quote(&3u64, &u64::MAX, &u64::MAX).ok().unwrap(), 3); - assert!(Dex::quote(&u64::MAX, &3u64, &u64::MAX).is_err()); - assert_eq!(Dex::quote(&u64::MAX, &u64::MAX, &1u64).ok().unwrap(), 1); + assert_eq!(Dex::quote(3u64, u64::MAX, u64::MAX).ok().unwrap(), 3); + assert!(Dex::quote(u64::MAX, 3u64, u64::MAX).is_err()); + assert_eq!(Dex::quote(u64::MAX, u64::MAX, 1u64).ok().unwrap(), 1); - assert_eq!(Dex::get_amount_out(&100u64, &u64::MAX, &u64::MAX).ok().unwrap(), 99); - assert_eq!(Dex::get_amount_in(&100u64, &u64::MAX, &u64::MAX).ok().unwrap(), 101); + assert_eq!(Dex::get_amount_out(100u64, u64::MAX, u64::MAX).ok().unwrap(), 99); + assert_eq!(Dex::get_amount_in(100u64, u64::MAX, u64::MAX).ok().unwrap(), 101); }); } @@ -97,74 +97,67 @@ fn can_create_pool() { new_test_ext().execute_with(|| { let coin_account_deposit: u64 = 0; let user: PublicKey = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Monero; - let pool_id = (token_1, token_2); + let coin1 = Coin::native(); + let coin2 = Coin::Monero; + let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); - let lp_token = Dex::get_next_pool_coin_id(); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(1000) })); - assert_ok!(Dex::create_pool(token_2)); + let lp_token = coin2; + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(1000) })); + assert_ok!(Dex::create_pool(coin2)); - assert_eq!(balance(user, Coin::native()), 1000 - coin_account_deposit); - assert_eq!(lp_token + 1, Dex::get_next_pool_coin_id()); + assert_eq!(balance(user, coin1), 1000 - coin_account_deposit); assert_eq!( events(), [Event::::PoolCreated { pool_id, - pool_account: Dex::get_pool_account(&pool_id), + pool_account: Dex::get_pool_account(pool_id), lp_token }] ); assert_eq!(pools(), vec![pool_id]); - assert_noop!(Dex::create_pool(token_1), Error::::EqualCoins); + assert_noop!(Dex::create_pool(coin1), Error::::EqualCoins); }); } #[test] fn create_same_pool_twice_should_fail() { new_test_ext().execute_with(|| { - let token_2 = Coin::Dai; - - let lp_token = Dex::get_next_pool_coin_id(); - assert_ok!(Dex::create_pool(token_2)); - let expected_free = lp_token + 1; - assert_eq!(expected_free, Dex::get_next_pool_coin_id()); - - assert_noop!(Dex::create_pool(token_2), Error::::PoolExists); - assert_eq!(expected_free, Dex::get_next_pool_coin_id()); + let coin = Coin::Dai; + assert_ok!(Dex::create_pool(coin)); + assert_noop!(Dex::create_pool(coin), Error::::PoolExists); }); } #[test] fn different_pools_should_have_different_lp_tokens() { new_test_ext().execute_with(|| { - let token_1 = Coin::native(); - let token_2 = Coin::Bitcoin; - let token_3 = Coin::Ether; - let pool_id_1_2 = (token_1, token_2); - let pool_id_1_3 = (token_1, token_3); + let coin1 = Coin::native(); + let coin2 = Coin::Bitcoin; + let coin3 = Coin::Ether; + let pool_id_1_2 = Dex::get_pool_id(coin1, coin2).unwrap(); + let pool_id_1_3 = Dex::get_pool_id(coin1, coin3).unwrap(); - let lp_token2_1 = Dex::get_next_pool_coin_id(); - assert_ok!(Dex::create_pool(token_2)); - let lp_token3_1 = Dex::get_next_pool_coin_id(); + let lp_token2_1 = coin2; + assert_ok!(Dex::create_pool(coin2)); + let lp_token3_1 = coin3; assert_eq!( events(), [Event::::PoolCreated { pool_id: pool_id_1_2, - pool_account: Dex::get_pool_account(&pool_id_1_2), + pool_account: Dex::get_pool_account(pool_id_1_2), lp_token: lp_token2_1 }] ); - assert_ok!(Dex::create_pool(token_3)); + assert_ok!(Dex::create_pool(coin3)); assert_eq!( events(), [Event::::PoolCreated { pool_id: pool_id_1_3, - pool_account: Dex::get_pool_account(&pool_id_1_3), + pool_account: Dex::get_pool_account(pool_id_1_3), lp_token: lp_token3_1, }] ); @@ -177,75 +170,59 @@ fn different_pools_should_have_different_lp_tokens() { fn can_add_liquidity() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Dai; - let token_3 = Coin::Monero; + let coin1 = Coin::native(); + let coin2 = Coin::Dai; + let coin3 = Coin::Monero; - let lp_token1 = Dex::get_next_pool_coin_id(); - assert_ok!(Dex::create_pool(token_2)); - let lp_token2 = Dex::get_next_pool_coin_id(); - assert_ok!(Dex::create_pool(token_3)); + let lp_token1 = coin2; + assert_ok!(Dex::create_pool(coin2)); + let lp_token2 = coin3; + assert_ok!(Dex::create_pool(coin3)); - let ed = get_ed(); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(10000 * 2 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_3, amount: Amount(1000) })); - - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_2, - 10000, - 10, - 10000, - 10, + assert_ok!(CoinsPallet::::mint( user, + Balance { coin: coin1, amount: Amount(10000 * 2 + 1) } )); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin3, amount: Amount(1000) })); - let pool_id = (token_1, token_2); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,)); + + let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); assert!(events().contains(&Event::::LiquidityAdded { who: user, mint_to: user, pool_id, - amount1_provided: 10000, - amount2_provided: 10, + sri_amount: 10000, + coin_amount: 10, lp_token: lp_token1, lp_token_minted: 216, })); - let pallet_account = Dex::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 = Dex::get_pool_account(pool_id); + assert_eq!(balance(pallet_account, coin1), 10000); + assert_eq!(balance(pallet_account, coin2), 10); + assert_eq!(balance(user, coin1), 10000 + 1); + assert_eq!(balance(user, coin2), 1000 - 10); assert_eq!(pool_balance(user, lp_token1), 216); // try to pass the non-native - native coins, the result should be the same - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_3, - token_1, - 10, - 10000, - 10, - 10000, - user, - )); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin3, 10, 10000, 10, 10000, user,)); - let pool_id = (token_1, token_3); + let pool_id = Dex::get_pool_id(coin1, coin3).unwrap(); assert!(events().contains(&Event::::LiquidityAdded { who: user, mint_to: user, pool_id, - amount1_provided: 10000, - amount2_provided: 10, + sri_amount: 10000, + coin_amount: 10, lp_token: lp_token2, lp_token_minted: 216, })); - let pallet_account = Dex::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 = Dex::get_pool_account(pool_id); + assert_eq!(balance(pallet_account, coin1), 10000); + assert_eq!(balance(pallet_account, coin3), 10); + assert_eq!(balance(user, coin1), 1); + assert_eq!(balance(user, coin3), 1000 - 10); assert_eq!(pool_balance(user, lp_token2), 216); }); } @@ -254,16 +231,16 @@ fn can_add_liquidity() { fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Bitcoin; + let coin1 = Coin::native(); + let coin2 = Coin::Bitcoin; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(1000) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); assert_noop!( - Dex::add_liquidity(RuntimeOrigin::signed(user), token_1, token_2, get_ed(), 1, 1, 1, user), + Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 1, 1, 1, 1, user), Error::::InsufficientLiquidityMinted ); }); @@ -273,46 +250,33 @@ 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 = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Ether; - let token_3 = Coin::Dai; - - assert_ok!(Dex::create_pool(token_2)); - assert_ok!(Dex::create_pool(token_3)); - - let ed = get_ed(); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(10000 * 2 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(10000) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_3, amount: Amount(10000) })); - - // check we're still able to add the liquidity even when the pool already has some token_1 - let pallet_account = Dex::get_pool_account(&(token_1, token_2)); - assert_ok!(CoinsPallet::mint(pallet_account, Balance { coin: token_1, amount: Amount(1000) })); - - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_2, - 10000, - 10, - 10000, - 10, - user, + let coin1 = Coin::native(); + let coin2 = Coin::Ether; + let coin3 = Coin::Dai; + + assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin3)); + + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000 * 2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(10000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin3, amount: Amount(10000) })); + + // check we're still able to add the liquidity even when the pool already has some coin1 + let pallet_account = Dex::get_pool_account(Dex::get_pool_id(coin1, coin2).unwrap()); + assert_ok!(CoinsPallet::::mint( + pallet_account, + Balance { coin: coin1, amount: Amount(1000) } )); - // check the same but for token_3 (non-native token) - let pallet_account = Dex::get_pool_account(&(token_1, token_3)); - assert_ok!(CoinsPallet::mint(pallet_account, Balance { coin: token_2, amount: Amount(1) })); - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_3, - 10000, - 10, - 10000, - 10, - user, + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,)); + + // check the same but for coin3 (non-native token) + let pallet_account = Dex::get_pool_account(Dex::get_pool_id(coin1, coin3).unwrap()); + assert_ok!(CoinsPallet::::mint( + pallet_account, + Balance { coin: coin2, amount: Amount(1) } )); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin3, 10, 10000, 10, 10000, user,)); }); } @@ -320,24 +284,26 @@ fn add_tiny_liquidity_directly_to_pool_address() { fn can_remove_liquidity() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Monero; - let pool_id = (token_1, token_2); + let coin1 = Coin::native(); + let coin2 = Coin::Monero; + let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); - let lp_token = Dex::get_next_pool_coin_id(); - assert_ok!(Dex::create_pool(token_2)); + let lp_token = coin2; + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(10000000000) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(100000) })); + assert_ok!(CoinsPallet::::mint( + user, + Balance { coin: coin1, amount: Amount(10000000000) } + )); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(100000) })); assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - 1000000000, + coin2, 100000, 1000000000, 100000, + 1000000000, user, )); @@ -345,8 +311,7 @@ fn can_remove_liquidity() { assert_ok!(Dex::remove_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + coin2, total_lp_received, 0, 0, @@ -357,19 +322,19 @@ fn can_remove_liquidity() { who: user, withdraw_to: user, pool_id, - amount1: 999990000, - amount2: 99999, + sri_amount: 999990000, + coin_amount: 99999, lp_token, lp_token_burned: total_lp_received, })); - let pool_account = Dex::get_pool_account(&pool_id); - assert_eq!(balance(pool_account, token_1), 10000); - assert_eq!(balance(pool_account, token_2), 1); + let pool_account = Dex::get_pool_account(pool_id); + assert_eq!(balance(pool_account, coin1), 10000); + assert_eq!(balance(pool_account, coin2), 1); assert_eq!(pool_balance(pool_account, lp_token), 100); - assert_eq!(balance(user, token_1), 10000000000 - 1000000000 + 999990000); - assert_eq!(balance(user, token_2), 99999); + assert_eq!(balance(user, coin1), 10000000000 - 1000000000 + 999990000); + assert_eq!(balance(user, coin2), 99999); assert_eq!(pool_balance(user, lp_token), 0); }); } @@ -378,28 +343,16 @@ fn can_remove_liquidity() { fn can_not_redeem_more_lp_tokens_than_were_minted() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Dai; - let lp_token = Dex::get_next_pool_coin_id(); + let coin1 = Coin::native(); + let coin2 = Coin::Dai; + let lp_token = coin2; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint( - user, - Balance { coin: token_1, amount: Amount(10000 + get_ed()) } - )); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_2, - 10000, - 10, - 10000, - 10, - user, - )); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,)); // Only 216 lp_tokens_minted assert_eq!(pool_balance(user, lp_token), 216); @@ -407,14 +360,13 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { assert_noop!( Dex::remove_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + coin2, 216 + 1, // Try and redeem 10 lp tokens while only 9 minted. 0, 0, user, ), - liquidity_tokens::Error::::NotEnoughCoins + LiquidityTokensError::::NotEnoughCoins ); }); } @@ -423,54 +375,45 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() { fn can_quote_price() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Ether; + let coin1 = Coin::native(); + let coin2 = Coin::Ether; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(100000) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(100000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_2, - 10000, - 200, - 1, - 1, - user, - )); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,)); assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(Coin::native(), token_2, 3000, false,), + Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, 3000, false,), Some(60) ); // including fee so should get less out... assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(Coin::native(), token_2, 3000, true,), + Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, 3000, true,), Some(46) ); // Check it still gives same price: // (if the above accidentally exchanged then it would not give same quote as before) assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(Coin::native(), token_2, 3000, false,), + Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, 3000, false,), Some(60) ); // including fee so should get less out... assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(Coin::native(), token_2, 3000, true,), + Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, 3000, true,), Some(46) ); // Check inverse: assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(token_2, Coin::native(), 60, false,), + Dex::quote_price_exact_tokens_for_tokens(coin2, Coin::native(), 60, false,), Some(3000) ); // including fee so should get less out... assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(token_2, Coin::native(), 60, true,), + Dex::quote_price_exact_tokens_for_tokens(coin2, Coin::native(), 60, true,), Some(2302) ); @@ -478,34 +421,34 @@ fn can_quote_price() { // same tests as above but for quote_price_tokens_for_exact_tokens: // assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(Coin::native(), token_2, 60, false,), + Dex::quote_price_tokens_for_exact_tokens(Coin::native(), coin2, 60, false,), Some(3000) ); // including fee so should need to put more in... assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(Coin::native(), token_2, 60, true,), + Dex::quote_price_tokens_for_exact_tokens(Coin::native(), coin2, 60, true,), Some(4299) ); // Check it still gives same price: // (if the above accidentally exchanged then it would not give same quote as before) assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(Coin::native(), token_2, 60, false,), + Dex::quote_price_tokens_for_exact_tokens(Coin::native(), coin2, 60, false,), Some(3000) ); // including fee so should need to put more in... assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(Coin::native(), token_2, 60, true,), + Dex::quote_price_tokens_for_exact_tokens(Coin::native(), coin2, 60, true,), Some(4299) ); // Check inverse: assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(token_2, Coin::native(), 3000, false,), + Dex::quote_price_tokens_for_exact_tokens(coin2, Coin::native(), 3000, false,), Some(60) ); // including fee so should need to put more in... assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(token_2, Coin::native(), 3000, true,), + Dex::quote_price_tokens_for_exact_tokens(coin2, Coin::native(), 3000, true,), Some(86) ); @@ -515,44 +458,28 @@ fn can_quote_price() { let amount_in = 100; assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(token_2, Coin::native(), amount_in, false,) - .and_then(|amount| Dex::quote_price_exact_tokens_for_tokens( - Coin::native(), - token_2, - amount, - false, - )), + Dex::quote_price_exact_tokens_for_tokens(coin2, Coin::native(), amount_in, false,).and_then( + |amount| Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, amount, false,) + ), Some(amount_in) ); assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(Coin::native(), token_2, amount_in, false,) - .and_then(|amount| Dex::quote_price_exact_tokens_for_tokens( - token_2, - Coin::native(), - amount, - false, - )), + Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, amount_in, false,).and_then( + |amount| Dex::quote_price_exact_tokens_for_tokens(coin2, Coin::native(), amount, false,) + ), Some(amount_in) ); assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(token_2, Coin::native(), amount_in, false,) - .and_then(|amount| Dex::quote_price_tokens_for_exact_tokens( - Coin::native(), - token_2, - amount, - false, - )), + Dex::quote_price_tokens_for_exact_tokens(coin2, Coin::native(), amount_in, false,).and_then( + |amount| Dex::quote_price_tokens_for_exact_tokens(Coin::native(), coin2, amount, false,) + ), Some(amount_in) ); assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(Coin::native(), token_2, amount_in, false,) - .and_then(|amount| Dex::quote_price_tokens_for_exact_tokens( - token_2, - Coin::native(), - amount, - false, - )), + Dex::quote_price_tokens_for_exact_tokens(Coin::native(), coin2, amount_in, false,).and_then( + |amount| Dex::quote_price_tokens_for_exact_tokens(coin2, Coin::native(), amount, false,) + ), Some(amount_in) ); }); @@ -563,44 +490,35 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let user2 = system_address(b"user2").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Bitcoin; + let coin1 = Coin::native(); + let coin2 = Coin::Bitcoin; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(100000) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(100000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_2, - 10000, - 200, - 1, - 1, - user, - )); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,)); let amount = 1; let quoted_price = 49; assert_eq!( - Dex::quote_price_exact_tokens_for_tokens(token_2, token_1, amount, true,), + Dex::quote_price_exact_tokens_for_tokens(coin2, coin1, amount, true,), Some(quoted_price) ); - assert_ok!(CoinsPallet::mint(user2, Balance { coin: token_2, amount: Amount(amount) })); - let prior_dot_balance = 0; // TODO: This was set to 20000. Why? - assert_eq!(prior_dot_balance, balance(user2, token_1)); + assert_ok!(CoinsPallet::::mint(user2, Balance { coin: coin2, amount: Amount(amount) })); + let prior_sri_balance = 0; + assert_eq!(prior_sri_balance, balance(user2, coin1)); assert_ok!(Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user2), - bvec![token_2, token_1], + bvec![coin2, coin1], amount, 1, user2, )); - assert_eq!(prior_dot_balance + quoted_price, balance(user2, token_1)); + assert_eq!(prior_sri_balance + quoted_price, balance(user2, coin1)); }); } @@ -609,47 +527,38 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let user2 = system_address(b"user2").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Monero; + let coin1 = Coin::native(); + let coin2 = Coin::Monero; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(100000) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(100000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_2, - 10000, - 200, - 1, - 1, - user, - )); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,)); let amount = 49; let quoted_price = 1; assert_eq!( - Dex::quote_price_tokens_for_exact_tokens(token_2, token_1, amount, true,), + Dex::quote_price_tokens_for_exact_tokens(coin2, coin1, amount, true,), Some(quoted_price) ); - assert_ok!(CoinsPallet::mint(user2, Balance { coin: token_2, amount: Amount(amount) })); - let prior_dot_balance = 0; // TODO: This was set to 20000. Why? - assert_eq!(prior_dot_balance, balance(user2, token_1)); + assert_ok!(CoinsPallet::::mint(user2, Balance { coin: coin2, amount: Amount(amount) })); + let prior_sri_balance = 0; + assert_eq!(prior_sri_balance, balance(user2, coin1)); let prior_coin_balance = 49; - assert_eq!(prior_coin_balance, balance(user2, token_2)); + assert_eq!(prior_coin_balance, balance(user2, coin2)); assert_ok!(Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user2), - bvec![token_2, token_1], + bvec![coin2, coin1], amount, 1, user2, )); - assert_eq!(prior_dot_balance + amount, balance(user2, token_1)); - assert_eq!(prior_coin_balance - quoted_price, balance(user2, token_2)); + assert_eq!(prior_sri_balance + amount, balance(user2, coin1)); + assert_eq!(prior_coin_balance - quoted_price, balance(user2, coin2)); }); } @@ -657,46 +566,44 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() { fn can_swap_with_native() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Ether; - let pool_id = (token_1, token_2); + let coin1 = Coin::native(); + let coin2 = Coin::Ether; + let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - let ed = get_ed(); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(10000 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user, )); let input_amount = 100; - let expect_receive = Dex::get_amount_out(&input_amount, &liquidity2, &liquidity1).ok().unwrap(); + let expect_receive = Dex::get_amount_out(input_amount, liquidity2, liquidity1).ok().unwrap(); assert_ok!(Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![coin2, coin1], input_amount, 1, user, )); - let pallet_account = Dex::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 = Dex::get_pool_account(pool_id); + assert_eq!(balance(user, coin1), expect_receive); + assert_eq!(balance(user, coin2), 1000 - liquidity2 - input_amount); + assert_eq!(balance(pallet_account, coin1), liquidity1 - expect_receive); + assert_eq!(balance(pallet_account, coin2), liquidity2 + input_amount); }); } @@ -710,17 +617,22 @@ fn can_swap_with_realistic_values() { const UNIT: u64 = 1_000_000_000; - assert_ok!(CoinsPallet::mint(user, Balance { coin: sri, amount: Amount(300_000 * UNIT) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: dai, amount: Amount(1_100_000 * UNIT) })); + assert_ok!(CoinsPallet::::mint( + user, + Balance { coin: sri, amount: Amount(300_000 * UNIT) } + )); + assert_ok!(CoinsPallet::::mint( + user, + Balance { coin: dai, amount: Amount(1_100_000 * UNIT) } + )); - let liquidity_dot = 200_000 * UNIT; // ratio for a 5$ price + let liquidity_sri = 200_000 * UNIT; // ratio for a 5$ price let liquidity_dai = 1_000_000 * UNIT; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - sri, dai, - liquidity_dot, liquidity_dai, + liquidity_sri, 1, 1, user, @@ -750,16 +662,16 @@ fn can_swap_with_realistic_values() { fn can_not_swap_in_pool_with_no_liquidity_added_yet() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Monero; + let coin1 = Coin::native(); + let coin2 = Coin::Monero; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); // Check can't swap an empty pool assert_noop!( Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![coin2, coin1], 10, 1, user, @@ -773,26 +685,24 @@ 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 = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Bitcoin; - let pool_id = (token_1, token_2); - let lp_token = Dex::get_next_pool_coin_id(); + let coin1 = Coin::native(); + let coin2 = Coin::Bitcoin; + let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); + let lp_token = coin2; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - let ed = get_ed(); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(10000 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user, @@ -803,20 +713,19 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { who: user, mint_to: user, pool_id, - amount1_provided: liquidity1, - amount2_provided: liquidity2, + sri_amount: liquidity1, + coin_amount: liquidity2, lp_token, lp_token_minted, })); - let pallet_account = Dex::get_pool_account(&pool_id); - assert_eq!(balance(pallet_account, token_1), liquidity1); - assert_eq!(balance(pallet_account, token_2), liquidity2); + let pallet_account = Dex::get_pool_account(pool_id); + assert_eq!(balance(pallet_account, coin1), liquidity1); + assert_eq!(balance(pallet_account, coin2), liquidity2); assert_ok!(Dex::remove_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, + coin2, lp_token_minted, 1, 1, @@ -825,44 +734,44 @@ 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, coin1), 708); + assert_eq!(balance(pallet_account, coin2), 15); // validate the reserve should always stay above the ED // Following test fail again due to the force on ED being > 1. // assert_noop!( // Dex::swap_tokens_for_exact_tokens( // RuntimeOrigin::signed(user), - // bvec![token_2, token_1], + // bvec![coin2, coin1], // 708 - ed + 1, // amount_out // 500, // amount_in_max // user, // ), - // Error::::ReserveLeftLessThanMinimal + // Error::::ReserveLeftLessThanMinimum // ); assert_ok!(Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![coin2, coin1], 608, // amount_out 500, // amount_in_max user, )); - 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, coin1); + let token_2_left = balance(pallet_account, coin2); assert_eq!(token_1_left, 708 - 608); // The price for the last tokens should be very high assert_eq!( - Dex::get_amount_in(&(token_1_left - 1), &token_2_left, &token_1_left).ok().unwrap(), + Dex::get_amount_in(token_1_left - 1, token_2_left, token_1_left).ok().unwrap(), 10625 ); assert_noop!( Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![coin2, coin1], token_1_left - 1, // amount_out 1000, // amount_in_max user, @@ -874,7 +783,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() { assert_noop!( Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![coin2, coin1], token_1_left, // amount_out 1000, // amount_in_max user, @@ -888,26 +797,22 @@ 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 = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Ether; + let coin1 = Coin::native(); + let coin2 = Coin::Ether; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint( - user, - Balance { coin: token_1, amount: Amount(10000 + get_ed()) } - )); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user, @@ -918,7 +823,7 @@ fn swap_should_not_work_if_too_much_slippage() { assert_noop!( Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1], + bvec![coin2, coin1], exchange_amount, // amount_in 4000, // amount_out_min user, @@ -932,55 +837,53 @@ fn swap_should_not_work_if_too_much_slippage() { fn can_swap_tokens_for_exact_tokens() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Dai; - let pool_id = (token_1, token_2); + let coin1 = Coin::native(); + let coin2 = Coin::Dai; + let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - let ed = get_ed(); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(20000 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(20000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); - let pallet_account = Dex::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 = Dex::get_pool_account(pool_id); + let before1 = balance(pallet_account, coin1) + balance(user, coin1); + let before2 = balance(pallet_account, coin2) + balance(user, coin2); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user, )); let exchange_out = 50; - let expect_in = Dex::get_amount_in(&exchange_out, &liquidity1, &liquidity2).ok().unwrap(); + let expect_in = Dex::get_amount_in(exchange_out, liquidity1, liquidity2).ok().unwrap(); assert_ok!(Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![coin1, coin2], exchange_out, // amount_out 3500, // amount_in_max user, )); - 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, coin1), 10000 - expect_in); + assert_eq!(balance(user, coin2), 1000 - liquidity2 + exchange_out); + assert_eq!(balance(pallet_account, coin1), liquidity1 + expect_in); + assert_eq!(balance(pallet_account, coin2), liquidity2 - exchange_out); // check invariants: // native and coin 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, coin1) + balance(user, coin1)); + assert_eq!(before2, balance(pallet_account, coin2) + balance(user, coin2)); }); } @@ -989,69 +892,65 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); let user2 = system_address(b"user2").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Monero; - let pool_id = (token_1, token_2); - let lp_token = Dex::get_next_pool_coin_id(); + let coin1 = Coin::native(); + let coin2 = Coin::Monero; + let pool_id = Dex::get_pool_id(coin1, coin2).unwrap(); + let lp_token = coin2; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - let ed = get_ed(); let base1 = 10000; let base2 = 1000; - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(base1 + ed) })); - assert_ok!(CoinsPallet::mint(user2, Balance { coin: token_1, amount: Amount(base1 + ed) })); - assert_ok!(CoinsPallet::mint(user2, Balance { coin: token_2, amount: Amount(base2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(base1) })); + assert_ok!(CoinsPallet::::mint(user2, Balance { coin: coin1, amount: Amount(base1) })); + assert_ok!(CoinsPallet::::mint(user2, Balance { coin: coin2, amount: Amount(base2) })); - let pallet_account = Dex::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 = Dex::get_pool_account(pool_id); + let before1 = balance(pallet_account, coin1) + balance(user, coin1) + balance(user2, coin1); + let before2 = balance(pallet_account, coin2) + balance(user, coin2) + balance(user2, coin2); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user2), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user2, )); - assert_eq!(balance(user, token_1), base1 + ed); - assert_eq!(balance(user, token_2), 0); + assert_eq!(balance(user, coin1), base1); + assert_eq!(balance(user, coin2), 0); let exchange_out = 50; - let expect_in = Dex::get_amount_in(&exchange_out, &liquidity1, &liquidity2).ok().unwrap(); + let expect_in = Dex::get_amount_in(exchange_out, liquidity1, liquidity2).ok().unwrap(); assert_ok!(Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![coin1, coin2], exchange_out, // amount_out 3500, // amount_in_max user, )); - 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, coin1), base1 - expect_in); + assert_eq!(balance(pallet_account, coin1), liquidity1 + expect_in); + assert_eq!(balance(user, coin2), exchange_out); + assert_eq!(balance(pallet_account, coin2), liquidity2 - exchange_out); // check invariants: // native and coin totals should be preserved. assert_eq!( before1, - balance(pallet_account, token_1) + balance(user, token_1) + balance(user2, token_1) + balance(pallet_account, coin1) + balance(user, coin1) + balance(user2, coin1) ); assert_eq!( before2, - balance(pallet_account, token_2) + balance(user, token_2) + balance(user2, token_2) + balance(pallet_account, coin2) + balance(user, coin2) + balance(user2, coin2) ); let lp_token_minted = pool_balance(user2, lp_token); @@ -1059,8 +958,7 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { assert_ok!(Dex::remove_liquidity( RuntimeOrigin::signed(user2), - token_1, - token_2, + coin2, lp_token_minted, 0, 0, @@ -1073,26 +971,22 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() { fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Ether; + let coin1 = Coin::native(); + let coin2 = Coin::Ether; - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); - assert_ok!(CoinsPallet::mint( - user, - Balance { coin: token_1, amount: Amount(20000 + get_ed()) } - )); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(20000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(1000) })); let liquidity1 = 10000; let liquidity2 = 200; assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user, @@ -1103,7 +997,7 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() { assert_noop!( Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_2], + bvec![coin1, coin2], exchange_out, // amount_out 50, // amount_in_max just greater than slippage. user, @@ -1117,19 +1011,18 @@ 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 = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Dai; - let token_3 = Coin::Monero; + let coin1 = Coin::native(); + let coin2 = Coin::Dai; + let coin3 = Coin::Monero; - assert_ok!(Dex::create_pool(token_2)); - assert_ok!(Dex::create_pool(token_3)); + assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin3)); - let ed = get_ed(); let base1 = 10000; let base2 = 10000; - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(base1 * 2 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(base2) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_3, amount: Amount(base2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(base1 * 2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(base2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin3, amount: Amount(base2) })); let liquidity1 = 10000; let liquidity2 = 200; @@ -1137,33 +1030,31 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user, )); assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_3, - liquidity1, + coin3, liquidity3, + liquidity1, 1, 1, user, )); let input_amount = 500; - let expect_out2 = Dex::get_amount_out(&input_amount, &liquidity2, &liquidity1).ok().unwrap(); - let expect_out3 = Dex::get_amount_out(&expect_out2, &liquidity1, &liquidity3).ok().unwrap(); + let expect_out2 = Dex::get_amount_out(input_amount, liquidity2, liquidity1).ok().unwrap(); + let expect_out3 = Dex::get_amount_out(expect_out2, liquidity1, liquidity3).ok().unwrap(); assert_noop!( Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1], + bvec![coin1], input_amount, 80, user, @@ -1174,7 +1065,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_noop!( Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1, token_2], + bvec![coin2, coin1, coin2], input_amount, 80, user, @@ -1184,23 +1075,23 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() { assert_ok!(Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1, token_3], + bvec![coin2, coin1, coin3], input_amount, // amount_in 80, // amount_out_min user, )); - let pool_id1 = (token_1, token_2); - let pool_id2 = (token_1, token_3); - let pallet_account1 = Dex::get_pool_account(&pool_id1); - let pallet_account2 = Dex::get_pool_account(&pool_id2); - - assert_eq!(balance(user, token_2), base2 - liquidity2 - input_amount); - assert_eq!(balance(pallet_account1, token_2), liquidity2 + input_amount); - assert_eq!(balance(pallet_account1, token_1), liquidity1 - expect_out2); - assert_eq!(balance(pallet_account2, token_1), liquidity1 + expect_out2); - assert_eq!(balance(pallet_account2, token_3), liquidity3 - expect_out3); - assert_eq!(balance(user, token_3), 10000 - liquidity3 + expect_out3); + let pool_id1 = Dex::get_pool_id(coin1, coin2).unwrap(); + let pool_id2 = Dex::get_pool_id(coin1, coin3).unwrap(); + let pallet_account1 = Dex::get_pool_account(pool_id1); + let pallet_account2 = Dex::get_pool_account(pool_id2); + + assert_eq!(balance(user, coin2), base2 - liquidity2 - input_amount); + assert_eq!(balance(pallet_account1, coin2), liquidity2 + input_amount); + assert_eq!(balance(pallet_account1, coin1), liquidity1 - expect_out2); + assert_eq!(balance(pallet_account2, coin1), liquidity1 + expect_out2); + assert_eq!(balance(pallet_account2, coin3), liquidity3 - expect_out3); + assert_eq!(balance(user, coin3), 10000 - liquidity3 + expect_out3); }); } @@ -1208,19 +1099,18 @@ 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 = system_address(b"user1").into(); - let token_1 = Coin::native(); - let token_2 = Coin::Bitcoin; - let token_3 = Coin::Ether; + let coin1 = Coin::native(); + let coin2 = Coin::Bitcoin; + let coin3 = Coin::Ether; - assert_ok!(Dex::create_pool(token_2)); - assert_ok!(Dex::create_pool(token_3)); + assert_ok!(Dex::create_pool(coin2)); + assert_ok!(Dex::create_pool(coin3)); - let ed = get_ed(); let base1 = 10000; let base2 = 10000; - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(base1 * 2 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(base2) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_3, amount: Amount(base2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(base1 * 2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(base2) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin3, amount: Amount(base2) })); let liquidity1 = 10000; let liquidity2 = 200; @@ -1228,48 +1118,46 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_2, - liquidity1, + coin2, liquidity2, + liquidity1, 1, 1, user, )); assert_ok!(Dex::add_liquidity( RuntimeOrigin::signed(user), - token_1, - token_3, - liquidity1, + coin3, liquidity3, + liquidity1, 1, 1, user, )); let exchange_out3 = 100; - let expect_in2 = Dex::get_amount_in(&exchange_out3, &liquidity1, &liquidity3).ok().unwrap(); - let expect_in1 = Dex::get_amount_in(&expect_in2, &liquidity2, &liquidity1).ok().unwrap(); + let expect_in2 = Dex::get_amount_in(exchange_out3, liquidity1, liquidity3).ok().unwrap(); + let expect_in1 = Dex::get_amount_in(expect_in2, liquidity2, liquidity1).ok().unwrap(); assert_ok!(Dex::swap_tokens_for_exact_tokens( RuntimeOrigin::signed(user), - bvec![token_2, token_1, token_3], + bvec![coin2, coin1, coin3], exchange_out3, // amount_out 1000, // amount_in_max user, )); - let pool_id1 = (token_1, token_2); - let pool_id2 = (token_1, token_3); - let pallet_account1 = Dex::get_pool_account(&pool_id1); - let pallet_account2 = Dex::get_pool_account(&pool_id2); - - assert_eq!(balance(user, token_2), base2 - liquidity2 - expect_in1); - assert_eq!(balance(pallet_account1, token_1), liquidity1 - expect_in2); - assert_eq!(balance(pallet_account1, token_2), liquidity2 + expect_in1); - assert_eq!(balance(pallet_account2, token_1), liquidity1 + expect_in2); - assert_eq!(balance(pallet_account2, token_3), liquidity3 - exchange_out3); - assert_eq!(balance(user, token_3), 10000 - liquidity3 + exchange_out3); + let pool_id1 = Dex::get_pool_id(coin1, coin2).unwrap(); + let pool_id2 = Dex::get_pool_id(coin1, coin3).unwrap(); + let pallet_account1 = Dex::get_pool_account(pool_id1); + let pallet_account2 = Dex::get_pool_account(pool_id2); + + assert_eq!(balance(user, coin2), base2 - liquidity2 - expect_in1); + assert_eq!(balance(pallet_account1, coin1), liquidity1 - expect_in2); + assert_eq!(balance(pallet_account1, coin2), liquidity2 + expect_in1); + assert_eq!(balance(pallet_account2, coin1), liquidity1 + expect_in2); + assert_eq!(balance(pallet_account2, coin3), liquidity3 - exchange_out3); + assert_eq!(balance(user, coin3), 10000 - liquidity3 + exchange_out3); }); } @@ -1277,23 +1165,14 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() { fn can_not_swap_same_coin() { new_test_ext().execute_with(|| { let user = system_address(b"user1").into(); - let token_1 = Coin::Dai; + let coin1 = Coin::Dai; - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(1000) })); let liquidity1 = 1000; let liquidity2 = 20; assert_noop!( - Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_1, - liquidity1, - liquidity2, - 1, - 1, - user, - ), + Dex::add_liquidity(RuntimeOrigin::signed(user), coin1, liquidity2, liquidity1, 1, 1, user,), Error::::PoolNotFound ); @@ -1301,7 +1180,7 @@ fn can_not_swap_same_coin() { assert_noop!( Dex::swap_exact_tokens_for_tokens( RuntimeOrigin::signed(user), - bvec![token_1, token_1], + bvec![coin1, coin1], exchange_amount, 1, user, @@ -1317,7 +1196,7 @@ fn can_not_swap_same_coin() { 1, user, ), - Error::::PoolNotFound + Error::::EqualCoins ); }); } @@ -1330,10 +1209,10 @@ fn validate_pool_id_sorting() { let native = Coin::native(); let coin1 = Coin::Bitcoin; let coin2 = Coin::Monero; - assert_eq!(Dex::get_pool_id(native, coin2), (native, coin2)); - assert_eq!(Dex::get_pool_id(coin2, native), (native, coin2)); - assert_eq!(Dex::get_pool_id(native, native), (native, native)); - assert_eq!(Dex::get_pool_id(coin2, coin1), (coin1, coin2)); + assert_eq!(Dex::get_pool_id(native, coin2).unwrap(), coin2); + assert_eq!(Dex::get_pool_id(coin2, native).unwrap(), coin2); + assert!(matches!(Dex::get_pool_id(native, native), Err(Error::::EqualCoins))); + assert!(matches!(Dex::get_pool_id(coin2, coin1), Err(Error::::PoolNotFound))); assert!(coin2 > coin1); assert!(coin1 <= coin1); assert_eq!(coin1, coin1); @@ -1349,29 +1228,28 @@ fn cannot_block_pool_creation() { // User 2 is the attacker let attacker = system_address(b"attacker").into(); - let ed = get_ed(); - assert_ok!(CoinsPallet::mint( + assert_ok!(CoinsPallet::::mint( attacker, - Balance { coin: Coin::native(), amount: Amount(10000 + ed) } + Balance { coin: Coin::native(), amount: Amount(10000) } )); // The target pool the user wants to create is Native <=> Coin(2) - let token_1 = Coin::native(); - let token_2 = Coin::Ether; + let coin1 = Coin::native(); + let coin2 = Coin::Ether; // Attacker computes the still non-existing pool account for the target pair - let pool_account = Dex::get_pool_account(&Dex::get_pool_id(token_2, token_1)); - // And transfers the ED to that pool account - assert_ok!(CoinsPallet::transfer_internal( + let pool_account = Dex::get_pool_account(Dex::get_pool_id(coin2, coin1).unwrap()); + // And transfers 1 to that pool account + assert_ok!(CoinsPallet::::transfer_internal( attacker, pool_account, - Balance { coin: Coin::native(), amount: Amount(ed) } + Balance { coin: Coin::native(), amount: Amount(1) } )); // Then, the attacker creates 14 tokens and sends one of each to the pool account - // skip the token_1 and token_2 coins. - for coin in coins().into_iter().filter(|c| (*c != token_1 && *c != token_2)) { - assert_ok!(CoinsPallet::mint(attacker, Balance { coin, amount: Amount(1000) })); - assert_ok!(CoinsPallet::transfer_internal( + // skip the coin1 and coin2 coins. + for coin in coins().into_iter().filter(|c| (*c != coin1 && *c != coin2)) { + assert_ok!(CoinsPallet::::mint(attacker, Balance { coin, amount: Amount(1000) })); + assert_ok!(CoinsPallet::::transfer_internal( attacker, pool_account, Balance { coin, amount: Amount(1) } @@ -1379,33 +1257,24 @@ fn cannot_block_pool_creation() { } // User can still create the pool - assert_ok!(Dex::create_pool(token_2)); + assert_ok!(Dex::create_pool(coin2)); // User has to transfer one Coin(2) token to the pool account (otherwise add_liquidity will // fail with `CoinTwoDepositDidNotMeetMinimum`), also transfer native token for the same error. - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_1, amount: Amount(10000 + ed) })); - assert_ok!(CoinsPallet::mint(user, Balance { coin: token_2, amount: Amount(10000) })); - assert_ok!(CoinsPallet::transfer_internal( + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin1, amount: Amount(10000) })); + assert_ok!(CoinsPallet::::mint(user, Balance { coin: coin2, amount: Amount(10000) })); + assert_ok!(CoinsPallet::::transfer_internal( user, pool_account, - Balance { coin: token_2, amount: Amount(1) } + Balance { coin: coin2, amount: Amount(1) } )); - assert_ok!(CoinsPallet::transfer_internal( + assert_ok!(CoinsPallet::::transfer_internal( user, pool_account, - Balance { coin: token_1, amount: Amount(100) } + Balance { coin: coin1, amount: Amount(100) } )); // add_liquidity shouldn't fail because of the number of consumers - assert_ok!(Dex::add_liquidity( - RuntimeOrigin::signed(user), - token_1, - token_2, - 9900, - 100, - 9900, - 10, - user, - )); + assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 100, 9900, 10, 9900, user,)); }); } diff --git a/substrate/dex/pallet/src/types.rs b/substrate/dex/pallet/src/types.rs new file mode 100644 index 000000000..8be6af560 --- /dev/null +++ b/substrate/dex/pallet/src/types.rs @@ -0,0 +1,64 @@ +// This file was originally: + +// 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. + +// It has been forked into a crate distributed under the AGPL 3.0. +// Please check the current distribution for up-to-date copyright and licensing information. + +use super::*; + +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +/// Stores the lp_token coin id a particular pool has been assigned. +#[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)] +pub struct PoolInfo { + /// Liquidity pool coin + pub lp_token: PoolCoinId, +} + +/// Trait for providing methods to swap between the various coin classes. +pub trait Swap { + /// Swap exactly `amount_in` of coin `path[0]` for coin `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]` coin from `sender`, deposits the `path[1]` coin to `send_to`, + /// + /// 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, + ) -> Result; + + /// Take the `path[0]` coin 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]` coin from `sender`, deposits `path[1]` coin to `send_to`, + /// + /// 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, + ) -> Result; +} diff --git a/substrate/dex/pallet/src/weights.rs b/substrate/dex/pallet/src/weights.rs index 23c2c299f..e32f30691 100644 --- a/substrate/dex/pallet/src/weights.rs +++ b/substrate/dex/pallet/src/weights.rs @@ -18,7 +18,7 @@ // It has been forked into a crate distributed under the AGPL 3.0. // Please check the current distribution for up-to-date copyright and licensing information. -//! Autogenerated weights for pallet_coin_conversion +//! Autogenerated weights for Dex Pallet. //! //! 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: `[]` @@ -36,10 +36,10 @@ // --wasm-execution=compiled // --heap-pages=4096 // --json-file=/builds/parity/mirrors/substrate/.git/.artifacts/bench.json -// --pallet=pallet_coin_conversion +// --pallet=serai_dex_pallet // --chain=dev // --header=./HEADER-APACHE2 -// --output=./frame/coin-conversion/src/weights.rs +// --output=./substrate/dex/pallet/src/weights.rs // --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -50,7 +50,7 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_coin_conversion. +/// Weight functions needed for Dex Pallet. pub trait WeightInfo { fn create_pool() -> Weight; fn add_liquidity() -> Weight; @@ -59,19 +59,19 @@ pub trait WeightInfo { fn swap_tokens_for_exact_tokens() -> Weight; } -/// Weights for pallet_coin_conversion using the Substrate node and recommended hardware. +/// Weights for Dex Pallet using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `CoinConversion::Pools` (r:1 w:1) - /// Proof: `CoinConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::Pools` (r:1 w:1) + /// Proof: `DexPallet::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: `Coins::Account` (r:1 w:1) /// Proof: `Coins::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `Coins::Coin` (r:1 w:1) /// Proof: `Coins::Coin` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `CoinConversion::NextPoolCoinId` (r:1 w:1) - /// Proof: `CoinConversion::NextPoolCoinId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::NextPoolCoinId` (r:1 w:1) + /// Proof: `DexPallet::NextPoolCoinId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PoolCoins::Coin` (r:1 w:1) /// Proof: `PoolCoins::Coin` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `PoolCoins::Account` (r:1 w:1) @@ -85,8 +85,8 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } - /// Storage: `CoinConversion::Pools` (r:1 w:0) - /// Proof: `CoinConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::Pools` (r:1 w:0) + /// Proof: `DexPallet::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: `Coins::Coin` (r:1 w:1) @@ -106,8 +106,8 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } - /// Storage: `CoinConversion::Pools` (r:1 w:0) - /// Proof: `CoinConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::Pools` (r:1 w:0) + /// Proof: `DexPallet::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: `Coins::Coin` (r:1 w:1) @@ -161,16 +161,16 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: `CoinConversion::Pools` (r:1 w:1) - /// Proof: `CoinConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::Pools` (r:1 w:1) + /// Proof: `DexPallet::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: `Coins::Account` (r:1 w:1) /// Proof: `Coins::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) /// Storage: `Coins::Coin` (r:1 w:1) /// Proof: `Coins::Coin` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `CoinConversion::NextPoolCoinId` (r:1 w:1) - /// Proof: `CoinConversion::NextPoolCoinId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::NextPoolCoinId` (r:1 w:1) + /// Proof: `DexPallet::NextPoolCoinId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `PoolCoins::Coin` (r:1 w:1) /// Proof: `PoolCoins::Coin` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) /// Storage: `PoolCoins::Account` (r:1 w:1) @@ -184,8 +184,8 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } - /// Storage: `CoinConversion::Pools` (r:1 w:0) - /// Proof: `CoinConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::Pools` (r:1 w:0) + /// Proof: `DexPallet::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: `Coins::Coin` (r:1 w:1) @@ -205,8 +205,8 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } - /// Storage: `CoinConversion::Pools` (r:1 w:0) - /// Proof: `CoinConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `DexPallet::Pools` (r:1 w:0) + /// Proof: `DexPallet::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: `Coins::Coin` (r:1 w:1) diff --git a/substrate/dex/primitives/Cargo.toml b/substrate/dex/primitives/Cargo.toml deleted file mode 100644 index 7b5c0a9a9..000000000 --- a/substrate/dex/primitives/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "serai-dex-primitives" -version = "0.1.0" -description = "Dex pallet primitives" -license = "AGPL-3.0-only" -repository = "https://github.com/serai-dex/serai/tree/develop/substrate/dex/primitives" -authors = ["Parity Technologies , Akil Demir "] -edition = "2021" - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } - -frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } -frame-benchmarking = { git = "https://github.com/serai-dex/substrate", default-features = false, optional = true } - -sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } -sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false } - -serai-primitives = { path = "../../primitives", default-features = false } - -[features] -default = [ "std" ] -std = [ - "codec/std", - "scale-info/std", - - "frame-support/std", - "frame-benchmarking?/std", - - "serai-primitives/std", - - "sp-runtime/std", - "sp-std/std", -] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", -] diff --git a/substrate/dex/primitives/LICENSE-AGPL3 b/substrate/dex/primitives/LICENSE-AGPL3 deleted file mode 100644 index f684d0271..000000000 --- a/substrate/dex/primitives/LICENSE-AGPL3 +++ /dev/null @@ -1,15 +0,0 @@ -AGPL-3.0-only license - -Copyright (c) 2023 Luke Parker - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License Version 3 as -published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . diff --git a/substrate/dex/primitives/LICENSE-APACHE2 b/substrate/dex/primitives/LICENSE-APACHE2 deleted file mode 100644 index fbb0616d1..000000000 --- a/substrate/dex/primitives/LICENSE-APACHE2 +++ /dev/null @@ -1,211 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. - - NOTE - -Individual files contain the following tag instead of the full license -text. - - SPDX-License-Identifier: Apache-2.0 - -This enables machine processing of license information based on the SPDX -License Identifiers that are here available: http://spdx.org/licenses/ \ No newline at end of file diff --git a/substrate/dex/primitives/src/lib.rs b/substrate/dex/primitives/src/lib.rs deleted file mode 100644 index 725e37f07..000000000 --- a/substrate/dex/primitives/src/lib.rs +++ /dev/null @@ -1,221 +0,0 @@ -// This file was originally: - -// 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. - -// It has been forked into a crate distributed under the AGPL 3.0. -// Please check the current distribution for up-to-date copyright and licensing information. - -#![cfg_attr(not(feature = "std"), no_std)] - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -use sp_runtime::DispatchError; -use sp_std::vec::Vec; - -use frame_support::traits::tokens::{Balance, AssetId as CoinId}; - -use serai_primitives::Coin; - -/// Stores the lp_token coin id a particular pool has been assigned. -#[derive(Decode, Encode, Default, PartialEq, Eq, MaxEncodedLen, TypeInfo)] -pub struct PoolInfo { - /// Liquidity pool coin - pub lp_token: PoolCoinId, -} - -/// A trait that converts between a MultiCoinId and either the native currency or an CoinId. -pub trait MultiCoinIdConverter { - /// Returns the MultiCoinId representing the native currency of the chain. - fn get_native() -> MultiCoinId; - - /// Returns true if the given MultiCoinId is the native currency. - fn is_native(coin: &MultiCoinId) -> bool; - - /// If it's not native, returns the CoinId for the given MultiCoinId. - fn try_convert(coin: &MultiCoinId) -> MultiCoinIdConversionResult; -} - -/// Result of `MultiCoinIdConverter::try_convert`. -#[cfg_attr(feature = "std", derive(PartialEq, Debug))] -pub enum MultiCoinIdConversionResult { - /// Input coin is successfully converted. Means that converted coin is supported. - Converted(CoinId), - /// Means that input coin is the chain's native coin, if it has one, so no conversion (see - /// `MultiCoinIdConverter::get_native`). - Native, - /// Means input coin is not supported for pool. - Unsupported(MultiCoinId), -} - -/// Benchmark Helper -#[cfg(feature = "runtime-benchmarks")] -pub trait BenchmarkHelper { - /// Returns an `CoinId` from a given integer. - fn coin_id(coin_id: u32) -> CoinId; -} - -#[cfg(feature = "runtime-benchmarks")] -mod runtime_benchmarks { - use super::*; - use serai_primitives::COINS; - impl BenchmarkHelper for () { - fn coin_id(coin_id: u32) -> Coin { - // we shift id 1 unit to the left, since id 0 is the native coin. - COINS[(usize::try_from(coin_id).unwrap() % COINS.len()) + 1] - } - } -} - -/// Trait for providing methods to swap between the various coin classes. -pub trait Swap { - /// Swap exactly `amount_in` of coin `path[0]` for coin `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]` coin from `sender`, deposits the `path[1]` coin to `send_to`, - /// - /// 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, - ) -> Result; - - /// Take the `path[0]` coin 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]` coin from `sender`, deposits `path[1]` coin to `send_to`, - /// - /// 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, - ) -> Result; -} - -// TODO: Sized should be there? -/// Native coin trait for Dex pallet. -pub trait Currency: Sized { - /// Balance of an Account. - type Balance: Balance; - - /// Returns the balance of an account. - fn balance(of: &AccountId) -> Self::Balance; - - /// Returns the minimum allowed balance of an account - fn minimum_balance() -> Self::Balance; - - /// Transfers the given `amount` from `from` to `to`. - fn transfer( - from: &AccountId, - to: &AccountId, - amount: Self::Balance, - ) -> Result; - - /// mints the given `amount` into `to`. - fn mint(to: &AccountId, amount: Self::Balance) -> Result; -} - -/// External coin trait for Dex pallet. -pub trait Coins: Sized { - /// Balance of an Account. - type Balance: Balance; - - /// Coin identifier. - type CoinId: CoinId; - - /// Returns the balance of an account. - fn balance(coin: Self::CoinId, of: &AccountId) -> Self::Balance; - - /// Returns the minimum allowed balance of an account - fn minimum_balance(coin: Self::CoinId) -> Self::Balance; - - /// Transfers the given `amount` from `from` to `to`. - fn transfer( - coin: Self::CoinId, - from: &AccountId, - to: &AccountId, - amount: Self::Balance, - ) -> Result; - - /// mints the given `amount` of `coin` into `to`. - fn mint( - coin: Self::CoinId, - to: &AccountId, - amount: Self::Balance, - ) -> Result; -} - -/// Liquidity tokens trait for Dex pallet. -pub trait LiquidityTokens: Sized { - /// Amount type. - type Balance: Balance; - - /// Coin identifier. - type CoinId: CoinId; - - /// Returns the `token` balance of and account. - fn balance(token: Self::CoinId, of: &AccountId) -> Self::Balance; - - /// Mints `amount` to `to`. - fn mint_into( - token: Self::CoinId, - to: &AccountId, - amount: Self::Balance, - ) -> Result; - - /// Burns `amount` from `from`. - fn burn_from( - token: Self::CoinId, - from: &AccountId, - amount: Self::Balance, - ) -> Result; - - /// Returns total supply for `token`. - fn total_issuance(token: Self::CoinId) -> Self::Balance; - - /// Returns an iterator of the collections in existence. - fn coin_ids() -> Vec; -} - -pub struct CoinConverter; -impl MultiCoinIdConverter for CoinConverter { - /// Returns the MultiCoinId representing the native currency of the chain. - fn get_native() -> Coin { - Coin::native() - } - - /// Returns true if the given MultiCoinId is the native currency. - fn is_native(coin: &Coin) -> bool { - coin.is_native() - } - - /// If it's not native, returns the CoinId for the given MultiCoinId. - fn try_convert(coin: &Coin) -> MultiCoinIdConversionResult { - if coin.is_native() { - MultiCoinIdConversionResult::Native - } else { - MultiCoinIdConversionResult::Converted(*coin) - } - } -} diff --git a/substrate/in-instructions/pallet/src/lib.rs b/substrate/in-instructions/pallet/src/lib.rs index 30b9dae79..88fb24719 100644 --- a/substrate/in-instructions/pallet/src/lib.rs +++ b/substrate/in-instructions/pallet/src/lib.rs @@ -28,7 +28,7 @@ pub mod pallet { use sp_runtime::traits::Zero; use sp_core::sr25519::Public; - use serai_primitives::{Coin, SubstrateAmount, Amount, Balance}; + use serai_primitives::{Coin, Amount, Balance}; use frame_support::pallet_prelude::*; use frame_system::{pallet_prelude::*, RawOrigin}; @@ -46,12 +46,7 @@ pub mod pallet { use super::*; #[pallet::config] - pub trait Config: - frame_system::Config - + CoinsConfig - + DexConfig - + ValidatorSetsConfig - { + pub trait Config: frame_system::Config + CoinsConfig + DexConfig + ValidatorSetsConfig { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } @@ -127,7 +122,6 @@ pub mod pallet { Dex::::add_liquidity( origin.clone().into(), coin, - Coin::Serai, half, sri_amount, 1, @@ -185,7 +179,7 @@ pub mod pallet { // do the swap let origin = RawOrigin::Signed(IN_INSTRUCTION_EXECUTOR.into()); Dex::::swap_exact_tokens_for_tokens( - origin.into(), + origin.clone().into(), BoundedVec::try_from(path).unwrap(), instruction.balance.amount.0, out_balance.amount.0, @@ -206,7 +200,7 @@ pub mod pallet { }, balance: Balance { coin: out_balance.coin, amount: coin_balance }, }; - Coins::::burn_non_sri(IN_INSTRUCTION_EXECUTOR.into(), instruction)?; + Coins::::burn_with_instruction(origin.into(), instruction)?; } } } diff --git a/substrate/liquidity-tokens/pallet/Cargo.toml b/substrate/liquidity-tokens/pallet/Cargo.toml deleted file mode 100644 index 467911df2..000000000 --- a/substrate/liquidity-tokens/pallet/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "serai-liquidity-tokens-pallet" -version = "0.1.0" -description = "liquidity tokens pallet for Serai" -license = "AGPL-3.0-only" -repository = "https://github.com/serai-dex/serai/tree/develop/substrate/liquidity-tokens/pallet" -authors = ["Akil Demir "] -edition = "2021" - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[dependencies] -parity-scale-codec = { version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"] } - -frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } -frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } - -sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } -sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false } - -dex-primitives = { package = "serai-dex-primitives", path = "../../dex/primitives", default-features = false } - -serai-primitives = { path = "../../primitives", default-features = false } - -[features] -std = [ - "frame-system/std", - "frame-support/std", - - "sp-core/std", - "sp-std/std", - - "dex-primitives/std", - - "serai-primitives/std", -] - -runtime-benchmarks = [ - "frame-system/runtime-benchmarks", - "frame-support/runtime-benchmarks", -] - -default = ["std"] diff --git a/substrate/liquidity-tokens/pallet/LICENSE b/substrate/liquidity-tokens/pallet/LICENSE deleted file mode 100644 index f684d0271..000000000 --- a/substrate/liquidity-tokens/pallet/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -AGPL-3.0-only license - -Copyright (c) 2023 Luke Parker - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License Version 3 as -published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . diff --git a/substrate/liquidity-tokens/pallet/src/lib.rs b/substrate/liquidity-tokens/pallet/src/lib.rs deleted file mode 100644 index 3ed46eb29..000000000 --- a/substrate/liquidity-tokens/pallet/src/lib.rs +++ /dev/null @@ -1,152 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -#[frame_support::pallet] -pub mod pallet { - use sp_core::sr25519::Public; - use sp_std::vec::Vec; - use frame_support::pallet_prelude::*; - - use dex_primitives::LiquidityTokens; - use serai_primitives::*; - - #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - } - - #[pallet::error] - pub enum Error { - AmountOverflowed, - NotEnoughCoins, - } - - #[pallet::event] - #[pallet::generate_deposit(fn deposit_event)] - pub enum Event { - LtMint { to: Public, token: u32, amount: Amount }, - LtBurn { from: Public, token: u32, amount: Amount }, - } - - #[pallet::pallet] - pub struct Pallet(PhantomData); - - /// The amount of coins each account has. - // Identity is used as the second key's hasher due to it being a non-manipulatable fixed-space - // ID. - #[pallet::storage] - #[pallet::getter(fn balances)] - pub type Balances = StorageDoubleMap< - _, - Blake2_128Concat, - Public, - Blake2_128Concat, - u32, - SubstrateAmount, - OptionQuery, - >; - - /// The total supply of each coin. - // We use Identity type here again due to reasons stated in the Balances Storage. - #[pallet::storage] - #[pallet::getter(fn supply)] - pub type Supply = StorageMap<_, Blake2_128Concat, u32, SubstrateAmount, ValueQuery>; - - // TODO: apis: supply, mint, burn, transfer - impl Pallet { - /// Returns the balance of a given account for `token`. - pub fn balance(token: u32, of: T::AccountId) -> SubstrateAmount { - Self::balances(of, token).unwrap_or(0) - } - - /// Mint `balance` to the given account. - /// - /// Errors if any amount overflows. - pub fn mint_into(token: u32, to: Public, amount: SubstrateAmount) -> Result<(), Error> { - let balance = Self::balances(to, token).unwrap_or(0); - - // update the balance - let new_amount = balance.checked_add(amount).ok_or(Error::::AmountOverflowed)?; - - // save - Balances::::set(to, token, Some(new_amount)); - - // update the supply - let new_supply = - Self::supply(token).checked_add(amount).ok_or(Error::::AmountOverflowed)?; - Supply::::set(token, new_supply); - - Self::deposit_event(Event::LtMint { to, token, amount: Amount(amount) }); - Ok(()) - } - - // Burn `balance` from the specified account. - pub fn burn_from(token: u32, from: Public, amount: SubstrateAmount) -> Result<(), Error> { - let balance = Self::balances(from, token); - if balance.is_none() { - Err(Error::::NotEnoughCoins)?; - } - - // update the balance - let new_amount = balance.unwrap().checked_sub(amount).ok_or(Error::::NotEnoughCoins)?; - - // save - if new_amount == 0 { - Balances::::remove(from, token); - } else { - Balances::::set(from, token, Some(new_amount)); - } - - // update the supply - let new_supply = Self::supply(token).checked_sub(amount).unwrap(); - if new_supply == 0 { - Supply::::remove(token); - } else { - Supply::::set(token, new_supply); - } - - Self::deposit_event(Event::LtBurn { from, token, amount: Amount(amount) }); - Ok(()) - } - - pub fn total_issuance(token: u32) -> SubstrateAmount { - Supply::::get(token) - } - } - - impl LiquidityTokens for Pallet { - type Balance = SubstrateAmount; - type CoinId = u32; - - fn mint_into( - token: Self::CoinId, - to: &Public, - amount: Self::Balance, - ) -> Result { - Self::mint_into(token, *to, amount)?; - Ok(amount) - } - - fn burn_from( - token: Self::CoinId, - from: &Public, - amount: Self::Balance, - ) -> Result { - Self::burn_from(token, *from, amount)?; - Ok(amount) - } - - fn total_issuance(token: Self::CoinId) -> Self::Balance { - Self::total_issuance(token) - } - - fn coin_ids() -> Vec { - Supply::::iter_keys().collect::>() - } - - fn balance(token: Self::CoinId, of: &Public) -> Self::Balance { - Self::balance(token, *of) - } - } -} - -pub use pallet::*; diff --git a/substrate/node/src/chain_spec.rs b/substrate/node/src/chain_spec.rs index e3dd46699..1c0e4f659 100644 --- a/substrate/node/src/chain_spec.rs +++ b/substrate/node/src/chain_spec.rs @@ -41,9 +41,13 @@ fn testnet_genesis( .into_iter() .map(|a| (a, Balance { coin: Coin::Serai, amount: Amount(1 << 60) })) .collect(), + _ignore: Default::default(), }, - dex: DexConfig { pools: vec![Coin::Bitcoin, Coin::Ether, Coin::Dai, Coin::Monero] }, + dex: DexConfig { + pools: vec![Coin::Bitcoin, Coin::Ether, Coin::Dai, Coin::Monero], + _ignore: Default::default(), + }, validator_sets: ValidatorSetsConfig { networks: serai_runtime::primitives::NETWORKS diff --git a/substrate/runtime/Cargo.toml b/substrate/runtime/Cargo.toml index 6b5d60fba..6e1db90ab 100644 --- a/substrate/runtime/Cargo.toml +++ b/substrate/runtime/Cargo.toml @@ -40,14 +40,12 @@ frame-executive = { git = "https://github.com/serai-dex/substrate", default-feat frame-benchmarking = { git = "https://github.com/serai-dex/substrate", default-features = false, optional = true } serai-primitives = { path = "../primitives", default-features = false } -serai-dex-primitives = { path = "../dex/primitives", default-features = false } pallet-timestamp = { git = "https://github.com/serai-dex/substrate", default-features = false } pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false } coins-pallet = { package = "serai-coins-pallet", path = "../coins/pallet", default-features = false } -liquidity-tokens-pallet = { package = "serai-liquidity-tokens-pallet", path = "../liquidity-tokens/pallet", default-features = false } dex-pallet = { package = "serai-dex-pallet", path = "../dex/pallet", default-features = false } validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../validator-sets/pallet", default-features = false } @@ -97,14 +95,12 @@ std = [ "frame-executive/std", "serai-primitives/std", - "serai-dex-primitives/std", "pallet-timestamp/std", "pallet-transaction-payment/std", "coins-pallet/std", - "liquidity-tokens-pallet/std", "dex-pallet/std", "validator-sets-pallet/std", @@ -132,8 +128,6 @@ runtime-benchmarks = [ "pallet-timestamp/runtime-benchmarks", - "dex-pallet/runtime-benchmarks", - "pallet-babe/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", ] diff --git a/substrate/runtime/src/lib.rs b/substrate/runtime/src/lib.rs index fa40715b3..2a30e4707 100644 --- a/substrate/runtime/src/lib.rs +++ b/substrate/runtime/src/lib.rs @@ -17,7 +17,6 @@ pub use pallet_timestamp as timestamp; pub use pallet_transaction_payment as transaction_payment; pub use coins_pallet as coins; -pub use liquidity_tokens_pallet as liquidity_tokens; pub use dex_pallet as dex; pub use validator_sets_pallet as validator_sets; @@ -47,7 +46,7 @@ use sp_runtime::{ ApplyExtrinsicResult, Perbill, }; -use primitives::{PublicKey, SeraiAddress, Coin, AccountLookup, Signature, SubstrateAmount}; +use primitives::{PublicKey, SeraiAddress, AccountLookup, Signature, SubstrateAmount}; use support::{ traits::{ConstU8, ConstU32, ConstU64, Contains}, @@ -157,6 +156,12 @@ impl Contains for CallFilter { // All of these pallets are our own, and all of their written calls are intended to be called RuntimeCall::Coins(call) => !matches!(call, coins::Call::__Ignore(_, _)), + RuntimeCall::LiquidityTokens(call) => match call { + coins::Call::transfer { .. } => true, + coins::Call::burn { .. } => true, + coins::Call::burn_with_instruction { .. } => false, + coins::Call::__Ignore(_, _) => false, + }, RuntimeCall::Dex(call) => !matches!(call, dex::Call::__Ignore(_, _)), RuntimeCall::ValidatorSets(call) => !matches!(call, validator_sets::Call::__Ignore(_, _)), RuntimeCall::InInstructions(call) => !matches!(call, in_instructions::Call::__Ignore(_, _)), @@ -234,25 +239,12 @@ impl coins::Config for Runtime { type RuntimeEvent = RuntimeEvent; } -impl liquidity_tokens::Config for Runtime { +impl coins::Config for Runtime { type RuntimeEvent = RuntimeEvent; } impl dex::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Currency = Coins; - type Balance = SubstrateAmount; - type CoinBalance = SubstrateAmount; - // TODO: Review if this should be u64/u128 or u64/u256 (and rounding in general). - type HigherPrecisionBalance = u128; - - type CoinId = Coin; - type MultiCoinId = Coin; - type MultiCoinIdConverter = serai_dex_primitives::CoinConverter; - type PoolCoinId = u32; - - type Coins = Coins; - type PoolCoins = LiquidityTokens; type LPFee = ConstU32<3>; // 0.3% type MintMinLiquidity = ConstU64<10000>; @@ -260,9 +252,6 @@ impl dex::Config for Runtime { type MaxSwapPathLength = ConstU32<3>; // coin1 -> SRI -> coin2 type WeightInfo = dex::weights::SubstrateWeight; - - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } impl validator_sets::Config for Runtime { @@ -364,7 +353,7 @@ construct_runtime!( TransactionPayment: transaction_payment, Coins: coins, - LiquidityTokens: liquidity_tokens, + LiquidityTokens: coins::::{Pallet, Call, Storage, Event}, Dex: dex, ValidatorSets: validator_sets, diff --git a/tests/coordinator/src/tests/sign.rs b/tests/coordinator/src/tests/sign.rs index 0a8dfffc9..a00935ee9 100644 --- a/tests/coordinator/src/tests/sign.rs +++ b/tests/coordinator/src/tests/sign.rs @@ -275,7 +275,12 @@ async fn sign_test() { serai .publish( &serai - .sign(&serai_pair, &SeraiCoins::burn(out_instruction.clone()), 0, Default::default()) + .sign( + &serai_pair, + &SeraiCoins::burn_with_instruction(out_instruction.clone()), + 0, + Default::default(), + ) .unwrap(), ) .await @@ -293,7 +298,7 @@ async fn sign_test() { let burn_events = serai .as_of(serai.block_by_number(last_serai_block).await.unwrap().unwrap().hash()) .coins() - .burn_events() + .burn_with_instruction_events() .await .unwrap(); @@ -301,7 +306,10 @@ async fn sign_test() { assert_eq!(burn_events.len(), 1); assert_eq!( burn_events[0], - CoinsEvent::Burn { from: serai_addr.into(), instruction: out_instruction.clone() } + CoinsEvent::BurnWithInstruction { + from: serai_addr.into(), + instruction: out_instruction.clone() + } ); break 'outer; } diff --git a/tests/full-stack/src/tests/mint_and_burn.rs b/tests/full-stack/src/tests/mint_and_burn.rs index 8221228d2..cc5b3af00 100644 --- a/tests/full-stack/src/tests/mint_and_burn.rs +++ b/tests/full-stack/src/tests/mint_and_burn.rs @@ -508,7 +508,12 @@ async fn mint_and_burn_test() { serai .publish( &serai - .sign(serai_pair, &SeraiCoins::burn(out_instruction), nonce, Default::default()) + .sign( + serai_pair, + &SeraiCoins::burn_with_instruction(out_instruction), + nonce, + Default::default(), + ) .unwrap(), ) .await