diff --git a/Cargo.lock b/Cargo.lock index 6b3d11c6..734e8354 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5076,7 +5076,7 @@ dependencies = [ [[package]] name = "pallet-stableswap" -version = "1.2.0" +version = "1.3.0" dependencies = [ "bitflags", "frame-benchmarking", diff --git a/stableswap/Cargo.toml b/stableswap/Cargo.toml index 3d225b0e..30fc77c3 100644 --- a/stableswap/Cargo.toml +++ b/stableswap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = 'pallet-stableswap' -version = '1.2.0' +version = '1.3.0' description = 'AMM for correlated assets' authors = ['GalacticCouncil'] edition = '2021' diff --git a/stableswap/src/lib.rs b/stableswap/src/lib.rs index 54cb6f08..373ffc17 100644 --- a/stableswap/src/lib.rs +++ b/stableswap/src/lib.rs @@ -111,8 +111,8 @@ pub mod pallet { /// Multi currency mechanism type Currency: MultiCurrency; - /// Account ID constructor - type ShareAccountId: AccountIdFor, AccountId = Self::AccountId>; + /// Account ID constructor - pool account are derived from unique pool id + type ShareAccountId: AccountIdFor; /// Asset registry mechanism type AssetRegistry: Registry, Balance, DispatchError>; @@ -462,8 +462,8 @@ pub mod pallet { let pool = Pools::::get(pool_id).ok_or(Error::::PoolNotFound)?; let asset_idx = pool.find_asset(asset_id).ok_or(Error::::AssetNotInPool)?; - let pool_account = pool.pool_account::(); - let balances = pool.balances::(); + let pool_account = Self::pool_account(pool_id); + let balances = pool.balances::(&pool_account); let share_issuance = T::Currency::total_issuance(pool_id); ensure!( @@ -542,8 +542,7 @@ pub mod pallet { ensure!(amount_out >= min_buy_amount, Error::::BuyLimitNotReached); - let pool = Pools::::get(pool_id).ok_or(Error::::PoolNotFound)?; - let pool_account = pool.pool_account::(); + let pool_account = Self::pool_account(pool_id); T::Currency::transfer(asset_in, &who, &pool_account, amount_in)?; T::Currency::transfer(asset_out, &pool_account, &who, amount_out)?; @@ -599,8 +598,7 @@ pub mod pallet { let (amount_in, fee_amount) = Self::calculate_in_amount(pool_id, asset_in, asset_out, amount_out)?; - let pool = Pools::::get(pool_id).ok_or(Error::::PoolNotFound)?; - let pool_account = pool.pool_account::(); + let pool_account = Self::pool_account(pool_id); ensure!(amount_in <= max_sell_amount, Error::::SellLimitExceeded); @@ -666,7 +664,8 @@ impl Pallet { let index_in = pool.find_asset(asset_in).ok_or(Error::::AssetNotInPool)?; let index_out = pool.find_asset(asset_out).ok_or(Error::::AssetNotInPool)?; - let balances = pool.balances::(); + let pool_account = Self::pool_account(pool_id); + let balances = pool.balances::(&pool_account); ensure!(balances[index_in] > Balance::zero(), Error::::InsufficientLiquidity); ensure!(balances[index_out] > Balance::zero(), Error::::InsufficientLiquidity); @@ -693,7 +692,8 @@ impl Pallet { let index_in = pool.find_asset(asset_in).ok_or(Error::::AssetNotInPool)?; let index_out = pool.find_asset(asset_out).ok_or(Error::::AssetNotInPool)?; - let balances = pool.balances::(); + let pool_account = Self::pool_account(pool_id); + let balances = pool.balances::(&pool_account); ensure!(balances[index_out] > amount_out, Error::::InsufficientLiquidity); ensure!(balances[index_in] > Balance::zero(), Error::::InsufficientLiquidity); @@ -777,7 +777,7 @@ impl Pallet { added_assets.insert(asset.asset_id, asset.amount); } - let pool_account = pool.pool_account::(); + let pool_account = Self::pool_account(pool_id); let mut initial_reserves = Vec::new(); let mut updated_reserves = Vec::new(); for pool_asset in pool.assets.iter() { @@ -820,4 +820,8 @@ impl Pallet { fn is_asset_allowed(pool_id: T::AssetId, asset_id: T::AssetId, operation: Tradability) -> bool { AssetTradability::::get(pool_id, asset_id).contains(operation) } + + fn pool_account(pool_id: T::AssetId) -> T::AccountId { + T::ShareAccountId::from_assets(&pool_id, Some(POOL_IDENTIFIER)) + } } diff --git a/stableswap/src/tests/add_liquidity.rs b/stableswap/src/tests/add_liquidity.rs index 4757ce66..ba756f9e 100644 --- a/stableswap/src/tests/add_liquidity.rs +++ b/stableswap/src/tests/add_liquidity.rs @@ -2,7 +2,6 @@ use crate::tests::mock::*; use crate::types::{AssetLiquidity, PoolInfo}; use crate::{assert_balance, Error}; use frame_support::{assert_noop, assert_ok}; -use hydradx_traits::AccountIdFor; use sp_runtime::Permill; #[test] @@ -35,7 +34,7 @@ fn add_initial_liquidity_should_work_when_called_first_time() { let initial_liquidity_amount = 100 * ONE; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_ok!(Stableswap::add_liquidity( RuntimeOrigin::signed(BOB), @@ -90,7 +89,7 @@ fn add_initial_liquidity_should_fail_when_lp_has_insufficient_balance() { let initial_liquidity_amount = 100 * ONE; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_noop!( Stableswap::add_liquidity( @@ -159,7 +158,7 @@ fn add_liquidity_should_work_when_initial_liquidity_has_been_provided() { let amount_added = 100 * ONE; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_ok!(Stableswap::add_liquidity( RuntimeOrigin::signed(BOB), @@ -226,7 +225,7 @@ fn add_liquidity_should_work_when_order_is_not_sorted() { let amount_added = 100 * ONE; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_ok!(Stableswap::add_liquidity( RuntimeOrigin::signed(BOB), diff --git a/stableswap/src/tests/invariants.rs b/stableswap/src/tests/invariants.rs index f4502cfd..ebb5e862 100644 --- a/stableswap/src/tests/invariants.rs +++ b/stableswap/src/tests/invariants.rs @@ -1,7 +1,6 @@ use crate::tests::mock::*; use crate::types::{AssetLiquidity, PoolInfo}; use frame_support::assert_ok; -use hydradx_traits::AccountIdFor; use sp_runtime::{FixedU128, Permill}; use hydra_dx_math::stableswap::calculate_d; @@ -83,7 +82,7 @@ proptest! { .execute_with(|| { let pool_id = get_pool_id_at(0); - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); let asset_a_reserve = Tokens::free_balance(asset_a, &pool_account); let asset_b_reserve = Tokens::free_balance(asset_b, &pool_account); @@ -158,7 +157,7 @@ proptest! { .execute_with(|| { let pool_id = get_pool_id_at(0); - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); let asset_a_reserve = Tokens::free_balance(asset_a, &pool_account); let asset_b_reserve = Tokens::free_balance(asset_b, &pool_account); @@ -227,7 +226,7 @@ proptest! { let pool_id = get_pool_id_at(0); - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); let asset_a_reserve = Tokens::free_balance(asset_a, &pool_account); let asset_b_reserve = Tokens::free_balance(asset_b, &pool_account); diff --git a/stableswap/src/tests/mock.rs b/stableswap/src/tests/mock.rs index dd2c8ff0..b05afce3 100644 --- a/stableswap/src/tests/mock.rs +++ b/stableswap/src/tests/mock.rs @@ -319,31 +319,29 @@ where pub struct AccountIdConstructor; -impl AccountIdFor> for AccountIdConstructor { +impl AccountIdFor for AccountIdConstructor { type AccountId = AccountId; - fn from_assets(assets: &Vec, _identifier: Option<&[u8]>) -> Self::AccountId { - let mut a = assets[0]; - let mut b = assets[1]; - if a > b { - std::mem::swap(&mut a, &mut b) - } - (a * 1000 + b) as u64 + fn from_assets(asset: &u32, _identifier: Option<&[u8]>) -> Self::AccountId { + (asset * 1000) as u64 } - fn name(assets: &Vec, identifier: Option<&[u8]>) -> Vec { + fn name(asset: &u32, identifier: Option<&[u8]>) -> Vec { let mut buf: Vec = if let Some(ident) = identifier { ident.to_vec() } else { vec![] }; - buf.extend_from_slice(&(assets[0]).to_le_bytes()); - buf.extend_from_slice(&(assets[1]).to_le_bytes()); + buf.extend_from_slice(&(asset).to_le_bytes()); buf } } +pub(crate) fn pool_account(asset: u32) -> AccountId { + AccountIdConstructor::from_assets(&asset, None) +} + pub(crate) fn retrieve_current_asset_id() -> AssetId { REGISTERED_ASSETS.with(|v| v.borrow().len() as AssetId) } diff --git a/stableswap/src/tests/remove_liquidity.rs b/stableswap/src/tests/remove_liquidity.rs index 42078174..13acdf0e 100644 --- a/stableswap/src/tests/remove_liquidity.rs +++ b/stableswap/src/tests/remove_liquidity.rs @@ -2,7 +2,6 @@ use crate::tests::mock::*; use crate::types::{AssetLiquidity, PoolInfo}; use crate::{assert_balance, Error}; use frame_support::{assert_noop, assert_ok}; -use hydradx_traits::AccountIdFor; use sp_runtime::Permill; #[test] @@ -53,7 +52,7 @@ fn remove_liquidity_should_work_when_withdrawing_all_shares() { let amount_added = 200 * ONE; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_ok!(Stableswap::add_liquidity( RuntimeOrigin::signed(BOB), @@ -130,7 +129,7 @@ fn remove_liquidity_should_apply_fee_when_withdrawing_all_shares() { let amount_added = 200 * ONE; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_ok!(Stableswap::add_liquidity( RuntimeOrigin::signed(BOB), @@ -409,7 +408,7 @@ fn verify_remove_liquidity_against_research_impl() { let amount_added = 100_000 * ONE; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b, asset_c, asset_d], None); + let pool_account = pool_account(pool_id); assert_ok!(Stableswap::add_liquidity( RuntimeOrigin::signed(BOB), diff --git a/stableswap/src/tests/trades.rs b/stableswap/src/tests/trades.rs index 2b53aa2c..fadec009 100644 --- a/stableswap/src/tests/trades.rs +++ b/stableswap/src/tests/trades.rs @@ -1,7 +1,6 @@ use crate::tests::mock::*; use crate::types::{AssetLiquidity, PoolInfo}; use crate::{assert_balance, Error}; -use hydradx_traits::AccountIdFor; use frame_support::{assert_noop, assert_ok}; use sp_runtime::Permill; @@ -51,7 +50,7 @@ fn sell_should_work_when_correct_input_provided() { let expected = 29_950_934_311_773u128; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_balance!(BOB, asset_a, 170 * ONE); assert_balance!(BOB, asset_b, expected); @@ -105,7 +104,7 @@ fn buy_should_work_when_correct_input_provided() { let expected_to_sell = 30049242502720u128; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_balance!(BOB, asset_a, 200 * ONE - expected_to_sell); assert_balance!(BOB, asset_b, 30 * ONE); @@ -164,7 +163,7 @@ fn sell_with_fee_should_work_when_correct_input_provided() { let expected = expected - fee; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_balance!(BOB, asset_a, 170 * ONE); assert_balance!(BOB, asset_b, expected); @@ -222,7 +221,7 @@ fn sell_should_work_when_fee_is_small() { let expected = expected - fee; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_balance!(BOB, asset_a, 170 * ONE); assert_balance!(BOB, asset_b, expected); @@ -280,7 +279,7 @@ fn buy_should_work_when_fee_is_set() { let expected_to_sell = expected_to_sell + fee; - let pool_account = AccountIdConstructor::from_assets(&vec![asset_a, asset_b], None); + let pool_account = pool_account(pool_id); assert_balance!(BOB, asset_a, 200 * ONE - expected_to_sell); assert_balance!(BOB, asset_b, 30 * ONE); diff --git a/stableswap/src/types.rs b/stableswap/src/types.rs index aa09608c..20902ede 100644 --- a/stableswap/src/types.rs +++ b/stableswap/src/types.rs @@ -1,4 +1,4 @@ -use crate::{Config, MAX_ASSETS_IN_POOL, POOL_IDENTIFIER}; +use crate::{Config, MAX_ASSETS_IN_POOL}; use sp_runtime::Permill; use sp_std::collections::btree_set::BTreeSet; use sp_std::prelude::*; @@ -6,7 +6,6 @@ use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::ConstU32; use frame_support::BoundedVec; -use hydradx_traits::AccountIdFor; use orml_traits::MultiCurrency; use scale_info::TypeInfo; use sp_core::RuntimeDebug; @@ -46,22 +45,13 @@ where has_unique_elements(&mut self.assets.iter()) } - pub fn pool_account(&self) -> T::AccountId + pub fn balances(&self, account: &T::AccountId) -> Vec where - T::ShareAccountId: AccountIdFor, AccountId = T::AccountId>, - { - T::ShareAccountId::from_assets(&self.assets, Some(POOL_IDENTIFIER)) - } - - pub fn balances(&self) -> Vec - where - T::ShareAccountId: AccountIdFor, AccountId = T::AccountId>, T::AssetId: From, { - let acc = self.pool_account::(); self.assets .iter() - .map(|asset| T::Currency::free_balance((*asset).into(), &acc)) + .map(|asset| T::Currency::free_balance((*asset).into(), account)) .collect() } }