mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
add specific network/coin/balance types (#619)
* add specific network/coin/balance types * misc fixes * fix clippy * misc fixes * fix pr comments * Make halting for external networks * fix encode/decode
This commit is contained in:
@@ -38,7 +38,7 @@ type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup
|
||||
|
||||
type LiquidityTokens<T> = coins_pallet::Pallet<T, coins_pallet::Instance1>;
|
||||
|
||||
fn create_coin<T: Config>(coin: &Coin) -> (T::AccountId, AccountIdLookupOf<T>) {
|
||||
fn create_coin<T: Config>(coin: &ExternalCoin) -> (T::AccountId, AccountIdLookupOf<T>) {
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
let caller_lookup = T::Lookup::unlookup(caller);
|
||||
assert_ok!(Coins::<T>::mint(
|
||||
@@ -47,12 +47,14 @@ fn create_coin<T: Config>(coin: &Coin) -> (T::AccountId, AccountIdLookupOf<T>) {
|
||||
));
|
||||
assert_ok!(Coins::<T>::mint(
|
||||
caller,
|
||||
Balance { coin: *coin, amount: Amount(INITIAL_COIN_BALANCE) }
|
||||
Balance { coin: (*coin).into(), amount: Amount(INITIAL_COIN_BALANCE) }
|
||||
));
|
||||
(caller, caller_lookup)
|
||||
}
|
||||
|
||||
fn create_coin_and_pool<T: Config>(coin: &Coin) -> (Coin, T::AccountId, AccountIdLookupOf<T>) {
|
||||
fn create_coin_and_pool<T: Config>(
|
||||
coin: &ExternalCoin,
|
||||
) -> (ExternalCoin, T::AccountId, AccountIdLookupOf<T>) {
|
||||
let (caller, caller_lookup) = create_coin::<T>(coin);
|
||||
assert_ok!(Dex::<T>::create_pool(*coin));
|
||||
|
||||
@@ -62,7 +64,7 @@ fn create_coin_and_pool<T: Config>(coin: &Coin) -> (Coin, T::AccountId, AccountI
|
||||
benchmarks! {
|
||||
add_liquidity {
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Bitcoin;
|
||||
let coin2 = ExternalCoin::Bitcoin;
|
||||
let (lp_token, caller, _) = create_coin_and_pool::<T>(&coin2);
|
||||
let add_amount: u64 = 1000;
|
||||
}: _(
|
||||
@@ -75,13 +77,13 @@ benchmarks! {
|
||||
caller
|
||||
)
|
||||
verify {
|
||||
let pool_id = Dex::<T>::get_pool_id(coin1, coin2).unwrap();
|
||||
let pool_id = Dex::<T>::get_pool_id(coin1, coin2.into()).unwrap();
|
||||
let lp_minted = Dex::<T>::calc_lp_amount_for_zero_supply(
|
||||
add_amount,
|
||||
1000u64,
|
||||
).unwrap();
|
||||
assert_eq!(
|
||||
LiquidityTokens::<T>::balance(caller, lp_token).0,
|
||||
LiquidityTokens::<T>::balance(caller, lp_token.into()).0,
|
||||
lp_minted
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -91,7 +93,7 @@ benchmarks! {
|
||||
assert_eq!(
|
||||
Coins::<T>::balance(
|
||||
Dex::<T>::get_pool_account(pool_id),
|
||||
Coin::Bitcoin,
|
||||
ExternalCoin::Bitcoin.into(),
|
||||
).0,
|
||||
1000
|
||||
);
|
||||
@@ -99,7 +101,7 @@ benchmarks! {
|
||||
|
||||
remove_liquidity {
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Monero;
|
||||
let coin2 = ExternalCoin::Monero;
|
||||
let (lp_token, caller, _) = create_coin_and_pool::<T>(&coin2);
|
||||
let add_amount: u64 = 100;
|
||||
let lp_minted = Dex::<T>::calc_lp_amount_for_zero_supply(
|
||||
@@ -117,7 +119,7 @@ benchmarks! {
|
||||
0u64,
|
||||
caller,
|
||||
)?;
|
||||
let total_supply = LiquidityTokens::<T>::supply(lp_token);
|
||||
let total_supply = LiquidityTokens::<T>::supply(Coin::from(lp_token));
|
||||
}: _(
|
||||
SystemOrigin::Signed(caller),
|
||||
coin2,
|
||||
@@ -127,7 +129,7 @@ benchmarks! {
|
||||
caller
|
||||
)
|
||||
verify {
|
||||
let new_total_supply = LiquidityTokens::<T>::supply(lp_token);
|
||||
let new_total_supply = LiquidityTokens::<T>::supply(Coin::from(lp_token));
|
||||
assert_eq!(
|
||||
new_total_supply,
|
||||
total_supply - remove_lp_amount
|
||||
@@ -136,8 +138,8 @@ benchmarks! {
|
||||
|
||||
swap_exact_tokens_for_tokens {
|
||||
let native = Coin::native();
|
||||
let coin1 = Coin::Bitcoin;
|
||||
let coin2 = Coin::Ether;
|
||||
let coin1 = ExternalCoin::Bitcoin;
|
||||
let coin2 = ExternalCoin::Ether;
|
||||
let (_, caller, _) = create_coin_and_pool::<T>(&coin1);
|
||||
let (_, _) = create_coin::<T>(&coin2);
|
||||
|
||||
@@ -168,21 +170,21 @@ benchmarks! {
|
||||
caller,
|
||||
)?;
|
||||
|
||||
let path = vec![coin1, native, coin2];
|
||||
let path = vec![Coin::from(coin1), native, Coin::from(coin2)];
|
||||
let path = BoundedVec::<_, T::MaxSwapPathLength>::try_from(path).unwrap();
|
||||
let native_balance = Coins::<T>::balance(caller, native).0;
|
||||
let coin1_balance = Coins::<T>::balance(caller, Coin::Bitcoin).0;
|
||||
let coin1_balance = Coins::<T>::balance(caller, ExternalCoin::Bitcoin.into()).0;
|
||||
}: _(SystemOrigin::Signed(caller), path, swap_amount, 1u64, caller)
|
||||
verify {
|
||||
let ed_bump = 2u64;
|
||||
let new_coin1_balance = Coins::<T>::balance(caller, Coin::Bitcoin).0;
|
||||
let new_coin1_balance = Coins::<T>::balance(caller, ExternalCoin::Bitcoin.into()).0;
|
||||
assert_eq!(new_coin1_balance, coin1_balance - 100u64);
|
||||
}
|
||||
|
||||
swap_tokens_for_exact_tokens {
|
||||
let native = Coin::native();
|
||||
let coin1 = Coin::Bitcoin;
|
||||
let coin2 = Coin::Ether;
|
||||
let coin1 = ExternalCoin::Bitcoin;
|
||||
let coin2 = ExternalCoin::Ether;
|
||||
let (_, caller, _) = create_coin_and_pool::<T>(&coin1);
|
||||
let (_, _) = create_coin::<T>(&coin2);
|
||||
|
||||
@@ -208,10 +210,10 @@ benchmarks! {
|
||||
0u64,
|
||||
caller,
|
||||
)?;
|
||||
let path = vec![coin1, native, coin2];
|
||||
let path = vec![Coin::from(coin1), native, Coin::from(coin2)];
|
||||
|
||||
let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap();
|
||||
let coin2_balance = Coins::<T>::balance(caller, Coin::Ether).0;
|
||||
let coin2_balance = Coins::<T>::balance(caller, ExternalCoin::Ether.into()).0;
|
||||
}: _(
|
||||
SystemOrigin::Signed(caller),
|
||||
path.clone(),
|
||||
@@ -220,7 +222,7 @@ benchmarks! {
|
||||
caller
|
||||
)
|
||||
verify {
|
||||
let new_coin2_balance = Coins::<T>::balance(caller, Coin::Ether).0;
|
||||
let new_coin2_balance = Coins::<T>::balance(caller, ExternalCoin::Ether.into()).0;
|
||||
assert_eq!(new_coin2_balance, coin2_balance + 100u64);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ mod tests;
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
use frame_support::ensure;
|
||||
use frame_support::{ensure, pallet_prelude::*, BoundedBTreeSet};
|
||||
use frame_system::{
|
||||
pallet_prelude::{BlockNumberFor, OriginFor},
|
||||
ensure_signed,
|
||||
@@ -86,9 +86,12 @@ use frame_system::{
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
use sp_runtime::{traits::TrailingZeroInput, DispatchError};
|
||||
use sp_runtime::{
|
||||
traits::{TrailingZeroInput, IntegerSquareRoot},
|
||||
DispatchError,
|
||||
};
|
||||
|
||||
use serai_primitives::{NetworkId, Coin, SubstrateAmount};
|
||||
use serai_primitives::*;
|
||||
|
||||
use sp_std::prelude::*;
|
||||
pub use types::*;
|
||||
@@ -103,20 +106,16 @@ pub use weights::WeightInfo;
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::{pallet_prelude::*, BoundedBTreeSet};
|
||||
|
||||
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, reverse_lexicographic_order};
|
||||
|
||||
/// Pool ID.
|
||||
///
|
||||
/// The pool's `AccountId` is derived from this type. Any changes to the type may necessitate a
|
||||
/// migration.
|
||||
pub type PoolId = Coin;
|
||||
pub type PoolId = ExternalCoin;
|
||||
|
||||
/// LiquidityTokens Pallet as an instance of coins pallet.
|
||||
pub type LiquidityTokens<T> = coins_pallet::Pallet<T, coins_pallet::Instance1>;
|
||||
@@ -164,7 +163,7 @@ pub mod pallet {
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn spot_price_for_block)]
|
||||
pub type SpotPriceForBlock<T: Config> =
|
||||
StorageDoubleMap<_, Identity, BlockNumberFor<T>, Identity, Coin, Amount, OptionQuery>;
|
||||
StorageDoubleMap<_, Identity, BlockNumberFor<T>, Identity, ExternalCoin, Amount, OptionQuery>;
|
||||
|
||||
/// Moving window of prices from each block.
|
||||
///
|
||||
@@ -173,30 +172,32 @@ pub mod pallet {
|
||||
/// low to high.
|
||||
#[pallet::storage]
|
||||
pub type SpotPrices<T: Config> =
|
||||
StorageDoubleMap<_, Identity, Coin, Identity, [u8; 8], u16, OptionQuery>;
|
||||
StorageDoubleMap<_, Identity, ExternalCoin, Identity, [u8; 8], u16, OptionQuery>;
|
||||
|
||||
// SpotPrices, yet with keys stored in reverse lexicographic order.
|
||||
#[pallet::storage]
|
||||
pub type ReverseSpotPrices<T: Config> =
|
||||
StorageDoubleMap<_, Identity, Coin, Identity, [u8; 8], (), OptionQuery>;
|
||||
StorageDoubleMap<_, Identity, ExternalCoin, Identity, [u8; 8], (), OptionQuery>;
|
||||
|
||||
/// Current length of the `SpotPrices` map.
|
||||
#[pallet::storage]
|
||||
pub type SpotPricesLength<T: Config> = StorageMap<_, Identity, Coin, u16, OptionQuery>;
|
||||
pub type SpotPricesLength<T: Config> = StorageMap<_, Identity, ExternalCoin, u16, OptionQuery>;
|
||||
|
||||
/// Current position of the median within the `SpotPrices` map;
|
||||
#[pallet::storage]
|
||||
pub type CurrentMedianPosition<T: Config> = StorageMap<_, Identity, Coin, u16, OptionQuery>;
|
||||
pub type CurrentMedianPosition<T: Config> =
|
||||
StorageMap<_, Identity, ExternalCoin, u16, OptionQuery>;
|
||||
|
||||
/// Current median price of the prices in the `SpotPrices` map at any given time.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn median_price)]
|
||||
pub type MedianPrice<T: Config> = StorageMap<_, Identity, Coin, Amount, OptionQuery>;
|
||||
pub type MedianPrice<T: Config> = StorageMap<_, Identity, ExternalCoin, Amount, OptionQuery>;
|
||||
|
||||
/// The price used for evaluating economic security, which is the highest observed median price.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn security_oracle_value)]
|
||||
pub type SecurityOracleValue<T: Config> = StorageMap<_, Identity, Coin, Amount, OptionQuery>;
|
||||
pub type SecurityOracleValue<T: Config> =
|
||||
StorageMap<_, Identity, ExternalCoin, Amount, OptionQuery>;
|
||||
|
||||
/// Total swap volume of a given pool in terms of SRI.
|
||||
#[pallet::storage]
|
||||
@@ -205,7 +206,7 @@ pub mod pallet {
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
fn restore_median(
|
||||
coin: Coin,
|
||||
coin: ExternalCoin,
|
||||
mut current_median_pos: u16,
|
||||
mut current_median: Amount,
|
||||
length: u16,
|
||||
@@ -256,7 +257,7 @@ pub mod pallet {
|
||||
MedianPrice::<T>::set(coin, Some(current_median));
|
||||
}
|
||||
|
||||
pub(crate) fn insert_into_median(coin: Coin, amount: Amount) {
|
||||
pub(crate) fn insert_into_median(coin: ExternalCoin, amount: Amount) {
|
||||
let new_quantity_of_presences =
|
||||
SpotPrices::<T>::get(coin, amount.0.to_be_bytes()).unwrap_or(0) + 1;
|
||||
SpotPrices::<T>::set(coin, amount.0.to_be_bytes(), Some(new_quantity_of_presences));
|
||||
@@ -286,7 +287,7 @@ pub mod pallet {
|
||||
Self::restore_median(coin, current_median_pos, current_median, new_length);
|
||||
}
|
||||
|
||||
pub(crate) fn remove_from_median(coin: Coin, amount: Amount) {
|
||||
pub(crate) fn remove_from_median(coin: ExternalCoin, amount: Amount) {
|
||||
let mut current_median = MedianPrice::<T>::get(coin).unwrap();
|
||||
|
||||
let mut current_median_pos = CurrentMedianPosition::<T>::get(coin).unwrap();
|
||||
@@ -451,7 +452,7 @@ pub mod pallet {
|
||||
// insert the new price to our oracle window
|
||||
// The spot price for 1 coin, in atomic units, to SRI is used
|
||||
let sri_per_coin =
|
||||
if let Ok((sri_balance, coin_balance)) = Self::get_reserves(&Coin::native(), &coin) {
|
||||
if let Ok((sri_balance, coin_balance)) = Self::get_reserves(&Coin::Serai, &coin.into()) {
|
||||
// We use 1 coin to handle rounding errors which may occur with atomic units
|
||||
// If we used atomic units, any coin whose atomic unit is worth less than SRI's atomic
|
||||
// unit would cause a 'price' of 0
|
||||
@@ -493,9 +494,9 @@ 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(coin: Coin) -> DispatchResult {
|
||||
pub(crate) fn create_pool(coin: ExternalCoin) -> DispatchResult {
|
||||
// get pool_id
|
||||
let pool_id = Self::get_pool_id(coin, Coin::Serai)?;
|
||||
let pool_id = Self::get_pool_id(coin.into(), Coin::native())?;
|
||||
ensure!(!Pools::<T>::contains_key(pool_id), Error::<T>::PoolExists);
|
||||
|
||||
let pool_account = Self::get_pool_account(pool_id);
|
||||
@@ -508,9 +509,11 @@ pub mod pallet {
|
||||
|
||||
/// A hook to be called whenever a network's session is rotated.
|
||||
pub fn on_new_session(network: NetworkId) {
|
||||
// reset the oracle value
|
||||
for coin in network.coins() {
|
||||
SecurityOracleValue::<T>::set(*coin, Self::median_price(coin));
|
||||
// Only track the price for non-SRI coins as this is SRI denominated
|
||||
if let NetworkId::External(n) = network {
|
||||
for coin in n.coins() {
|
||||
SecurityOracleValue::<T>::set(coin, Self::median_price(coin));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,7 +535,7 @@ pub mod pallet {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn add_liquidity(
|
||||
origin: OriginFor<T>,
|
||||
coin: Coin,
|
||||
coin: ExternalCoin,
|
||||
coin_desired: SubstrateAmount,
|
||||
sri_desired: SubstrateAmount,
|
||||
coin_min: SubstrateAmount,
|
||||
@@ -542,7 +545,7 @@ pub mod pallet {
|
||||
let sender = ensure_signed(origin)?;
|
||||
ensure!((sri_desired > 0) && (coin_desired > 0), Error::<T>::WrongDesiredAmount);
|
||||
|
||||
let pool_id = Self::get_pool_id(coin, Coin::Serai)?;
|
||||
let pool_id = Self::get_pool_id(coin.into(), Coin::native())?;
|
||||
|
||||
// create the pool if it doesn't exist. We can just attempt to do that because our checks
|
||||
// far enough to allow that.
|
||||
@@ -552,7 +555,7 @@ pub mod pallet {
|
||||
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 coin_reserve = Self::get_balance(&pool_account, coin.into());
|
||||
|
||||
let sri_amount: SubstrateAmount;
|
||||
let coin_amount: SubstrateAmount;
|
||||
@@ -583,16 +586,20 @@ pub mod pallet {
|
||||
&pool_account,
|
||||
Balance { coin: Coin::Serai, amount: Amount(sri_amount) },
|
||||
)?;
|
||||
Self::transfer(&sender, &pool_account, Balance { coin, amount: Amount(coin_amount) })?;
|
||||
Self::transfer(
|
||||
&sender,
|
||||
&pool_account,
|
||||
Balance { coin: coin.into(), amount: Amount(coin_amount) },
|
||||
)?;
|
||||
|
||||
let total_supply = LiquidityTokens::<T>::supply(coin);
|
||||
let total_supply = LiquidityTokens::<T>::supply(Coin::from(coin));
|
||||
|
||||
let lp_token_amount: SubstrateAmount;
|
||||
if total_supply == 0 {
|
||||
lp_token_amount = Self::calc_lp_amount_for_zero_supply(sri_amount, coin_amount)?;
|
||||
LiquidityTokens::<T>::mint(
|
||||
pool_account,
|
||||
Balance { coin, amount: Amount(T::MintMinLiquidity::get()) },
|
||||
Balance { coin: coin.into(), amount: Amount(T::MintMinLiquidity::get()) },
|
||||
)?;
|
||||
} else {
|
||||
let side1 = Self::mul_div(sri_amount, total_supply, sri_reserve)?;
|
||||
@@ -605,7 +612,10 @@ pub mod pallet {
|
||||
Error::<T>::InsufficientLiquidityMinted
|
||||
);
|
||||
|
||||
LiquidityTokens::<T>::mint(mint_to, Balance { coin, amount: Amount(lp_token_amount) })?;
|
||||
LiquidityTokens::<T>::mint(
|
||||
mint_to,
|
||||
Balance { coin: coin.into(), amount: Amount(lp_token_amount) },
|
||||
)?;
|
||||
|
||||
Self::deposit_event(Event::LiquidityAdded {
|
||||
who: sender,
|
||||
@@ -626,25 +636,24 @@ pub mod pallet {
|
||||
#[pallet::weight(T::WeightInfo::remove_liquidity())]
|
||||
pub fn remove_liquidity(
|
||||
origin: OriginFor<T>,
|
||||
coin: Coin,
|
||||
coin: ExternalCoin,
|
||||
lp_token_burn: SubstrateAmount,
|
||||
coin_min_receive: SubstrateAmount,
|
||||
sri_min_receive: SubstrateAmount,
|
||||
withdraw_to: T::AccountId,
|
||||
) -> DispatchResult {
|
||||
let sender = ensure_signed(origin.clone())?;
|
||||
ensure!(coin != Coin::Serai, Error::<T>::EqualCoins);
|
||||
|
||||
let pool_id = Self::get_pool_id(coin, Coin::Serai).unwrap();
|
||||
let pool_id = Self::get_pool_id(coin.into(), Coin::native()).unwrap();
|
||||
ensure!(lp_token_burn > 0, Error::<T>::ZeroLiquidity);
|
||||
|
||||
Pools::<T>::get(pool_id).as_ref().ok_or(Error::<T>::PoolNotFound)?;
|
||||
|
||||
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 coin_reserve = Self::get_balance(&pool_account, coin.into());
|
||||
|
||||
let total_supply = LiquidityTokens::<T>::supply(coin);
|
||||
let total_supply = LiquidityTokens::<T>::supply(Coin::from(coin));
|
||||
let lp_redeem_amount = lp_token_burn;
|
||||
|
||||
let sri_amount = Self::mul_div(lp_redeem_amount, sri_reserve, total_supply)?;
|
||||
@@ -665,14 +674,21 @@ pub mod pallet {
|
||||
ensure!(coin_reserve_left >= 1, Error::<T>::ReserveLeftLessThanMinimum);
|
||||
|
||||
// burn the provided lp token amount that includes the fee
|
||||
LiquidityTokens::<T>::burn(origin, Balance { coin, amount: Amount(lp_token_burn) })?;
|
||||
LiquidityTokens::<T>::burn(
|
||||
origin,
|
||||
Balance { coin: coin.into(), amount: Amount(lp_token_burn) },
|
||||
)?;
|
||||
|
||||
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::transfer(
|
||||
&pool_account,
|
||||
&withdraw_to,
|
||||
Balance { coin: coin.into(), amount: Amount(coin_amount) },
|
||||
)?;
|
||||
|
||||
Self::deposit_event(Event::LiquidityRemoved {
|
||||
who: sender,
|
||||
@@ -920,11 +936,9 @@ pub mod pallet {
|
||||
pub fn get_pool_id(coin1: Coin, coin2: Coin) -> Result<PoolId, Error<T>> {
|
||||
ensure!((coin1 == Coin::Serai) || (coin2 == Coin::Serai), Error::<T>::PoolNotFound);
|
||||
ensure!(coin1 != coin2, Error::<T>::EqualCoins);
|
||||
if coin1 == Coin::Serai {
|
||||
Ok(coin2)
|
||||
} else {
|
||||
Ok(coin1)
|
||||
}
|
||||
ExternalCoin::try_from(coin1)
|
||||
.or_else(|()| ExternalCoin::try_from(coin2))
|
||||
.map_err(|()| Error::<T>::PoolNotFound)
|
||||
}
|
||||
|
||||
/// Returns the balance of each coin in the pool.
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
// 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 crate::{mock::*, *};
|
||||
use crate::{
|
||||
mock::{*, MEDIAN_PRICE_WINDOW_LENGTH},
|
||||
*,
|
||||
};
|
||||
use frame_support::{assert_noop, assert_ok};
|
||||
|
||||
pub use coins_pallet as coins;
|
||||
@@ -72,11 +75,13 @@ fn check_pool_accounts_dont_collide() {
|
||||
let mut map = HashSet::new();
|
||||
|
||||
for coin in coins() {
|
||||
let account = Dex::get_pool_account(coin);
|
||||
if map.contains(&account) {
|
||||
panic!("Collision at {coin:?}");
|
||||
if let Coin::External(c) = coin {
|
||||
let account = Dex::get_pool_account(c);
|
||||
if map.contains(&account) {
|
||||
panic!("Collision at {c:?}");
|
||||
}
|
||||
map.insert(account);
|
||||
}
|
||||
map.insert(account);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,11 +103,11 @@ fn can_create_pool() {
|
||||
let coin_account_deposit: u64 = 0;
|
||||
let user: PublicKey = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Monero;
|
||||
let coin2 = Coin::External(ExternalCoin::Monero);
|
||||
let pool_id = Dex::get_pool_id(coin1, coin2).unwrap();
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(1000) }));
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_eq!(balance(user, coin1), 1000 - coin_account_deposit);
|
||||
|
||||
@@ -111,15 +116,13 @@ fn can_create_pool() {
|
||||
[Event::<Test>::PoolCreated { pool_id, pool_account: Dex::get_pool_account(pool_id) }]
|
||||
);
|
||||
assert_eq!(pools(), vec![pool_id]);
|
||||
|
||||
assert_noop!(Dex::create_pool(coin1), Error::<Test>::EqualCoins);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_same_pool_twice_should_fail() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let coin = Coin::Dai;
|
||||
let coin = ExternalCoin::Dai;
|
||||
assert_ok!(Dex::create_pool(coin));
|
||||
assert_noop!(Dex::create_pool(coin), Error::<Test>::PoolExists);
|
||||
});
|
||||
@@ -129,13 +132,13 @@ fn create_same_pool_twice_should_fail() {
|
||||
fn different_pools_should_have_different_lp_tokens() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Bitcoin;
|
||||
let coin3 = Coin::Ether;
|
||||
let coin2 = Coin::External(ExternalCoin::Bitcoin);
|
||||
let coin3 = Coin::External(ExternalCoin::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 = coin2;
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
let lp_token3_1 = coin3;
|
||||
|
||||
assert_eq!(
|
||||
@@ -146,7 +149,7 @@ fn different_pools_should_have_different_lp_tokens() {
|
||||
}]
|
||||
);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin3));
|
||||
assert_ok!(Dex::create_pool(coin3.try_into().unwrap()));
|
||||
assert_eq!(
|
||||
events(),
|
||||
[Event::<Test>::PoolCreated {
|
||||
@@ -164,13 +167,13 @@ fn can_add_liquidity() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Dai;
|
||||
let coin3 = Coin::Monero;
|
||||
let coin2 = Coin::External(ExternalCoin::Dai);
|
||||
let coin3 = Coin::External(ExternalCoin::Monero);
|
||||
|
||||
let lp_token1 = coin2;
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
let lp_token2 = coin3;
|
||||
assert_ok!(Dex::create_pool(coin3));
|
||||
assert_ok!(Dex::create_pool(coin3.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(
|
||||
user,
|
||||
@@ -179,7 +182,15 @@ fn can_add_liquidity() {
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin3, amount: Amount(1000) }));
|
||||
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2.try_into().unwrap(),
|
||||
10,
|
||||
10000,
|
||||
10,
|
||||
10000,
|
||||
user,
|
||||
));
|
||||
|
||||
let pool_id = Dex::get_pool_id(coin1, coin2).unwrap();
|
||||
assert!(events().contains(&Event::<Test>::LiquidityAdded {
|
||||
@@ -198,7 +209,15 @@ fn can_add_liquidity() {
|
||||
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), coin3, 10, 10000, 10, 10000, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin3.try_into().unwrap(),
|
||||
10,
|
||||
10000,
|
||||
10,
|
||||
10000,
|
||||
user,
|
||||
));
|
||||
|
||||
let pool_id = Dex::get_pool_id(coin1, coin3).unwrap();
|
||||
assert!(events().contains(&Event::<Test>::LiquidityAdded {
|
||||
@@ -223,12 +242,15 @@ fn add_tiny_liquidity_leads_to_insufficient_liquidity_minted_error() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Bitcoin;
|
||||
let coin2 = ExternalCoin::Bitcoin;
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(1000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(
|
||||
user,
|
||||
Balance { coin: coin2.into(), amount: Amount(1000) }
|
||||
));
|
||||
|
||||
assert_noop!(
|
||||
Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 1, 1, 1, 1, user),
|
||||
@@ -242,11 +264,11 @@ fn add_tiny_liquidity_directly_to_pool_address() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Ether;
|
||||
let coin3 = Coin::Dai;
|
||||
let coin2 = Coin::External(ExternalCoin::Ether);
|
||||
let coin3 = Coin::External(ExternalCoin::Dai);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin3));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
assert_ok!(Dex::create_pool(coin3.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(10000 * 2) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(10000) }));
|
||||
@@ -259,7 +281,15 @@ fn add_tiny_liquidity_directly_to_pool_address() {
|
||||
Balance { coin: coin1, amount: Amount(1000) }
|
||||
));
|
||||
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2.try_into().unwrap(),
|
||||
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());
|
||||
@@ -267,7 +297,15 @@ fn add_tiny_liquidity_directly_to_pool_address() {
|
||||
pallet_account,
|
||||
Balance { coin: coin2, amount: Amount(1) }
|
||||
));
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin3, 10, 10000, 10, 10000, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin3.try_into().unwrap(),
|
||||
10,
|
||||
10000,
|
||||
10,
|
||||
10000,
|
||||
user,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -276,11 +314,11 @@ fn can_remove_liquidity() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Monero;
|
||||
let coin2 = Coin::External(ExternalCoin::Monero);
|
||||
let pool_id = Dex::get_pool_id(coin1, coin2).unwrap();
|
||||
|
||||
let lp_token = coin2;
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(
|
||||
user,
|
||||
@@ -290,7 +328,7 @@ fn can_remove_liquidity() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
100000,
|
||||
1000000000,
|
||||
100000,
|
||||
@@ -302,7 +340,7 @@ fn can_remove_liquidity() {
|
||||
|
||||
assert_ok!(Dex::remove_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
total_lp_received,
|
||||
0,
|
||||
0,
|
||||
@@ -334,15 +372,23 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Dai;
|
||||
let coin2 = Coin::External(ExternalCoin::Dai);
|
||||
let lp_token = coin2;
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(10000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 10, 10000, 10, 10000, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2.try_into().unwrap(),
|
||||
10,
|
||||
10000,
|
||||
10,
|
||||
10000,
|
||||
user,
|
||||
));
|
||||
|
||||
// Only 216 lp_tokens_minted
|
||||
assert_eq!(pool_balance(user, lp_token), 216);
|
||||
@@ -350,7 +396,7 @@ fn can_not_redeem_more_lp_tokens_than_were_minted() {
|
||||
assert_noop!(
|
||||
Dex::remove_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
216 + 1, // Try and redeem 10 lp tokens while only 9 minted.
|
||||
0,
|
||||
0,
|
||||
@@ -366,14 +412,22 @@ fn can_quote_price() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Ether;
|
||||
let coin2 = Coin::External(ExternalCoin::Ether);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(100000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2.try_into().unwrap(),
|
||||
200,
|
||||
10000,
|
||||
1,
|
||||
1,
|
||||
user,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Dex::quote_price_exact_tokens_for_tokens(Coin::native(), coin2, 3000, false,),
|
||||
@@ -481,14 +535,22 @@ fn quote_price_exact_tokens_for_tokens_matches_execution() {
|
||||
let user = system_address(b"user1").into();
|
||||
let user2 = system_address(b"user2").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Bitcoin;
|
||||
let coin2 = Coin::External(ExternalCoin::Bitcoin);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(100000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2.try_into().unwrap(),
|
||||
200,
|
||||
10000,
|
||||
1,
|
||||
1,
|
||||
user,
|
||||
));
|
||||
|
||||
let amount = 1;
|
||||
let quoted_price = 49;
|
||||
@@ -518,14 +580,22 @@ fn quote_price_tokens_for_exact_tokens_matches_execution() {
|
||||
let user = system_address(b"user1").into();
|
||||
let user2 = system_address(b"user2").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Monero;
|
||||
let coin2 = Coin::External(ExternalCoin::Monero);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(100000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 200, 10000, 1, 1, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2.try_into().unwrap(),
|
||||
200,
|
||||
10000,
|
||||
1,
|
||||
1,
|
||||
user,
|
||||
));
|
||||
|
||||
let amount = 49;
|
||||
let quoted_price = 1;
|
||||
@@ -557,10 +627,10 @@ fn can_swap_with_native() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Ether;
|
||||
let coin2 = Coin::External(ExternalCoin::Ether);
|
||||
let pool_id = Dex::get_pool_id(coin1, coin2).unwrap();
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(10000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
@@ -570,7 +640,7 @@ fn can_swap_with_native() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -602,8 +672,8 @@ fn can_swap_with_realistic_values() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let sri = Coin::native();
|
||||
let dai = Coin::Dai;
|
||||
assert_ok!(Dex::create_pool(dai));
|
||||
let dai = Coin::External(ExternalCoin::Dai);
|
||||
assert_ok!(Dex::create_pool(dai.try_into().unwrap()));
|
||||
|
||||
const UNIT: u64 = 1_000_000_000;
|
||||
|
||||
@@ -620,7 +690,7 @@ fn can_swap_with_realistic_values() {
|
||||
let liquidity_dai = 1_000_000 * UNIT;
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
dai,
|
||||
dai.try_into().unwrap(),
|
||||
liquidity_dai,
|
||||
liquidity_sri,
|
||||
1,
|
||||
@@ -653,9 +723,9 @@ fn can_not_swap_in_pool_with_no_liquidity_added_yet() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Monero;
|
||||
let coin2 = Coin::External(ExternalCoin::Monero);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
// Check can't swap an empty pool
|
||||
assert_noop!(
|
||||
@@ -676,11 +746,11 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Bitcoin;
|
||||
let coin2 = Coin::External(ExternalCoin::Bitcoin);
|
||||
let pool_id = Dex::get_pool_id(coin1, coin2).unwrap();
|
||||
let lp_token = coin2;
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(10000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
@@ -690,7 +760,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -714,7 +784,7 @@ fn check_no_panic_when_try_swap_close_to_empty_pool() {
|
||||
|
||||
assert_ok!(Dex::remove_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
lp_token_minted,
|
||||
1,
|
||||
1,
|
||||
@@ -787,9 +857,9 @@ fn swap_should_not_work_if_too_much_slippage() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Ether;
|
||||
let coin2 = Coin::External(ExternalCoin::Ether);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(10000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
@@ -799,7 +869,7 @@ fn swap_should_not_work_if_too_much_slippage() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -827,10 +897,10 @@ fn can_swap_tokens_for_exact_tokens() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Dai;
|
||||
let coin2 = Coin::External(ExternalCoin::Dai);
|
||||
let pool_id = Dex::get_pool_id(coin1, coin2).unwrap();
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(20000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
@@ -844,7 +914,7 @@ fn can_swap_tokens_for_exact_tokens() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -882,11 +952,11 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() {
|
||||
let user = system_address(b"user1").into();
|
||||
let user2 = system_address(b"user2").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Monero;
|
||||
let coin2 = Coin::External(ExternalCoin::Monero);
|
||||
let pool_id = Dex::get_pool_id(coin1, coin2).unwrap();
|
||||
let lp_token = coin2;
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
let base1 = 10000;
|
||||
let base2 = 1000;
|
||||
@@ -903,7 +973,7 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user2),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -947,7 +1017,7 @@ fn can_swap_tokens_for_exact_tokens_when_not_liquidity_provider() {
|
||||
|
||||
assert_ok!(Dex::remove_liquidity(
|
||||
RuntimeOrigin::signed(user2),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
lp_token_minted,
|
||||
0,
|
||||
0,
|
||||
@@ -961,9 +1031,9 @@ 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 coin1 = Coin::native();
|
||||
let coin2 = Coin::Ether;
|
||||
let coin2 = Coin::External(ExternalCoin::Ether);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(20000) }));
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin2, amount: Amount(1000) }));
|
||||
@@ -973,7 +1043,7 @@ fn swap_tokens_for_exact_tokens_should_not_work_if_too_much_slippage() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -1001,11 +1071,11 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Dai;
|
||||
let coin3 = Coin::Monero;
|
||||
let coin2 = Coin::External(ExternalCoin::Dai);
|
||||
let coin3 = Coin::External(ExternalCoin::Monero);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin3));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
assert_ok!(Dex::create_pool(coin3.try_into().unwrap()));
|
||||
|
||||
let base1 = 10000;
|
||||
let base2 = 10000;
|
||||
@@ -1019,7 +1089,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -1028,7 +1098,7 @@ fn swap_exact_tokens_for_tokens_in_multi_hops() {
|
||||
));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin3,
|
||||
coin3.try_into().unwrap(),
|
||||
liquidity3,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -1089,11 +1159,11 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let user = system_address(b"user1").into();
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Bitcoin;
|
||||
let coin3 = Coin::Ether;
|
||||
let coin2 = Coin::External(ExternalCoin::Bitcoin);
|
||||
let coin3 = Coin::External(ExternalCoin::Ether);
|
||||
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin3));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
assert_ok!(Dex::create_pool(coin3.try_into().unwrap()));
|
||||
|
||||
let base1 = 10000;
|
||||
let base2 = 10000;
|
||||
@@ -1107,7 +1177,7 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() {
|
||||
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2,
|
||||
coin2.try_into().unwrap(),
|
||||
liquidity2,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -1116,7 +1186,7 @@ fn swap_tokens_for_exact_tokens_in_multi_hops() {
|
||||
));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin3,
|
||||
coin3.try_into().unwrap(),
|
||||
liquidity3,
|
||||
liquidity1,
|
||||
1,
|
||||
@@ -1154,7 +1224,7 @@ 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 coin1 = Coin::Dai;
|
||||
let coin1 = Coin::External(ExternalCoin::Dai);
|
||||
assert_ok!(CoinsPallet::<Test>::mint(user, Balance { coin: coin1, amount: Amount(1000) }));
|
||||
|
||||
let exchange_amount = 10;
|
||||
@@ -1188,10 +1258,10 @@ fn validate_pool_id_sorting() {
|
||||
// Serai < Bitcoin < Ether < Dai < Monero.
|
||||
// coin1 <= coin2 for this test to pass.
|
||||
let native = Coin::native();
|
||||
let coin1 = Coin::Bitcoin;
|
||||
let coin2 = Coin::Monero;
|
||||
assert_eq!(Dex::get_pool_id(native, coin2).unwrap(), coin2);
|
||||
assert_eq!(Dex::get_pool_id(coin2, native).unwrap(), coin2);
|
||||
let coin1 = Coin::External(ExternalCoin::Bitcoin);
|
||||
let coin2 = Coin::External(ExternalCoin::Monero);
|
||||
assert_eq!(Dex::get_pool_id(native, coin2).unwrap(), coin2.try_into().unwrap());
|
||||
assert_eq!(Dex::get_pool_id(coin2, native).unwrap(), coin2.try_into().unwrap());
|
||||
assert!(matches!(Dex::get_pool_id(native, native), Err(Error::<Test>::EqualCoins)));
|
||||
assert!(matches!(Dex::get_pool_id(coin2, coin1), Err(Error::<Test>::PoolNotFound)));
|
||||
assert!(coin2 > coin1);
|
||||
@@ -1216,7 +1286,7 @@ fn cannot_block_pool_creation() {
|
||||
|
||||
// The target pool the user wants to create is Native <=> Coin(2)
|
||||
let coin1 = Coin::native();
|
||||
let coin2 = Coin::Ether;
|
||||
let coin2 = Coin::External(ExternalCoin::Ether);
|
||||
|
||||
// Attacker computes the still non-existing pool account for the target pair
|
||||
let pool_account = Dex::get_pool_account(Dex::get_pool_id(coin2, coin1).unwrap());
|
||||
@@ -1238,7 +1308,7 @@ fn cannot_block_pool_creation() {
|
||||
}
|
||||
|
||||
// User can still create the pool
|
||||
assert_ok!(Dex::create_pool(coin2));
|
||||
assert_ok!(Dex::create_pool(coin2.try_into().unwrap()));
|
||||
|
||||
// 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.
|
||||
@@ -1256,7 +1326,15 @@ fn cannot_block_pool_creation() {
|
||||
));
|
||||
|
||||
// add_liquidity shouldn't fail because of the number of consumers
|
||||
assert_ok!(Dex::add_liquidity(RuntimeOrigin::signed(user), coin2, 100, 9900, 10, 9900, user,));
|
||||
assert_ok!(Dex::add_liquidity(
|
||||
RuntimeOrigin::signed(user),
|
||||
coin2.try_into().unwrap(),
|
||||
100,
|
||||
9900,
|
||||
10,
|
||||
9900,
|
||||
user,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1281,7 +1359,7 @@ fn test_median_price() {
|
||||
prices.push(OsRng.next_u64());
|
||||
}
|
||||
}
|
||||
let coin = Coin::Bitcoin;
|
||||
let coin = ExternalCoin::Bitcoin;
|
||||
|
||||
assert!(prices.len() >= (2 * usize::from(MEDIAN_PRICE_WINDOW_LENGTH)));
|
||||
for i in 0 .. prices.len() {
|
||||
|
||||
Reference in New Issue
Block a user