diff --git a/Cargo.lock b/Cargo.lock index aeb03543a..22b4fa212 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14332,6 +14332,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "sp-arithmetic", "sp-core", "sp-runtime", "test-case", @@ -14627,6 +14628,7 @@ dependencies = [ "arbitrary", "frame-support", "libfuzzer-sys", + "sp-arithmetic", "zeitgeist-primitives", "zrml-prediction-markets", "zrml-simple-disputes", @@ -14726,6 +14728,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-api", + "sp-arithmetic", "sp-io", "sp-runtime", "substrate-fixed", diff --git a/docs/changelog_for_devs.md b/docs/changelog_for_devs.md index 953ffe489..fbdf342e4 100644 --- a/docs/changelog_for_devs.md +++ b/docs/changelog_for_devs.md @@ -34,6 +34,27 @@ All things about Global Disputes Fix ⚠️ : ### Added +- Add market creator incentives. + - The following dispatchable calls within the prediction markets pallet now + expect a market creator fee denoted as type `Perbill` after the `base_asset` + parameter. The fee is bounded by the pallet's `Config` parameter + `MaxCreatorFee`: + - `create_market` + - `create_cpmm_market_and_deploy_assets` + - The market type now holds an additional field `creator_fee` using the type + `Perbill` after the `creation` field. + - The swaps pallet's `Config` parameter `MaxSwapFee` now is a boundary for the + sum of all fees, currently the liqudity provider fee and the market creator + fee. It is checked during the execution of the public function + `create_pool`. + - Fees are always transferred from the trader's account to the market + creator's account either before or after the trade. The base asset is always + preferred to pay fees. If the trade does not include the base asset, the + pallet will try to convert the outcome asset to the base asset by executing + a swap. + - A new event `MarketCreatorFeesPaid` is emitted by the swaps pallet after + successful payment of fees to the market creator. It contains the fields + `\[payer, payee, amount, asset\]`. - ⚠️ Add court production implementation ([#976]). Dispatchable calls are: - `join_court` - Join the court with a stake to become a juror in order to get the stake-weighted chance to be selected for decision making. diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 0e44d19a0..8e7eb15c7 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -8,6 +8,7 @@ orml-traits = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive", "max-encoded-len"] } scale-info = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"], optional = true } +sp-arithmetic = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } diff --git a/primitives/src/constants/mock.rs b/primitives/src/constants/mock.rs index 05626c688..2bfae8ecc 100644 --- a/primitives/src/constants/mock.rs +++ b/primitives/src/constants/mock.rs @@ -25,6 +25,7 @@ use crate::{ }; use frame_support::{parameter_types, traits::LockIdentifier, PalletId}; use orml_traits::parameter_type_with_key; +use sp_arithmetic::Perbill; // Authorized parameter_types! { @@ -75,6 +76,7 @@ parameter_types! { pub const DisputeBond: Balance = 5 * BASE; pub const DisputeFactor: Balance = 2 * BASE; pub const MaxCategories: u16 = 10; + pub const MaxCreatorFee: Perbill = Perbill::from_percent(1); pub const MaxDisputeDuration: BlockNumber = 50; pub const MaxDisputes: u16 = 6; pub const MaxEditReasonLen: u32 = 1024; diff --git a/primitives/src/market.rs b/primitives/src/market.rs index 3deb85494..c590c0d54 100644 --- a/primitives/src/market.rs +++ b/primitives/src/market.rs @@ -21,12 +21,13 @@ use alloc::vec::Vec; use core::ops::{Range, RangeInclusive}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_arithmetic::per_things::Perbill; use sp_runtime::RuntimeDebug; /// Types /// /// * `AI`: Account id -/// * `BA`: Balance type for bonds +/// * `BA`: Balance type /// * `BN`: Block number /// * `M`: Moment (time moment) /// * `A`: Asset @@ -38,8 +39,8 @@ pub struct Market { pub creator: AI, /// Creation type. pub creation: MarketCreation, - /// The fee the creator gets from each winning share. - pub creator_fee: u8, + /// A fee that is charged each trade and given to the market creator. + pub creator_fee: Perbill, /// Oracle that reports the outcome of this market. pub oracle: AI, /// Metadata for the market, usually a content address of IPFS @@ -150,7 +151,7 @@ where AI::max_encoded_len() .saturating_add(A::max_encoded_len()) .saturating_add(MarketCreation::max_encoded_len()) - .saturating_add(u8::max_encoded_len()) + .saturating_add(Perbill::max_encoded_len()) .saturating_add(AI::max_encoded_len()) // We assume that at max. a 512 bit hash function is used .saturating_add(u8::max_encoded_len().saturating_mul(68)) @@ -378,7 +379,7 @@ mod tests { base_asset: Asset::Ztg, creator: 1, creation: MarketCreation::Permissionless, - creator_fee: 2, + creator_fee: Default::default(), oracle: 3, metadata: vec![4u8; 5], market_type, // : MarketType::Categorical(6), diff --git a/primitives/src/traits/swaps.rs b/primitives/src/traits/swaps.rs index 007808286..b193dcfb0 100644 --- a/primitives/src/traits/swaps.rs +++ b/primitives/src/traits/swaps.rs @@ -1,3 +1,4 @@ +// Copyright 2023 Forecasting Technologies LTD. // Copyright 2021-2022 Zeitgeist PM LLC. // // This file is part of Zeitgeist. @@ -152,6 +153,8 @@ pub trait Swaps { /// * `asset_out`: Asset leaving the pool. /// * `min_asset_amount_out`: Minimum asset amount that can leave the pool. /// * `max_price`: Market price must be equal or less than the provided value. + /// * `handle_fees`: Whether additional fees are handled or not (sets LP fee to 0) + #[allow(clippy::too_many_arguments)] fn swap_exact_amount_in( who: AccountId, pool_id: PoolId, @@ -160,6 +163,7 @@ pub trait Swaps { asset_out: Asset, min_asset_amount_out: Option, max_price: Option, + handle_fees: bool, ) -> Result; /// Swap - Exact amount out @@ -175,6 +179,8 @@ pub trait Swaps { /// * `asset_out`: Asset leaving the pool. /// * `asset_amount_out`: Amount that will be transferred from the pool to the provider. /// * `max_price`: Market price must be equal or less than the provided value. + /// * `handle_fees`: Whether additional fees are handled or not (sets LP fee to 0) + #[allow(clippy::too_many_arguments)] fn swap_exact_amount_out( who: AccountId, pool_id: PoolId, @@ -183,5 +189,6 @@ pub trait Swaps { asset_out: Asset, asset_amount_out: Self::Balance, max_price: Option, + handle_fees: bool, ) -> Result; } diff --git a/runtime/battery-station/src/parameters.rs b/runtime/battery-station/src/parameters.rs index b3317c3bc..adf67ddaa 100644 --- a/runtime/battery-station/src/parameters.rs +++ b/runtime/battery-station/src/parameters.rs @@ -205,6 +205,8 @@ parameter_types! { pub const DisputeBond: Balance = 25 * BASE; /// Maximum Categories a prediciton market can have (excluding base asset). pub const MaxCategories: u16 = MAX_CATEGORIES; + /// Max creator fee, bounds the fraction per trade volume that is moved to the market creator. + pub const MaxCreatorFee: Perbill = Perbill::from_percent(1); /// Maximum block period for a dispute. pub const MaxDisputeDuration: BlockNumber = MAX_DISPUTE_DURATION; /// Maximum number of disputes. diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index c43311299..bc33c2c17 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -60,8 +60,8 @@ macro_rules! decl_common_types { orml_asset_registry::Migration, orml_unknown_tokens::Migration, pallet_xcm::migration::v1::MigrateToV1, - // IMPORTANT that AddDisputeBond comes before MoveDataToSimpleDisputes!!! - zrml_prediction_markets::migrations::AddDisputeBond, + // IMPORTANT that AddDisputeBondAndConvertCreatorFee comes before MoveDataToSimpleDisputes!!! + zrml_prediction_markets::migrations::AddDisputeBondAndConvertCreatorFee, zrml_prediction_markets::migrations::MoveDataToSimpleDisputes, zrml_global_disputes::migrations::ModifyGlobalDisputesStructures, ); @@ -69,8 +69,8 @@ macro_rules! decl_common_types { #[cfg(not(feature = "parachain"))] type Migrations = ( pallet_grandpa::migrations::CleanupSetIdSessionMap, - // IMPORTANT that AddDisputeBond comes before MoveDataToSimpleDisputes!!! - zrml_prediction_markets::migrations::AddDisputeBond, + // IMPORTANT that AddDisputeBondAndConvertCreatorFee comes before MoveDataToSimpleDisputes!!! + zrml_prediction_markets::migrations::AddDisputeBondAndConvertCreatorFee, zrml_prediction_markets::migrations::MoveDataToSimpleDisputes, zrml_global_disputes::migrations::ModifyGlobalDisputesStructures, ); @@ -1126,6 +1126,7 @@ macro_rules! impl_config_traits { type LiquidityMining = NoopLiquidityMining; // type LiquidityMining = LiquidityMining; type MaxCategories = MaxCategories; + type MaxCreatorFee = MaxCreatorFee; type MaxDisputes = MaxDisputes; type MaxMarketLifetime = MaxMarketLifetime; type MinDisputeDuration = MinDisputeDuration; diff --git a/runtime/zeitgeist/src/parameters.rs b/runtime/zeitgeist/src/parameters.rs index 2afd3dc66..2406637e2 100644 --- a/runtime/zeitgeist/src/parameters.rs +++ b/runtime/zeitgeist/src/parameters.rs @@ -205,6 +205,8 @@ parameter_types! { pub const DisputeBond: Balance = 2_000 * BASE; /// Maximum Categories a prediciton market can have (excluding base asset). pub const MaxCategories: u16 = MAX_CATEGORIES; + /// Max creator fee, bounds the fraction per trade volume that is moved to the market creator. + pub const MaxCreatorFee: Perbill = Perbill::from_percent(1); /// Maximum block period for a dispute. pub const MaxDisputeDuration: BlockNumber = MAX_DISPUTE_DURATION; /// Maximum number of disputes. diff --git a/zrml/authorized/src/lib.rs b/zrml/authorized/src/lib.rs index 1dc53f750..b5b13b02e 100644 --- a/zrml/authorized/src/lib.rs +++ b/zrml/authorized/src/lib.rs @@ -382,7 +382,7 @@ where zeitgeist_primitives::types::Market { base_asset: Asset::Ztg, creation: zeitgeist_primitives::types::MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: sp_runtime::Perbill::zero(), creator: T::PalletId::get().into_account_truncating(), market_type: zeitgeist_primitives::types::MarketType::Scalar(0..=100), dispute_mechanism: zeitgeist_primitives::types::MarketDisputeMechanism::Authorized, diff --git a/zrml/court/src/benchmarks.rs b/zrml/court/src/benchmarks.rs index d18860390..fdc20aae2 100644 --- a/zrml/court/src/benchmarks.rs +++ b/zrml/court/src/benchmarks.rs @@ -56,7 +56,7 @@ where Market { base_asset: Asset::Ztg, creation: MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: sp_runtime::Perbill::zero(), creator: account("creator", 0, 0), market_type: MarketType::Scalar(0..=100), dispute_mechanism: MarketDisputeMechanism::Court, diff --git a/zrml/court/src/tests.rs b/zrml/court/src/tests.rs index 61fb11d2d..72fd7a378 100644 --- a/zrml/court/src/tests.rs +++ b/zrml/court/src/tests.rs @@ -64,7 +64,7 @@ const ORACLE_REPORT: OutcomeReport = OutcomeReport::Scalar(u128::MAX); const DEFAULT_MARKET: MarketOf = Market { base_asset: Asset::Ztg, creation: MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: sp_runtime::Perbill::zero(), creator: 0, market_type: MarketType::Scalar(0..=100), dispute_mechanism: MarketDisputeMechanism::Court, diff --git a/zrml/global-disputes/src/utils.rs b/zrml/global-disputes/src/utils.rs index fd0fc7bbb..866bb06e5 100644 --- a/zrml/global-disputes/src/utils.rs +++ b/zrml/global-disputes/src/utils.rs @@ -42,7 +42,7 @@ where zeitgeist_primitives::types::Market { base_asset: zeitgeist_primitives::types::Asset::Ztg, creation: zeitgeist_primitives::types::MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: sp_runtime::Perbill::zero(), creator: T::GlobalDisputesPalletId::get().into_account_truncating(), market_type: zeitgeist_primitives::types::MarketType::Scalar(0..=u128::MAX), dispute_mechanism: zeitgeist_primitives::types::MarketDisputeMechanism::SimpleDisputes, diff --git a/zrml/liquidity-mining/src/tests.rs b/zrml/liquidity-mining/src/tests.rs index c4c2deb76..380ed39dc 100644 --- a/zrml/liquidity-mining/src/tests.rs +++ b/zrml/liquidity-mining/src/tests.rs @@ -205,7 +205,7 @@ fn create_default_market(market_id: u128, period: Range) { Market { base_asset: Asset::Ztg, creation: MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: sp_runtime::Perbill::zero(), creator: 0, market_type: MarketType::Categorical(0), dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, diff --git a/zrml/market-commons/src/tests.rs b/zrml/market-commons/src/tests.rs index 61c5feb5e..a65462392 100644 --- a/zrml/market-commons/src/tests.rs +++ b/zrml/market-commons/src/tests.rs @@ -23,7 +23,7 @@ use crate::{ MarketCounter, Markets, }; use frame_support::{assert_err, assert_noop, assert_ok}; -use sp_runtime::DispatchError; +use sp_runtime::{DispatchError, Perbill}; use zeitgeist_primitives::{ traits::MarketCommonsPalletApi, types::{ @@ -36,7 +36,7 @@ use zeitgeist_primitives::{ const MARKET_DUMMY: Market> = Market { base_asset: Asset::Ztg, creation: MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: Perbill::zero(), creator: 0, market_type: MarketType::Scalar(0..=100), dispute_mechanism: MarketDisputeMechanism::Authorized, diff --git a/zrml/prediction-markets/fuzz/Cargo.toml b/zrml/prediction-markets/fuzz/Cargo.toml index 8e256abd3..4f88a31d2 100644 --- a/zrml/prediction-markets/fuzz/Cargo.toml +++ b/zrml/prediction-markets/fuzz/Cargo.toml @@ -8,6 +8,7 @@ test = false arbitrary = { workspace = true, features = ["derive"] } frame-support = { workspace = true, features = ["default"] } libfuzzer-sys = { workspace = true } +sp-arithmetic = { workspace = true, features = ["default"] } zeitgeist-primitives = { workspace = true, features = ["arbitrary", "mock", "default"] } zrml-prediction-markets = { workspace = true, features = ["mock", "default"] } zrml-simple-disputes = { workspace = true, features = ["default"] } diff --git a/zrml/prediction-markets/fuzz/pm_full_workflow.rs b/zrml/prediction-markets/fuzz/pm_full_workflow.rs index 9f4b04df5..7bb2df0e7 100644 --- a/zrml/prediction-markets/fuzz/pm_full_workflow.rs +++ b/zrml/prediction-markets/fuzz/pm_full_workflow.rs @@ -22,9 +22,13 @@ use arbitrary::Arbitrary; use core::ops::{Range, RangeInclusive}; use frame_support::traits::Hooks; use libfuzzer_sys::fuzz_target; -use zeitgeist_primitives::types::{ - Asset, Deadlines, MarketCreation, MarketDisputeMechanism, MarketPeriod, MarketType, MultiHash, - OutcomeReport, ScoringRule, +use sp_arithmetic::Perbill; +use zeitgeist_primitives::{ + constants::mock::MaxCreatorFee, + types::{ + Asset, Deadlines, MarketCreation, MarketDisputeMechanism, MarketPeriod, MarketType, + MultiHash, OutcomeReport, ScoringRule, + }, }; use zrml_prediction_markets::mock::{ExtBuilder, PredictionMarkets, RuntimeOrigin, System}; @@ -39,9 +43,13 @@ fuzz_target!(|data: Data| { oracle_duration: 1_u32.into(), dispute_duration: 3_u32.into(), }; + let max_parts_per_bill = MaxCreatorFee::get().deconstruct(); + let bounded_parts = data.create_scalar_market_fee % max_parts_per_bill as u128; + let fee = Perbill::from_parts(bounded_parts.try_into().unwrap()); let _ = PredictionMarkets::create_market( RuntimeOrigin::signed(data.create_scalar_market_origin.into()), Asset::Ztg, + fee, data.create_scalar_market_oracle.into(), MarketPeriod::Block(data.create_scalar_market_period), deadlines, @@ -95,6 +103,7 @@ fuzz_target!(|data: Data| { struct Data { create_scalar_market_origin: u8, create_scalar_market_oracle: u8, + create_scalar_market_fee: u128, create_scalar_market_period: Range, create_scalar_market_metadata: MultiHash, create_scalar_market_creation: u8, diff --git a/zrml/prediction-markets/src/benchmarks.rs b/zrml/prediction-markets/src/benchmarks.rs index db2284574..dea996ae6 100644 --- a/zrml/prediction-markets/src/benchmarks.rs +++ b/zrml/prediction-markets/src/benchmarks.rs @@ -34,7 +34,10 @@ use frame_support::{ }; use frame_system::RawOrigin; use orml_traits::MultiCurrency; -use sp_runtime::traits::{One, SaturatedConversion, Saturating, Zero}; +use sp_runtime::{ + traits::{One, SaturatedConversion, Saturating, Zero}, + Perbill, +}; use zeitgeist_primitives::{ constants::mock::{MaxSwapFee, MinWeight, BASE, MILLISECS_PER_BLOCK}, traits::{DisputeApi, Swaps}, @@ -89,11 +92,13 @@ fn create_market_common( pallet_timestamp::Pallet::::set_timestamp(0u32.into()); let range_start: MomentOf = 100_000u64.saturated_into(); let range_end: MomentOf = 1_000_000u64.saturated_into(); + let creator_fee: Perbill = Perbill::zero(); let period = period.unwrap_or(MarketPeriod::Timestamp(range_start..range_end)); let (caller, oracle, deadlines, metadata, creation) = create_market_common_parameters::(permission)?; Call::::create_market { base_asset: Asset::Ztg, + creator_fee, oracle, period, deadlines, @@ -625,6 +630,7 @@ benchmarks! { }: _( RawOrigin::Signed(caller), Asset::Ztg, + Perbill::zero(), oracle, period, deadlines, @@ -648,6 +654,7 @@ benchmarks! { create_market_common_parameters::(MarketCreation::Advised)?; Call::::create_market { base_asset: Asset::Ztg, + creator_fee: Perbill::zero(), oracle: oracle.clone(), period: period.clone(), deadlines, diff --git a/zrml/prediction-markets/src/lib.rs b/zrml/prediction-markets/src/lib.rs index 63ca4512e..12984ce5b 100644 --- a/zrml/prediction-markets/src/lib.rs +++ b/zrml/prediction-markets/src/lib.rs @@ -715,6 +715,7 @@ mod pallet { pub fn create_cpmm_market_and_deploy_assets( origin: OriginFor, base_asset: Asset>, + creator_fee: Perbill, oracle: T::AccountId, period: MarketPeriod>, deadlines: Deadlines, @@ -730,6 +731,7 @@ mod pallet { let create_market_weight = Self::create_market( origin.clone(), base_asset, + creator_fee, oracle, period, deadlines, @@ -769,6 +771,7 @@ mod pallet { pub fn create_market( origin: OriginFor, base_asset: Asset>, + creator_fee: Perbill, oracle: T::AccountId, period: MarketPeriod>, deadlines: Deadlines, @@ -797,7 +800,7 @@ mod pallet { let market = Self::construct_market( base_asset, sender.clone(), - 0_u8, + creator_fee, oracle, period, deadlines, @@ -1625,6 +1628,9 @@ mod pallet { #[pallet::constant] type MinCategories: Get; + /// A upper bound for the fee that is charged each trade and given to the market creator. + type MaxCreatorFee: Get; + /// The shortest period of collecting subsidy for a Rikiddo market. #[pallet::constant] type MinSubsidyPeriod: Get>; @@ -1814,6 +1820,8 @@ mod pallet { UnregisteredForeignAsset, /// The start of the global dispute for this market happened already. GlobalDisputeExistsAlready, + /// The fee is too high. + FeeTooHigh, } #[pallet::event] @@ -3050,7 +3058,7 @@ mod pallet { fn construct_market( base_asset: Asset>, creator: T::AccountId, - creator_fee: u8, + creator_fee: Perbill, oracle: T::AccountId, period: MarketPeriod>, deadlines: Deadlines, @@ -3076,6 +3084,7 @@ mod pallet { _ => false, }; + ensure!(creator_fee <= T::MaxCreatorFee::get(), Error::::FeeTooHigh); ensure!(valid_base_asset, Error::::InvalidBaseAsset); let MultiHash::Sha3_384(multihash) = metadata; ensure!(multihash[0] == 0x15 && multihash[1] == 0x30, >::InvalidMultihash); diff --git a/zrml/prediction-markets/src/migrations.rs b/zrml/prediction-markets/src/migrations.rs index 2134275b0..6a28e7444 100644 --- a/zrml/prediction-markets/src/migrations.rs +++ b/zrml/prediction-markets/src/migrations.rs @@ -35,7 +35,7 @@ use frame_support::{ }; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_runtime::traits::Saturating; +use sp_runtime::{traits::Saturating, Perbill}; use zeitgeist_primitives::types::{ Asset, Bond, Deadlines, Market, MarketBonds, MarketCreation, MarketDisputeMechanism, MarketPeriod, MarketStatus, MarketType, OutcomeReport, Report, ScoringRule, @@ -92,21 +92,24 @@ pub(crate) type Markets = StorageMap< OldMarketOf, >; -pub struct AddDisputeBond(PhantomData); +pub struct AddDisputeBondAndConvertCreatorFee(PhantomData); -impl OnRuntimeUpgrade for AddDisputeBond { +impl OnRuntimeUpgrade + for AddDisputeBondAndConvertCreatorFee +{ fn on_runtime_upgrade() -> Weight { let mut total_weight = T::DbWeight::get().reads(1); let market_commons_version = StorageVersion::get::>(); if market_commons_version != MARKET_COMMONS_REQUIRED_STORAGE_VERSION { log::info!( - "AddDisputeBond: market-commons version is {:?}, but {:?} is required", + "AddDisputeBondAndConvertCreatorFee: market-commons version is {:?}, but {:?} is \ + required", market_commons_version, MARKET_COMMONS_REQUIRED_STORAGE_VERSION, ); return total_weight; } - log::info!("AddDisputeBond: Starting..."); + log::info!("AddDisputeBondAndConvertCreatorFee: Starting..."); let mut translated = 0u64; zrml_market_commons::Markets::::translate::, _>( @@ -128,7 +131,8 @@ impl OnRuntimeUpgrade for AddDisputeBon base_asset: old_market.base_asset, creator: old_market.creator, creation: old_market.creation, - creator_fee: old_market.creator_fee, + // Zero can be safely assumed here as it was hardcoded before + creator_fee: Perbill::zero(), oracle: old_market.oracle, metadata: old_market.metadata, market_type: old_market.market_type, @@ -150,13 +154,13 @@ impl OnRuntimeUpgrade for AddDisputeBon Some(new_market) }, ); - log::info!("AddDisputeBond: Upgraded {} markets.", translated); + log::info!("AddDisputeBondAndConvertCreatorFee: Upgraded {} markets.", translated); total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(translated, translated)); StorageVersion::new(MARKET_COMMONS_NEXT_STORAGE_VERSION).put::>(); total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); - log::info!("AddDisputeBond: Done!"); + log::info!("AddDisputeBondAndConvertCreatorFee: Done!"); total_weight } @@ -199,7 +203,6 @@ impl OnRuntimeUpgrade for AddDisputeBon assert_eq!(new_market.base_asset, old_market.base_asset); assert_eq!(new_market.creator, old_market.creator); assert_eq!(new_market.creation, old_market.creation); - assert_eq!(new_market.creator_fee, old_market.creator_fee); assert_eq!(new_market.oracle, old_market.oracle); assert_eq!(new_market.metadata, old_market.metadata); assert_eq!(new_market.market_type, old_market.market_type); @@ -214,6 +217,7 @@ impl OnRuntimeUpgrade for AddDisputeBon assert_eq!(new_market.bonds.creation, old_market.bonds.creation); assert_eq!(new_market.bonds.outsider, old_market.bonds.outsider); // new fields + assert_eq!(new_market.creator_fee, Perbill::zero()); // other dispute mechanisms are regarded in the migration after this migration if let MarketDisputeMechanism::Authorized = new_market.dispute_mechanism { let old_disputes = crate::Disputes::::get(market_id); @@ -233,7 +237,10 @@ impl OnRuntimeUpgrade for AddDisputeBon } } - log::info!("AddDisputeBond: Market Counter post-upgrade is {}!", new_market_count); + log::info!( + "AddDisputeBondAndConvertCreatorFee: Market Counter post-upgrade is {}!", + new_market_count + ); assert!(new_market_count > 0); Ok(()) } @@ -255,7 +262,7 @@ mod tests { fn on_runtime_upgrade_increments_the_storage_version() { ExtBuilder::default().build().execute_with(|| { set_up_version(); - AddDisputeBond::::on_runtime_upgrade(); + AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); assert_eq!( StorageVersion::get::>(), MARKET_COMMONS_NEXT_STORAGE_VERSION @@ -273,7 +280,7 @@ mod tests { MARKETS, new_markets.clone(), ); - AddDisputeBond::::on_runtime_upgrade(); + AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); let actual = >::market(&0u128).unwrap(); assert_eq!(actual, new_markets[0]); }); @@ -289,7 +296,7 @@ mod tests { MARKETS, old_markets, ); - AddDisputeBond::::on_runtime_upgrade(); + AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); let actual = >::market(&0u128).unwrap(); assert_eq!(actual, new_markets[0]); }); @@ -311,7 +318,7 @@ mod tests { MARKETS, old_markets, ); - AddDisputeBond::::on_runtime_upgrade(); + AddDisputeBondAndConvertCreatorFee::::on_runtime_upgrade(); let actual = >::market(&0u128).unwrap(); assert_eq!(actual, new_markets[0]); }); @@ -327,7 +334,8 @@ mod tests { ) -> (Vec>, Vec>) { let base_asset = Asset::Ztg; let creator = 999; - let creator_fee = 1; + let old_creator_fee = 0; + let new_creator_fee = Perbill::zero(); let oracle = 2; let metadata = vec![3, 4, 5]; let market_type = MarketType::Categorical(6); @@ -356,7 +364,7 @@ mod tests { base_asset, creator, creation: creation.clone(), - creator_fee, + creator_fee: old_creator_fee, oracle, metadata: metadata.clone(), market_type: market_type.clone(), @@ -373,7 +381,7 @@ mod tests { base_asset, creator, creation, - creator_fee, + creator_fee: new_creator_fee, oracle, metadata, market_type, @@ -764,7 +772,7 @@ mod tests_simple_disputes_migration { fn get_market(dispute_mechanism: MarketDisputeMechanism) -> MarketOf { let base_asset = Asset::Ztg; let creator = 999; - let creator_fee = 1; + let creator_fee = Perbill::zero(); let oracle = 2; let metadata = vec![3, 4, 5]; let market_type = MarketType::Categorical(6); diff --git a/zrml/prediction-markets/src/mock.rs b/zrml/prediction-markets/src/mock.rs index f7807b67a..016ab3e76 100644 --- a/zrml/prediction-markets/src/mock.rs +++ b/zrml/prediction-markets/src/mock.rs @@ -42,13 +42,14 @@ use zeitgeist_primitives::{ BlockHashCount, BlocksPerYear, CorrectionPeriod, CourtPalletId, ExistentialDeposit, ExistentialDeposits, ExitFee, GetNativeCurrencyId, InflationPeriod, LiquidityMiningPalletId, LockId, MaxAppeals, MaxApprovals, MaxAssets, MaxCategories, - MaxCourtParticipants, MaxDelegations, MaxDisputeDuration, MaxDisputes, MaxEditReasonLen, - MaxGracePeriod, MaxInRatio, MaxMarketLifetime, MaxOracleDuration, MaxOutRatio, - MaxRejectReasonLen, MaxReserves, MaxSelectedDraws, MaxSubsidyPeriod, MaxSwapFee, - MaxTotalWeight, MaxWeight, MinAssets, MinCategories, MinDisputeDuration, MinJurorStake, - MinOracleDuration, MinSubsidy, MinSubsidyPeriod, MinWeight, MinimumPeriod, OutcomeBond, - OutcomeFactor, OutsiderBond, PmPalletId, RequestInterval, SimpleDisputesPalletId, - SwapsPalletId, TreasuryPalletId, VotePeriod, BASE, CENT, MILLISECS_PER_BLOCK, + MaxCourtParticipants, MaxCreatorFee, MaxDelegations, MaxDisputeDuration, MaxDisputes, + MaxEditReasonLen, MaxGracePeriod, MaxInRatio, MaxMarketLifetime, MaxOracleDuration, + MaxOutRatio, MaxRejectReasonLen, MaxReserves, MaxSelectedDraws, MaxSubsidyPeriod, + MaxSwapFee, MaxTotalWeight, MaxWeight, MinAssets, MinCategories, MinDisputeDuration, + MinJurorStake, MinOracleDuration, MinSubsidy, MinSubsidyPeriod, MinWeight, MinimumPeriod, + OutcomeBond, OutcomeFactor, OutsiderBond, PmPalletId, RequestInterval, + SimpleDisputesPalletId, SwapsPalletId, TreasuryPalletId, VotePeriod, BASE, CENT, + MILLISECS_PER_BLOCK, }, types::{ AccountIdTest, Amount, Asset, Balance, BasicCurrencyAdapter, BlockNumber, BlockTest, @@ -119,6 +120,7 @@ impl crate::Config for Runtime { type AssetRegistry = MockRegistry; type Authorized = Authorized; type CloseOrigin = EnsureSignedBy; + type MaxCreatorFee = MaxCreatorFee; type Court = Court; type DestroyOrigin = EnsureSignedBy; type DisputeBond = DisputeBond; diff --git a/zrml/prediction-markets/src/tests.rs b/zrml/prediction-markets/src/tests.rs index 2269a8455..9b79c33e1 100644 --- a/zrml/prediction-markets/src/tests.rs +++ b/zrml/prediction-markets/src/tests.rs @@ -37,6 +37,7 @@ use test_case::test_case; use zrml_court::{types::*, Error as CError}; use orml_traits::{MultiCurrency, MultiReservableCurrency}; +use sp_arithmetic::Perbill; use sp_runtime::traits::{AccountIdConversion, Hash, SaturatedConversion, Zero}; use zeitgeist_primitives::{ constants::mock::{ @@ -107,6 +108,7 @@ fn simple_create_categorical_market( assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(period), get_deadlines(), @@ -127,6 +129,7 @@ fn simple_create_scalar_market( assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(period), get_deadlines(), @@ -177,6 +180,7 @@ fn admin_move_market_to_closed_successfully_closes_market_and_sets_end_timestamp assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(start..end), get_deadlines(), @@ -253,6 +257,7 @@ fn admin_move_market_to_closed_correctly_clears_auto_open_and_close_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(22..66), get_deadlines(), @@ -266,6 +271,7 @@ fn admin_move_market_to_closed_correctly_clears_auto_open_and_close_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(33..66), get_deadlines(), @@ -279,6 +285,7 @@ fn admin_move_market_to_closed_correctly_clears_auto_open_and_close_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(22..33), get_deadlines(), @@ -309,6 +316,7 @@ fn create_scalar_market_fails_on_invalid_range(range: RangeInclusive) { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(123..456), get_deadlines(), @@ -335,6 +343,7 @@ fn create_market_fails_on_min_dispute_period() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -361,6 +370,7 @@ fn create_market_fails_on_min_oracle_duration() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -387,6 +397,7 @@ fn create_market_fails_on_max_dispute_period() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -413,6 +424,7 @@ fn create_market_fails_on_max_grace_period() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -439,6 +451,7 @@ fn create_market_fails_on_max_oracle_duration() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -469,6 +482,7 @@ fn create_market_with_foreign_assets() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::ForeignAsset(420), + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -485,6 +499,7 @@ fn create_market_with_foreign_assets() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::ForeignAsset(50), + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -500,6 +515,7 @@ fn create_market_with_foreign_assets() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::ForeignAsset(100), + Perbill::zero(), BOB, MarketPeriod::Block(123..456), deadlines, @@ -1002,6 +1018,7 @@ fn admin_destroy_market_correctly_cleans_up_accounts() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), ALICE, MarketPeriod::Block(0..42), get_deadlines(), @@ -1067,6 +1084,7 @@ fn admin_destroy_market_correctly_clears_auto_open_and_close_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(22..66), get_deadlines(), @@ -1080,6 +1098,7 @@ fn admin_destroy_market_correctly_clears_auto_open_and_close_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(33..66), get_deadlines(), @@ -1093,6 +1112,7 @@ fn admin_destroy_market_correctly_clears_auto_open_and_close_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(22..33), get_deadlines(), @@ -1286,6 +1306,7 @@ fn it_does_not_create_market_with_too_few_categories() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..100), get_deadlines(), @@ -1307,6 +1328,7 @@ fn it_does_not_create_market_with_too_many_categories() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..100), get_deadlines(), @@ -1788,6 +1810,7 @@ fn on_market_open_successfully_auto_opens_market_pool_with_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(start..end), get_deadlines(), @@ -1819,6 +1842,7 @@ fn on_market_close_successfully_auto_closes_market_with_blocks() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(0..end), get_deadlines(), @@ -1857,6 +1881,7 @@ fn on_market_open_successfully_auto_opens_market_with_timestamps() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Timestamp(start..end), get_deadlines(), @@ -1891,6 +1916,7 @@ fn on_market_close_successfully_auto_closes_market_with_timestamps() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Timestamp(0..end), get_deadlines(), @@ -1937,6 +1963,7 @@ fn on_market_open_successfully_auto_opens_multiple_markets_after_stall() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Timestamp(start..end), get_deadlines(), @@ -1950,6 +1977,7 @@ fn on_market_open_successfully_auto_opens_multiple_markets_after_stall() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Timestamp(start..end), get_deadlines(), @@ -1982,6 +2010,7 @@ fn on_market_close_successfully_auto_closes_multiple_markets_after_stall() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Timestamp(0..end), get_deadlines(), @@ -1995,6 +2024,7 @@ fn on_market_close_successfully_auto_closes_multiple_markets_after_stall() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Timestamp(0..end), get_deadlines(), @@ -2034,6 +2064,7 @@ fn on_initialize_skips_the_genesis_block() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Timestamp(0..end), get_deadlines(), @@ -2127,6 +2158,7 @@ fn create_categorical_market_fails_if_market_begin_is_equal_to_end() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(3..3), get_deadlines(), @@ -2157,6 +2189,7 @@ fn create_categorical_market_fails_if_market_period_is_invalid( PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, period, get_deadlines(), @@ -2180,6 +2213,7 @@ fn create_categorical_market_fails_if_end_is_not_far_enough_ahead() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..end_block), get_deadlines(), @@ -2197,6 +2231,7 @@ fn create_categorical_market_fails_if_end_is_not_far_enough_ahead() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..end_time), get_deadlines(), @@ -2538,6 +2573,7 @@ fn it_allows_only_oracle_to_report_the_outcome_of_a_market_during_oracle_duratio assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -2696,6 +2732,7 @@ fn dispute_fails_disputed_already() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -2736,6 +2773,7 @@ fn dispute_fails_if_market_not_reported() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -2770,6 +2808,7 @@ fn dispute_reserves_dispute_bond() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -2815,6 +2854,7 @@ fn dispute_updates_market() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -2861,6 +2901,7 @@ fn dispute_emits_event() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -3161,6 +3202,7 @@ fn it_resolves_a_disputed_court_market() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -3428,6 +3470,7 @@ fn it_appeals_a_court_market_to_global_dispute() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -3547,6 +3590,7 @@ fn start_global_dispute_fails_on_wrong_mdm() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..2), get_deadlines(), @@ -3641,6 +3685,7 @@ fn create_market_and_deploy_assets_results_in_expected_balances_and_pool_params( assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), oracle, period, get_deadlines(), @@ -4008,6 +4053,7 @@ fn the_entire_market_lifecycle_works_with_timestamps() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -4047,6 +4093,7 @@ fn full_scalar_market_lifecycle() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -4255,6 +4302,7 @@ fn market_resolve_does_not_hold_liquidity_withdraw() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4296,6 +4344,7 @@ fn authorized_correctly_resolves_disputed_market() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4441,6 +4490,7 @@ fn approve_market_correctly_unreserves_advisory_bond() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..100), get_deadlines(), @@ -4479,6 +4529,7 @@ fn deploy_swap_pool_correctly_sets_weight_of_base_asset() { assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), ALICE, MarketPeriod::Block(0..42), get_deadlines(), @@ -4505,6 +4556,7 @@ fn deploy_swap_pool_for_market_returns_error_if_weights_is_too_short() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..100), get_deadlines(), @@ -4542,6 +4594,7 @@ fn deploy_swap_pool_for_market_returns_error_if_weights_is_too_long() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(0..100), get_deadlines(), @@ -4582,6 +4635,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4627,6 +4681,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..100), get_deadlines(), @@ -4692,6 +4747,7 @@ fn outsider_reports_wrong_outcome() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4770,6 +4826,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_approved_advised_ma assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4815,6 +4872,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_approved_advised_ma assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4861,6 +4919,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4911,6 +4970,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_approved_advised_ma assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -4962,6 +5022,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -5021,6 +5082,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_advised_approved_ma assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -5078,6 +5140,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_permissionless_mark assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -5149,6 +5212,7 @@ fn on_resolution_correctly_reserves_and_unreserves_bonds_for_advised_approved_ma assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), base_asset, + Perbill::zero(), BOB, MarketPeriod::Block(0..end), get_deadlines(), @@ -5215,6 +5279,7 @@ fn report_fails_on_market_state_proposed() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -5237,6 +5302,7 @@ fn report_fails_on_market_state_closed_for_advised_market() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -5259,6 +5325,7 @@ fn report_fails_on_market_state_collecting_subsidy() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(100_000_000..200_000_000), get_deadlines(), @@ -5281,6 +5348,7 @@ fn report_fails_on_market_state_insufficient_subsidy() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(100_000_000..200_000_000), get_deadlines(), @@ -5307,6 +5375,7 @@ fn report_fails_on_market_state_active() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -5329,6 +5398,7 @@ fn report_fails_on_market_state_suspended() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -5355,6 +5425,7 @@ fn report_fails_on_market_state_resolved() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -5381,6 +5452,7 @@ fn report_fails_if_reporter_is_not_the_oracle() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(0..100_000_000), get_deadlines(), @@ -5421,6 +5493,7 @@ fn create_market_succeeds_if_market_duration_is_maximal_in_blocks() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(start..end), get_deadlines(), @@ -5448,6 +5521,7 @@ fn create_market_suceeds_if_market_duration_is_maximal_in_moments() { assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(start..end), get_deadlines(), @@ -5475,6 +5549,7 @@ fn create_market_fails_if_market_duration_is_too_long_in_blocks() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Block(start..end), get_deadlines(), @@ -5505,6 +5580,7 @@ fn create_market_fails_if_market_duration_is_too_long_in_moments() { PredictionMarkets::create_market( RuntimeOrigin::signed(ALICE), Asset::Ztg, + Perbill::zero(), BOB, MarketPeriod::Timestamp(start..end), get_deadlines(), @@ -5560,9 +5636,11 @@ fn create_market_sets_the_correct_market_parameters_and_reserves_the_correct_amo let MultiHash::Sha3_384(multihash) = metadata; let market_type = MarketType::Categorical(7); let dispute_mechanism = MarketDisputeMechanism::Authorized; + let creator_fee = Perbill::from_parts(1); assert_ok!(PredictionMarkets::create_market( RuntimeOrigin::signed(creator), Asset::Ztg, + creator_fee, oracle, period.clone(), deadlines, @@ -5575,7 +5653,7 @@ fn create_market_sets_the_correct_market_parameters_and_reserves_the_correct_amo let market = MarketCommons::market(&0).unwrap(); assert_eq!(market.creator, creator); assert_eq!(market.creation, creation); - assert_eq!(market.creator_fee, 0); + assert_eq!(market.creator_fee, creator_fee); assert_eq!(market.oracle, oracle); assert_eq!(market.metadata, multihash); assert_eq!(market.market_type, market_type); @@ -5590,6 +5668,154 @@ fn create_market_sets_the_correct_market_parameters_and_reserves_the_correct_amo }); } +#[test] +fn create_cpmm_market_and_deploy_assets_sets_the_correct_market_parameters_and_reserves_the_correct_amount() + { + ExtBuilder::default().build().execute_with(|| { + let creator = ALICE; + let oracle = BOB; + let bonds = MarketBonds { + creation: Some(Bond::new(ALICE, ::ValidityBond::get())), + oracle: Some(Bond::new(ALICE, ::OracleBond::get())), + outsider: None, + dispute: None, + }; + let period = MarketPeriod::Block(1..2); + let deadlines = Deadlines { + grace_period: 1, + oracle_duration: ::MinOracleDuration::get() + 2, + dispute_duration: ::MinDisputeDuration::get() + 3, + }; + let metadata = gen_metadata(0x99); + let MultiHash::Sha3_384(multihash) = metadata; + let category_count = 7; + let market_type = MarketType::Categorical(category_count); + let dispute_mechanism = MarketDisputeMechanism::Authorized; + let creator_fee = Perbill::from_parts(1); + let lp_fee = 0; + let weight = ::MinWeight::get(); + let weights = vec![weight; category_count.into()]; + assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( + RuntimeOrigin::signed(creator), + Asset::Ztg, + creator_fee, + oracle, + period.clone(), + deadlines, + metadata, + market_type.clone(), + dispute_mechanism.clone(), + lp_fee, + LIQUIDITY, + weights.clone(), + )); + let market = MarketCommons::market(&0).unwrap(); + assert_eq!(market.creator, creator); + assert_eq!(market.creation, MarketCreation::Permissionless); + assert_eq!(market.creator_fee, creator_fee); + assert_eq!(market.oracle, oracle); + assert_eq!(market.metadata, multihash); + assert_eq!(market.market_type, market_type); + assert_eq!(market.period, period); + assert_eq!(market.deadlines, deadlines); + assert_eq!(market.scoring_rule, ScoringRule::CPMM); + assert_eq!(market.status, MarketStatus::Active); + assert_eq!(market.report, None); + assert_eq!(market.resolved_outcome, None); + assert_eq!(market.dispute_mechanism, dispute_mechanism); + assert_eq!(market.bonds, bonds); + }); +} + +#[test] +fn create_market_functions_respect_fee_boundaries() { + ExtBuilder::default().build().execute_with(|| { + let creator = ALICE; + let oracle = BOB; + let base_asset = Asset::Ztg; + let mut creator_fee = ::MaxCreatorFee::get(); + let period = MarketPeriod::Block(1..2); + let deadlines = Deadlines { + grace_period: 1, + oracle_duration: ::MinOracleDuration::get() + 2, + dispute_duration: ::MinDisputeDuration::get() + 3, + }; + let metadata = gen_metadata(0x99); + let category_count = 3; + let weight = ::MinWeight::get(); + let weights = vec![weight; category_count.into()]; + let scoring_rule = ScoringRule::CPMM; + let market_type = MarketType::Categorical(category_count); + let creation_type = MarketCreation::Permissionless; + let dispute_mechanism = MarketDisputeMechanism::Authorized; + let lp_fee = 0; + + assert_ok!(PredictionMarkets::create_market( + RuntimeOrigin::signed(creator), + base_asset, + creator_fee, + oracle, + period.clone(), + deadlines, + metadata.clone(), + creation_type.clone(), + market_type.clone(), + dispute_mechanism.clone(), + scoring_rule, + )); + assert_ok!(PredictionMarkets::create_cpmm_market_and_deploy_assets( + RuntimeOrigin::signed(creator), + base_asset, + creator_fee, + oracle, + period.clone(), + deadlines, + metadata.clone(), + market_type.clone(), + dispute_mechanism.clone(), + lp_fee, + LIQUIDITY, + weights.clone(), + )); + + creator_fee = creator_fee + Perbill::from_parts(1); + + assert_err!( + PredictionMarkets::create_market( + RuntimeOrigin::signed(creator), + base_asset, + creator_fee, + oracle, + period.clone(), + deadlines, + metadata.clone(), + creation_type.clone(), + market_type.clone(), + dispute_mechanism.clone(), + scoring_rule, + ), + Error::::FeeTooHigh + ); + assert_err!( + PredictionMarkets::create_cpmm_market_and_deploy_assets( + RuntimeOrigin::signed(creator), + base_asset, + creator_fee, + oracle, + period, + deadlines, + metadata, + market_type, + dispute_mechanism, + lp_fee, + LIQUIDITY, + weights, + ), + Error::::FeeTooHigh + ); + }); +} + fn deploy_swap_pool( market: Market>, market_id: u128, diff --git a/zrml/simple-disputes/src/lib.rs b/zrml/simple-disputes/src/lib.rs index b4494127a..8304fa5ce 100644 --- a/zrml/simple-disputes/src/lib.rs +++ b/zrml/simple-disputes/src/lib.rs @@ -538,7 +538,7 @@ mod pallet { } } -#[cfg(any(feature = "runtime-benchmarks", test))] +#[cfg(feature = "runtime-benchmarks")] pub(crate) fn market_mock() -> MarketOf where T: crate::Config, @@ -550,7 +550,7 @@ where zeitgeist_primitives::types::Market { base_asset: Asset::Ztg, creation: zeitgeist_primitives::types::MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: sp_runtime::Perbill::zero(), creator: T::PalletId::get().into_account_truncating(), market_type: zeitgeist_primitives::types::MarketType::Scalar(0..=100), dispute_mechanism: zeitgeist_primitives::types::MarketDisputeMechanism::SimpleDisputes, diff --git a/zrml/simple-disputes/src/tests.rs b/zrml/simple-disputes/src/tests.rs index f5f35ba89..383792a5a 100644 --- a/zrml/simple-disputes/src/tests.rs +++ b/zrml/simple-disputes/src/tests.rs @@ -35,7 +35,7 @@ use zeitgeist_primitives::{ const DEFAULT_MARKET: MarketOf = Market { base_asset: Asset::Ztg, creation: MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: sp_runtime::Perbill::zero(), creator: 0, market_type: MarketType::Scalar(0..=100), dispute_mechanism: MarketDisputeMechanism::SimpleDisputes, diff --git a/zrml/swaps/Cargo.toml b/zrml/swaps/Cargo.toml index 8300b9210..efac5dfb8 100644 --- a/zrml/swaps/Cargo.toml +++ b/zrml/swaps/Cargo.toml @@ -5,11 +5,11 @@ frame-system = { workspace = true } orml-traits = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive", "max-encoded-len"] } scale-info = { workspace = true, features = ["derive"] } +sp-arithmetic = { workspace = true } sp-runtime = { workspace = true } substrate-fixed = { workspace = true } zeitgeist-primitives = { workspace = true } zrml-liquidity-mining = { workspace = true } -zrml-market-commons = { workspace = true } zrml-rikiddo = { workspace = true } # Mock @@ -20,6 +20,7 @@ pallet-balances = { workspace = true, optional = true } pallet-timestamp = { workspace = true, optional = true } sp-api = { workspace = true, optional = true } sp-io = { workspace = true, optional = true } +zrml-market-commons = { workspace = true, optional = true } zrml-swaps-runtime-api = { workspace = true, optional = true } [dev-dependencies] @@ -37,6 +38,7 @@ mock = [ "sp-api/default", "sp-io/default", "zeitgeist-primitives/mock", + "zrml-market-commons/default", "zrml-swaps-runtime-api/default", ] runtime-benchmarks = [ @@ -53,7 +55,6 @@ std = [ "sp-runtime/std", "substrate-fixed/std", "zeitgeist-primitives/std", - "zrml-market-commons/std", "zrml-liquidity-mining/std", "zrml-rikiddo/std", ] diff --git a/zrml/swaps/fuzz/create_pool.rs b/zrml/swaps/fuzz/create_pool.rs index 21362f997..0438e0b8a 100644 --- a/zrml/swaps/fuzz/create_pool.rs +++ b/zrml/swaps/fuzz/create_pool.rs @@ -1,3 +1,4 @@ +// Copyright 2023 Forecasting Technologies LTD. // Copyright 2021-2022 Zeitgeist PM LLC. // // This file is part of Zeitgeist. @@ -20,7 +21,7 @@ use libfuzzer_sys::fuzz_target; use zeitgeist_primitives::{traits::Swaps as SwapsTrait, types::ScoringRule}; -use zrml_swaps::mock::{ExtBuilder, Swaps}; +use zrml_swaps::mock::{ExtBuilder, Swaps, DEFAULT_MARKET_ID}; mod utils; use utils::{construct_asset, PoolCreationData}; @@ -32,7 +33,7 @@ fuzz_target!(|data: PoolCreationData| { data.origin, data.assets.into_iter().map(construct_asset).collect(), construct_asset(data.base_asset), - data.market_id, + DEFAULT_MARKET_ID, ScoringRule::CPMM, data.swap_fee, data.amount, diff --git a/zrml/swaps/fuzz/utils.rs b/zrml/swaps/fuzz/utils.rs index b03364729..6c8dfff73 100644 --- a/zrml/swaps/fuzz/utils.rs +++ b/zrml/swaps/fuzz/utils.rs @@ -1,3 +1,4 @@ +// Copyright 2023 Forecasting Technologies LTD. // Copyright 2021-2022 Zeitgeist PM LLC. // // This file is part of Zeitgeist. @@ -30,7 +31,7 @@ use zeitgeist_primitives::{ traits::Swaps as SwapsTrait, types::{Asset, PoolId, ScalarPosition, ScoringRule, SerdeWrapper}, }; -use zrml_swaps::mock::Swaps; +use zrml_swaps::mock::{Swaps, DEFAULT_MARKET_ID}; pub fn construct_asset(seed: (u8, u128, u16)) -> Asset { let (module, seed0, seed1) = seed; @@ -56,7 +57,6 @@ pub struct ValidPoolData { pub origin: u128, pub assets: Vec<(u8, u128, u16)>, pub base_asset: (u8, u128, u16), - pub market_id: u128, pub swap_fee: u128, pub amount: u128, pub weights: Vec, @@ -70,7 +70,7 @@ impl ValidPoolData { self.origin, self.assets.into_iter().map(construct_asset).collect(), construct_asset(self.base_asset), - self.market_id, + DEFAULT_MARKET_ID, ScoringRule::CPMM, construct_swap_fee(self.swap_fee), Some(self.amount), @@ -100,13 +100,12 @@ impl<'a> arbitrary::Arbitrary<'a> for ValidPoolData { .ok_or(::IncorrectFormat)?; let origin = rng.gen::(); - let market_id = rng.gen::(); let swap_fee = rng.gen_range(0..BASE); // Slightly dirty hack: We're assuming that the minimum liquidity is CENT. This is not // guaranteed by the protocol, but will most likely remain so forever. let amount = rng.gen_range(CENT..u128::MAX); - Ok(ValidPoolData { origin, assets, base_asset, market_id, swap_fee, amount, weights }) + Ok(ValidPoolData { origin, assets, base_asset, swap_fee, amount, weights }) } } @@ -209,7 +208,6 @@ pub struct PoolCreationData { pub origin: u128, pub assets: Vec<(u8, u128, u16)>, pub base_asset: (u8, u128, u16), - pub market_id: u128, pub swap_fee: Option, pub amount: Option, pub weights: Option>, diff --git a/zrml/swaps/src/benchmarks.rs b/zrml/swaps/src/benchmarks.rs index d456425e9..033a68738 100644 --- a/zrml/swaps/src/benchmarks.rs +++ b/zrml/swaps/src/benchmarks.rs @@ -31,29 +31,50 @@ use super::*; use crate::Pallet as Swaps; use crate::{fixed::bmul, pallet::ARBITRAGE_MAX_ITERATIONS, Config, Event, MarketIdOf}; use frame_benchmarking::{account, benchmarks, vec, whitelisted_caller, Vec}; -use frame_support::{dispatch::UnfilteredDispatchable, traits::Get, weights::Weight}; +use frame_support::{ + dispatch::{DispatchResult, UnfilteredDispatchable}, + traits::{Currency, Get}, + weights::Weight, +}; use frame_system::RawOrigin; use orml_traits::MultiCurrency; use sp_runtime::{ - traits::{SaturatedConversion, Zero}, - DispatchError, + traits::{CheckedSub, SaturatedConversion, Zero}, + DispatchError, Perbill, }; use zeitgeist_primitives::{ constants::{BASE, CENT}, - traits::Swaps as _, + traits::{MarketCommonsPalletApi, Swaps as _}, types::{ Asset, Deadlines, Market, MarketBonds, MarketCreation, MarketDisputeMechanism, MarketPeriod, MarketStatus, MarketType, OutcomeReport, PoolId, PoolStatus, ScoringRule, }, }; -use zrml_market_commons::MarketCommonsPalletApi; +const DEFAULT_CREATOR_FEE: Perbill = Perbill::from_perthousand(1); const LIQUIDITY: u128 = 100 * BASE; +type MarketOf = zeitgeist_primitives::types::Market< + ::AccountId, + <<::MarketCommons as MarketCommonsPalletApi>::Currency as Currency< + ::AccountId, + >>::Balance, + <::MarketCommons as MarketCommonsPalletApi>::BlockNumber, + <::MarketCommons as MarketCommonsPalletApi>::Moment, + Asset<<::MarketCommons as MarketCommonsPalletApi>::MarketId>, +>; + fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } +fn set_default_creator_fee(market_id: MarketIdOf) -> DispatchResult { + T::MarketCommons::mutate_market(&market_id, |market: &mut MarketOf| { + market.creator_fee = DEFAULT_CREATOR_FEE; + Ok(()) + }) +} + // Generates `acc_total` accounts, of which `acc_asset` account do own `asset` fn generate_accounts_with_assets( acc_total: u32, @@ -102,6 +123,32 @@ fn generate_assets( assets } +fn push_default_market(caller: T::AccountId, oracle: T::AccountId) -> MarketIdOf { + let market = Market { + base_asset: Asset::Ztg, + creation: MarketCreation::Permissionless, + creator_fee: Perbill::zero(), + creator: caller, + market_type: MarketType::Categorical(3), + dispute_mechanism: MarketDisputeMechanism::Authorized, + metadata: vec![0; 50], + oracle, + period: MarketPeriod::Block(0u32.into()..1u32.into()), + deadlines: Deadlines { + grace_period: 1_u32.into(), + oracle_duration: 1_u32.into(), + dispute_duration: 1_u32.into(), + }, + report: None, + resolved_outcome: None, + scoring_rule: ScoringRule::CPMM, + status: MarketStatus::Active, + bonds: MarketBonds::default(), + }; + + T::MarketCommons::push_market(market).unwrap() +} + fn initialize_pool( caller: &T::AccountId, asset_count: Option, @@ -116,7 +163,6 @@ fn initialize_pool( } }; - let market_id = MarketIdOf::::from(0u8); let assets = generate_assets::(caller, asset_count_unwrapped, asset_amount); let some_weights = if weights.is_some() { weights @@ -124,6 +170,7 @@ fn initialize_pool( Some(vec![T::MinWeight::get(); asset_count_unwrapped]) }; let base_asset = *assets.last().unwrap(); + let market_id = push_default_market::(caller.clone(), caller.clone()); let pool_id = Pallet::::create_pool( caller.clone(), @@ -139,6 +186,7 @@ fn initialize_pool( (pool_id, base_asset, assets, market_id) } + // Creates a pool containing `asset_count` (default: max assets) assets. // Returns `PoolId`, `Vec>`, ``MarketId` fn bench_create_pool( @@ -179,7 +227,7 @@ benchmarks! { Market { base_asset: Asset::Ztg, creation: MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: Perbill::zero(), creator: caller.clone(), market_type: MarketType::Categorical(category_count), dispute_mechanism: MarketDisputeMechanism::Authorized, @@ -220,7 +268,7 @@ benchmarks! { Market { base_asset: Asset::Ztg, creation: MarketCreation::Permissionless, - creator_fee: 0, + creator_fee: Perbill::zero(), creator: caller.clone(), market_type: MarketType::Scalar(0..=99), dispute_mechanism: MarketDisputeMechanism::Authorized, @@ -276,7 +324,7 @@ benchmarks! { // Create `a` pools with huge balances and only a relatively small difference between them // to cause maximum iterations. for i in 0..a { - let market_id = i.into(); + let market_id = push_default_market::(caller.clone(), caller.clone()); let pool_id = Pallet::::create_pool( caller.clone(), assets.clone(), @@ -441,7 +489,7 @@ benchmarks! { // Create a pool with huge balances and only a relatively small difference between them to // cause at least 30 iterations. - let market_id = 0u8.into(); + let market_id = push_default_market::(caller.clone(), caller.clone()); let pool_id = Pallet::::create_pool( caller, assets.clone(), @@ -498,11 +546,12 @@ benchmarks! { // Create a pool with huge balances and only a relatively small difference between them to // cause at least 30 iterations. + let market_id = push_default_market::(caller.clone(), caller.clone()); let pool_id = Pallet::::create_pool( caller, assets.clone(), base_asset, - 0u8.into(), + market_id, ScoringRule::CPMM, Some(Zero::zero()), Some(balance), @@ -547,11 +596,12 @@ benchmarks! { weights.push(outcome_count as u128 * outcome_weight); // Create a pool with equal balances to ensure that the total spot price is equal to 1. + let market_id = push_default_market::(caller.clone(), caller.clone()); let pool_id = Pallet::::create_pool( caller, assets, base_asset, - 0u8.into(), + market_id, ScoringRule::CPMM, Some(Zero::zero()), Some(balance), @@ -732,7 +782,7 @@ benchmarks! { let mut weights = vec![weight_in; asset_count as usize]; weights[asset_count as usize - 1] = weight_out; let caller: T::AccountId = whitelisted_caller(); - let (pool_id, assets, ..) = bench_create_pool::( + let (pool_id, assets, market_id) = bench_create_pool::( caller.clone(), Some(asset_count as usize), Some(balance), @@ -740,6 +790,7 @@ benchmarks! { false, Some(weights), ); + set_default_creator_fee::(market_id)?; let asset_in = assets[0]; T::AssetManager::deposit(asset_in, &caller, u64::MAX.saturated_into()).unwrap(); let asset_out = assets[asset_count as usize - 1]; @@ -787,18 +838,19 @@ benchmarks! { // amount_out = 1/3 * balance_out, weight_out = 1, weight_in = 4. let asset_count = T::MaxAssets::get(); let balance: BalanceOf = LIQUIDITY.saturated_into(); - let asset_amount_out: BalanceOf = bmul( + let mut asset_amount_out: BalanceOf = bmul( balance.saturated_into(), T::MaxOutRatio::get().saturated_into(), ) .unwrap() .saturated_into(); + asset_amount_out = Perbill::one().checked_sub(&DEFAULT_CREATOR_FEE).unwrap().mul_floor(asset_amount_out); let weight_out = T::MinWeight::get(); let weight_in = 4 * weight_out; let mut weights = vec![weight_out; asset_count as usize]; weights[0] = weight_in; let caller: T::AccountId = whitelisted_caller(); - let (pool_id, assets, ..) = bench_create_pool::( + let (pool_id, assets, market_id) = bench_create_pool::( caller.clone(), Some(asset_count as usize), Some(balance), @@ -806,6 +858,7 @@ benchmarks! { false, Some(weights), ); + set_default_creator_fee::(market_id)?; let asset_in = assets[0]; T::AssetManager::deposit(asset_in, &caller, u64::MAX.saturated_into()).unwrap(); let asset_out = assets[asset_count as usize - 1]; diff --git a/zrml/swaps/src/lib.rs b/zrml/swaps/src/lib.rs index f9824bc7b..d3e5cf5a6 100644 --- a/zrml/swaps/src/lib.rs +++ b/zrml/swaps/src/lib.rs @@ -73,9 +73,13 @@ mod pallet { use frame_system::{ensure_root, ensure_signed, pallet_prelude::OriginFor}; use orml_traits::{BalanceStatus, MultiCurrency, MultiReservableCurrency}; use parity_scale_codec::{Decode, Encode}; + use sp_arithmetic::{ + traits::{CheckedSub, Saturating, Zero}, + Perbill, + }; use sp_runtime::{ - traits::{AccountIdConversion, CheckedSub, Saturating, Zero}, - ArithmeticError, DispatchError, DispatchResult, SaturatedConversion, + traits::AccountIdConversion, ArithmeticError, DispatchError, DispatchResult, + SaturatedConversion, }; use substrate_fixed::{ traits::{FixedSigned, FixedUnsigned, LossyFrom}, @@ -87,14 +91,13 @@ mod pallet { }; use zeitgeist_primitives::{ constants::{BASE, CENT}, - traits::{Swaps, ZeitgeistAssetManager}, + traits::{MarketCommonsPalletApi, Swaps, ZeitgeistAssetManager}, types::{ Asset, MarketType, OutcomeReport, Pool, PoolId, PoolStatus, ResultWithWeightInfo, ScoringRule, SerdeWrapper, }, }; use zrml_liquidity_mining::LiquidityMiningPalletApi; - use zrml_market_commons::MarketCommonsPalletApi; use zrml_rikiddo::{ constants::{EMA_LONG, EMA_SHORT}, traits::RikiddoMVPallet, @@ -717,6 +720,7 @@ mod pallet { asset_out, min_asset_amount_out, max_price, + false, )?; Ok(Some(weight).into()) } @@ -761,6 +765,7 @@ mod pallet { asset_out, asset_amount_out, max_price, + false, )?; Ok(Some(weight).into()) } @@ -1066,6 +1071,21 @@ mod pallet { SwapExactAmountOut( SwapEvent<::AccountId, Asset>, BalanceOf>, ), + /// Fees were paid to the market creators. \[payer, payee, amount, asset\] + MarketCreatorFeesPaid( + ::AccountId, + ::AccountId, + BalanceOf, + Asset>, + ), + /// Fee payment to market creator failed (usually due to existential deposit requirements) \[payer, payee, amount, asset, error\] + MarketCreatorFeePaymentFailed( + ::AccountId, + ::AccountId, + BalanceOf, + Asset>, + DispatchError, + ), } #[pallet::pallet] @@ -1399,9 +1419,15 @@ mod pallet { let out_weight = Self::pool_weight_rslt(&pool, asset_out)?; let swap_fee = if with_fees { - pool.swap_fee.ok_or(Error::::SwapFeeMissing)? + let swap_fee = pool.swap_fee.ok_or(Error::::SwapFeeMissing)?; + let market = T::MarketCommons::market(&pool.market_id)?; + market + .creator_fee + .mul_floor(BASE) + .checked_add(swap_fee.try_into().map_err(|_| Error::::SwapFeeTooHigh)?) + .ok_or(Error::::SwapFeeTooHigh)? } else { - BalanceOf::::zero() + BalanceOf::::zero().saturated_into() }; return Ok(crate::math::calc_spot_price( @@ -1409,7 +1435,7 @@ mod pallet { in_weight, balance_out.saturated_into(), out_weight, - swap_fee.saturated_into(), + swap_fee, )? .saturated_into()); } @@ -1553,6 +1579,64 @@ mod pallet { Ok(()) } + fn handle_creator_fee_transfer( + fee_asset: Asset>, + payer: T::AccountId, + payee: T::AccountId, + fee_amount: BalanceOf, + ) { + if let Err(err) = T::AssetManager::transfer(fee_asset, &payer, &payee, fee_amount) { + Self::deposit_event(Event::MarketCreatorFeePaymentFailed( + payer, payee, fee_amount, fee_asset, err, + )); + } else { + Self::deposit_event(Event::MarketCreatorFeesPaid( + payer, payee, fee_amount, fee_asset, + )); + } + } + + // Infallible, should fee transfer fail, the informant will keep the fees and an event is emitted. + fn handle_creator_fees( + amount: BalanceOf, + fee_asset: Asset>, + base_asset: Asset>, + fee: Perbill, + payee: T::AccountId, + payer: T::AccountId, + pool_id: PoolId, + ) { + if fee.is_zero() { + return; + }; + + let mut fee_amount = fee.mul_floor(amount); + + if fee_asset != base_asset { + let balance_before = T::AssetManager::free_balance(base_asset, &payer); + let swap_result = >::swap_exact_amount_in( + payer.clone(), + pool_id, + fee_asset, + fee_amount, + base_asset, + None, + Some(>::saturated_from(u128::MAX)), + true, + ); + + if swap_result.is_err() { + Self::handle_creator_fee_transfer(fee_asset, payer, payee, fee_amount); + return; + } + + let balance_after = T::AssetManager::free_balance(base_asset, &payer); + fee_amount = balance_after.saturating_sub(balance_before); + } + + Self::handle_creator_fee_transfer(base_asset, payer, payee, fee_amount); + } + pub(crate) fn burn_pool_shares( pool_id: PoolId, from: &T::AccountId, @@ -1755,6 +1839,7 @@ mod pallet { let pool_shares_id = Self::pool_shares_id(next_pool_id); let pool_account = Self::pool_account_id(&next_pool_id); let mut map = BTreeMap::new(); + let market = T::MarketCommons::market(&market_id)?; let mut total_weight = 0; let amount_unwrapped = amount.unwrap_or_else(BalanceOf::::zero); let mut sorted_assets = assets.clone(); @@ -1776,11 +1861,27 @@ mod pallet { amount_unwrapped >= Self::min_balance_of_pool(next_pool_id, &assets), Error::::InsufficientLiquidity ); + let swap_fee_unwrapped = swap_fee.ok_or(Error::::InvalidFeeArgument)?; + let total_fee = market + .creator_fee + .mul_floor(BASE) + .checked_add( + swap_fee_unwrapped + .try_into() + .map_err(|_| Error::::SwapFeeTooHigh)?, + ) + .ok_or(Error::::SwapFeeTooHigh)?; + + let total_fee_as_balance = >::try_from(total_fee) + .map_err(|_| Error::::SwapFeeTooHigh)?; + ensure!( - swap_fee_unwrapped <= T::MaxSwapFee::get(), + total_fee_as_balance <= T::MaxSwapFee::get(), Error::::SwapFeeTooHigh ); + ensure!(total_fee <= BASE, Error::::SwapFeeTooHigh); + let weights_unwrapped = weights.ok_or(Error::::InvalidWeightArgument)?; Self::check_provided_values_len_must_equal_assets_len( &assets, @@ -2288,26 +2389,51 @@ mod pallet { /// * `asset_out`: Asset leaving the pool. /// * `min_asset_amount_out`: Minimum asset amount that can leave the pool. /// * `max_price`: Market price must be equal or less than the provided value. + /// * `handle_fees`: Optional parameter to override the swap fee + #[allow(clippy::too_many_arguments)] fn swap_exact_amount_in( who: T::AccountId, pool_id: PoolId, asset_in: Asset>, - asset_amount_in: BalanceOf, + mut asset_amount_in: BalanceOf, asset_out: Asset>, min_asset_amount_out: Option>, max_price: Option>, + handle_fees: bool, ) -> Result { + ensure!( + min_asset_amount_out.is_some() || max_price.is_some(), + Error::::LimitMissing, + ); + let pool = Pallet::::pool_by_id(pool_id)?; let pool_account_id = Pallet::::pool_account_id(&pool_id); + let market = T::MarketCommons::market(&pool.market_id)?; + let creator_fee = market.creator_fee; + let mut fees_handled = false; + + if asset_in == pool.base_asset && !handle_fees { + Self::handle_creator_fees( + asset_amount_in, + asset_in, + pool.base_asset, + creator_fee, + market.creator.clone(), + who.clone(), + pool_id, + ); + + let fee_amount = creator_fee.mul_floor(asset_amount_in); + asset_amount_in = asset_amount_in.saturating_sub(fee_amount); + fees_handled = true; + } + ensure!( T::AssetManager::free_balance(asset_in, &who) >= asset_amount_in, Error::::InsufficientBalance ); - ensure!( - min_asset_amount_out.is_some() || max_price.is_some(), - Error::::LimitMissing, - ); + let balance_before = T::AssetManager::free_balance(asset_out, &who); let params = SwapExactAmountParams { asset_amounts: || { let asset_amount_out = match pool.scoring_rule { @@ -2325,13 +2451,18 @@ mod pallet { .saturated_into(), Error::::MaxInRatio ); + let swap_fee = if handle_fees { + 0u128 + } else { + pool.swap_fee.ok_or(Error::::PoolMissingFee)?.saturated_into() + }; crate::math::calc_out_given_in( balance_in.saturated_into(), Self::pool_weight_rslt(&pool, &asset_in)?, balance_out.saturated_into(), Self::pool_weight_rslt(&pool, &asset_out)?, asset_amount_in.saturated_into(), - pool.swap_fee.ok_or(Error::::PoolMissingFee)?.saturated_into(), + swap_fee, )? .saturated_into() } @@ -2368,8 +2499,15 @@ mod pallet { }; if let Some(maao) = min_asset_amount_out { - ensure!(asset_amount_out >= maao, Error::::LimitOut); + let asset_amount_out_check = if fees_handled { + asset_amount_out + } else { + asset_amount_out.saturating_sub(creator_fee.mul_floor(asset_amount_out)) + }; + + ensure!(asset_amount_out_check >= maao, Error::::LimitOut); } + Self::ensure_minimum_balance(pool_id, &pool, asset_out, asset_amount_out)?; Ok([asset_amount_in, asset_amount_out]) @@ -2383,10 +2521,25 @@ mod pallet { pool_account_id: &pool_account_id, pool_id, pool: &pool, - who, + who: who.clone(), }; swap_exact_amount::<_, _, _, T>(params)?; + if !fees_handled && !handle_fees { + let balance_after = T::AssetManager::free_balance(asset_out, &who); + let asset_amount_out = balance_after.saturating_sub(balance_before); + + Self::handle_creator_fees( + asset_amount_out, + asset_out, + pool.base_asset, + creator_fee, + market.creator.clone(), + who.clone(), + pool_id, + ); + } + match pool.scoring_rule { ScoringRule::CPMM => Ok(T::WeightInfo::swap_exact_amount_in_cpmm()), ScoringRule::RikiddoSigmoidFeeMarketEma => Ok( @@ -2395,19 +2548,48 @@ mod pallet { } } + /// Swap - Exact amount out + /// + /// Swaps a given `asset_amount_out` of the `asset_in/asset_out` pair to `origin`. + /// + /// # Arguments + /// + /// * `who`: The account whose assets should be transferred. + /// * `pool_id`: Unique pool identifier. + /// * `asset_in`: Asset entering the pool. + /// * `max_amount_asset_in`: Maximum asset amount that can enter the pool. + /// * `asset_out`: Asset leaving the pool. + /// * `asset_amount_out`: Amount that will be transferred from the pool to the provider. + /// * `max_price`: Market price must be equal or less than the provided value. + /// * `handle_fees`: Whether additional fees are handled or not (sets LP fee to 0) + #[allow(clippy::too_many_arguments)] fn swap_exact_amount_out( who: T::AccountId, pool_id: PoolId, asset_in: Asset>, max_asset_amount_in: Option>, asset_out: Asset>, - asset_amount_out: BalanceOf, + mut asset_amount_out: BalanceOf, max_price: Option>, + handle_fees: bool, ) -> Result { let pool = Pallet::::pool_by_id(pool_id)?; let pool_account_id = Pallet::::pool_account_id(&pool_id); ensure!(max_asset_amount_in.is_some() || max_price.is_some(), Error::::LimitMissing); Self::ensure_minimum_balance(pool_id, &pool, asset_out, asset_amount_out)?; + let market = T::MarketCommons::market(&pool.market_id)?; + let creator_fee = market.creator_fee; + let mut fee_amount = >::zero(); + + let to_adjust_in_value = if asset_in == pool.base_asset { + // Can't adjust the value inside the anonymous function for asset_amounts + true + } else { + fee_amount = creator_fee.mul_floor(asset_amount_out); + asset_amount_out = asset_amount_out.saturating_add(fee_amount); + false + }; + let params = SwapExactAmountParams { asset_amounts: || { let balance_out = T::AssetManager::free_balance(asset_out, &pool_account_id); @@ -2425,13 +2607,18 @@ mod pallet { let balance_in = T::AssetManager::free_balance(asset_in, &pool_account_id); + let swap_fee = if handle_fees { + 0u128 + } else { + pool.swap_fee.ok_or(Error::::PoolMissingFee)?.saturated_into() + }; crate::math::calc_in_given_out( balance_in.saturated_into(), Self::pool_weight_rslt(&pool, &asset_in)?, balance_out.saturated_into(), Self::pool_weight_rslt(&pool, &asset_out)?, asset_amount_out.saturated_into(), - pool.swap_fee.ok_or(Error::::PoolMissingFee)?.saturated_into(), + swap_fee, )? .saturated_into() } @@ -2467,9 +2654,29 @@ mod pallet { } }; + if asset_in == pool.base_asset && !handle_fees && to_adjust_in_value { + Self::handle_creator_fees( + asset_amount_in, + asset_in, + pool.base_asset, + creator_fee, + market.creator.clone(), + who.clone(), + pool_id, + ); + } + if let Some(maai) = max_asset_amount_in { - ensure!(asset_amount_in <= maai, Error::::LimitIn); + let asset_amount_in_check = if to_adjust_in_value { + let fee_amount = creator_fee.mul_floor(asset_amount_in); + asset_amount_in.saturating_add(fee_amount) + } else { + asset_amount_in + }; + + ensure!(asset_amount_in_check <= maai, Error::::LimitIn); } + Ok([asset_amount_in, asset_amount_out]) }, asset_bound: max_asset_amount_in, @@ -2481,10 +2688,24 @@ mod pallet { pool_account_id: &pool_account_id, pool_id, pool: &pool, - who, + who: who.clone(), }; swap_exact_amount::<_, _, _, T>(params)?; + if !to_adjust_in_value && !handle_fees { + asset_amount_out = asset_amount_out.saturating_sub(fee_amount); + + Self::handle_creator_fees( + asset_amount_out, + asset_out, + pool.base_asset, + creator_fee, + market.creator.clone(), + who.clone(), + pool_id, + ); + } + match pool.scoring_rule { ScoringRule::CPMM => Ok(T::WeightInfo::swap_exact_amount_out_cpmm()), ScoringRule::RikiddoSigmoidFeeMarketEma => { diff --git a/zrml/swaps/src/mock.rs b/zrml/swaps/src/mock.rs index 91d8ff17a..1ab5585dc 100644 --- a/zrml/swaps/src/mock.rs +++ b/zrml/swaps/src/mock.rs @@ -29,25 +29,33 @@ )] use crate as zrml_swaps; -use frame_support::{construct_runtime, parameter_types, traits::Everything}; +use frame_support::{ + construct_runtime, parameter_types, + traits::{Contains, Everything}, +}; +use orml_traits::parameter_type_with_key; +use sp_arithmetic::Perbill; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, IdentityLookup}, + traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, DispatchError, }; use substrate_fixed::{types::extra::U33, FixedI128, FixedU128}; use zeitgeist_primitives::{ constants::mock::{ - BalanceFractionalDecimals, BlockHashCount, ExistentialDeposit, ExistentialDeposits, - GetNativeCurrencyId, LiquidityMiningPalletId, MaxAssets, MaxInRatio, MaxLocks, MaxOutRatio, - MaxReserves, MaxSwapFee, MaxTotalWeight, MaxWeight, MinAssets, MinSubsidy, MinWeight, - MinimumPeriod, PmPalletId, SwapsPalletId, BASE, + BalanceFractionalDecimals, BlockHashCount, ExistentialDeposit, GetNativeCurrencyId, + LiquidityMiningPalletId, MaxAssets, MaxInRatio, MaxLocks, MaxOutRatio, MaxReserves, + MaxSwapFee, MaxTotalWeight, MaxWeight, MinAssets, MinSubsidy, MinWeight, MinimumPeriod, + PmPalletId, SwapsPalletId, BASE, }, types::{ AccountIdTest, Amount, Asset, Balance, BasicCurrencyAdapter, BlockNumber, BlockTest, - CurrencyId, Hash, Index, MarketId, Moment, PoolId, SerdeWrapper, UncheckedExtrinsicTest, + CurrencyId, Deadlines, Hash, Index, Market, MarketBonds, MarketCreation, + MarketDisputeMechanism, MarketId, MarketPeriod, MarketStatus, MarketType, Moment, PoolId, + ScoringRule, SerdeWrapper, UncheckedExtrinsicTest, }, }; +use zrml_market_commons::MarketCommonsPalletApi; use zrml_rikiddo::types::{EmaMarketVolume, FeeSigmoid, RikiddoSigmoidMV}; pub const ALICE: AccountIdTest = 0; @@ -56,6 +64,23 @@ pub const CHARLIE: AccountIdTest = 2; pub const DAVE: AccountIdTest = 3; pub const EVE: AccountIdTest = 4; +pub const ASSET_A: Asset = Asset::CategoricalOutcome(0, 65); +pub const ASSET_B: Asset = Asset::CategoricalOutcome(0, 66); +pub const ASSET_C: Asset = Asset::CategoricalOutcome(0, 67); +pub const ASSET_D: Asset = Asset::CategoricalOutcome(0, 68); +pub const ASSET_E: Asset = Asset::CategoricalOutcome(0, 69); + +pub const ASSETS: [Asset; 4] = [ASSET_A, ASSET_B, ASSET_C, ASSET_D]; +pub const BASE_ASSET: Asset = if let Some(asset) = ASSETS.last() { + *asset +} else { + panic!("Invalid asset vector"); +}; + +pub const DEFAULT_MARKET_ID: MarketId = 0; +pub const DEFAULT_MARKET_ORACLE: AccountIdTest = DAVE; +pub const DEFAULT_MARKET_CREATOR: AccountIdTest = DAVE; + pub type UncheckedExtrinsic = UncheckedExtrinsicTest; // Mocked exit fee for easier calculations @@ -142,11 +167,46 @@ impl orml_currencies::Config for Runtime { type WeightInfo = (); } +parameter_type_with_key! { + pub ExistentialDeposits: |currency_id: CurrencyId| -> Balance { + match currency_id { + &BASE_ASSET => ExistentialDeposit::get(), + Asset::Ztg => ExistentialDeposit::get(), + _ => 0, + } + }; +} + +pub struct DustRemovalWhitelist; + +impl Contains for DustRemovalWhitelist +where + frame_support::PalletId: AccountIdConversion, +{ + fn contains(ai: &AccountIdTest) -> bool { + let pallets = vec![LiquidityMiningPalletId::get(), PmPalletId::get(), SwapsPalletId::get()]; + + if let Some(pallet_id) = frame_support::PalletId::try_from_sub_account::(ai) { + return pallets.contains(&pallet_id.0); + } + + for pallet_id in pallets { + let pallet_acc: AccountIdTest = pallet_id.into_account_truncating(); + + if pallet_acc == *ai { + return true; + } + } + + false + } +} + impl orml_tokens::Config for Runtime { type Amount = Amount; type Balance = Balance; type CurrencyId = CurrencyId; - type DustRemovalWhitelist = Everything; + type DustRemovalWhitelist = DustRemovalWhitelist; type RuntimeEvent = RuntimeEvent; type ExistentialDeposits = ExistentialDeposits; type MaxLocks = MaxLocks; @@ -219,13 +279,20 @@ impl Default for ExtBuilder { impl ExtBuilder { pub fn build(self) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + let mut storage = + frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: self.balances } - .assimilate_storage(&mut t) + .assimilate_storage(&mut storage) .unwrap(); - t.into() + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + MarketCommons::push_market(mock_market(4)).unwrap(); + }); + + ext } } @@ -258,3 +325,25 @@ sp_api::mock_impl_runtime_apis! { } } } + +pub(super) fn mock_market( + categories: u16, +) -> Market> { + Market { + base_asset: BASE_ASSET, + creation: MarketCreation::Permissionless, + creator_fee: Perbill::from_parts(0), + creator: DEFAULT_MARKET_CREATOR, + market_type: MarketType::Categorical(categories), + dispute_mechanism: MarketDisputeMechanism::Authorized, + metadata: vec![0; 50], + oracle: DEFAULT_MARKET_ORACLE, + period: MarketPeriod::Block(0..1), + deadlines: Deadlines::default(), + report: None, + resolved_outcome: None, + scoring_rule: ScoringRule::CPMM, + status: MarketStatus::Active, + bonds: MarketBonds::default(), + } +} diff --git a/zrml/swaps/src/tests.rs b/zrml/swaps/src/tests.rs index 57d3f4f86..7ffe19af4 100644 --- a/zrml/swaps/src/tests.rs +++ b/zrml/swaps/src/tests.rs @@ -27,8 +27,9 @@ use crate::{ events::{CommonPoolEventParams, PoolAssetEvent, PoolAssetsEvent, SwapEvent}, + math::{calc_in_given_out, calc_out_given_in, calc_spot_price}, mock::*, - BalanceOf, Config, Event, MarketIdOf, PoolsCachedForArbitrage, SubsidyProviders, + BalanceOf, Config, Error, Event, MarketIdOf, PoolsCachedForArbitrage, SubsidyProviders, ARBITRAGE_MAX_ITERATIONS, }; use frame_support::{ @@ -36,30 +37,21 @@ use frame_support::{ weights::Weight, }; use more_asserts::{assert_ge, assert_le}; -use orml_traits::{MultiCurrency, MultiReservableCurrency}; -use sp_runtime::SaturatedConversion; +use orml_traits::{GetByKey, MultiCurrency, MultiReservableCurrency}; +use sp_arithmetic::{traits::SaturatedConversion, Perbill}; +use sp_runtime::DispatchResult; #[allow(unused_imports)] use test_case::test_case; use zeitgeist_primitives::{ constants::BASE, traits::Swaps as _, types::{ - AccountIdTest, Asset, Balance, BlockNumber, Deadlines, Market, MarketBonds, MarketCreation, - MarketDisputeMechanism, MarketId, MarketPeriod, MarketStatus, MarketType, Moment, - OutcomeReport, PoolId, PoolStatus, ScoringRule, + AccountIdTest, Asset, MarketId, MarketType, OutcomeReport, PoolId, PoolStatus, ScoringRule, }, }; use zrml_market_commons::MarketCommonsPalletApi; use zrml_rikiddo::traits::RikiddoMVPallet; -pub const ASSET_A: Asset = Asset::CategoricalOutcome(0, 65); -pub const ASSET_B: Asset = Asset::CategoricalOutcome(0, 66); -pub const ASSET_C: Asset = Asset::CategoricalOutcome(0, 67); -pub const ASSET_D: Asset = Asset::CategoricalOutcome(0, 68); -pub const ASSET_E: Asset = Asset::CategoricalOutcome(0, 69); - -pub const ASSETS: [Asset; 4] = [ASSET_A, ASSET_B, ASSET_C, ASSET_D]; - pub const SENTINEL_AMOUNT: u128 = 123456789; const _1_2: u128 = BASE / 2; @@ -93,7 +85,17 @@ const _900: u128 = 900 * BASE; const _1234: u128 = 1234 * BASE; const _10000: u128 = 10000 * BASE; -const LIQUIDITY: u128 = _100; +const DEFAULT_POOL_ID: PoolId = 0; +const DEFAULT_LIQUIDITY: u128 = _100; +const DEFAULT_WEIGHT: u128 = _2; + +type MarketOf = zeitgeist_primitives::types::Market< + AccountIdTest, + BalanceOf, + ::BlockNumber, + ::Moment, + Asset, +>; // Macro for comparing fixed point u128. #[allow(unused_macros)] @@ -132,10 +134,10 @@ fn create_pool_fails_with_duplicate_assets(assets: Vec 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), - Some(vec![_2; asset_count]), + Some(DEFAULT_LIQUIDITY), + Some(vec![DEFAULT_WEIGHT; asset_count]), ), - crate::Error::::SomeIdenticalAssets + Error::::SomeIdenticalAssets ); }); } @@ -144,7 +146,7 @@ fn create_pool_fails_with_duplicate_assets(assets: Vec fn destroy_pool_fails_if_pool_does_not_exist() { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::CPMM, Some(0), true); - assert_noop!(Swaps::destroy_pool(42), crate::Error::::PoolDoesNotExist); + assert_noop!(Swaps::destroy_pool(42), Error::::PoolDoesNotExist); }); } @@ -152,18 +154,17 @@ fn destroy_pool_fails_if_pool_does_not_exist() { fn destroy_pool_correctly_cleans_up_pool() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; let alice_balance_before = [ Currencies::free_balance(ASSET_A, &ALICE), Currencies::free_balance(ASSET_B, &ALICE), Currencies::free_balance(ASSET_C, &ALICE), Currencies::free_balance(ASSET_D, &ALICE), ]; - assert_ok!(Swaps::destroy_pool(pool_id)); - assert_err!(Swaps::pool(pool_id), crate::Error::::PoolDoesNotExist); + assert_ok!(Swaps::destroy_pool(DEFAULT_POOL_ID)); + assert_err!(Swaps::pool(DEFAULT_POOL_ID), Error::::PoolDoesNotExist); // Ensure that funds _outside_ of the pool are not impacted! // TODO(#792): Remove pool shares. - let total_pool_shares = Currencies::total_issuance(Swaps::pool_shares_id(0)); + let total_pool_shares = Currencies::total_issuance(Swaps::pool_shares_id(DEFAULT_POOL_ID)); assert_all_parameters(alice_balance_before, 0, [0, 0, 0, 0], total_pool_shares); }); } @@ -173,9 +174,8 @@ fn destroy_pool_emits_correct_event() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; - assert_ok!(Swaps::destroy_pool(pool_id)); - System::assert_last_event(Event::PoolDestroyed(pool_id).into()); + assert_ok!(Swaps::destroy_pool(DEFAULT_POOL_ID)); + System::assert_last_event(Event::PoolDestroyed(DEFAULT_POOL_ID).into()); }); } @@ -184,25 +184,27 @@ fn allows_the_full_user_lifecycle() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_join(alice_signed(), 0, _5, vec!(_25, _25, _25, _25),)); + assert_ok!( + Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _5, vec!(_25, _25, _25, _25),) + ); let asset_a_bal = Currencies::free_balance(ASSET_A, &ALICE); let asset_b_bal = Currencies::free_balance(ASSET_B, &ALICE); // swap_exact_amount_in - let spot_price = Swaps::get_spot_price(&0, &ASSET_A, &ASSET_B, true).unwrap(); + let spot_price = Swaps::get_spot_price(&DEFAULT_POOL_ID, &ASSET_A, &ASSET_B, true).unwrap(); assert_eq!(spot_price, _1); - let pool_account = Swaps::pool_account_id(&0); + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); let in_balance = Currencies::free_balance(ASSET_A, &pool_account); assert_eq!(in_balance, _105); - let expected = crate::math::calc_out_given_in( + let expected = calc_out_given_in( in_balance, - _2, + DEFAULT_WEIGHT, Currencies::free_balance(ASSET_B, &pool_account), - _2, + DEFAULT_WEIGHT, _1, 0, ) @@ -210,7 +212,7 @@ fn allows_the_full_user_lifecycle() { assert_ok!(Swaps::swap_exact_amount_in( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, _1, ASSET_B, @@ -229,9 +231,9 @@ fn allows_the_full_user_lifecycle() { // swap_exact_amount_out let expected_in = crate::math::calc_in_given_out( Currencies::free_balance(ASSET_A, &pool_account), - _2, + DEFAULT_WEIGHT, Currencies::free_balance(ASSET_B, &pool_account), - _2, + DEFAULT_WEIGHT, _1, 0, ) @@ -241,7 +243,7 @@ fn allows_the_full_user_lifecycle() { assert_ok!(Swaps::swap_exact_amount_out( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, Some(_2), ASSET_B, @@ -267,39 +269,83 @@ fn assets_must_be_bounded() { })); assert_noop!( - Swaps::swap_exact_amount_in(alice_signed(), 0, ASSET_A, 1, ASSET_B, Some(1), Some(1)), - crate::Error::::AssetNotBound + Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + 1, + ASSET_B, + Some(1), + Some(1) + ), + Error::::AssetNotBound ); assert_noop!( - Swaps::swap_exact_amount_in(alice_signed(), 0, ASSET_B, 1, ASSET_A, Some(1), Some(1)), - crate::Error::::AssetNotBound + Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_B, + 1, + ASSET_A, + Some(1), + Some(1) + ), + Error::::AssetNotBound ); assert_noop!( - Swaps::swap_exact_amount_out(alice_signed(), 0, ASSET_A, Some(1), ASSET_B, 1, Some(1)), - crate::Error::::AssetNotBound + Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + Some(1), + ASSET_B, + 1, + Some(1) + ), + Error::::AssetNotBound ); assert_noop!( - Swaps::swap_exact_amount_out(alice_signed(), 0, ASSET_B, Some(1), ASSET_A, 1, Some(1)), - crate::Error::::AssetNotBound + Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_B, + Some(1), + ASSET_A, + 1, + Some(1) + ), + Error::::AssetNotBound ); assert_noop!( - Swaps::pool_join_with_exact_asset_amount(alice_signed(), 0, ASSET_B, 1, 1), - crate::Error::::AssetNotBound + Swaps::pool_join_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_B, + 1, + 1 + ), + Error::::AssetNotBound ); assert_noop!( - Swaps::pool_join_with_exact_pool_amount(alice_signed(), 0, ASSET_B, 1, 1), - crate::Error::::AssetNotBound + Swaps::pool_join_with_exact_pool_amount(alice_signed(), DEFAULT_POOL_ID, ASSET_B, 1, 1), + Error::::AssetNotBound ); assert_noop!( - Swaps::pool_exit_with_exact_pool_amount(alice_signed(), 0, ASSET_B, 1, 1), - crate::Error::::AssetNotBound + Swaps::pool_exit_with_exact_pool_amount(alice_signed(), DEFAULT_POOL_ID, ASSET_B, 1, 1), + Error::::AssetNotBound ); assert_noop!( - Swaps::pool_exit_with_exact_asset_amount(alice_signed(), 0, ASSET_B, 1, 1), - crate::Error::::AssetNotBound + Swaps::pool_exit_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_B, + 1, + 1 + ), + Error::::AssetNotBound ); }); } @@ -312,15 +358,14 @@ fn create_pool_generates_a_new_pool_with_correct_parameters_for_cpmm() { let next_pool_before = Swaps::next_pool_id(); assert_eq!(next_pool_before, 0); - let amount = LIQUIDITY; - let base_asset = ASSETS.last().unwrap(); + let amount = DEFAULT_LIQUIDITY; ASSETS.iter().cloned().for_each(|asset| { assert_ok!(Currencies::deposit(asset, &BOB, amount)); }); assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *base_asset, + BASE_ASSET, 0, ScoringRule::CPMM, Some(1), @@ -331,11 +376,11 @@ fn create_pool_generates_a_new_pool_with_correct_parameters_for_cpmm() { let next_pool_after = Swaps::next_pool_id(); assert_eq!(next_pool_after, 1); - let pool = Swaps::pools(0).unwrap(); + let pool = Swaps::pools(DEFAULT_POOL_ID).unwrap(); assert_eq!(pool.assets, ASSETS); - assert_eq!(pool.base_asset, *base_asset); - assert_eq!(pool.market_id, 0); + assert_eq!(pool.base_asset, BASE_ASSET); + assert_eq!(pool.market_id, DEFAULT_MARKET_ID); assert_eq!(pool.pool_status, PoolStatus::Initialized); assert_eq!(pool.scoring_rule, ScoringRule::CPMM); assert_eq!(pool.swap_fee, Some(1)); @@ -347,7 +392,7 @@ fn create_pool_generates_a_new_pool_with_correct_parameters_for_cpmm() { assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_C).unwrap(), _2); assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_D).unwrap(), _1); - let pool_account = Swaps::pool_account_id(&0); + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); System::assert_last_event( Event::PoolCreate( CommonPoolEventParams { pool_id: next_pool_before, who: BOB }, @@ -370,7 +415,7 @@ fn create_pool_generates_a_new_pool_with_correct_parameters_for_rikiddo() { let next_pool_after = Swaps::next_pool_id(); assert_eq!(next_pool_after, 1); - let pool = Swaps::pools(0).unwrap(); + let pool = Swaps::pools(DEFAULT_POOL_ID).unwrap(); assert_eq!(pool.assets, ASSETS.to_vec()); assert_eq!(pool.base_asset, ASSET_D); @@ -389,13 +434,13 @@ fn destroy_pool_in_subsidy_phase_returns_subsidy_and_closes_pool() { frame_system::Pallet::::set_block_number(1); // Errors trigger correctly. assert_noop!( - Swaps::destroy_pool_in_subsidy_phase(0), - crate::Error::::PoolDoesNotExist + Swaps::destroy_pool_in_subsidy_phase(DEFAULT_POOL_ID), + Error::::PoolDoesNotExist ); create_initial_pool(ScoringRule::CPMM, Some(0), true); assert_noop!( - Swaps::destroy_pool_in_subsidy_phase(0), - crate::Error::::InvalidStateTransition + Swaps::destroy_pool_in_subsidy_phase(DEFAULT_POOL_ID), + Error::::InvalidStateTransition ); create_initial_pool_with_funds_for_alice( @@ -428,10 +473,9 @@ fn distribute_pool_share_rewards() { ExtBuilder::default().build().execute_with(|| { // Create Rikiddo pool create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, false); - let pool_id = 0; let subsidy_per_acc = ::MinSubsidy::get(); let asset_per_acc = subsidy_per_acc / 10; - let base_asset = Swaps::pool_by_id(pool_id).unwrap().base_asset; + let base_asset = Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().base_asset; let winning_asset = ASSET_A; // Join subsidy with some providers @@ -440,13 +484,13 @@ fn distribute_pool_share_rewards() { assert_ok!(Currencies::deposit(base_asset, provider, subsidy_per_acc)); assert_ok!(Swaps::pool_join_subsidy( RuntimeOrigin::signed(*provider), - pool_id, + DEFAULT_POOL_ID, subsidy_per_acc )); }); // End subsidy phase - assert_ok!(Swaps::end_subsidy_phase(pool_id)); + assert_ok!(Swaps::end_subsidy_phase(DEFAULT_POOL_ID)); // Buy some winning outcome assets with other accounts and remember how many let asset_holders: Vec = (1010..1020).collect(); @@ -454,7 +498,7 @@ fn distribute_pool_share_rewards() { assert_ok!(Currencies::deposit(base_asset, asset_holder, asset_per_acc + 20)); assert_ok!(Swaps::swap_exact_amount_out( RuntimeOrigin::signed(*asset_holder), - pool_id, + DEFAULT_POOL_ID, base_asset, Some(asset_per_acc + 20), winning_asset, @@ -465,11 +509,11 @@ fn distribute_pool_share_rewards() { let total_winning_assets = asset_holders.len().saturated_into::() * asset_per_acc; // Distribute pool share rewards - let pool = Swaps::pool(pool_id).unwrap(); + let pool = Swaps::pool(DEFAULT_POOL_ID).unwrap(); let winner_payout_account: AccountIdTest = 1337; Swaps::distribute_pool_share_rewards( &pool, - pool_id, + DEFAULT_POOL_ID, base_asset, winning_asset, &winner_payout_account, @@ -499,8 +543,11 @@ fn end_subsidy_phase_distributes_shares_and_outcome_assets() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool(ScoringRule::CPMM, Some(0), true); - assert_noop!(Swaps::end_subsidy_phase(0), crate::Error::::InvalidStateTransition); - assert_noop!(Swaps::end_subsidy_phase(1), crate::Error::::PoolDoesNotExist); + assert_noop!( + Swaps::end_subsidy_phase(DEFAULT_POOL_ID), + Error::::InvalidStateTransition + ); + assert_noop!(Swaps::end_subsidy_phase(1), Error::::PoolDoesNotExist); create_initial_pool_with_funds_for_alice( ScoringRule::RikiddoSigmoidFeeMarketEma, None, @@ -561,56 +608,73 @@ fn end_subsidy_phase_distributes_shares_and_outcome_assets() { fn single_asset_operations_and_swaps_fail_on_invalid_status_before_clean(status: PoolStatus) { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; // For this test, we need to give Alice some pool shares, as well. We don't do this in // `create_initial_pool_...` so that there are exacly 100 pool shares, making computations // in other tests easier. - assert_ok!(Currencies::deposit(Swaps::pool_shares_id(0), &ALICE, _25)); - assert_ok!(Swaps::mutate_pool(pool_id, |pool| { + assert_ok!(Currencies::deposit(Swaps::pool_shares_id(DEFAULT_POOL_ID), &ALICE, _25)); + assert_ok!(Swaps::mutate_pool(DEFAULT_POOL_ID, |pool| { pool.pool_status = status; Ok(()) })); assert_noop!( - Swaps::pool_exit_with_exact_asset_amount(alice_signed(), pool_id, ASSET_A, _1, _2), - crate::Error::::PoolIsNotActive + Swaps::pool_exit_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _1, + _2 + ), + Error::::PoolIsNotActive ); assert_noop!( - Swaps::pool_exit_with_exact_pool_amount(alice_signed(), pool_id, ASSET_A, _1, _1_2), - crate::Error::::PoolIsNotActive + Swaps::pool_exit_with_exact_pool_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _1, + _1_2 + ), + Error::::PoolIsNotActive ); assert_noop!( - Swaps::pool_join_with_exact_asset_amount(alice_signed(), pool_id, ASSET_E, 1, 1), - crate::Error::::PoolIsNotActive + Swaps::pool_join_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_E, + 1, + 1 + ), + Error::::PoolIsNotActive ); assert_noop!( - Swaps::pool_join_with_exact_pool_amount(alice_signed(), pool_id, ASSET_E, 1, 1), - crate::Error::::PoolIsNotActive + Swaps::pool_join_with_exact_pool_amount(alice_signed(), DEFAULT_POOL_ID, ASSET_E, 1, 1), + Error::::PoolIsNotActive ); assert_ok!(Currencies::deposit(ASSET_A, &ALICE, u64::MAX.into())); assert_noop!( Swaps::swap_exact_amount_in( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, u64::MAX.into(), ASSET_B, Some(_1), Some(_1), ), - crate::Error::::PoolIsNotActive + Error::::PoolIsNotActive ); assert_noop!( Swaps::swap_exact_amount_out( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, Some(u64::MAX.into()), ASSET_B, _1, Some(_1), ), - crate::Error::::PoolIsNotActive + Error::::PoolIsNotActive ); }); } @@ -619,11 +683,15 @@ fn single_asset_operations_and_swaps_fail_on_invalid_status_before_clean(status: fn pool_join_fails_if_pool_is_closed() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; - assert_ok!(Swaps::close_pool(pool_id)); + assert_ok!(Swaps::close_pool(DEFAULT_POOL_ID)); assert_noop!( - Swaps::pool_join(RuntimeOrigin::signed(ALICE), pool_id, _1, vec![_1, _1, _1, _1]), - crate::Error::::InvalidPoolStatus, + Swaps::pool_join( + RuntimeOrigin::signed(ALICE), + DEFAULT_POOL_ID, + _1, + vec![_1, _1, _1, _1] + ), + Error::::InvalidPoolStatus, ); }); } @@ -632,11 +700,10 @@ fn pool_join_fails_if_pool_is_closed() { fn most_operations_fail_if_pool_is_clean() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; - assert_ok!(Swaps::close_pool(pool_id)); + assert_ok!(Swaps::close_pool(DEFAULT_POOL_ID)); assert_ok!(Swaps::clean_up_pool( &MarketType::Categorical(0), - pool_id, + DEFAULT_POOL_ID, &OutcomeReport::Categorical(if let Asset::CategoricalOutcome(_, idx) = ASSET_A { idx } else { @@ -646,49 +713,67 @@ fn most_operations_fail_if_pool_is_clean() { )); assert_noop!( - Swaps::pool_join(RuntimeOrigin::signed(ALICE), pool_id, _1, vec![_10]), - crate::Error::::InvalidPoolStatus, + Swaps::pool_join(RuntimeOrigin::signed(ALICE), DEFAULT_POOL_ID, _1, vec![_10]), + Error::::InvalidPoolStatus, ); assert_noop!( - Swaps::pool_exit_with_exact_asset_amount(alice_signed(), pool_id, ASSET_A, _1, _2), - crate::Error::::PoolIsNotActive + Swaps::pool_exit_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _1, + _2 + ), + Error::::PoolIsNotActive ); assert_noop!( - Swaps::pool_exit_with_exact_pool_amount(alice_signed(), pool_id, ASSET_A, _1, _1_2), - crate::Error::::PoolIsNotActive + Swaps::pool_exit_with_exact_pool_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _1, + _1_2 + ), + Error::::PoolIsNotActive ); assert_noop!( - Swaps::pool_join_with_exact_asset_amount(alice_signed(), pool_id, ASSET_E, 1, 1), - crate::Error::::PoolIsNotActive + Swaps::pool_join_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_E, + 1, + 1 + ), + Error::::PoolIsNotActive ); assert_noop!( - Swaps::pool_join_with_exact_pool_amount(alice_signed(), pool_id, ASSET_E, 1, 1), - crate::Error::::PoolIsNotActive + Swaps::pool_join_with_exact_pool_amount(alice_signed(), DEFAULT_POOL_ID, ASSET_E, 1, 1), + Error::::PoolIsNotActive ); assert_ok!(Currencies::deposit(ASSET_A, &ALICE, u64::MAX.into())); assert_noop!( Swaps::swap_exact_amount_in( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, u64::MAX.into(), ASSET_B, Some(_1), Some(_1), ), - crate::Error::::PoolIsNotActive + Error::::PoolIsNotActive ); assert_noop!( Swaps::swap_exact_amount_out( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, Some(u64::MAX.into()), ASSET_B, _1, Some(_1), ), - crate::Error::::PoolIsNotActive + Error::::PoolIsNotActive ); }); } @@ -716,22 +801,21 @@ fn get_spot_price_returns_correct_results_cpmm( ) { ExtBuilder::default().build().execute_with(|| { // We always swap ASSET_A for ASSET_B, but we vary the weights, balances and swap fees. - let amount_in_pool = LIQUIDITY; + let amount_in_pool = DEFAULT_LIQUIDITY; ASSETS.iter().cloned().for_each(|asset| { assert_ok!(Currencies::deposit(asset, &BOB, amount_in_pool)); }); assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(swap_fee), Some(amount_in_pool), Some(vec!(weight_in, weight_out, _2, _3)) )); - let pool_id = 0; - let pool_account = Swaps::pool_account_id(&pool_id); + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); // Modify pool balances according to test data. assert_ok!(Currencies::deposit(ASSET_A, &pool_account, balance_in - amount_in_pool)); @@ -739,12 +823,12 @@ fn get_spot_price_returns_correct_results_cpmm( let abs_tol = 100; assert_approx!( - Swaps::get_spot_price(&pool_id, &ASSET_A, &ASSET_B, true).unwrap(), + Swaps::get_spot_price(&DEFAULT_POOL_ID, &ASSET_A, &ASSET_B, true).unwrap(), expected_spot_price_with_fees, abs_tol, ); assert_approx!( - Swaps::get_spot_price(&pool_id, &ASSET_A, &ASSET_B, false).unwrap(), + Swaps::get_spot_price(&DEFAULT_POOL_ID, &ASSET_A, &ASSET_B, false).unwrap(), expected_spot_price_without_fees, abs_tol, ); @@ -755,26 +839,25 @@ fn get_spot_price_returns_correct_results_cpmm( fn get_spot_price_returns_correct_results_rikiddo() { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, false); - let pool_id = 0; assert_noop!( - Swaps::get_spot_price(&pool_id, &ASSETS[0], &ASSETS[0], true), - crate::Error::::PoolIsNotActive + Swaps::get_spot_price(&DEFAULT_POOL_ID, &ASSETS[0], &ASSETS[0], true), + Error::::PoolIsNotActive ); - subsidize_and_start_rikiddo_pool(pool_id, &ALICE, 0); + subsidize_and_start_rikiddo_pool(DEFAULT_POOL_ID, &ALICE, 0); // Asset out, base currency in. Should receive about 1/3 -> price about 3 let price_base_in = - Swaps::get_spot_price(&pool_id, &ASSETS[0], ASSETS.last().unwrap(), true).unwrap(); + Swaps::get_spot_price(&DEFAULT_POOL_ID, &ASSETS[0], &BASE_ASSET, true).unwrap(); // Between 0.3 and 0.4 assert!(price_base_in > 28 * BASE / 10 && price_base_in < 31 * BASE / 10); // Base currency in, asset out. Price about 3. let price_base_out = - Swaps::get_spot_price(&pool_id, ASSETS.last().unwrap(), &ASSETS[0], true).unwrap(); + Swaps::get_spot_price(&DEFAULT_POOL_ID, &BASE_ASSET, &ASSETS[0], true).unwrap(); // Between 2.9 and 3.1 assert!(price_base_out > 3 * BASE / 10 && price_base_out < 4 * BASE / 10); // Asset in, asset out. Price about 1. let price_asset_in_out = - Swaps::get_spot_price(&pool_id, &ASSETS[0], &ASSETS[1], true).unwrap(); + Swaps::get_spot_price(&DEFAULT_POOL_ID, &ASSETS[0], &ASSETS[1], true).unwrap(); // Between 0.9 and 1.1 assert!(price_asset_in_out > 9 * BASE / 10 && price_asset_in_out < 11 * BASE / 10); }); @@ -784,15 +867,14 @@ fn get_spot_price_returns_correct_results_rikiddo() { fn get_all_spot_price_returns_correct_results_rikiddo() { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, false); - let pool_id = 0; assert_noop!( - Swaps::get_spot_price(&pool_id, &ASSETS[0], &ASSETS[0], true), - crate::Error::::PoolIsNotActive + Swaps::get_spot_price(&DEFAULT_POOL_ID, &ASSETS[0], &ASSETS[0], true), + Error::::PoolIsNotActive ); - subsidize_and_start_rikiddo_pool(pool_id, &ALICE, 0); + subsidize_and_start_rikiddo_pool(DEFAULT_POOL_ID, &ALICE, 0); let prices = - Swaps::get_all_spot_prices(&pool_id, false).expect("get_all_spot_prices fails"); + Swaps::get_all_spot_prices(&DEFAULT_POOL_ID, false).expect("get_all_spot_prices fails"); // Base currency in, asset out. // Price Between 0.3 and 0.4 for (asset, price) in prices { @@ -834,18 +916,17 @@ fn get_all_spot_prices_returns_correct_results_cpmm( assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(swap_fee), Some(_100), Some(vec!(weight_a, weight_b, weight_c, weight_d)) )); - let pool_id = 0; // Gets spot prices for all assets against base_asset. let prices = - Swaps::get_all_spot_prices(&pool_id, true).expect("get_all_spot_prices failed"); + Swaps::get_all_spot_prices(&DEFAULT_POOL_ID, true).expect("get_all_spot_prices failed"); for (asset, price) in prices { if asset == ASSET_A { assert_eq!(exp_spot_price_a_with_fees, price); @@ -877,7 +958,7 @@ fn in_amount_must_be_equal_or_less_than_max_in_ratio() { Some(_1), Some(_1), ), - crate::Error::::MaxInRatio + Error::::MaxInRatio ); }); } @@ -887,32 +968,31 @@ fn pool_exit_with_exact_asset_amount_satisfies_max_out_ratio_constraints() { ExtBuilder::default().build().execute_with(|| { // We make sure that the individual asset weights don't divide total weight so we trigger // the calculation of exp using the binomial series. - let amount_in_pool = LIQUIDITY; + let amount_in_pool = DEFAULT_LIQUIDITY; ASSETS.iter().cloned().for_each(|asset| { assert_ok!(Currencies::deposit(asset, &BOB, amount_in_pool)); }); assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), Some(amount_in_pool), Some(vec!(_2, _2, _2, _5)), )); - let pool_id = 0; - assert_ok!(Swaps::open_pool(pool_id)); + assert_ok!(Swaps::open_pool(DEFAULT_POOL_ID)); assert_noop!( Swaps::pool_exit_with_exact_asset_amount( RuntimeOrigin::signed(BOB), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _50, _10000, ), - crate::Error::::MaxOutRatio, + Error::::MaxOutRatio, ); }); } @@ -922,32 +1002,31 @@ fn pool_exit_with_exact_pool_amount_satisfies_max_in_ratio_constraints() { ExtBuilder::default().build().execute_with(|| { // We make sure that the individual asset weights don't divide total weight so we trigger // the calculation of exp using the binomial series. - let amount_in_pool = LIQUIDITY; + let amount_in_pool = DEFAULT_LIQUIDITY; ASSETS.iter().cloned().for_each(|asset| { assert_ok!(Currencies::deposit(asset, &BOB, amount_in_pool)); }); assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), Some(amount_in_pool), Some(vec!(_2, _2, _2, _5)), )); - let pool_id = 0; - assert_ok!(Swaps::open_pool(pool_id)); + assert_ok!(Swaps::open_pool(DEFAULT_POOL_ID)); assert_noop!( Swaps::pool_exit_with_exact_pool_amount( RuntimeOrigin::signed(BOB), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _50, _10000, ), - crate::Error::::MaxInRatio, + Error::::MaxInRatio, ); }); } @@ -957,34 +1036,33 @@ fn pool_join_with_exact_asset_amount_satisfies_max_in_ratio_constraints() { ExtBuilder::default().build().execute_with(|| { // We make sure that the individual asset weights don't divide total weight so we trigger // the calculation of exp using the binomial series. - let amount_in_pool = LIQUIDITY; + let amount_in_pool = DEFAULT_LIQUIDITY; ASSETS.iter().cloned().for_each(|asset| { assert_ok!(Currencies::deposit(asset, &BOB, amount_in_pool)); }); assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), Some(amount_in_pool), Some(vec!(_2, _2, _2, _5)), )); - let pool_id = 0; - assert_ok!(Swaps::open_pool(pool_id)); - let asset_amount = LIQUIDITY; + assert_ok!(Swaps::open_pool(DEFAULT_POOL_ID)); + let asset_amount = DEFAULT_LIQUIDITY; assert_ok!(Currencies::deposit(ASSET_A, &ALICE, asset_amount)); assert_noop!( Swaps::pool_join_with_exact_asset_amount( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, asset_amount, 0, ), - crate::Error::::MaxInRatio, + Error::::MaxInRatio, ); }); } @@ -998,34 +1076,33 @@ fn pool_join_with_exact_pool_amount_satisfies_max_out_ratio_constraints() { ExtBuilder::default().build().execute_with(|| { // We make sure that the individual asset weights don't divide total weight so we trigger // the calculation of exp using the binomial series. - let amount_in_pool = LIQUIDITY; + let amount_in_pool = DEFAULT_LIQUIDITY; ASSETS.iter().cloned().for_each(|asset| { assert_ok!(Currencies::deposit(asset, &BOB, amount_in_pool)); }); assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), Some(amount_in_pool), Some(vec!(_2, _2, _2, _5)), )); - let pool_id = 0; - assert_ok!(Swaps::open_pool(pool_id)); + assert_ok!(Swaps::open_pool(DEFAULT_POOL_ID)); let max_asset_amount = _10000; assert_ok!(Currencies::deposit(ASSET_A, &ALICE, max_asset_amount)); assert_noop!( Swaps::pool_join_with_exact_pool_amount( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _100, max_asset_amount, ), - crate::Error::::MaxOutRatio, + Error::::MaxOutRatio, ); }); } @@ -1035,10 +1112,13 @@ fn admin_clean_up_pool_fails_if_origin_is_not_root() { ExtBuilder::default().build().execute_with(|| { let idx = if let Asset::CategoricalOutcome(_, idx) = ASSET_A { idx } else { 0 }; create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(MarketCommons::push_market(mock_market(69))); - assert_ok!(MarketCommons::insert_market_pool(0, 0)); + assert_ok!(MarketCommons::insert_market_pool(DEFAULT_MARKET_ID, DEFAULT_POOL_ID)); assert_noop!( - Swaps::admin_clean_up_pool(alice_signed(), 0, OutcomeReport::Categorical(idx)), + Swaps::admin_clean_up_pool( + alice_signed(), + DEFAULT_POOL_ID, + OutcomeReport::Categorical(idx) + ), BadOrigin ); }); @@ -1059,7 +1139,7 @@ fn out_amount_must_be_equal_or_less_than_max_out_ratio() { _50, Some(_1), ), - crate::Error::::MaxOutRatio + Error::::MaxOutRatio ); }); } @@ -1070,33 +1150,45 @@ fn pool_join_or_exit_raises_on_zero_value() { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); assert_noop!( - Swaps::pool_join(alice_signed(), 0, 0, vec!(_1, _1, _1, _1)), - crate::Error::::ZeroAmount + Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, 0, vec!(_1, _1, _1, _1)), + Error::::ZeroAmount ); assert_noop!( - Swaps::pool_exit(alice_signed(), 0, 0, vec!(_1, _1, _1, _1)), - crate::Error::::ZeroAmount + Swaps::pool_exit(alice_signed(), DEFAULT_POOL_ID, 0, vec!(_1, _1, _1, _1)), + Error::::ZeroAmount ); assert_noop!( - Swaps::pool_join_with_exact_pool_amount(alice_signed(), 0, ASSET_A, 0, 0), - crate::Error::::ZeroAmount + Swaps::pool_join_with_exact_pool_amount(alice_signed(), DEFAULT_POOL_ID, ASSET_A, 0, 0), + Error::::ZeroAmount ); assert_noop!( - Swaps::pool_join_with_exact_asset_amount(alice_signed(), 0, ASSET_A, 0, 0), - crate::Error::::ZeroAmount + Swaps::pool_join_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + 0, + 0 + ), + Error::::ZeroAmount ); assert_noop!( - Swaps::pool_exit_with_exact_pool_amount(alice_signed(), 0, ASSET_A, 0, 0), - crate::Error::::ZeroAmount + Swaps::pool_exit_with_exact_pool_amount(alice_signed(), DEFAULT_POOL_ID, ASSET_A, 0, 0), + Error::::ZeroAmount ); assert_noop!( - Swaps::pool_exit_with_exact_asset_amount(alice_signed(), 0, ASSET_A, 0, 0), - crate::Error::::ZeroAmount + Swaps::pool_exit_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + 0, + 0 + ), + Error::::ZeroAmount ); }); } @@ -1108,15 +1200,15 @@ fn pool_exit_decreases_correct_pool_parameters() { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_join(alice_signed(), 0, _1, vec!(_1, _1, _1, _1),)); + assert_ok!(Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1, _1, _1),)); - assert_ok!(Swaps::pool_exit(alice_signed(), 0, _1, vec!(_1, _1, _1, _1),)); + assert_ok!(Swaps::pool_exit(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1, _1, _1),)); System::assert_last_event( Event::PoolExit(PoolAssetsEvent { assets: vec![ASSET_A, ASSET_B, ASSET_C, ASSET_D], bounds: vec![_1, _1, _1, _1], - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: vec![_1 + 1, _1 + 1, _1 + 1, _1 + 1], pool_amount: _1, }) @@ -1125,8 +1217,13 @@ fn pool_exit_decreases_correct_pool_parameters() { assert_all_parameters( [_25 + 1, _25 + 1, _25 + 1, _25 + 1], 0, - [LIQUIDITY - 1, LIQUIDITY - 1, LIQUIDITY - 1, LIQUIDITY - 1], - LIQUIDITY, + [ + DEFAULT_LIQUIDITY - 1, + DEFAULT_LIQUIDITY - 1, + DEFAULT_LIQUIDITY - 1, + DEFAULT_LIQUIDITY - 1, + ], + DEFAULT_LIQUIDITY, ); }) } @@ -1136,13 +1233,18 @@ fn pool_exit_emits_correct_events() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_exit(RuntimeOrigin::signed(BOB), 0, _1, vec!(1, 2, 3, 4),)); + assert_ok!(Swaps::pool_exit( + RuntimeOrigin::signed(BOB), + DEFAULT_POOL_ID, + _1, + vec!(1, 2, 3, 4), + )); let amount = _1 - BASE / 10; // Subtract 10% fees! System::assert_last_event( Event::PoolExit(PoolAssetsEvent { assets: vec![ASSET_A, ASSET_B, ASSET_C, ASSET_D], bounds: vec![1, 2, 3, 4], - cpep: CommonPoolEventParams { pool_id: 0, who: BOB }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: BOB }, transferred: vec![amount; 4], pool_amount: _1, }) @@ -1157,26 +1259,31 @@ fn pool_exit_decreases_correct_pool_parameters_with_exit_fee() { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_exit(RuntimeOrigin::signed(BOB), 0, _10, vec!(_1, _1, _1, _1),)); + assert_ok!(Swaps::pool_exit( + RuntimeOrigin::signed(BOB), + DEFAULT_POOL_ID, + _10, + vec!(_1, _1, _1, _1), + )); - let pool_account = Swaps::pool_account_id(&0); - let pool_shares_id = Swaps::pool_shares_id(0); + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); + let pool_shares_id = Swaps::pool_shares_id(DEFAULT_POOL_ID); assert_eq!(Currencies::free_balance(ASSET_A, &BOB), _9); assert_eq!(Currencies::free_balance(ASSET_B, &BOB), _9); assert_eq!(Currencies::free_balance(ASSET_C, &BOB), _9); assert_eq!(Currencies::free_balance(ASSET_D, &BOB), _9); - assert_eq!(Currencies::free_balance(pool_shares_id, &BOB), LIQUIDITY - _10); - assert_eq!(Currencies::free_balance(ASSET_A, &pool_account), LIQUIDITY - _9); - assert_eq!(Currencies::free_balance(ASSET_B, &pool_account), LIQUIDITY - _9); - assert_eq!(Currencies::free_balance(ASSET_C, &pool_account), LIQUIDITY - _9); - assert_eq!(Currencies::free_balance(ASSET_D, &pool_account), LIQUIDITY - _9); - assert_eq!(Currencies::total_issuance(pool_shares_id), LIQUIDITY - _10); + assert_eq!(Currencies::free_balance(pool_shares_id, &BOB), DEFAULT_LIQUIDITY - _10); + assert_eq!(Currencies::free_balance(ASSET_A, &pool_account), DEFAULT_LIQUIDITY - _9); + assert_eq!(Currencies::free_balance(ASSET_B, &pool_account), DEFAULT_LIQUIDITY - _9); + assert_eq!(Currencies::free_balance(ASSET_C, &pool_account), DEFAULT_LIQUIDITY - _9); + assert_eq!(Currencies::free_balance(ASSET_D, &pool_account), DEFAULT_LIQUIDITY - _9); + assert_eq!(Currencies::total_issuance(pool_shares_id), DEFAULT_LIQUIDITY - _10); System::assert_last_event( Event::PoolExit(PoolAssetsEvent { assets: vec![ASSET_A, ASSET_B, ASSET_C, ASSET_D], bounds: vec![_1, _1, _1, _1], - cpep: CommonPoolEventParams { pool_id: 0, who: BOB }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: BOB }, transferred: vec![_9, _9, _9, _9], pool_amount: _10, }) @@ -1191,23 +1298,22 @@ fn pool_exit_decreases_correct_pool_parameters_on_cleaned_up_pool() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(MarketCommons::push_market(mock_market(69))); - assert_ok!(MarketCommons::insert_market_pool(0, 0)); + assert_ok!(MarketCommons::insert_market_pool(DEFAULT_MARKET_ID, DEFAULT_POOL_ID)); - assert_ok!(Swaps::pool_join(alice_signed(), 0, _1, vec!(_1, _1, _1, _1),)); - assert_ok!(Swaps::close_pool(0)); + assert_ok!(Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1, _1, _1),)); + assert_ok!(Swaps::close_pool(DEFAULT_POOL_ID)); assert_ok!(Swaps::admin_clean_up_pool( RuntimeOrigin::root(), - 0, + DEFAULT_POOL_ID, OutcomeReport::Categorical(65), )); - assert_ok!(Swaps::pool_exit(alice_signed(), 0, _1, vec!(_1, _1),)); + assert_ok!(Swaps::pool_exit(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1),)); System::assert_last_event( Event::PoolExit(PoolAssetsEvent { assets: vec![ASSET_A, ASSET_D], bounds: vec![_1, _1], - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: vec![_1 + 1, _1 + 1], pool_amount: _1, }) @@ -1218,8 +1324,13 @@ fn pool_exit_decreases_correct_pool_parameters_on_cleaned_up_pool() { 0, // Note: Although the asset is deleted from the pool, the assets B/C still remain on the // pool account. - [LIQUIDITY - 1, LIQUIDITY + _1, LIQUIDITY + _1, LIQUIDITY - 1], - LIQUIDITY, + [ + DEFAULT_LIQUIDITY - 1, + DEFAULT_LIQUIDITY + _1, + DEFAULT_LIQUIDITY + _1, + DEFAULT_LIQUIDITY - 1, + ], + DEFAULT_LIQUIDITY, ); }) } @@ -1235,42 +1346,46 @@ fn pool_exit_subsidy_unreserves_correct_values() { None, false, ); - let pool_id = 0; // Add some subsidy - assert_ok!(Swaps::pool_join_subsidy(alice_signed(), pool_id, _25)); + assert_ok!(Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, _25)); let mut reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - let mut noted = >::get(pool_id, ALICE).unwrap(); - let mut total_subsidy = Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap(); + let mut noted = >::get(DEFAULT_POOL_ID, ALICE).unwrap(); + let mut total_subsidy = Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap(); assert_eq!(reserved, _25); assert_eq!(reserved, noted); assert_eq!(reserved, total_subsidy); // Exit 5 subsidy and see if the storage is consistent - assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), pool_id, _5)); + assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, _5)); reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - noted = >::get(pool_id, ALICE).unwrap(); - total_subsidy = Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap(); + noted = >::get(DEFAULT_POOL_ID, ALICE).unwrap(); + total_subsidy = Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap(); assert_eq!(reserved, noted); assert_eq!(reserved, total_subsidy); System::assert_last_event( - Event::PoolExitSubsidy(ASSET_D, _5, CommonPoolEventParams { pool_id, who: ALICE }, _5) - .into(), + Event::PoolExitSubsidy( + ASSET_D, + _5, + CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: ALICE }, + _5, + ) + .into(), ); // Exit the remaining subsidy (in fact, we attempt to exit with more than remaining!) and // see if the storage is consistent - assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), pool_id, _25)); + assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, _25)); reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - assert!(>::get(pool_id, ALICE).is_none()); - total_subsidy = Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap(); + assert!(>::get(DEFAULT_POOL_ID, ALICE).is_none()); + total_subsidy = Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap(); assert_eq!(reserved, 0); assert_eq!(reserved, total_subsidy); System::assert_last_event( Event::PoolExitSubsidy( ASSET_D, _25, - CommonPoolEventParams { pool_id, who: ALICE }, + CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: ALICE }, _20, ) .into(), @@ -1278,12 +1393,12 @@ fn pool_exit_subsidy_unreserves_correct_values() { // Add some subsidy, manually remove some reserved balance (create inconsistency) // and check if the internal values are adjusted to the inconsistency. - assert_ok!(Swaps::pool_join_subsidy(alice_signed(), pool_id, _25)); + assert_ok!(Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, _25)); assert_eq!(Currencies::unreserve(ASSET_D, &ALICE, _20), 0); - assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), pool_id, _20)); + assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, _20)); reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - assert!(>::get(pool_id, ALICE).is_none()); - total_subsidy = Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap(); + assert!(>::get(DEFAULT_POOL_ID, ALICE).is_none()); + total_subsidy = Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap(); assert_eq!(reserved, 0); assert_eq!(reserved, total_subsidy); }); @@ -1298,8 +1413,8 @@ fn pool_exit_subsidy_fails_if_no_subsidy_is_provided() { false, ); assert_noop!( - Swaps::pool_exit_subsidy(alice_signed(), 0, _1), - crate::Error::::NoSubsidyProvided + Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, _1), + Error::::NoSubsidyProvided ); }); } @@ -1313,8 +1428,8 @@ fn pool_exit_subsidy_fails_if_amount_is_zero() { false, ); assert_noop!( - Swaps::pool_exit_subsidy(alice_signed(), 0, 0), - crate::Error::::ZeroAmount + Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, 0), + Error::::ZeroAmount ); }); } @@ -1323,8 +1438,8 @@ fn pool_exit_subsidy_fails_if_amount_is_zero() { fn pool_exit_subsidy_fails_if_pool_does_not_exist() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - Swaps::pool_exit_subsidy(alice_signed(), 0, _1), - crate::Error::::PoolDoesNotExist + Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, _1), + Error::::PoolDoesNotExist ); }); } @@ -1334,8 +1449,8 @@ fn pool_exit_subsidy_fails_if_scoring_rule_is_not_rikiddo() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); assert_noop!( - Swaps::pool_exit_subsidy(alice_signed(), 0, _1), - crate::Error::::InvalidScoringRule + Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, _1), + Error::::InvalidScoringRule ); }); } @@ -1358,17 +1473,17 @@ fn pool_exit_with_exact_pool_amount_exchanges_correct_values( create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); assert_ok!(Swaps::pool_join_with_exact_asset_amount( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, asset_amount_joined, 0 )); - let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(0), &ALICE); + let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(DEFAULT_POOL_ID), &ALICE); assert_eq!(pool_amount, pool_amount_expected); // (This is just a sanity check) assert_ok!(Swaps::pool_exit_with_exact_pool_amount( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, pool_amount, bound, @@ -1377,7 +1492,7 @@ fn pool_exit_with_exact_pool_amount_exchanges_correct_values( Event::PoolExitWithExactPoolAmount(PoolAssetEvent { asset: ASSET_A, bound, - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: asset_amount_expected, pool_amount, }) @@ -1387,12 +1502,12 @@ fn pool_exit_with_exact_pool_amount_exchanges_correct_values( [_25 - asset_amount_joined + asset_amount_expected, _25, _25, _25], 0, [ - LIQUIDITY + asset_amount_joined - asset_amount_expected, - LIQUIDITY, - LIQUIDITY, - LIQUIDITY, + DEFAULT_LIQUIDITY + asset_amount_joined - asset_amount_expected, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, ], - LIQUIDITY, + DEFAULT_LIQUIDITY, ) }); } @@ -1418,14 +1533,14 @@ fn pool_exit_with_exact_asset_amount_exchanges_correct_values( create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); assert_ok!(Swaps::pool_join_with_exact_asset_amount( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, asset_amount_joined, 0 )); // (Sanity check for dust size) - let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(0), &ALICE); + let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(DEFAULT_POOL_ID), &ALICE); let abs_diff = |x, y| { if x < y { y - x } else { x - y } }; @@ -1434,7 +1549,7 @@ fn pool_exit_with_exact_asset_amount_exchanges_correct_values( assert_ok!(Swaps::pool_exit_with_exact_asset_amount( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, asset_amount, bound, @@ -1443,7 +1558,7 @@ fn pool_exit_with_exact_asset_amount_exchanges_correct_values( Event::PoolExitWithExactAssetAmount(PoolAssetEvent { asset: ASSET_A, bound, - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: asset_amount, pool_amount: pool_amount_expected, }) @@ -1452,8 +1567,13 @@ fn pool_exit_with_exact_asset_amount_exchanges_correct_values( assert_all_parameters( [_25 - asset_amount_joined + asset_amount, _25, _25, _25], dust, - [LIQUIDITY + asset_amount_joined - asset_amount, LIQUIDITY, LIQUIDITY, LIQUIDITY], - LIQUIDITY + dust, + [ + DEFAULT_LIQUIDITY + asset_amount_joined - asset_amount, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + ], + DEFAULT_LIQUIDITY + dust, ) }); } @@ -1466,15 +1586,15 @@ fn pool_exit_is_not_allowed_with_insufficient_funds() { // Alice has no pool shares! assert_noop!( - Swaps::pool_exit(alice_signed(), 0, _1, vec!(0, 0, 0, 0)), - crate::Error::::InsufficientBalance, + Swaps::pool_exit(alice_signed(), DEFAULT_POOL_ID, _1, vec!(0, 0, 0, 0)), + Error::::InsufficientBalance, ); // Now Alice has 25 pool shares! - let _ = Currencies::deposit(Swaps::pool_shares_id(0), &ALICE, _25); + let _ = Currencies::deposit(Swaps::pool_shares_id(DEFAULT_POOL_ID), &ALICE, _25); assert_noop!( - Swaps::pool_exit(alice_signed(), 0, _26, vec!(0, 0, 0, 0)), - crate::Error::::InsufficientBalance, + Swaps::pool_exit(alice_signed(), DEFAULT_POOL_ID, _26, vec!(0, 0, 0, 0)), + Error::::InsufficientBalance, ); }) } @@ -1485,12 +1605,14 @@ fn pool_join_increases_correct_pool_parameters() { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_join(alice_signed(), 0, _5, vec!(_25, _25, _25, _25),)); + assert_ok!( + Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _5, vec!(_25, _25, _25, _25),) + ); System::assert_last_event( Event::PoolJoin(PoolAssetsEvent { assets: vec![ASSET_A, ASSET_B, ASSET_C, ASSET_D], bounds: vec![_25, _25, _25, _25], - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: vec![_5, _5, _5, _5], pool_amount: _5, }) @@ -1505,12 +1627,12 @@ fn pool_join_emits_correct_events() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_join(alice_signed(), 0, _1, vec!(_1, _1, _1, _1),)); + assert_ok!(Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1, _1, _1),)); System::assert_last_event( Event::PoolJoin(PoolAssetsEvent { assets: vec![ASSET_A, ASSET_B, ASSET_C, ASSET_D], bounds: vec![_1, _1, _1, _1], - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: vec![_1, _1, _1, _1], pool_amount: _1, }) @@ -1529,28 +1651,37 @@ fn pool_join_subsidy_reserves_correct_values() { None, false, ); - let pool_id = 0; - assert_ok!(Swaps::pool_join_subsidy(alice_signed(), pool_id, _20)); + assert_ok!(Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, _20)); let mut reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - let mut noted = >::get(pool_id, ALICE).unwrap(); + let mut noted = >::get(DEFAULT_POOL_ID, ALICE).unwrap(); assert_eq!(reserved, _20); assert_eq!(reserved, noted); - assert_eq!(reserved, Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap()); + assert_eq!(reserved, Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap()); System::assert_last_event( - Event::PoolJoinSubsidy(ASSET_D, _20, CommonPoolEventParams { pool_id, who: ALICE }) - .into(), + Event::PoolJoinSubsidy( + ASSET_D, + _20, + CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: ALICE }, + ) + .into(), ); - assert_ok!(Swaps::pool_join_subsidy(alice_signed(), pool_id, _5)); + assert_ok!(Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, _5)); reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - noted = >::get(pool_id, ALICE).unwrap(); + noted = >::get(DEFAULT_POOL_ID, ALICE).unwrap(); assert_eq!(reserved, _25); assert_eq!(reserved, noted); - assert_eq!(reserved, Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap()); - assert_storage_noop!(Swaps::pool_join_subsidy(alice_signed(), pool_id, _5).unwrap_or(())); + assert_eq!(reserved, Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap()); + assert_storage_noop!( + Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, _5).unwrap_or(()) + ); System::assert_last_event( - Event::PoolJoinSubsidy(ASSET_D, _5, CommonPoolEventParams { pool_id, who: ALICE }) - .into(), + Event::PoolJoinSubsidy( + ASSET_D, + _5, + CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: ALICE }, + ) + .into(), ); }); } @@ -1564,8 +1695,8 @@ fn pool_join_subsidy_fails_if_amount_is_zero() { false, ); assert_noop!( - Swaps::pool_join_subsidy(alice_signed(), 0, 0), - crate::Error::::ZeroAmount + Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, 0), + Error::::ZeroAmount ); }); } @@ -1574,8 +1705,8 @@ fn pool_join_subsidy_fails_if_amount_is_zero() { fn pool_join_subsidy_fails_if_pool_does_not_exist() { ExtBuilder::default().build().execute_with(|| { assert_noop!( - Swaps::pool_join_subsidy(alice_signed(), 0, _1), - crate::Error::::PoolDoesNotExist + Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, _1), + Error::::PoolDoesNotExist ); }); } @@ -1585,8 +1716,8 @@ fn pool_join_subsidy_fails_if_scoring_rule_is_not_rikiddo() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); assert_noop!( - Swaps::pool_join_subsidy(alice_signed(), 0, _1), - crate::Error::::InvalidScoringRule + Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, _1), + Error::::InvalidScoringRule ); }); } @@ -1605,7 +1736,7 @@ fn pool_join_subsidy_fails_if_subsidy_is_below_min_per_account() { 0, ::MinSubsidyPerAccount::get() - 1 ), - crate::Error::::InvalidSubsidyAmount, + Error::::InvalidSubsidyAmount, ); }); } @@ -1618,15 +1749,14 @@ fn pool_join_subsidy_with_small_amount_is_ok_if_account_is_already_a_provider() None, false, ); - let pool_id = 0; let large_amount = ::MinSubsidyPerAccount::get(); let small_amount = 1; let total_amount = large_amount + small_amount; - assert_ok!(Swaps::pool_join_subsidy(alice_signed(), pool_id, large_amount)); - assert_ok!(Swaps::pool_join_subsidy(alice_signed(), pool_id, small_amount)); + assert_ok!(Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, large_amount)); + assert_ok!(Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, small_amount)); let reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - let noted = >::get(pool_id, ALICE).unwrap(); - let total_subsidy = Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap(); + let noted = >::get(DEFAULT_POOL_ID, ALICE).unwrap(); + let total_subsidy = Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap(); assert_eq!(reserved, total_amount); assert_eq!(noted, total_amount); assert_eq!(total_subsidy, total_amount); @@ -1642,14 +1772,13 @@ fn pool_exit_subsidy_unreserves_remaining_subsidy_if_below_min_per_account() { None, false, ); - let pool_id = 0; let large_amount = ::MinSubsidyPerAccount::get(); let small_amount = 1; - assert_ok!(Swaps::pool_join_subsidy(alice_signed(), pool_id, large_amount)); - assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), pool_id, small_amount)); + assert_ok!(Swaps::pool_join_subsidy(alice_signed(), DEFAULT_POOL_ID, large_amount)); + assert_ok!(Swaps::pool_exit_subsidy(alice_signed(), DEFAULT_POOL_ID, small_amount)); let reserved = Currencies::reserved_balance(ASSET_D, &ALICE); - let noted = >::get(pool_id, ALICE); - let total_subsidy = Swaps::pool_by_id(pool_id).unwrap().total_subsidy.unwrap(); + let noted = >::get(DEFAULT_POOL_ID, ALICE); + let total_subsidy = Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().total_subsidy.unwrap(); assert_eq!(reserved, 0); assert!(noted.is_none()); assert_eq!(total_subsidy, 0); @@ -1657,7 +1786,7 @@ fn pool_exit_subsidy_unreserves_remaining_subsidy_if_below_min_per_account() { Event::PoolExitSubsidy( ASSET_D, small_amount, - CommonPoolEventParams { pool_id, who: ALICE }, + CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: ALICE }, large_amount, ) .into(), @@ -1679,7 +1808,7 @@ fn pool_join_with_exact_asset_amount_exchanges_correct_values( let alice_sent = _1; assert_ok!(Swaps::pool_join_with_exact_asset_amount( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, asset_amount, bound, @@ -1688,7 +1817,7 @@ fn pool_join_with_exact_asset_amount_exchanges_correct_values( Event::PoolJoinWithExactAssetAmount(PoolAssetEvent { asset: ASSET_A, bound, - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: asset_amount, pool_amount: pool_amount_expected, }) @@ -1697,8 +1826,13 @@ fn pool_join_with_exact_asset_amount_exchanges_correct_values( assert_all_parameters( [_25 - asset_amount, _25, _25, _25], pool_amount_expected, - [LIQUIDITY + alice_sent, LIQUIDITY, LIQUIDITY, LIQUIDITY], - LIQUIDITY + pool_amount_expected, + [ + DEFAULT_LIQUIDITY + alice_sent, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + ], + DEFAULT_LIQUIDITY + pool_amount_expected, ); }); } @@ -1716,7 +1850,7 @@ fn pool_join_with_exact_pool_amount_exchanges_correct_values( let bound = _5; assert_ok!(Swaps::pool_join_with_exact_pool_amount( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, pool_amount, bound, @@ -1725,7 +1859,7 @@ fn pool_join_with_exact_pool_amount_exchanges_correct_values( Event::PoolJoinWithExactPoolAmount(PoolAssetEvent { asset: ASSET_A, bound, - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, transferred: asset_amount_expected, pool_amount, }) @@ -1734,8 +1868,13 @@ fn pool_join_with_exact_pool_amount_exchanges_correct_values( assert_all_parameters( [_25 - asset_amount_expected, _25, _25, _25], pool_amount, - [LIQUIDITY + asset_amount_expected, LIQUIDITY, LIQUIDITY, LIQUIDITY], - LIQUIDITY + pool_amount, + [ + DEFAULT_LIQUIDITY + asset_amount_expected, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + ], + DEFAULT_LIQUIDITY + pool_amount, ); }); } @@ -1745,12 +1884,12 @@ fn provided_values_len_must_equal_assets_len() { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::CPMM, Some(0), true); assert_noop!( - Swaps::pool_join(alice_signed(), 0, _5, vec![]), - crate::Error::::ProvidedValuesLenMustEqualAssetsLen + Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _5, vec![]), + Error::::ProvidedValuesLenMustEqualAssetsLen ); assert_noop!( - Swaps::pool_exit(alice_signed(), 0, _5, vec![]), - crate::Error::::ProvidedValuesLenMustEqualAssetsLen + Swaps::pool_exit(alice_signed(), DEFAULT_POOL_ID, _5, vec![]), + Error::::ProvidedValuesLenMustEqualAssetsLen ); }); } @@ -1760,19 +1899,18 @@ fn clean_up_pool_leaves_only_correct_assets() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; - assert_ok!(Swaps::close_pool(pool_id)); + assert_ok!(Swaps::close_pool(DEFAULT_POOL_ID)); let cat_idx = if let Asset::CategoricalOutcome(_, cidx) = ASSET_A { cidx } else { 0 }; assert_ok!(Swaps::clean_up_pool( &MarketType::Categorical(4), - pool_id, + DEFAULT_POOL_ID, &OutcomeReport::Categorical(cat_idx), &Default::default() )); - let pool = Swaps::pool(pool_id).unwrap(); + let pool = Swaps::pool(DEFAULT_POOL_ID).unwrap(); assert_eq!(pool.pool_status, PoolStatus::Clean); - assert_eq!(Swaps::pool_by_id(pool_id).unwrap().assets, vec![ASSET_A, ASSET_D]); - System::assert_last_event(Event::PoolCleanedUp(pool_id).into()); + assert_eq!(Swaps::pool_by_id(DEFAULT_POOL_ID).unwrap().assets, vec![ASSET_A, ASSET_D]); + System::assert_last_event(Event::PoolCleanedUp(DEFAULT_POOL_ID).into()); }); } @@ -1780,25 +1918,24 @@ fn clean_up_pool_leaves_only_correct_assets() { fn clean_up_pool_handles_rikiddo_pools_properly() { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, false); - let pool_id = 0; let cat_idx = if let Asset::CategoricalOutcome(_, cidx) = ASSET_A { cidx } else { 0 }; // We need to forcefully close the pool (Rikiddo pools are not allowed to be cleaned // up when CollectingSubsidy). - assert_ok!(Swaps::mutate_pool(pool_id, |pool| { + assert_ok!(Swaps::mutate_pool(DEFAULT_POOL_ID, |pool| { pool.pool_status = PoolStatus::Closed; Ok(()) })); assert_ok!(Swaps::clean_up_pool( &MarketType::Categorical(4), - pool_id, + DEFAULT_POOL_ID, &OutcomeReport::Categorical(cat_idx), &Default::default() )); // Rikiddo instance does not exist anymore. - assert_storage_noop!(RikiddoSigmoidFeeMarketEma::clear(pool_id).unwrap_or(())); + assert_storage_noop!(RikiddoSigmoidFeeMarketEma::clear(DEFAULT_POOL_ID).unwrap_or(())); }); } @@ -1809,21 +1946,19 @@ fn clean_up_pool_handles_rikiddo_pools_properly() { fn clean_up_pool_fails_if_pool_is_not_closed(pool_status: PoolStatus) { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, false); - let pool_id = 0; - assert_ok!(Swaps::mutate_pool(pool_id, |pool| { + assert_ok!(Swaps::mutate_pool(DEFAULT_POOL_ID, |pool| { pool.pool_status = pool_status; Ok(()) })); - let pool_id = 0; let cat_idx = if let Asset::CategoricalOutcome(_, cidx) = ASSET_A { cidx } else { 0 }; assert_noop!( Swaps::clean_up_pool( &MarketType::Categorical(4), - pool_id, + DEFAULT_POOL_ID, &OutcomeReport::Categorical(cat_idx), &Default::default() ), - crate::Error::::InvalidStateTransition + Error::::InvalidStateTransition ); }); } @@ -1832,16 +1967,15 @@ fn clean_up_pool_fails_if_pool_is_not_closed(pool_status: PoolStatus) { fn clean_up_pool_fails_if_winning_asset_is_not_found() { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; - assert_ok!(Swaps::close_pool(pool_id)); + assert_ok!(Swaps::close_pool(DEFAULT_POOL_ID)); assert_noop!( Swaps::clean_up_pool( &MarketType::Categorical(1337), - pool_id, + DEFAULT_POOL_ID, &OutcomeReport::Categorical(1337), &Default::default() ), - crate::Error::::WinningAssetNotFound + Error::::WinningAssetNotFound ); }); } @@ -1855,7 +1989,7 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm() { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); assert_ok!(Swaps::swap_exact_amount_in( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, _1, ASSET_B, @@ -1869,7 +2003,7 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm() { asset_bound, asset_in: ASSET_A, asset_out: ASSET_B, - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, max_price, }) .into(), @@ -1877,8 +2011,13 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm() { assert_all_parameters( [_24, _25 + 9900990100, _25, _25], 0, - [LIQUIDITY + _1, LIQUIDITY - 9900990100, LIQUIDITY, LIQUIDITY], - LIQUIDITY, + [ + DEFAULT_LIQUIDITY + _1, + DEFAULT_LIQUIDITY - 9900990100, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + ], + DEFAULT_LIQUIDITY, ); }); } @@ -1894,15 +2033,14 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm_with_fees() { assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(BASE / 10), - Some(LIQUIDITY), - Some(vec!(_2, _2, _2, _2)), + Some(DEFAULT_LIQUIDITY), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), )); - let pool_id = 0; - assert_ok!(Swaps::open_pool(pool_id)); + assert_ok!(Swaps::open_pool(DEFAULT_POOL_ID)); let asset_bound = Some(_1 / 2); let max_price = Some(_2); @@ -1912,7 +2050,7 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm_with_fees() { let asset_amount_out = 9_900_990_100; assert_ok!(Swaps::swap_exact_amount_in( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, asset_amount_in, ASSET_B, @@ -1926,7 +2064,7 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm_with_fees() { asset_bound, asset_in: ASSET_A, asset_out: ASSET_B, - cpep: CommonPoolEventParams { pool_id, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, max_price, }) .into(), @@ -1934,8 +2072,13 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm_with_fees() { assert_all_parameters( [_25 - asset_amount_in, _25 + asset_amount_out, _25, _25], 0, - [LIQUIDITY + asset_amount_in, LIQUIDITY - asset_amount_out, LIQUIDITY, LIQUIDITY], - LIQUIDITY, + [ + DEFAULT_LIQUIDITY + asset_amount_in, + DEFAULT_LIQUIDITY - asset_amount_out, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + ], + DEFAULT_LIQUIDITY, ); }); } @@ -1946,8 +2089,16 @@ fn swap_exact_amount_in_fails_if_no_limit_is_specified() { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); assert_noop!( - Swaps::swap_exact_amount_in(alice_signed(), 0, ASSET_A, _1, ASSET_B, None, None,), - crate::Error::::LimitMissing + Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _1, + ASSET_B, + None, + None, + ), + Error::::LimitMissing ); }); } @@ -1969,7 +2120,7 @@ fn swap_exact_amount_in_fails_if_min_asset_amount_out_is_not_satisfied_with_cpmm Some(expected_amount + 1), // We expect 1 more than we will actually receive! None, ), - crate::Error::::LimitOut, + Error::::LimitOut, ); }); } @@ -1981,8 +2132,16 @@ fn swap_exact_amount_in_fails_if_max_price_is_not_satisfied_with_cpmm() { // We're swapping 1:1, but due to slippage the price will exceed _1, so this should raise an // error: assert_noop!( - Swaps::swap_exact_amount_in(alice_signed(), 0, ASSET_A, _1, ASSET_B, None, Some(_1)), - crate::Error::::BadLimitPrice, + Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _1, + ASSET_B, + None, + Some(_1) + ), + Error::::BadLimitPrice, ); }); } @@ -1991,36 +2150,35 @@ fn swap_exact_amount_in_fails_if_max_price_is_not_satisfied_with_cpmm() { fn swap_exact_amount_in_exchanges_correct_values_with_rikiddo() { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, true); - let pool_id = 0; // Generate funds, add subsidy and start pool. - subsidize_and_start_rikiddo_pool(pool_id, &ALICE, _1); + subsidize_and_start_rikiddo_pool(DEFAULT_POOL_ID, &ALICE, _1); assert_ok!(Currencies::deposit(ASSET_A, &ALICE, _1)); // Check if unsupport trades are catched (base_asset in || asset_in == asset_out). assert_noop!( Swaps::swap_exact_amount_in( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_D, _1, ASSET_B, Some(_1 / 2), Some(_2), ), - crate::Error::::UnsupportedTrade + Error::::UnsupportedTrade ); assert_noop!( Swaps::swap_exact_amount_in( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_D, _1, ASSET_D, Some(_1 / 2), Some(_2), ), - crate::Error::::UnsupportedTrade + Error::::UnsupportedTrade ); assert_ok!(Currencies::withdraw(ASSET_D, &ALICE, _1)); @@ -2028,7 +2186,7 @@ fn swap_exact_amount_in_exchanges_correct_values_with_rikiddo() { let asset_a_issuance = Currencies::total_issuance(ASSET_A); assert_ok!(Swaps::swap_exact_amount_in( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _1, ASSET_D, @@ -2057,7 +2215,7 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm() { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); assert_ok!(Swaps::swap_exact_amount_out( alice_signed(), - 0, + DEFAULT_POOL_ID, ASSET_A, asset_bound, ASSET_B, @@ -2071,7 +2229,7 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm() { asset_bound, asset_in: ASSET_A, asset_out: ASSET_B, - cpep: CommonPoolEventParams { pool_id: 0, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, max_price, }) .into(), @@ -2079,8 +2237,13 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm() { assert_all_parameters( [239898989900, _26, _25, _25], 0, - [LIQUIDITY + _1 + 101010100, LIQUIDITY - _1, LIQUIDITY, LIQUIDITY], - LIQUIDITY, + [ + DEFAULT_LIQUIDITY + _1 + 101010100, + DEFAULT_LIQUIDITY - _1, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + ], + DEFAULT_LIQUIDITY, ); }); } @@ -2096,15 +2259,14 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm_with_fees() { assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(BASE / 10), - Some(LIQUIDITY), - Some(vec!(_2, _2, _2, _2)), + Some(DEFAULT_LIQUIDITY), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), )); - let pool_id = 0; - assert_ok!(Swaps::open_pool(pool_id)); + assert_ok!(Swaps::open_pool(DEFAULT_POOL_ID)); let asset_amount_out = _1; let asset_amount_in = 11223344556; // 10101010100 / 0.9 @@ -2112,7 +2274,7 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm_with_fees() { let max_price = Some(_3); assert_ok!(Swaps::swap_exact_amount_out( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_A, asset_bound, ASSET_B, @@ -2126,7 +2288,7 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm_with_fees() { asset_bound, asset_in: ASSET_A, asset_out: ASSET_B, - cpep: CommonPoolEventParams { pool_id, who: 0 }, + cpep: CommonPoolEventParams { pool_id: DEFAULT_POOL_ID, who: 0 }, max_price, }) .into(), @@ -2134,8 +2296,13 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm_with_fees() { assert_all_parameters( [_25 - asset_amount_in, _25 + asset_amount_out, _25, _25], 0, - [LIQUIDITY + asset_amount_in, LIQUIDITY - asset_amount_out, LIQUIDITY, LIQUIDITY], - LIQUIDITY, + [ + DEFAULT_LIQUIDITY + asset_amount_in, + DEFAULT_LIQUIDITY - asset_amount_out, + DEFAULT_LIQUIDITY, + DEFAULT_LIQUIDITY, + ], + DEFAULT_LIQUIDITY, ); }); } @@ -2146,8 +2313,16 @@ fn swap_exact_amount_out_fails_if_no_limit_is_specified() { frame_system::Pallet::::set_block_number(1); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); assert_noop!( - Swaps::swap_exact_amount_out(alice_signed(), 0, ASSET_A, None, ASSET_B, _1, None,), - crate::Error::::LimitMissing + Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + None, + ASSET_B, + _1, + None, + ), + Error::::LimitMissing ); }); } @@ -2169,7 +2344,7 @@ fn swap_exact_amount_out_fails_if_min_asset_amount_out_is_not_satisfied_with_cpm _1, None, ), - crate::Error::::LimitIn, + Error::::LimitIn, ); }); } @@ -2181,8 +2356,16 @@ fn swap_exact_amount_out_fails_if_max_price_is_not_satisfied_with_cpmm() { // We're swapping 1:1, but due to slippage the price will exceed 1, so this should raise an // error: assert_noop!( - Swaps::swap_exact_amount_out(alice_signed(), 0, ASSET_A, None, ASSET_B, _1, Some(_1)), - crate::Error::::BadLimitPrice, + Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + None, + ASSET_B, + _1, + Some(_1) + ), + Error::::BadLimitPrice, ); }); } @@ -2192,42 +2375,41 @@ fn swap_exact_amount_out_exchanges_correct_values_with_rikiddo() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, true); - let pool_id = 0; // Generate funds, add subsidy and start pool. - subsidize_and_start_rikiddo_pool(pool_id, &ALICE, (BASE * 4) / 10); + subsidize_and_start_rikiddo_pool(DEFAULT_POOL_ID, &ALICE, (BASE * 4) / 10); // Check if unsupport trades are catched (base_asset out || asset_in == asset_out). assert_noop!( Swaps::swap_exact_amount_out( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_B, Some(_20), ASSET_D, _1, Some(_20), ), - crate::Error::::UnsupportedTrade + Error::::UnsupportedTrade ); assert_noop!( Swaps::swap_exact_amount_out( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_D, Some(_2), ASSET_D, _1, Some(_2), ), - crate::Error::::UnsupportedTrade + Error::::UnsupportedTrade ); // Check if the trade is executed. let asset_a_issuance = Currencies::total_issuance(ASSET_A); assert_ok!(Swaps::swap_exact_amount_out( alice_signed(), - pool_id, + DEFAULT_POOL_ID, ASSET_D, Some(_1), ASSET_A, @@ -2253,7 +2435,7 @@ fn create_pool_fails_on_too_many_assets() { let length = ::MaxAssets::get(); let assets: Vec> = (0..=length).map(|x| Asset::CategoricalOutcome(0, x)).collect::>(); - let weights = vec![_2; length.into()]; + let weights = vec![DEFAULT_WEIGHT; length.into()]; assets.iter().cloned().for_each(|asset| { let _ = Currencies::deposit(asset, &BOB, _100); @@ -2267,10 +2449,10 @@ fn create_pool_fails_on_too_many_assets() { 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), + Some(DEFAULT_LIQUIDITY), Some(weights), ), - crate::Error::::TooManyAssets + Error::::TooManyAssets ); }); } @@ -2286,10 +2468,10 @@ fn create_pool_fails_on_too_few_assets() { 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), - Some(vec!(_2, _2, _2, _2)), + Some(DEFAULT_LIQUIDITY), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), ), - crate::Error::::TooFewAssets + Error::::TooFewAssets ); }); } @@ -2305,10 +2487,10 @@ fn create_pool_fails_if_base_asset_is_not_in_asset_vector() { 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), - Some(vec!(_2, _2, _2)), + Some(DEFAULT_LIQUIDITY), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), ), - crate::Error::::BaseAssetNotFound + Error::::BaseAssetNotFound ); }); } @@ -2329,9 +2511,9 @@ fn create_pool_fails_if_swap_fee_is_too_high() { ScoringRule::CPMM, Some(::MaxSwapFee::get() + 1), Some(amount), - Some(vec!(_2, _2, _2)), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), ), - crate::Error::::SwapFeeTooHigh + Error::::SwapFeeTooHigh ); }); } @@ -2352,9 +2534,9 @@ fn create_pool_fails_if_swap_fee_is_unspecified_for_cpmm() { ScoringRule::CPMM, None, Some(amount), - Some(vec!(_2, _2, _2)), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), ), - crate::Error::::InvalidFeeArgument + Error::::InvalidFeeArgument ); }); } @@ -2371,15 +2553,20 @@ fn join_pool_exit_pool_does_not_create_extra_tokens() { let amount = 123_456_789_123; // Strange number to force rounding errors! assert_ok!(Swaps::pool_join( RuntimeOrigin::signed(CHARLIE), - 0, + DEFAULT_POOL_ID, amount, vec![_10000, _10000, _10000, _10000] )); - assert_ok!(Swaps::pool_exit(RuntimeOrigin::signed(CHARLIE), 0, amount, vec![0, 0, 0, 0])); + assert_ok!(Swaps::pool_exit( + RuntimeOrigin::signed(CHARLIE), + DEFAULT_POOL_ID, + amount, + vec![0, 0, 0, 0] + )); // Check that the pool retains more tokens than before, and that Charlie loses some tokens // due to fees. - let pool_account_id = Swaps::pool_account_id(&0); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); assert_ge!(Currencies::free_balance(ASSET_A, &pool_account_id), _100); assert_ge!(Currencies::free_balance(ASSET_B, &pool_account_id), _100); assert_ge!(Currencies::free_balance(ASSET_C, &pool_account_id), _100); @@ -2401,14 +2588,19 @@ fn create_pool_fails_on_weight_below_minimum_weight() { Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), - Some(vec!(_2, ::MinWeight::get() - 1, _2, _2)), + Some(DEFAULT_LIQUIDITY), + Some(vec!( + DEFAULT_WEIGHT, + ::MinWeight::get() - 1, + DEFAULT_WEIGHT, + DEFAULT_WEIGHT + )), ), - crate::Error::::BelowMinimumWeight, + Error::::BelowMinimumWeight, ); }); } @@ -2423,14 +2615,19 @@ fn create_pool_fails_on_weight_above_maximum_weight() { Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), - Some(vec!(_2, ::MaxWeight::get() + 1, _2, _2)), + Some(DEFAULT_LIQUIDITY), + Some(vec!( + DEFAULT_WEIGHT, + ::MaxWeight::get() + 1, + DEFAULT_WEIGHT, + DEFAULT_WEIGHT + )), ), - crate::Error::::AboveMaximumWeight, + Error::::AboveMaximumWeight, ); }); } @@ -2446,14 +2643,14 @@ fn create_pool_fails_on_total_weight_above_maximum_total_weight() { Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), + Some(DEFAULT_LIQUIDITY), Some(vec![weight; 4]), ), - crate::Error::::MaxTotalWeight, + Error::::MaxTotalWeight, ); }); } @@ -2469,14 +2666,14 @@ fn create_pool_fails_on_insufficient_liquidity() { Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), Some(min_balance - 1), - Some(vec!(_2, _2, _2, _2)), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), ), - crate::Error::::InsufficientLiquidity, + Error::::InsufficientLiquidity, ); }); } @@ -2493,12 +2690,12 @@ fn create_pool_succeeds_on_min_liquidity() { assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), Some(min_balance), - Some(vec!(_2, _2, _2, _2)), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), )); assert_all_parameters( [0; 4], @@ -2506,7 +2703,7 @@ fn create_pool_succeeds_on_min_liquidity() { [min_balance, min_balance, min_balance, min_balance], min_balance, ); - let pool_shares_id = Swaps::pool_shares_id(0); + let pool_shares_id = Swaps::pool_shares_id(DEFAULT_POOL_ID); assert_eq!(Currencies::free_balance(pool_shares_id, &BOB), min_balance); }); } @@ -2520,22 +2717,22 @@ fn create_pool_transfers_the_correct_amount_of_tokens() { assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), + BASE_ASSET, 0, ScoringRule::CPMM, Some(0), Some(_1234), - Some(vec!(_2, _2, _2, _2)), + Some(vec!(DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT)), )); - let pool_shares_id = Swaps::pool_shares_id(0); + let pool_shares_id = Swaps::pool_shares_id(DEFAULT_POOL_ID); assert_eq!(Currencies::free_balance(pool_shares_id, &BOB), _1234); assert_eq!(Currencies::free_balance(ASSET_A, &BOB), _10000 - _1234); assert_eq!(Currencies::free_balance(ASSET_B, &BOB), _10000 - _1234); assert_eq!(Currencies::free_balance(ASSET_C, &BOB), _10000 - _1234); assert_eq!(Currencies::free_balance(ASSET_D, &BOB), _10000 - _1234); - let pool_account_id = Swaps::pool_account_id(&0); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); assert_eq!(Currencies::free_balance(ASSET_A, &pool_account_id), _1234); assert_eq!(Currencies::free_balance(ASSET_B, &pool_account_id), _1234); assert_eq!(Currencies::free_balance(ASSET_C, &pool_account_id), _1234); @@ -2546,7 +2743,7 @@ fn create_pool_transfers_the_correct_amount_of_tokens() { #[test] fn close_pool_fails_if_pool_does_not_exist() { ExtBuilder::default().build().execute_with(|| { - assert_noop!(Swaps::close_pool(0), crate::Error::::PoolDoesNotExist); + assert_noop!(Swaps::close_pool(0), Error::::PoolDoesNotExist); }); } @@ -2556,12 +2753,11 @@ fn close_pool_fails_if_pool_does_not_exist() { fn close_pool_fails_if_pool_is_not_active_or_initialized(pool_status: PoolStatus) { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; - assert_ok!(Swaps::mutate_pool(pool_id, |pool| { + assert_ok!(Swaps::mutate_pool(DEFAULT_POOL_ID, |pool| { pool.pool_status = pool_status; Ok(()) })); - assert_noop!(Swaps::close_pool(0), crate::Error::::InvalidStateTransition); + assert_noop!(Swaps::close_pool(0), Error::::InvalidStateTransition); }); } @@ -2570,18 +2766,17 @@ fn close_pool_succeeds_and_emits_correct_event_if_pool_exists() { ExtBuilder::default().build().execute_with(|| { frame_system::Pallet::::set_block_number(1); create_initial_pool(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; - assert_ok!(Swaps::close_pool(pool_id)); - let pool = Swaps::pool(pool_id).unwrap(); + assert_ok!(Swaps::close_pool(DEFAULT_POOL_ID)); + let pool = Swaps::pool(DEFAULT_POOL_ID).unwrap(); assert_eq!(pool.pool_status, PoolStatus::Closed); - System::assert_last_event(Event::PoolClosed(pool_id).into()); + System::assert_last_event(Event::PoolClosed(DEFAULT_POOL_ID).into()); }); } #[test] fn open_pool_fails_if_pool_does_not_exist() { ExtBuilder::default().build().execute_with(|| { - assert_noop!(Swaps::open_pool(0), crate::Error::::PoolDoesNotExist); + assert_noop!(Swaps::open_pool(0), Error::::PoolDoesNotExist); }); } @@ -2592,12 +2787,11 @@ fn open_pool_fails_if_pool_does_not_exist() { fn open_pool_fails_if_pool_is_not_closed(pool_status: PoolStatus) { ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - assert_ok!(Swaps::mutate_pool(pool_id, |pool| { + assert_ok!(Swaps::mutate_pool(DEFAULT_POOL_ID, |pool| { pool.pool_status = pool_status; Ok(()) })); - assert_noop!(Swaps::open_pool(pool_id), crate::Error::::InvalidStateTransition); + assert_noop!(Swaps::open_pool(DEFAULT_POOL_ID), Error::::InvalidStateTransition); }); } @@ -2619,11 +2813,10 @@ fn open_pool_succeeds_and_emits_correct_event_if_pool_exists() { Some(amount), Some(vec!(_1, _2, _3, _4)), )); - let pool_id = 0; - assert_ok!(Swaps::open_pool(pool_id)); - let pool = Swaps::pool(pool_id).unwrap(); + assert_ok!(Swaps::open_pool(DEFAULT_POOL_ID)); + let pool = Swaps::pool(DEFAULT_POOL_ID).unwrap(); assert_eq!(pool.pool_status, PoolStatus::Active); - System::assert_last_event(Event::PoolActive(pool_id).into()); + System::assert_last_event(Event::PoolActive(DEFAULT_POOL_ID).into()); }); } @@ -2632,8 +2825,8 @@ fn pool_join_fails_if_max_assets_in_is_violated() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); assert_noop!( - Swaps::pool_join(alice_signed(), 0, _1, vec!(_1, _1, _1 - 1, _1)), - crate::Error::::LimitIn, + Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1, _1 - 1, _1)), + Error::::LimitIn, ); }); } @@ -2652,7 +2845,7 @@ fn pool_join_with_exact_asset_amount_fails_if_min_pool_tokens_is_violated() { _1, expected_pool_amount + 1, // We expect 1 pool share than we will actually receive. ), - crate::Error::::LimitOut, + Error::::LimitOut, ); }); } @@ -2671,7 +2864,7 @@ fn pool_join_with_exact_pool_amount_fails_if_max_asset_amount_is_violated() { _1, expected_asset_amount - 1, // We want to pay 1 less than we actually have to pay. ), - crate::Error::::LimitIn, + Error::::LimitIn, ); }); } @@ -2680,10 +2873,10 @@ fn pool_join_with_exact_pool_amount_fails_if_max_asset_amount_is_violated() { fn pool_exit_fails_if_min_assets_out_is_violated() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_join(alice_signed(), 0, _1, vec!(_1, _1, _1, _1))); + assert_ok!(Swaps::pool_join(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1, _1, _1))); assert_noop!( - Swaps::pool_exit(alice_signed(), 0, _1, vec!(_1, _1, _1 + 1, _1)), - crate::Error::::LimitOut, + Swaps::pool_exit(alice_signed(), DEFAULT_POOL_ID, _1, vec!(_1, _1, _1 + 1, _1)), + Error::::LimitOut, ); }); } @@ -2693,8 +2886,14 @@ fn pool_exit_with_exact_asset_amount_fails_if_min_pool_amount_is_violated() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&(BASE / 10)); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); - assert_ok!(Swaps::pool_join_with_exact_asset_amount(alice_signed(), 0, ASSET_A, _5, 0)); - let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(0), &ALICE); + assert_ok!(Swaps::pool_join_with_exact_asset_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _5, + 0 + )); + let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(DEFAULT_POOL_ID), &ALICE); let expected_amount = 45_082_061_850; assert_noop!( Swaps::pool_exit_with_exact_pool_amount( @@ -2704,7 +2903,7 @@ fn pool_exit_with_exact_asset_amount_fails_if_min_pool_amount_is_violated() { pool_amount, expected_amount + 100, ), - crate::Error::::LimitOut, + Error::::LimitOut, ); }); } @@ -2715,7 +2914,13 @@ fn pool_exit_with_exact_pool_amount_fails_if_max_asset_amount_is_violated() { ::ExitFee::set(&(BASE / 10)); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true); let asset_before_join = Currencies::free_balance(ASSET_A, &ALICE); - assert_ok!(Swaps::pool_join_with_exact_pool_amount(alice_signed(), 0, ASSET_A, _1, _5)); + assert_ok!(Swaps::pool_join_with_exact_pool_amount( + alice_signed(), + DEFAULT_POOL_ID, + ASSET_A, + _1, + _5 + )); let asset_after_join = asset_before_join - Currencies::free_balance(ASSET_A, &ALICE); let exit_amount = (asset_after_join * 9) / 10; let expected_amount = 9_984_935_413; @@ -2727,7 +2932,7 @@ fn pool_exit_with_exact_pool_amount_fails_if_max_asset_amount_is_violated() { exit_amount, expected_amount - 100, ), - crate::Error::::LimitIn, + Error::::LimitIn, ); }); } @@ -2745,7 +2950,7 @@ fn create_pool_correctly_associates_weights_with_assets() { 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), + Some(DEFAULT_LIQUIDITY), Some(vec!(_1, _2, _3, _4)), )); let pool = Swaps::pool(0).unwrap(); @@ -2766,19 +2971,18 @@ fn single_asset_join_and_exit_are_inverse() { let asset = ASSET_B; let amount_in = _1; create_initial_pool(ScoringRule::CPMM, Some(0), true); - let pool_id = 0; assert_ok!(Currencies::deposit(asset, &ALICE, amount_in)); assert_ok!(Swaps::pool_join_with_exact_asset_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, asset, amount_in, 0, )); - let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(pool_id), &ALICE); + let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(DEFAULT_POOL_ID), &ALICE); assert_ok!(Swaps::pool_exit_with_exact_pool_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, asset, pool_amount, 0, @@ -2803,19 +3007,18 @@ fn single_asset_operations_are_equivalent_to_swaps() { let amount_out_single_asset_ops = ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0); create_initial_pool(ScoringRule::CPMM, Some(swap_fee), true); - let pool_id = 0; assert_ok!(Currencies::deposit(asset_in, &ALICE, amount_in)); assert_ok!(Swaps::pool_join_with_exact_asset_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, asset_in, amount_in, 0, )); - let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(pool_id), &ALICE); + let pool_amount = Currencies::free_balance(Swaps::pool_shares_id(DEFAULT_POOL_ID), &ALICE); assert_ok!(Swaps::pool_exit_with_exact_pool_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, asset_out, pool_amount, 0, @@ -2825,11 +3028,10 @@ fn single_asset_operations_are_equivalent_to_swaps() { let amount_out_swap = ExtBuilder::default().build().execute_with(|| { create_initial_pool(ScoringRule::CPMM, Some(swap_fee), true); - let pool_id = 0; assert_ok!(Currencies::deposit(asset_in, &ALICE, amount_in)); assert_ok!(Swaps::swap_exact_amount_in( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, asset_in, amount_in, asset_out, @@ -2848,10 +3050,14 @@ fn pool_join_with_uneven_balances() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); assert_ok!(Currencies::deposit(ASSET_A, &pool_account_id, _50)); - assert_ok!(Swaps::pool_join(RuntimeOrigin::signed(ALICE), pool_id, _10, vec![_100; 4])); + assert_ok!(Swaps::pool_join( + RuntimeOrigin::signed(ALICE), + DEFAULT_POOL_ID, + _10, + vec![_100; 4] + )); assert_eq!(Currencies::free_balance(ASSET_A, &pool_account_id), _165); assert_eq!(Currencies::free_balance(ASSET_B, &pool_account_id), _110); assert_eq!(Currencies::free_balance(ASSET_C, &pool_account_id), _110); @@ -2866,8 +3072,7 @@ fn pool_exit_fails_if_balances_drop_too_low() { // `Swaps::min_balance(...)`. ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); assert_ok!(Currencies::withdraw( ASSET_A, @@ -2892,8 +3097,8 @@ fn pool_exit_fails_if_balances_drop_too_low() { // We withdraw 99% of it, leaving 0.01 of each asset, which is below minimum balance. assert_noop!( - Swaps::pool_exit(RuntimeOrigin::signed(BOB), pool_id, _10, vec![0; 4]), - crate::Error::::PoolDrain, + Swaps::pool_exit(RuntimeOrigin::signed(BOB), DEFAULT_POOL_ID, _10, vec![0; 4]), + Error::::PoolDrain, ); }); } @@ -2905,8 +3110,7 @@ fn pool_exit_fails_if_liquidity_drops_too_low() { // `Swaps::min_balance(...)`. ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); // There's 1000 left of each asset. assert_ok!(Currencies::deposit(ASSET_A, &pool_account_id, _900)); @@ -2918,11 +3122,11 @@ fn pool_exit_fails_if_liquidity_drops_too_low() { assert_noop!( Swaps::pool_exit( RuntimeOrigin::signed(BOB), - pool_id, - _100 - Swaps::min_balance(Swaps::pool_shares_id(pool_id)) + 1, + DEFAULT_POOL_ID, + _100 - Swaps::min_balance(Swaps::pool_shares_id(DEFAULT_POOL_ID)) + 1, vec![0; 4] ), - crate::Error::::PoolDrain, + Error::::PoolDrain, ); }); } @@ -2932,8 +3136,7 @@ fn swap_exact_amount_in_fails_if_balances_drop_too_low() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); // There's only very little left of all assets! assert_ok!(Currencies::withdraw( @@ -2960,14 +3163,14 @@ fn swap_exact_amount_in_fails_if_balances_drop_too_low() { assert_noop!( Swaps::swap_exact_amount_in( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, Swaps::min_balance(ASSET_A) / 10, ASSET_B, Some(0), None, ), - crate::Error::::PoolDrain, + Error::::PoolDrain, ); }); } @@ -2977,8 +3180,7 @@ fn swap_exact_amount_out_fails_if_balances_drop_too_low() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); // There's only very little left of all assets! assert_ok!(Currencies::withdraw( @@ -3005,14 +3207,14 @@ fn swap_exact_amount_out_fails_if_balances_drop_too_low() { assert_noop!( Swaps::swap_exact_amount_out( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, Some(u128::MAX), ASSET_B, Swaps::min_balance(ASSET_B) / 10, None, ), - crate::Error::::PoolDrain, + Error::::PoolDrain, ); }); } @@ -3022,8 +3224,7 @@ fn pool_exit_with_exact_pool_amount_fails_if_balances_drop_too_low() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); // There's only very little left of all assets! assert_ok!(Currencies::withdraw( @@ -3050,12 +3251,12 @@ fn pool_exit_with_exact_pool_amount_fails_if_balances_drop_too_low() { assert_noop!( Swaps::pool_exit_with_exact_pool_amount( RuntimeOrigin::signed(BOB), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _1, 0 ), - crate::Error::::PoolDrain, + Error::::PoolDrain, ); }); } @@ -3065,8 +3266,7 @@ fn pool_exit_with_exact_pool_amount_fails_if_liquidity_drops_too_low() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); assert_ok!(Currencies::deposit(ASSET_A, &pool_account_id, _10000)); assert_ok!(Currencies::deposit(ASSET_B, &pool_account_id, _10000)); @@ -3074,7 +3274,7 @@ fn pool_exit_with_exact_pool_amount_fails_if_liquidity_drops_too_low() { assert_ok!(Currencies::deposit(ASSET_D, &pool_account_id, _10000)); // Reduce amount of liquidity so that doing the withdraw doesn't cause a `Min*Ratio` error! - let pool_shares_id = Swaps::pool_shares_id(pool_id); + let pool_shares_id = Swaps::pool_shares_id(DEFAULT_POOL_ID); assert_eq!(Currencies::total_issuance(pool_shares_id), _100); Currencies::slash(pool_shares_id, &BOB, _100 - Swaps::min_balance(pool_shares_id)); @@ -3082,12 +3282,12 @@ fn pool_exit_with_exact_pool_amount_fails_if_liquidity_drops_too_low() { assert_noop!( Swaps::pool_exit_with_exact_pool_amount( RuntimeOrigin::signed(BOB), - pool_id, + DEFAULT_POOL_ID, ASSET_A, ten_percent_of_pool, 0, ), - crate::Error::::PoolDrain, + Error::::PoolDrain, ); }); } @@ -3097,8 +3297,7 @@ fn pool_exit_with_exact_asset_amount_fails_if_balances_drop_too_low() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); // There's only very little left of all assets! assert_ok!(Currencies::withdraw( @@ -3126,12 +3325,12 @@ fn pool_exit_with_exact_asset_amount_fails_if_balances_drop_too_low() { assert_noop!( Swaps::pool_exit_with_exact_asset_amount( RuntimeOrigin::signed(BOB), - pool_id, + DEFAULT_POOL_ID, ASSET_A, ten_percent_of_balance, _100, ), - crate::Error::::PoolDrain, + Error::::PoolDrain, ); }); } @@ -3141,22 +3340,21 @@ fn pool_exit_with_exact_asset_amount_fails_if_liquidity_drops_too_low() { ExtBuilder::default().build().execute_with(|| { ::ExitFee::set(&0u128); create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; // Reduce amount of liquidity so that doing the withdraw doesn't cause a `Min*Ratio` error! - let pool_shares_id = Swaps::pool_shares_id(pool_id); + let pool_shares_id = Swaps::pool_shares_id(DEFAULT_POOL_ID); assert_eq!(Currencies::total_issuance(pool_shares_id), _100); Currencies::slash(pool_shares_id, &BOB, _100 - Swaps::min_balance(pool_shares_id)); assert_noop!( Swaps::pool_exit_with_exact_asset_amount( RuntimeOrigin::signed(BOB), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _25, _100, ), - crate::Error::::PoolDrain, + Error::::PoolDrain, ); }); } @@ -3165,70 +3363,69 @@ fn pool_exit_with_exact_asset_amount_fails_if_liquidity_drops_too_low() { fn trading_functions_cache_pool_ids() { ExtBuilder::default().build().execute_with(|| { create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(1), true); - let pool_id = 0; assert_ok!(Swaps::pool_join_with_exact_pool_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _2, u128::MAX, )); - assert!(PoolsCachedForArbitrage::::contains_key(pool_id)); - PoolsCachedForArbitrage::::remove(pool_id); + assert!(PoolsCachedForArbitrage::::contains_key(DEFAULT_POOL_ID)); + PoolsCachedForArbitrage::::remove(DEFAULT_POOL_ID); assert_ok!(Swaps::pool_join_with_exact_asset_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _2, 0, )); - assert!(PoolsCachedForArbitrage::::contains_key(pool_id)); - PoolsCachedForArbitrage::::remove(pool_id); + assert!(PoolsCachedForArbitrage::::contains_key(DEFAULT_POOL_ID)); + PoolsCachedForArbitrage::::remove(DEFAULT_POOL_ID); assert_ok!(Swaps::pool_exit_with_exact_asset_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _1, u128::MAX, )); - assert!(PoolsCachedForArbitrage::::contains_key(pool_id)); - PoolsCachedForArbitrage::::remove(pool_id); + assert!(PoolsCachedForArbitrage::::contains_key(DEFAULT_POOL_ID)); + PoolsCachedForArbitrage::::remove(DEFAULT_POOL_ID); assert_ok!(Swaps::pool_exit_with_exact_pool_amount( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _1, 0, )); - assert!(PoolsCachedForArbitrage::::contains_key(pool_id)); - PoolsCachedForArbitrage::::remove(pool_id); + assert!(PoolsCachedForArbitrage::::contains_key(DEFAULT_POOL_ID)); + PoolsCachedForArbitrage::::remove(DEFAULT_POOL_ID); assert_ok!(Swaps::swap_exact_amount_in( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, _1, ASSET_B, Some(0), None, )); - assert!(PoolsCachedForArbitrage::::contains_key(pool_id)); - PoolsCachedForArbitrage::::remove(pool_id); + assert!(PoolsCachedForArbitrage::::contains_key(DEFAULT_POOL_ID)); + PoolsCachedForArbitrage::::remove(DEFAULT_POOL_ID); assert_ok!(Swaps::swap_exact_amount_out( RuntimeOrigin::signed(ALICE), - pool_id, + DEFAULT_POOL_ID, ASSET_A, Some(u128::MAX), ASSET_B, _1, None, )); - assert!(PoolsCachedForArbitrage::::contains_key(pool_id)); + assert!(PoolsCachedForArbitrage::::contains_key(DEFAULT_POOL_ID)); }); } @@ -3249,14 +3446,13 @@ fn on_idle_skips_arbitrage_if_price_does_not_exceed_threshold() { 0, ScoringRule::CPMM, Some(0), - Some(LIQUIDITY), + Some(DEFAULT_LIQUIDITY), Some(vec![_3, _1, _1, _1]), )); - let pool_id = 0; // Force the pool into the cache. - crate::PoolsCachedForArbitrage::::insert(pool_id, ()); + crate::PoolsCachedForArbitrage::::insert(DEFAULT_POOL_ID, ()); Swaps::on_idle(System::block_number(), Weight::MAX); - System::assert_has_event(Event::ArbitrageSkipped(pool_id).into()); + System::assert_has_event(Event::ArbitrageSkipped(DEFAULT_POOL_ID).into()); }); } @@ -3280,16 +3476,15 @@ fn on_idle_arbitrages_pools_with_mint_sell() { Some(balance), Some(vec![_3, _1, _1, _1]), )); - let pool_id = 0; // Withdraw a certain amount of outcome tokens to push the total spot price above 1 // (ASSET_A is the base asset, all other assets are considered outcomes). - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); let amount_removed = _25; assert_ok!(Currencies::withdraw(ASSET_B, &pool_account_id, amount_removed)); // Force arbitrage hook. - crate::PoolsCachedForArbitrage::::insert(pool_id, ()); + crate::PoolsCachedForArbitrage::::insert(DEFAULT_POOL_ID, ()); Swaps::on_idle(System::block_number(), Weight::MAX); let arbitrage_amount = 49_537_658_690; @@ -3303,10 +3498,11 @@ fn on_idle_arbitrages_pools_with_mint_sell() { Currencies::free_balance(ASSET_B, &pool_account_id), balance + arbitrage_amount - amount_removed, ); - let market_id = 0; - let market_account_id = MarketCommons::market_account(market_id); + let market_account_id = MarketCommons::market_account(DEFAULT_MARKET_ID); assert_eq!(Currencies::free_balance(base_asset, &market_account_id), arbitrage_amount); - System::assert_has_event(Event::ArbitrageMintSell(pool_id, arbitrage_amount).into()); + System::assert_has_event( + Event::ArbitrageMintSell(DEFAULT_POOL_ID, arbitrage_amount).into(), + ); }); } @@ -3330,17 +3526,15 @@ fn on_idle_arbitrages_pools_with_buy_burn() { Some(balance), Some(vec![_3, _1, _1, _1]), )); - let pool_id = 0; // Withdraw a certain amount of base tokens to push the total spot price below 1 (ASSET_A // is the base asset, all other assets are considered outcomes). - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); let amount_removed = _25; assert_ok!(Currencies::withdraw(base_asset, &pool_account_id, amount_removed)); // Deposit funds into the prize pool to ensure that the transfers don't fail. - let market_id = 0; - let market_account_id = MarketCommons::market_account(market_id); + let market_account_id = MarketCommons::market_account(DEFAULT_MARKET_ID); let arbitrage_amount = 125_007_629_394; // "Should" be 125_000_000_000. assert_ok!(Currencies::deposit( base_asset, @@ -3349,7 +3543,7 @@ fn on_idle_arbitrages_pools_with_buy_burn() { )); // Force arbitrage hook. - crate::PoolsCachedForArbitrage::::insert(pool_id, ()); + crate::PoolsCachedForArbitrage::::insert(DEFAULT_POOL_ID, ()); Swaps::on_idle(System::block_number(), Weight::MAX); assert_eq!( @@ -3360,7 +3554,7 @@ fn on_idle_arbitrages_pools_with_buy_burn() { assert_eq!(Currencies::free_balance(ASSET_C, &pool_account_id), balance - arbitrage_amount); assert_eq!(Currencies::free_balance(ASSET_D, &pool_account_id), balance - arbitrage_amount); assert_eq!(Currencies::free_balance(base_asset, &market_account_id), SENTINEL_AMOUNT); - System::assert_has_event(Event::ArbitrageBuyBurn(pool_id, arbitrage_amount).into()); + System::assert_has_event(Event::ArbitrageBuyBurn(DEFAULT_POOL_ID, arbitrage_amount).into()); }); } @@ -3409,19 +3603,17 @@ fn execute_arbitrage_correctly_observes_min_balance_buy_burn() { Some(balance), Some(vec![_3, _1, _1, _1]), )); - let pool_id = 0; // Withdraw most base tokens to push the total spot price below 1 and most of one of the // outcome tokens to trigger an arbitrage that would cause minimum balances to be violated. // The total spot price should be slightly above 1/3. - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); let amount_removed = balance - 3 * min_balance / 2; assert_ok!(Currencies::withdraw(base_asset, &pool_account_id, amount_removed)); assert_ok!(Currencies::withdraw(ASSET_B, &pool_account_id, amount_removed)); // Deposit funds into the prize pool to ensure that the transfers don't fail. - let market_id = 0; - let market_account_id = MarketCommons::market_account(market_id); + let market_account_id = MarketCommons::market_account(DEFAULT_MARKET_ID); let arbitrage_amount = min_balance / 2; assert_ok!(Currencies::deposit( base_asset, @@ -3429,7 +3621,7 @@ fn execute_arbitrage_correctly_observes_min_balance_buy_burn() { arbitrage_amount + SENTINEL_AMOUNT, )); - assert_ok!(Swaps::execute_arbitrage(pool_id, ARBITRAGE_MAX_ITERATIONS)); + assert_ok!(Swaps::execute_arbitrage(DEFAULT_POOL_ID, ARBITRAGE_MAX_ITERATIONS)); assert_eq!( Currencies::free_balance(base_asset, &pool_account_id), @@ -3439,7 +3631,7 @@ fn execute_arbitrage_correctly_observes_min_balance_buy_burn() { assert_eq!(Currencies::free_balance(ASSET_C, &pool_account_id), balance - arbitrage_amount); assert_eq!(Currencies::free_balance(ASSET_D, &pool_account_id), balance - arbitrage_amount); assert_eq!(Currencies::free_balance(base_asset, &market_account_id), SENTINEL_AMOUNT); - System::assert_has_event(Event::ArbitrageBuyBurn(pool_id, arbitrage_amount).into()); + System::assert_has_event(Event::ArbitrageBuyBurn(DEFAULT_POOL_ID, arbitrage_amount).into()); }); } @@ -3468,13 +3660,12 @@ fn execute_arbitrage_observes_min_balances_mint_sell() { Some(balance), Some(vec![_3, _1, _1, _1]), )); - let pool_id = 0; // Withdraw a certain amount of outcome tokens to push the total spot price above 1 // (`ASSET_A` is the base asset, all other assets are considered outcomes). The exact choice // of balance for `ASSET_A` ensures that after one iteration, we slightly overshoot the // target (see below). - let pool_account_id = Swaps::pool_account_id(&pool_id); + let pool_account_id = Swaps::pool_account_id(&DEFAULT_POOL_ID); assert_ok!(Currencies::withdraw( ASSET_A, &pool_account_id, @@ -3487,7 +3678,7 @@ fn execute_arbitrage_observes_min_balances_mint_sell() { // The arbitrage amount of mint-sell should always be so that min_balances are not // violated (provided the pool starts in valid state), _except_ when the approximation // overshoots the target. We simulate this by using exactly one iteration. - assert_ok!(Swaps::execute_arbitrage(pool_id, 1)); + assert_ok!(Swaps::execute_arbitrage(DEFAULT_POOL_ID, 1)); // Using only one iteration means that the arbitrage amount will be slightly more than // 9 / 30 * min_balance, but that would result in a violation of the minimum balance of the @@ -3506,10 +3697,518 @@ fn execute_arbitrage_observes_min_balances_mint_sell() { Currencies::free_balance(ASSET_D, &pool_account_id), min_balance + arbitrage_amount, ); - let market_id = 0; - let market_account_id = MarketCommons::market_account(market_id); + let market_account_id = MarketCommons::market_account(DEFAULT_MARKET_ID); assert_eq!(Currencies::free_balance(base_asset, &market_account_id), arbitrage_amount); - System::assert_has_event(Event::ArbitrageMintSell(pool_id, arbitrage_amount).into()); + System::assert_has_event( + Event::ArbitrageMintSell(DEFAULT_POOL_ID, arbitrage_amount).into(), + ); + }); +} + +#[test_case( + 0, + Perbill::from_parts( + u32::try_from( + 1 + ((::MaxSwapFee::get() * 1_000_000_000 + ) / BASE)).unwrap() + ); "creator_fee_only" + ) +] +#[test_case( + 1 + BASE / 100 * 5, + Perbill::from_parts( + u32::try_from( + (::MaxSwapFee::get() * 1_000_000_000 / 2 + ) / BASE).unwrap() + ); "sum_of_all_fees" + ) +] +fn create_pool_respects_total_fee_limits(swap_fee: u128, creator_fee: Perbill) { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + ASSETS.iter().cloned().for_each(|asset| { + assert_ok!(Currencies::deposit(asset, &BOB, _10000)); + }); + assert_err!( + Swaps::create_pool( + BOB, + ASSETS.to_vec(), + BASE_ASSET, + DEFAULT_MARKET_ID, + ScoringRule::CPMM, + Some(swap_fee), + Some(DEFAULT_LIQUIDITY), + Some(vec![DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT]), + ), + Error::::SwapFeeTooHigh + ); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_in_creator_fee_charged_correctly( + asset_in: Asset, + asset_out: Asset, +) { + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + + let ed = ::ExistentialDeposits::get(&BASE_ASSET); + assert_ok!(>::deposit( + BASE_ASSET, + &DEFAULT_MARKET_CREATOR, + ed + )); + + let market_creator_balance_before = + Currencies::free_balance(BASE_ASSET, &DEFAULT_MARKET_CREATOR); + let asset_amount_in = _1; + let min_asset_amount_out = Some(_1 / 2); + let max_price = None; + let expected_fee = expected_creator_fee( + &DEFAULT_POOL_ID, + true, + &creator_fee, + swap_fee, + asset_amount_in, + asset_in, + asset_out, + ); + + assert_ok!(Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + asset_amount_in, + asset_out, + min_asset_amount_out, + max_price, + )); + + let market_creator_balance_after = + Currencies::free_balance(BASE_ASSET, &DEFAULT_MARKET_CREATOR); + + assert_eq!(market_creator_balance_after - market_creator_balance_before, expected_fee); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_in_creator_fee_respects_min_amount_out( + asset_in: Asset, + asset_out: Asset, +) { + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); + let pool_balance_in_before = Currencies::free_balance(asset_in, &pool_account); + let pool_balance_out_before = Currencies::free_balance(asset_out, &pool_account); + let min_asset_amount_out = _1; + // Does not regard market creator fee + let asset_amount_in = calc_in_given_out( + pool_balance_in_before, + DEFAULT_WEIGHT, + pool_balance_out_before, + DEFAULT_WEIGHT, + min_asset_amount_out, + swap_fee, + ) + .unwrap(); + + assert_err!( + Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + asset_amount_in, + asset_out, + Some(min_asset_amount_out), + None, + ), + Error::::LimitOut + ); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_in_creator_fee_respects_max_price( + asset_in: Asset, + asset_out: Asset, +) { + let mut max_spot_price = 0; + let asset_amount_in = _1; + + ExtBuilder::default().build().execute_with(|| { + let swap_fee = 0; + + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + assert_ok!(Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + asset_amount_in, + asset_out, + None, + Some(u128::MAX), + ),); + + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); + let pool_balance_in_after = Currencies::free_balance(asset_in, &pool_account); + let pool_balance_out_after = Currencies::free_balance(asset_out, &pool_account); + + // Does not regard market creator fee + max_spot_price = calc_spot_price( + pool_balance_in_after, + DEFAULT_WEIGHT, + pool_balance_out_after, + DEFAULT_WEIGHT, + swap_fee, + ) + .unwrap(); + }); + + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + + assert_err!( + Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + asset_amount_in, + asset_out, + None, + Some(max_spot_price), + ), + Error::::BadLimitPrice + ); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_in_with_creator_fee_respects_existential_deposit( + asset_in: Asset, + asset_out: Asset, +) { + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + // TODO(#1097) - using 10x ed since otherwise a MathApproximation bug is emitted. + let asset_amount = ::ExistentialDeposits::get(&BASE_ASSET) + .saturating_sub(1) + * 10; + + if asset_amount == 0 { + return; + } + + frame_system::Pallet::::set_block_number(1); + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + assert_ok!(Currencies::withdraw( + BASE_ASSET, + &DEFAULT_MARKET_CREATOR, + Currencies::free_balance(BASE_ASSET, &DEFAULT_MARKET_CREATOR) + )); + + let expected_fee = expected_creator_fee( + &DEFAULT_POOL_ID, + true, + &creator_fee, + swap_fee, + asset_amount, + asset_in, + asset_out, + ); + + assert_ok!(Swaps::swap_exact_amount_in( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + asset_amount, + asset_out, + Some(asset_amount / 2), + None, + )); + System::assert_has_event( + Event::MarketCreatorFeePaymentFailed( + ALICE, + DEFAULT_MARKET_CREATOR, + expected_fee, + BASE_ASSET, + orml_tokens::Error::::ExistentialDeposit.into(), + ) + .into(), + ); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_out_creator_fee_charged_correctly( + asset_in: Asset, + asset_out: Asset, +) { + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + + let ed = ::ExistentialDeposits::get(&BASE_ASSET); + assert_ok!(>::deposit( + BASE_ASSET, + &DEFAULT_MARKET_CREATOR, + ed + )); + + let market_creator_balance_before = + Currencies::free_balance(BASE_ASSET, &DEFAULT_MARKET_CREATOR); + let asset_amount_out = _1; + let max_asset_amount_in = Some(_2); + let max_price = None; + + let expected_fee = expected_creator_fee( + &DEFAULT_POOL_ID, + false, + &creator_fee, + swap_fee, + asset_amount_out, + asset_in, + asset_out, + ); + + assert_ok!(Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + max_asset_amount_in, + asset_out, + asset_amount_out, + max_price, + )); + + let market_creator_balance_after = + Currencies::free_balance(BASE_ASSET, &DEFAULT_MARKET_CREATOR); + + assert_eq!(market_creator_balance_after - market_creator_balance_before, expected_fee); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_out_creator_fee_respects_max_amount_in( + asset_in: Asset, + asset_out: Asset, +) { + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); + let pool_balance_in_before = Currencies::free_balance(asset_in, &pool_account); + let pool_balance_out_before = Currencies::free_balance(asset_out, &pool_account); + let max_asset_amount_in = _1; + // Does not regard market creator fee + let asset_amount_out = calc_out_given_in( + pool_balance_in_before, + DEFAULT_WEIGHT, + pool_balance_out_before, + DEFAULT_WEIGHT, + max_asset_amount_in, + swap_fee, + ) + .unwrap(); + + assert_err!( + Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + Some(max_asset_amount_in), + asset_out, + asset_amount_out, + None, + ), + Error::::LimitIn + ); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_out_creator_fee_respects_max_price( + asset_in: Asset, + asset_out: Asset, +) { + let mut max_spot_price = 0; + let asset_amount_out = _1; + + ExtBuilder::default().build().execute_with(|| { + let swap_fee = 0; + + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + assert_ok!(Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + None, + asset_out, + asset_amount_out, + Some(u128::MAX), + ),); + + let pool_account = Swaps::pool_account_id(&DEFAULT_POOL_ID); + let pool_balance_in_after = Currencies::free_balance(asset_in, &pool_account); + let pool_balance_out_after = Currencies::free_balance(asset_out, &pool_account); + + // Does not regard market creator fee + max_spot_price = calc_spot_price( + pool_balance_in_after, + DEFAULT_WEIGHT, + pool_balance_out_after, + DEFAULT_WEIGHT, + swap_fee, + ) + .unwrap(); + }); + + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + + assert_err!( + Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + None, + asset_out, + asset_amount_out, + Some(max_spot_price), + ), + Error::::BadLimitPrice + ); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_out_creator_fee_swaps_correct_amount_out( + asset_in: Asset, + asset_out: Asset, +) { + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + + let alice_balance_out_before = Currencies::free_balance(asset_out, &ALICE); + let asset_amount_out = _1; + + assert_ok!(Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + Some(u128::MAX), + asset_out, + asset_amount_out, + None, + )); + + let alice_balance_out_after = Currencies::free_balance(asset_out, &ALICE); + assert_eq!(alice_balance_out_after - alice_balance_out_before, asset_amount_out); + }); +} + +#[test_case(BASE_ASSET, ASSET_B; "base_asset_in")] +#[test_case(ASSET_B, BASE_ASSET; "base_asset_out")] +#[test_case(ASSET_B, ASSET_C; "no_base_asset")] +fn swap_exact_amount_out_with_creator_fee_respects_existential_deposit( + asset_in: Asset, + asset_out: Asset, +) { + ExtBuilder::default().build().execute_with(|| { + let creator_fee = Perbill::from_percent(1); + let swap_fee = 0; + let asset_amount = ::ExistentialDeposits::get(&BASE_ASSET) + .saturating_sub(1); + + if asset_amount == 0 { + return; + } + + frame_system::Pallet::::set_block_number(1); + assert_ok!(set_creator_fee(DEFAULT_MARKET_ID, creator_fee)); + create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(swap_fee), true); + assert_ok!(Currencies::withdraw( + BASE_ASSET, + &DEFAULT_MARKET_CREATOR, + Currencies::free_balance(BASE_ASSET, &DEFAULT_MARKET_CREATOR) + )); + + let expected_fee = expected_creator_fee( + &DEFAULT_POOL_ID, + false, + &creator_fee, + swap_fee, + asset_amount, + asset_in, + asset_out, + ); + + assert_ok!(Swaps::swap_exact_amount_out( + alice_signed(), + DEFAULT_POOL_ID, + asset_in, + Some(2 * asset_amount), + asset_out, + asset_amount, + None, + )); + System::assert_has_event( + Event::MarketCreatorFeePaymentFailed( + ALICE, + DEFAULT_MARKET_CREATOR, + expected_fee, + BASE_ASSET, + orml_tokens::Error::::ExistentialDeposit.into(), + ) + .into(), + ); }); } @@ -3517,6 +4216,80 @@ fn alice_signed() -> RuntimeOrigin { RuntimeOrigin::signed(ALICE) } +// Must be called before the swap happens. +fn expected_creator_fee( + pool_id: &PoolId, + swap_in: bool, + creator_fee: &Perbill, + swap_fee: BalanceOf, + asset_amount: BalanceOf, + asset_in: Asset, + asset_out: Asset, +) -> BalanceOf { + let pool_account = Swaps::pool_account_id(pool_id); + let pool_balance_in_before = Currencies::free_balance(asset_in, &pool_account); + let pool_balance_out_before = Currencies::free_balance(asset_out, &pool_account); + let pool_balance_base_out_before = Currencies::free_balance(BASE_ASSET, &pool_account); + + let expected_amount_without_fee = if swap_in { + calc_out_given_in( + pool_balance_in_before, + DEFAULT_WEIGHT, + pool_balance_out_before, + DEFAULT_WEIGHT, + asset_amount, + swap_fee, + ) + .unwrap() + } else { + calc_in_given_out( + pool_balance_in_before, + DEFAULT_WEIGHT, + pool_balance_out_before, + DEFAULT_WEIGHT, + asset_amount, + swap_fee, + ) + .unwrap() + }; + + if asset_in == BASE_ASSET { + if swap_in { + creator_fee.mul_floor(asset_amount) + } else { + creator_fee.mul_floor(expected_amount_without_fee) + } + } else if asset_out == BASE_ASSET { + if swap_in { + creator_fee.mul_floor(expected_amount_without_fee) + } else { + creator_fee.mul_floor(asset_amount) + } + } else if swap_in { + let fee_before_swap = creator_fee.mul_floor(expected_amount_without_fee); + calc_out_given_in( + DEFAULT_LIQUIDITY - expected_amount_without_fee, + DEFAULT_WEIGHT, + pool_balance_base_out_before, + DEFAULT_WEIGHT, + fee_before_swap, + swap_fee, + ) + .unwrap() + } else { + let fee_before_swap = creator_fee.mul_floor(asset_amount); + calc_out_given_in( + DEFAULT_LIQUIDITY - asset_amount - fee_before_swap, + DEFAULT_WEIGHT, + pool_balance_base_out_before, + DEFAULT_WEIGHT, + fee_before_swap, + swap_fee, + ) + .unwrap() + } +} + fn create_initial_pool( scoring_rule: ScoringRule, swap_fee: Option>, @@ -3532,12 +4305,16 @@ fn create_initial_pool( assert_ok!(Swaps::create_pool( BOB, ASSETS.to_vec(), - *ASSETS.last().unwrap(), - 0, + BASE_ASSET, + DEFAULT_MARKET_ID, scoring_rule, swap_fee, - if scoring_rule == ScoringRule::CPMM { Some(LIQUIDITY) } else { None }, - if scoring_rule == ScoringRule::CPMM { Some(vec!(_2, _2, _2, _2)) } else { None }, + if scoring_rule == ScoringRule::CPMM { Some(DEFAULT_LIQUIDITY) } else { None }, + if scoring_rule == ScoringRule::CPMM { + Some(vec![DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT, DEFAULT_WEIGHT]) + } else { + None + }, )); if scoring_rule == ScoringRule::CPMM { assert_ok!(Swaps::open_pool(pool_id)); @@ -3562,8 +4339,8 @@ fn assert_all_parameters( pool_assets: [u128; 4], total_issuance: u128, ) { - let pai = Swaps::pool_account_id(&0); - let psi = Swaps::pool_shares_id(0); + let pai = Swaps::pool_account_id(&DEFAULT_POOL_ID); + let psi = Swaps::pool_shares_id(DEFAULT_POOL_ID); assert_eq!(Currencies::free_balance(ASSET_A, &ALICE), alice_assets[0]); assert_eq!(Currencies::free_balance(ASSET_B, &ALICE), alice_assets[1]); @@ -3579,6 +4356,13 @@ fn assert_all_parameters( assert_eq!(Currencies::total_issuance(psi), total_issuance); } +fn set_creator_fee(market_id: MarketId, fee: Perbill) -> DispatchResult { + MarketCommons::mutate_market(&market_id, |market: &mut MarketOf| { + market.creator_fee = fee; + Ok(()) + }) +} + // Subsidize and start a Rikiddo pool. Extra is the amount of additional base asset added to who. fn subsidize_and_start_rikiddo_pool( pool_id: PoolId, @@ -3590,25 +4374,3 @@ fn subsidize_and_start_rikiddo_pool( assert_ok!(Swaps::pool_join_subsidy(RuntimeOrigin::signed(*who), pool_id, min_subsidy)); assert!(Swaps::end_subsidy_phase(pool_id).unwrap().result); } - -fn mock_market( - categories: u16, -) -> Market> { - Market { - base_asset: Asset::Ztg, - creation: MarketCreation::Permissionless, - creator_fee: 0, - creator: ALICE, - market_type: MarketType::Categorical(categories), - dispute_mechanism: MarketDisputeMechanism::Authorized, - metadata: vec![0; 50], - oracle: ALICE, - period: MarketPeriod::Block(0..1), - deadlines: Deadlines::default(), - report: None, - resolved_outcome: None, - scoring_rule: ScoringRule::CPMM, - status: MarketStatus::Active, - bonds: MarketBonds::default(), - } -} diff --git a/zrml/swaps/src/utils.rs b/zrml/swaps/src/utils.rs index f35314271..615611697 100644 --- a/zrml/swaps/src/utils.rs +++ b/zrml/swaps/src/utils.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Forecasting Technologies LTD. +// Copyright 2022-2023 Forecasting Technologies LTD. // Copyright 2021-2022 Zeitgeist PM LLC. // // This file is part of Zeitgeist. @@ -180,6 +180,10 @@ where let spot_price_before = Pallet::::get_spot_price(&p.pool_id, &p.asset_in, &p.asset_out, true)?; + // Duplicate call can be optimized + let spot_price_before_without_fees = + Pallet::::get_spot_price(&p.pool_id, &p.asset_in, &p.asset_out, false)?; + if let Some(max_price) = p.max_price { ensure!(spot_price_before <= max_price, Error::::BadLimitPrice); } @@ -234,7 +238,7 @@ where match p.pool.scoring_rule { ScoringRule::CPMM => ensure!( - spot_price_before + spot_price_before_without_fees <= bdiv(asset_amount_in.saturated_into(), asset_amount_out.saturated_into())? .saturated_into(), Error::::MathApproximation