Skip to content

Commit aa59ec1

Browse files
committed
Move do_compute_swap() to StableSwap module.
Add common_test_functions module and update add_remove_lp() test to use it. Minor refactoring to use references when possible.
1 parent f3a08df commit aa59ec1

File tree

6 files changed

+172
-106
lines changed

6 files changed

+172
-106
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use crate::{
2+
mock::{Pablo, *},
3+
PoolConfiguration::{ConstantProduct, StableSwap},
4+
PoolInitConfiguration,
5+
};
6+
use frame_support::{
7+
assert_ok,
8+
traits::fungibles::{Inspect, Mutate},
9+
};
10+
11+
pub fn common_add_remove_lp(
12+
init_config: PoolInitConfiguration<AssetId>,
13+
init_base_amount: Balance,
14+
init_quote_amount: Balance,
15+
base_amount: Balance,
16+
quote_amount: Balance,
17+
expected_lp_check: impl Fn(Balance, Balance, Balance) -> bool,
18+
) {
19+
/* NOTE: expected_lp_check takes base_amount, quote_amount and lp_tokens in order and returns
20+
* bool result if lp_tokens are expected for given base_amount, quote_amount
21+
*/
22+
let pool_id = Pablo::do_create_pool(&ALICE, init_config.clone()).expect("pool creation failed");
23+
let pair = match init_config {
24+
PoolInitConfiguration::StableSwap { pair, .. } => pair,
25+
PoolInitConfiguration::ConstantProduct { pair, .. } => pair,
26+
};
27+
// Mint the tokens
28+
assert_ok!(Tokens::mint_into(pair.base, &ALICE, init_base_amount));
29+
assert_ok!(Tokens::mint_into(pair.quote, &ALICE, init_quote_amount));
30+
31+
// Add the liquidity
32+
assert_ok!(Pablo::add_liquidity(
33+
Origin::signed(ALICE),
34+
pool_id,
35+
init_base_amount,
36+
init_quote_amount,
37+
0,
38+
false
39+
));
40+
41+
let pool = Pablo::pools(pool_id).expect("pool not found");
42+
let lp_token = match pool {
43+
StableSwap(pool) => pool.lp_token,
44+
ConstantProduct(pool) => pool.lp_token,
45+
};
46+
// Mint the tokens
47+
assert_ok!(Tokens::mint_into(pair.base, &BOB, base_amount));
48+
assert_ok!(Tokens::mint_into(pair.quote, &BOB, quote_amount));
49+
50+
let lp = Tokens::balance(lp_token, &BOB);
51+
assert_eq!(lp, 0_u128);
52+
// Add the liquidity
53+
assert_ok!(Pablo::add_liquidity(
54+
Origin::signed(BOB),
55+
pool_id,
56+
base_amount,
57+
quote_amount,
58+
0,
59+
false
60+
));
61+
let lp = Tokens::balance(lp_token, &BOB);
62+
assert!(expected_lp_check(base_amount, quote_amount, lp));
63+
assert_ok!(Pablo::remove_liquidity(Origin::signed(BOB), pool_id, lp, 0, 0));
64+
let lp = Tokens::balance(lp_token, &BOB);
65+
// all lp tokens must have been burnt
66+
assert_eq!(lp, 0_u128);
67+
}

frame/pablo/src/lib.rs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535

3636
pub use pallet::*;
3737

38+
#[cfg(test)]
39+
mod common_test_functions;
3840
#[cfg(test)]
3941
mod mock;
4042
#[cfg(test)]
@@ -418,31 +420,31 @@ pub mod pallet {
418420
T::PalletId::get().into_sub_account(pool_id)
419421
}
420422

421-
fn do_compute_swap(
422-
pool_id: T::PoolId,
423-
pair: CurrencyPair<T::AssetId>,
424-
quote_amount: T::Balance,
425-
apply_fees: bool,
426-
fee: Permill,
427-
protocol_fee: Permill,
428-
) -> Result<(T::Balance, T::Balance, T::Balance, T::Balance), DispatchError> {
429-
let base_amount = Self::get_exchange_value(pool_id, pair.base, quote_amount)?;
430-
let base_amount_u: u128 = T::Convert::convert(base_amount);
431-
432-
let (lp_fee, protocol_fee) = if apply_fees {
433-
let lp_fee = fee.mul_floor(base_amount_u);
434-
// protocol_fee is computed based on lp_fee
435-
let protocol_fee = protocol_fee.mul_floor(lp_fee);
436-
let lp_fee = T::Convert::convert(lp_fee);
437-
let protocol_fee = T::Convert::convert(protocol_fee);
438-
(lp_fee, protocol_fee)
439-
} else {
440-
(T::Balance::zero(), T::Balance::zero())
441-
};
442-
443-
let base_amount_excluding_fees = base_amount.safe_sub(&lp_fee)?;
444-
Ok((base_amount_excluding_fees, quote_amount, lp_fee, protocol_fee))
445-
}
423+
// fn do_compute_swap(
424+
// pool_id: T::PoolId,
425+
// pair: CurrencyPair<T::AssetId>,
426+
// quote_amount: T::Balance,
427+
// apply_fees: bool,
428+
// fee: Permill,
429+
// protocol_fee: Permill,
430+
// ) -> Result<(T::Balance, T::Balance, T::Balance, T::Balance), DispatchError> {
431+
// let base_amount = Self::get_exchange_value(pool_id, pair.base, quote_amount)?;
432+
// let base_amount_u: u128 = T::Convert::convert(base_amount);
433+
434+
// let (lp_fee, protocol_fee) = if apply_fees {
435+
// let lp_fee = fee.mul_floor(base_amount_u);
436+
// // protocol_fee is computed based on lp_fee
437+
// let protocol_fee = protocol_fee.mul_floor(lp_fee);
438+
// let lp_fee = T::Convert::convert(lp_fee);
439+
// let protocol_fee = T::Convert::convert(protocol_fee);
440+
// (lp_fee, protocol_fee)
441+
// } else {
442+
// (T::Balance::zero(), T::Balance::zero())
443+
// };
444+
445+
// let base_amount_excluding_fees = base_amount.safe_sub(&lp_fee)?;
446+
// Ok((base_amount_excluding_fees, quote_amount, lp_fee, protocol_fee))
447+
// }
446448
}
447449

448450
impl<T: Config> Amm for Pallet<T> {
@@ -476,14 +478,14 @@ pub mod pallet {
476478
match pool {
477479
PoolConfiguration::StableSwap(stable_swap_pool_info) =>
478480
StableSwap::<T>::get_exchange_value(
479-
stable_swap_pool_info,
480-
pool_account,
481+
&stable_swap_pool_info,
482+
&pool_account,
481483
asset_id,
482484
amount,
483485
),
484486
ConstantProduct(constant_product_pool_info) => Uniswap::<T>::get_exchange_value(
485-
constant_product_pool_info,
486-
pool_account,
487+
&constant_product_pool_info,
488+
&pool_account,
487489
asset_id,
488490
amount,
489491
),
@@ -611,14 +613,7 @@ pub mod pallet {
611613
// provided pair might have been swapped
612614
ensure!(pair == pool.pair, Error::<T>::PairMismatch);
613615
let (base_amount_excluding_fees, quote_amount, lp_fees, protocol_fees) =
614-
Self::do_compute_swap(
615-
pool_id,
616-
pair,
617-
quote_amount,
618-
true,
619-
pool.fee,
620-
pool.protocol_fee,
621-
)?;
616+
StableSwap::<T>::do_compute_swap(&pool, &pool_account, quote_amount, true)?;
622617

623618
ensure!(
624619
base_amount_excluding_fees >= min_receive,
@@ -657,7 +652,7 @@ pub mod pallet {
657652
let (base_amount, quote_amount_excluding_fees, lp_fees, owner_fees) =
658653
Uniswap::<T>::do_compute_swap(
659654
&constant_product_pool_info,
660-
pool_account,
655+
&pool_account,
661656
pair,
662657
quote_amount,
663658
true,
@@ -668,7 +663,6 @@ pub mod pallet {
668663

669664
ensure!(base_amount >= min_receive, Error::<T>::CannotRespectMinimumRequested);
670665

671-
let pool_account = Self::account_id(&pool_id);
672666
T::Assets::transfer(
673667
pair.quote,
674668
who,

frame/pablo/src/stable_swap.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ impl<T: Config> StableSwap<T> {
7474
}
7575

7676
pub fn get_exchange_value(
77-
pool: StableSwapPoolInfo<T::AccountId, T::AssetId>,
78-
pool_account: T::AccountId,
77+
pool: &StableSwapPoolInfo<T::AccountId, T::AssetId>,
78+
pool_account: &T::AccountId,
7979
asset_id: T::AssetId,
8080
amount: T::Balance,
8181
) -> Result<T::Balance, DispatchError> {
8282
let pair = if asset_id == pool.pair.base { pool.pair } else { pool.pair.swap() };
83-
let pool_base_aum = T::Assets::balance(pair.base, &pool_account);
84-
let pool_quote_aum = T::Assets::balance(pair.quote, &pool_account);
83+
let pool_base_aum = T::Assets::balance(pair.base, pool_account);
84+
let pool_quote_aum = T::Assets::balance(pair.quote, pool_account);
8585
let amp = T::Convert::convert(pool.amplification_coefficient.into());
8686
let d = Self::get_invariant(pool_base_aum, pool_quote_aum, amp)?;
8787
let new_quote_amount = pool_quote_aum.safe_add(&amount)?;
@@ -106,6 +106,31 @@ impl<T: Config> StableSwap<T> {
106106
Ok(difference)
107107
}
108108

109+
pub fn do_compute_swap(
110+
pool: &StableSwapPoolInfo<T::AccountId, T::AssetId>,
111+
pool_account: &T::AccountId,
112+
quote_amount: T::Balance,
113+
apply_fees: bool,
114+
) -> Result<(T::Balance, T::Balance, T::Balance, T::Balance), DispatchError> {
115+
let base_amount =
116+
Self::get_exchange_value(pool, pool_account, pool.pair.base, quote_amount)?;
117+
let base_amount_u: u128 = T::Convert::convert(base_amount);
118+
119+
let (lp_fee, protocol_fee) = if apply_fees {
120+
let lp_fee = pool.fee.mul_floor(base_amount_u);
121+
// protocol_fee is computed based on lp_fee
122+
let protocol_fee = pool.protocol_fee.mul_floor(lp_fee);
123+
let lp_fee = T::Convert::convert(lp_fee);
124+
let protocol_fee = T::Convert::convert(protocol_fee);
125+
(lp_fee, protocol_fee)
126+
} else {
127+
(T::Balance::zero(), T::Balance::zero())
128+
};
129+
130+
let base_amount_excluding_fees = base_amount.safe_sub(&lp_fee)?;
131+
Ok((base_amount_excluding_fees, quote_amount, lp_fee, protocol_fee))
132+
}
133+
109134
pub fn add_liquidity(
110135
who: &T::AccountId,
111136
pool: StableSwapPoolInfo<T::AccountId, T::AssetId>,

frame/pablo/src/stable_swap_tests.rs

Lines changed: 18 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![allow(unreachable_patterns)] // TODO: remove this when there are more pool configurations added.
22

33
use crate::{
4+
common_test_functions::*,
45
mock::{Pablo, *},
56
PoolConfiguration::StableSwap,
67
PoolInitConfiguration,
@@ -147,47 +148,29 @@ fn test_dex_demo() {
147148
#[test]
148149
fn add_remove_lp() {
149150
new_test_ext().execute_with(|| {
151+
let pool_init_config = PoolInitConfiguration::StableSwap {
152+
pair: CurrencyPair::new(USDC, USDT),
153+
amplification_coefficient: 10_u16,
154+
fee: Permill::zero(),
155+
protocol_fee: Permill::zero(),
156+
};
150157
let unit = 1_000_000_000_000_u128;
151158
let initial_usdt = 1_000_000_000_000_u128 * unit;
152159
let initial_usdc = 1_000_000_000_000_u128 * unit;
153-
let pool_id = create_stable_swap_pool(
154-
USDC,
155-
USDT,
160+
let usdc_amount = 1000 * unit;
161+
let usdt_amount = 1000 * unit;
162+
let expected_lp_check = |base_amount: Balance,
163+
quote_amount: Balance,
164+
lp: Balance|
165+
-> bool { base_amount + quote_amount == lp };
166+
common_add_remove_lp(
167+
pool_init_config,
156168
initial_usdc,
157169
initial_usdt,
158-
100_u16,
159-
Permill::zero(),
160-
Permill::zero(),
170+
usdc_amount,
171+
usdt_amount,
172+
expected_lp_check,
161173
);
162-
let pool = Pablo::pools(pool_id).expect("pool not found");
163-
let pool = match pool {
164-
StableSwap(pool) => pool,
165-
_ => panic!("expected stable_swap pool"),
166-
};
167-
let bob_usdc = 1000 * unit;
168-
let bob_usdt = 1000 * unit;
169-
// Mint the tokens
170-
assert_ok!(Tokens::mint_into(USDC, &BOB, bob_usdc));
171-
assert_ok!(Tokens::mint_into(USDT, &BOB, bob_usdt));
172-
173-
let lp = Tokens::balance(pool.lp_token, &BOB);
174-
assert_eq!(lp, 0_u128);
175-
// Add the liquidity
176-
assert_ok!(Pablo::add_liquidity(
177-
Origin::signed(BOB),
178-
pool_id,
179-
bob_usdc,
180-
bob_usdt,
181-
0,
182-
false
183-
));
184-
let lp = Tokens::balance(pool.lp_token, &BOB);
185-
// must have received some lp tokens
186-
assert!(lp == bob_usdt + bob_usdc);
187-
assert_ok!(Pablo::remove_liquidity(Origin::signed(BOB), pool_id, lp, 0, 0));
188-
let lp = Tokens::balance(pool.lp_token, &BOB);
189-
// all lp tokens must have been burnt
190-
assert_eq!(lp, 0_u128);
191174
});
192175
}
193176

frame/pablo/src/uniswap.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,15 @@ impl<T: Config> Uniswap<T> {
6161
}
6262

6363
pub(crate) fn get_exchange_value(
64-
pool: ConstantProductPoolInfo<T::AccountId, T::AssetId>,
65-
pool_account: T::AccountId,
64+
pool: &ConstantProductPoolInfo<T::AccountId, T::AssetId>,
65+
pool_account: &T::AccountId,
6666
asset_id: T::AssetId,
6767
amount: T::Balance,
6868
) -> Result<T::Balance, DispatchError> {
6969
let amount = T::Convert::convert(amount);
7070
let half_weight = Permill::from_percent(50);
71-
let pool_base_aum = T::Convert::convert(T::Assets::balance(pool.pair.base, &pool_account));
72-
let pool_quote_aum =
73-
T::Convert::convert(T::Assets::balance(pool.pair.quote, &pool_account));
71+
let pool_base_aum = T::Convert::convert(T::Assets::balance(pool.pair.base, pool_account));
72+
let pool_quote_aum = T::Convert::convert(T::Assets::balance(pool.pair.quote, pool_account));
7473
let exchange_amount = if asset_id == pool.pair.quote {
7574
compute_out_given_in(half_weight, half_weight, pool_quote_aum, pool_base_aum, amount)
7675
} else {
@@ -154,13 +153,13 @@ impl<T: Config> Uniswap<T> {
154153

155154
pub(crate) fn do_compute_swap(
156155
pool: &ConstantProductPoolInfo<T::AccountId, T::AssetId>,
157-
pool_account: T::AccountId,
156+
pool_account: &T::AccountId,
158157
pair: CurrencyPair<T::AssetId>,
159158
quote_amount: T::Balance,
160159
apply_fees: bool,
161160
) -> Result<(T::Balance, T::Balance, T::Balance, T::Balance), DispatchError> {
162-
let pool_base_aum = T::Convert::convert(T::Assets::balance(pair.base, &pool_account));
163-
let pool_quote_aum = T::Convert::convert(T::Assets::balance(pair.quote, &pool_account));
161+
let pool_base_aum = T::Convert::convert(T::Assets::balance(pair.base, pool_account));
162+
let pool_quote_aum = T::Convert::convert(T::Assets::balance(pair.quote, pool_account));
164163
let quote_amount = T::Convert::convert(quote_amount);
165164

166165
// https://uniswap.org/whitepaper.pdf

0 commit comments

Comments
 (0)