diff --git a/Cargo.lock b/Cargo.lock index 5bfbbe12b36..47a4a61c845 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6731,6 +6731,24 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-dex-router" +version = "0.0.1" +dependencies = [ + "composable-traits", + "frame-support", + "frame-system", + "orml-traits", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-dutch-auctions" version = "0.0.1" diff --git a/frame/composable-traits/src/dex.rs b/frame/composable-traits/src/dex.rs index cadb8af23db..f77a6fdef6f 100644 --- a/frame/composable-traits/src/dex.rs +++ b/frame/composable-traits/src/dex.rs @@ -2,6 +2,7 @@ use codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_runtime::{DispatchError, FixedU128, Permill}; use sp_std::vec::Vec; +use frame_support::RuntimeDebug; /// Implement AMM curve from "StableSwap - efficient mechanism for Stablecoin liquidity by Micheal /// Egorov" Also blog at https://miguelmota.com/blog/understanding-stableswap-curve/ has very good explanation. @@ -66,7 +67,7 @@ pub trait CurveAmm { } /// Pool type -#[derive(Encode, Decode, TypeInfo, Clone, Default, PartialEq, Eq, Debug)] +#[derive(Encode, Decode, TypeInfo, Clone, Default, PartialEq, Eq, RuntimeDebug)] pub struct StableSwapPoolInfo { /// Owner of pool pub owner: AccountId, @@ -100,10 +101,25 @@ pub trait SimpleExchange { ) -> Result; } -#[derive(Encode, Decode, TypeInfo, Clone, Default, PartialEq, Eq, Debug)] +#[derive(Encode, Decode, TypeInfo, Clone, Default, PartialEq, Eq, RuntimeDebug)] pub struct ConstantProductPoolInfo { /// Owner of pool pub owner: AccountId, /// Amount of the fee pool charges for the exchange pub fee: Permill, } + +/// Describes route for DEX, Direct gives pool_id to use, +/// Via gives recursive route with pair of pool_id, route_id. +#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, Eq, RuntimeDebug)] +pub enum DexRoute { + Direct(PoolId), + Via((PoolId, RouteId)) +} + +pub trait DexRouter { + /// if route is `None` then delete existing entry for `asset_pair` + /// if route is `Some` and no entry exist for `asset_pair` then add new entry else update + /// existing entry. + fn update(asset_pair : (AssetId, AssetId), route : Option>); +} diff --git a/frame/dex-router/Cargo.toml b/frame/dex-router/Cargo.toml new file mode 100644 index 00000000000..bbd94a31cd7 --- /dev/null +++ b/frame/dex-router/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "pallet-dex-router" +version = "0.0.1" +authors = ["Composable Developers"] +homepage = "https://composable.finance" +edition = "2021" +rust-version = "1.56" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +frame-support = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } +frame-system = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } + +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } +sp-arithmetic = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } +sp-io = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } + +composable-traits = { path = "../composable-traits", default-features = false } +orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "17a791edf431d7d7aee1ea3dfaeeb7bc21944301", default-features = false } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } + +[dependencies.codec] +default-features = false +features = ["derive"] +package = "parity-scale-codec" +version = "2.0.0" + +[dev-dependencies] +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "orml-traits/std", +] diff --git a/frame/dex-router/src/lib.rs b/frame/dex-router/src/lib.rs new file mode 100644 index 00000000000..34fbd3ac4b3 --- /dev/null +++ b/frame/dex-router/src/lib.rs @@ -0,0 +1,105 @@ +//! # DEX Router Pallet +//! +//! Is used to add route to DEX for given asset_id's pair. + +#![cfg_attr(not(test), warn(clippy::disallowed_method, clippy::indexing_slicing))] // allow in tests +#![warn(clippy::unseparated_literal_suffix, clippy::disallowed_type)] +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[frame_support::pallet] +pub mod pallet { + use codec::FullCodec; +use composable_traits::{ + currency::AssetIdLike, + dex::{DexRoute, DexRouter}, + }; + use frame_support::pallet_prelude::*; + + + #[pallet::config] + pub trait Config: frame_system::Config { + type Event: From> + IsType<::Event>; + type AssetId: AssetIdLike + Decode + Clone + core::fmt::Debug + Default; + type RouteId: FullCodec + Copy + Eq + PartialEq + core::fmt::Debug + TypeInfo; + type PoolId: FullCodec + Copy + Eq + PartialEq + core::fmt::Debug + TypeInfo; + } + + #[pallet::pallet] + #[pallet::generate_store(trait Store)] + pub struct Pallet(_); + + #[pallet::storage] + pub type DexRoutes = StorageDoubleMap< + _, + Blake2_128Concat, + T::AssetId, + Blake2_128Concat, + T::AssetId, + DexRoute, + OptionQuery, + >; + + #[pallet::error] + pub enum Error { + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + RouteAdded { x_asset_id: T::AssetId, y_asset_id: T::AssetId, route : DexRoute }, + RouteDeleted { x_asset_id: T::AssetId, y_asset_id: T::AssetId, route : DexRoute }, + RouteUpdated { x_asset_id: T::AssetId, y_asset_id: T::AssetId, route : DexRoute }, + } + + #[pallet::call] + impl Pallet { + } + + impl Pallet { + } + + impl DexRouter for Pallet { + fn update(asset_pair : (T::AssetId, T::AssetId), route : Option>) { + match route { + Some(r) => { + let mut update = false; + if DexRoutes::::contains_key(asset_pair.0, asset_pair.1) { + update = true; + } + DexRoutes::::insert(asset_pair.0, asset_pair.1, r.clone()); + if update { + Self::deposit_event(Event::RouteUpdated { + x_asset_id : asset_pair.0, + y_asset_id : asset_pair.1, + route: r, + }); + } else { + Self::deposit_event(Event::RouteAdded { + x_asset_id : asset_pair.0, + y_asset_id : asset_pair.1, + route: r, + }); + } + }, + None => { + if DexRoutes::::contains_key(asset_pair.0, asset_pair.1) { + let r = DexRoutes::::take(asset_pair.0, asset_pair.1).expect("inconsistent storage"); + Self::deposit_event(Event::RouteDeleted { + x_asset_id : asset_pair.0, + y_asset_id : asset_pair.1, + route: r, + }); + } + } + } + } + } +} diff --git a/frame/dex-router/src/mock.rs b/frame/dex-router/src/mock.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frame/dex-router/src/tests.rs b/frame/dex-router/src/tests.rs new file mode 100644 index 00000000000..e69de29bb2d