Skip to content

Commit

Permalink
feat: best trade swap router rpc
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Hill <[email protected]>
  • Loading branch information
gregdhill committed Feb 22, 2023
1 parent fdc136b commit 84d010b
Show file tree
Hide file tree
Showing 30 changed files with 1,079 additions and 69 deletions.
35 changes: 35 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions crates/dex-general/src/swap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,13 @@ impl<T: Config> Pallet<T> {
}

impl<T: Config> ExportDexGeneral<T::AccountId, T::AssetId> for Pallet<T> {
fn get_all_trading_pairs() -> Vec<(T::AssetId, T::AssetId)> {
PairStatuses::<T>::iter()
.filter(|(_, status)| matches!(status, PairStatus::Trading(_)))
.map(|(pair, _)| pair)
.collect()
}

fn get_amount_in_by_path(
amount_out: AssetBalance,
path: &[T::AssetId],
Expand Down Expand Up @@ -1052,6 +1059,10 @@ impl<T: Config> ExportDexGeneral<T::AccountId, T::AssetId> for Pallet<T> {
}

impl<AccountId, AssetId> ExportDexGeneral<AccountId, AssetId> for () {
fn get_all_trading_pairs() -> Vec<(AssetId, AssetId)> {
unimplemented!()
}

fn get_amount_in_by_path(_amount_out: AssetBalance, _path: &[AssetId]) -> Result<Vec<AssetBalance>, DispatchError> {
unimplemented!()
}
Expand Down
2 changes: 2 additions & 0 deletions crates/dex-general/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub trait GenerateLpAssetId<AssetId> {
}

pub trait ExportDexGeneral<AccountId, AssetId> {
fn get_all_trading_pairs() -> Vec<(AssetId, AssetId)>;

fn get_amount_in_by_path(amount_out: AssetBalance, path: &[AssetId]) -> Result<Vec<AssetBalance>, DispatchError>;

fn get_amount_out_by_path(amount_in: AssetBalance, path: &[AssetId]) -> Result<Vec<AssetBalance>, DispatchError>;
Expand Down
3 changes: 2 additions & 1 deletion crates/dex-stable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1410,7 +1410,7 @@ impl<T: Config> Pallet<T> {
) -> Result<Balance, DispatchError> {
let base_pool_currency = Self::get_lp_currency(base_pool_id).ok_or(Error::<T>::InvalidPoolId)?;
let base_pool_currency_index =
Self::get_currency_index(pool_id, base_pool_currency).ok_or(Error::<T>::InvalidBasePool)?;
Self::get_currency_index(pool_id, base_pool_currency).ok_or(Error::<T>::InvalidBasePool)? as u32;

let mut base_lp_amount = Balance::default();
if base_pool_currency_index != in_index {
Expand All @@ -1430,6 +1430,7 @@ impl<T: Config> Pallet<T> {
Ok(out_amount)
}

/// Returns the amount of LP tokens generated by supplying the `amounts` in the pool.
pub(crate) fn calculate_currency_amount(
pool_id: T::PoolId,
amounts: Vec<Balance>,
Expand Down
76 changes: 76 additions & 0 deletions crates/dex-stable/src/meta_pool_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4348,3 +4348,79 @@ fn meta_pool_swap_underlying_impact_on_base_pool_price_should_work() {
);
})
}

// TODO: rewrite to use mock values
fn calculate_swap(pool_id: PoolId, i: usize, j: usize, in_balance: Balance) -> Balance {
let pool = StableAmm::pools(pool_id).unwrap().get_pool_info();
let normalized_balances = StableAmm::xp(&pool.balances, &pool.token_multipliers).unwrap();
let new_in_balance = normalized_balances[i] + in_balance * pool.token_multipliers[i];
let out_balance = StableAmm::get_y(&pool, i, j, new_in_balance, &normalized_balances).unwrap();
let out_amount = (normalized_balances[j] - out_balance) / pool.token_multipliers[j];
let fee = (out_amount * pool.fee) / FEE_DENOMINATOR;
out_amount - fee
}

#[test]
fn should_calculate_swap_amount_from_base() {
new_test_ext().execute_with(|| {
// asset 0 (base): 1e20 + 1e20 + 1e20
// asset 1 (base): 1e8 + 1e8 + 1e8
// asset 2 (base): 1e8 + 1e8 + 1e8
// asset 0 (meta): 1e18
// asset 1 (meta): 1e18
let (base_pool_id, meta_pool_id) = setup_test_meta_pool();

fn calculate_token_amount(pool_id: PoolId, amounts: &Vec<Balance>, deposit: bool) -> Balance {
let pool = StableAmm::pools(pool_id).unwrap().get_pool_info();
let amp = pool.future_a;
let d0 = StableAmm::xp(&pool.balances, &pool.token_multipliers)
.and_then(|xp| StableAmm::get_d(&xp, amp))
.unwrap();
let new_balances = pool
.balances
.iter()
.zip(amounts.iter())
.map(|(x, y)| if deposit { x + y } else { x - y })
.collect::<Vec<_>>();
let d1 = StableAmm::xp(&new_balances, &pool.token_multipliers)
.and_then(|xp| StableAmm::get_d(&xp, amp))
.unwrap();
let total_supply = <Test as Config>::MultiCurrency::total_issuance(pool.lp_currency_id);
let diff = if deposit { d1 - d0 } else { d0 - d1 };
(diff * total_supply) / d0
}

let swap_amount = 100_000;
let mut base_amounts = vec![0; 3];
base_amounts[0] = swap_amount;
let base_lp_amount = calculate_token_amount(base_pool_id, &base_amounts, true);
assert_ok!(
StableAmm::stable_amm_calculate_currency_amount(base_pool_id, &base_amounts, true),
base_lp_amount
);

assert_eq!(
StableAmm::stable_amm_calculate_swap_amount_from_base(meta_pool_id, base_pool_id, 0, 0, swap_amount)
.unwrap()
.unwrap(),
calculate_swap(meta_pool_id, 0, 1, base_lp_amount),
);
})
}

#[test]
fn should_calculate_swap_amount_to_base() {
new_test_ext().execute_with(|| {
let (base_pool_id, meta_pool_id) = setup_test_meta_pool();
let base_pool = StableAmm::pools(base_pool_id).unwrap().get_pool_info();
let token_lp_amount = calculate_swap(meta_pool_id, 0, 1, 100_000);
assert_eq!(
StableAmm::stable_amm_calculate_swap_amount_to_base(meta_pool_id, base_pool_id, 0, 0, 100_000)
.unwrap()
.unwrap(),
StableAmm::calculate_base_remove_liquidity_one_token(&base_pool, token_lp_amount, 0)
.unwrap()
.0,
);
})
}
8 changes: 7 additions & 1 deletion crates/dex-stable/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ pub enum Pool<PoolId, CurrencyId, AccountId, BoundString> {
Meta(MetaPool<PoolId, CurrencyId, AccountId, BoundString>),
}

impl<PoolId, CurrencyId: Copy, AccountId: Clone, BoundString> Pool<PoolId, CurrencyId, AccountId, BoundString> {
impl<PoolId, CurrencyId: Copy + PartialEq, AccountId: Clone, BoundString>
Pool<PoolId, CurrencyId, AccountId, BoundString>
{
pub fn info(self) -> BasePool<CurrencyId, AccountId, BoundString> {
match self {
Pool::Base(bp) => bp,
Expand All @@ -88,6 +90,10 @@ impl<PoolId, CurrencyId: Copy, AccountId: Clone, BoundString> Pool<PoolId, Curre
}
}

pub fn get_currency_index(self, currency_id: CurrencyId) -> Option<usize> {
self.get_currency_ids().iter().position(|&r| r == currency_id)
}

pub fn get_lp_currency(&self) -> CurrencyId {
match self {
Pool::Base(bp) => bp.lp_currency_id,
Expand Down
13 changes: 5 additions & 8 deletions crates/dex-stable/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,12 @@ impl<T: Config> Pallet<T> {
Vec::new()
}

pub fn get_currency_index(pool_id: T::PoolId, currency_id: T::CurrencyId) -> Option<u32> {
pub fn get_currency_index(pool_id: T::PoolId, currency_id: T::CurrencyId) -> Option<usize> {
if let Some(pool) = Self::pools(pool_id) {
for (i, c) in pool.get_currency_ids().iter().enumerate() {
if *c == currency_id {
return Some(i as u32);
}
}
};
None
pool.get_currency_index(currency_id)
} else {
None
}
}

pub fn get_currency(pool_id: T::PoolId, index: u32) -> Option<T::CurrencyId> {
Expand Down
Loading

0 comments on commit 84d010b

Please sign in to comment.