Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/stable pool mgx 1307 #838

Merged
merged 31 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
38c80f5
adds stable swap imnpl with basic functionality
vanderian Oct 17, 2024
ea645c9
adds get_dx, get_dy, calc_lp_token apis
vanderian Oct 18, 2024
bc54955
fixes dx calculation to account for dynamic fee
vanderian Oct 19, 2024
9654dae
adds market pallet that wraps amm
vanderian Oct 24, 2024
fda1150
init runtime integration tests
vanderian Oct 25, 2024
88f08f9
adds multiswap
vanderian Oct 28, 2024
76fc642
adds buy and burn interface
vanderian Oct 28, 2024
1484d37
adds fee lock for swaps with runtime tests; adds runtime apis for market
vanderian Nov 13, 2024
c20cf19
adds multiswap buy variant
vanderian Nov 13, 2024
1b94b48
adds events & tests
vanderian Nov 14, 2024
5f985f1
adds rpc for market
vanderian Nov 15, 2024
771e1e4
adds pools rpc, aggregated events
vanderian Nov 18, 2024
3d2cef0
Merge remote-tracking branch 'origin/eth-rollup-develop' into feature…
vanderian Nov 18, 2024
bb4d2b0
fixes test build
vanderian Nov 19, 2024
0b1eea0
adds benchmarking to market pallet
vanderian Nov 19, 2024
272dd17
adds `get_pool` fn to RPCs
vanderian Nov 19, 2024
90c586f
format
vanderian Nov 20, 2024
10de76f
adds rest of the benchmarks, fixes bnb for sswap
vanderian Nov 20, 2024
1d30c8d
fixes rpc for Balance type to NumberOrHex in get_pools
vanderian Nov 21, 2024
a5f18cd
fixes tests
vanderian Nov 21, 2024
fc1a80a
remove xyk & stable swap extrinsics
vanderian Nov 21, 2024
9336d41
fixes tests after xyk calls removal
vanderian Nov 21, 2024
392c72c
cleanup
vanderian Nov 22, 2024
0c6afae
fixes if-else assetId check in pool [asset1, asset1]
vanderian Nov 22, 2024
ad5c8a5
adds pallet call weights
vanderian Nov 25, 2024
dde3ad4
Merge remote-tracking branch 'origin/eth-rollup-develop' into feature…
vanderian Nov 25, 2024
83da7a3
adds proper weights from CI run
vanderian Nov 26, 2024
06360c0
fmt
vanderian Nov 26, 2024
3eeca72
remove patch
vanderian Nov 26, 2024
792d032
adds different asset decimals test, add bench test to CI run
vanderian Nov 26, 2024
e71e8cd
fixes bench test ordering & fmt
vanderian Nov 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
368 changes: 227 additions & 141 deletions Cargo.lock

Large diffs are not rendered by default.

412 changes: 134 additions & 278 deletions Cargo.toml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ services:
- --rpc-cors=all
- --unsafe-rpc-external
- --node-key=0000000000000000000000000000000000000000000000000000000000000001
- --rpc-methods=unsafe
- --rpc-methods=unsafe
ports:
- 9944:9944
- 30333:30333
Expand Down
1 change: 1 addition & 0 deletions pallets/bootstrap/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ mockall::mock! {
liquidity_asset_id: TokenId,
) -> Result<Balance, DispatchError>;

fn rewards_period() -> u32;
}
}

Expand Down
69 changes: 69 additions & 0 deletions pallets/market/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
[package]
name = "pallet-market"
description = "An overarching pallet providing entry points to pools & trading."
version = "1.0.0"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { workspace = true, default-features = false }
log = { workspace = true, default-features = false }
scale-info = { workspace = true, default-features = false, features = ["derive"] }
serde = { workspace = true, optional = true, features = ["derive"] }

frame-benchmarking = { workspace = true, default-features = false }
frame-support = { workspace = true, default-features = false }
frame-system = { workspace = true, default-features = false }
mangata-support = { workspace = true, default-features = false }
mangata-types = { workspace = true, default-features = false }
sp-arithmetic = { workspace = true, default-features = false }
sp-api = { workspace = true, default-features = false }
sp-core = { workspace = true, default-features = false }
sp-io = { workspace = true, default-features = false }
sp-runtime = { workspace = true, default-features = false }
sp-std = { workspace = true, default-features = false }

orml-traits = { workspace = true, default-features = false }
orml-tokens = { workspace = true, default-features = false }

[dev-dependencies]
primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] }
mockall.workspace = true

pallet-xyk = { path = "../xyk" }
pallet-stable-swap = { path = "../stable-swap" }
pallet-vesting-mangata = { workspace = true }

[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking/std",
"frame-support/std",
"frame-system/std",
"mangata-support/std",
"scale-info/std",
"serde",
"sp-arithmetic/std",
"sp-api/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"orml-traits/std",
"orml-tokens/std",
]

runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]

try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
"orml-tokens/try-runtime",
]
33 changes: 33 additions & 0 deletions pallets/market/rpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "market-rpc"
description = "RPC for market APIs"
version = "1.0.0"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true

[dependencies]
codec = { workspace = true }
jsonrpsee = { workspace = true, features = ["server", "macros"] }
serde = { workspace = true, features = ["derive"], optional = true }

sp-api = { workspace = true, default-features = false }
sp-blockchain = { workspace = true, default-features = false }
sp-core = { workspace = true, default-features = false }
sp-rpc = { workspace = true, default-features = false }
sp-runtime = { workspace = true, default-features = false }
sp-std = { workspace = true, default-features = false }

pallet-market = { path = "../", default-features = false }

[features]
default = ["std"]
std = [
"serde",
"sp-api/std",
"sp-core/std",
"sp-std/std",
"sp-runtime/std",
"pallet-market/std",
]
252 changes: 252 additions & 0 deletions pallets/market/rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
use codec::Codec;
use jsonrpsee::{
core::{async_trait, RpcResult},
proc_macros::rpc,
types::error::ErrorObject,
};
pub use pallet_market::MarketRuntimeApi;
use pallet_market::{RpcAssetMetadata, RpcPoolInfo};
use sp_api::ProvideRuntimeApi;
use sp_blockchain::HeaderBackend;
use sp_core::U256;
use sp_rpc::number::NumberOrHex;
use sp_runtime::traits::{Block as BlockT, MaybeDisplay, MaybeFromStr};
use sp_std::convert::{TryFrom, TryInto};
use std::sync::Arc;

#[rpc(client, server)]
pub trait MarketApi<BlockHash, Balance, TokenId> {
#[method(name = "market_calculate_sell_price")]
fn calculate_sell_price(
&self,
pool_id: TokenId,
sell_asset_id: TokenId,
sell_amount: NumberOrHex,
at: Option<BlockHash>,
) -> RpcResult<NumberOrHex>;

#[method(name = "market_calculate_buy_price")]
fn calculate_buy_price(
&self,
pool_id: TokenId,
buy_asset_id: TokenId,
buy_amount: NumberOrHex,
at: Option<BlockHash>,
) -> RpcResult<NumberOrHex>;

#[method(name = "market_calculate_expected_amount_for_minting")]
fn calculate_expected_amount_for_minting(
&self,
pool_id: TokenId,
asset_id: TokenId,
amount: NumberOrHex,
at: Option<BlockHash>,
) -> RpcResult<NumberOrHex>;

#[method(name = "market_calculate_expected_lp_minted")]
fn calculate_expected_lp_minted(
&self,
pool_id: TokenId,
amounts: (NumberOrHex, NumberOrHex),
at: Option<BlockHash>,
) -> RpcResult<NumberOrHex>;

#[method(name = "market_get_burn_amount")]
fn get_burn_amount(
&self,
pool_id: TokenId,
liquidity_asset_amount: NumberOrHex,
at: Option<BlockHash>,
) -> RpcResult<(NumberOrHex, NumberOrHex)>;

#[method(name = "market_get_pools_for_trading")]
fn get_pools_for_trading(&self, at: Option<BlockHash>) -> RpcResult<Vec<TokenId>>;

#[method(name = "market_get_tradeable_tokens")]
fn get_tradeable_tokens(
&self,
at: Option<BlockHash>,
) -> RpcResult<sp_std::vec::Vec<RpcAssetMetadata<TokenId>>>;

#[method(name = "market_get_pools")]
fn get_pools(
&self,
pool_id: Option<TokenId>,
at: Option<BlockHash>,
) -> RpcResult<sp_std::vec::Vec<RpcPoolInfo<TokenId, NumberOrHex>>>;
}

pub struct Market<C, M> {
client: Arc<C>,
_marker: std::marker::PhantomData<M>,
}

impl<C, P> Market<C, P> {
pub fn new(client: Arc<C>) -> Self {
Self { client, _marker: Default::default() }
}
}

trait TryIntoBalance<Balance> {
fn try_into_balance(self) -> RpcResult<Balance>;
}

impl<T: TryFrom<U256>> TryIntoBalance<T> for NumberOrHex {
fn try_into_balance(self) -> RpcResult<T> {
self.into_u256().try_into().or(Err(ErrorObject::owned(
1,
"Unable to serve the request",
Some(String::from("input parameter doesnt fit into u128")),
)))
}
}

#[async_trait]
impl<C, Block, Balance, TokenId> MarketApiServer<<Block as BlockT>::Hash, Balance, TokenId>
for Market<C, Block>
where
Block: BlockT,
C: Send + Sync + 'static,
C: ProvideRuntimeApi<Block>,
C: HeaderBackend<Block>,
C::Api: MarketRuntimeApi<Block, Balance, TokenId>,
Balance: Codec + MaybeDisplay + MaybeFromStr + TryFrom<U256> + Into<NumberOrHex> + Default,
TokenId: Codec + MaybeDisplay + MaybeFromStr,
{
fn calculate_sell_price(
&self,
pool_id: TokenId,
sell_asset_id: TokenId,
sell_amount: NumberOrHex,
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<NumberOrHex> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

api.calculate_sell_price(at, pool_id, sell_asset_id, sell_amount.try_into_balance()?)
.map(|val| val.unwrap_or_default().into())
.map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}

fn calculate_buy_price(
&self,
pool_id: TokenId,
buy_asset_id: TokenId,
buy_amount: NumberOrHex,
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<NumberOrHex> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

api.calculate_buy_price(at, pool_id, buy_asset_id, buy_amount.try_into_balance()?)
.map(|val| val.unwrap_or_default().into())
.map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}

fn get_burn_amount(
&self,
pool_id: TokenId,
liquidity_asset_amount: NumberOrHex,
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<(NumberOrHex, NumberOrHex)> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

api.get_burn_amount(at, pool_id, liquidity_asset_amount.try_into_balance()?)
.map(|val| val.unwrap_or_default())
.map(|(val1, val2)| (val1.into(), val2.into()))
.map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}

fn get_pools_for_trading(
&self,
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Vec<TokenId>> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

api.get_pools_for_trading(at).map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}

fn get_tradeable_tokens(
&self,
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Vec<RpcAssetMetadata<TokenId>>> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

api.get_tradeable_tokens(at).map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}

fn calculate_expected_amount_for_minting(
&self,
pool_id: TokenId,
asset_id: TokenId,
amount: NumberOrHex,
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<NumberOrHex> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

api.calculate_expected_amount_for_minting(at, pool_id, asset_id, amount.try_into_balance()?)
.map(|val| val.unwrap_or_default().into())
.map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}

fn calculate_expected_lp_minted(
&self,
pool_id: TokenId,
amounts: (NumberOrHex, NumberOrHex),
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<NumberOrHex> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

let amount_0 = amounts.0.try_into_balance()?;
let amount_1 = amounts.1.try_into_balance()?;

api.calculate_expected_lp_minted(at, pool_id, (amount_0, amount_1))
.map(|val| val.unwrap_or_default().into())
.map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}

fn get_pools(
&self,
pool_id: Option<TokenId>,
_at: Option<<Block as BlockT>::Hash>,
) -> RpcResult<Vec<RpcPoolInfo<TokenId, NumberOrHex>>> {
let api = self.client.runtime_api();
let at = self.client.info().best_hash;

api.get_pools(at, pool_id)
.map(|infos| {
{
infos.into_iter().map(|info| RpcPoolInfo {
pool_id: info.pool_id,
kind: info.kind,
lp_token_id: info.lp_token_id,
assets: info.assets,
reserves: info.reserves.into_iter().map(|r| r.into()).collect(),
})
}
.collect()
})
.map_err(|e| {
ErrorObject::owned(1, "Unable to serve the request", Some(format!("{:?}", e)))
})
}
}
Loading
Loading