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

Minimum reserves check #19

Closed
wants to merge 11 commits into from
24 changes: 23 additions & 1 deletion amm/contracts/stable_pool/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ mod token_rate;
pub mod stable_pool {
use crate::token_rate::TokenRate;
use amm_helpers::{
constants::stable_pool::{MAX_AMP, MIN_AMP, RATE_PRECISION, TOKEN_TARGET_DECIMALS},
constants::stable_pool::{
MAX_AMP, MIN_AMP, MIN_RESERVE, RATE_PRECISION, TOKEN_TARGET_DECIMALS,
},
ensure,
stable_swap_math::{self as math, fees::Fees},
};
Expand Down Expand Up @@ -380,6 +382,7 @@ pub mod stable_pool {
self.pool.reserves[token_id] = self.pool.reserves[token_id]
.checked_sub(amount)
.ok_or(MathError::SubUnderflow(101))?;
self.check_min_reserve(token_id, self.pool.reserves[token_id])?;
Ok(())
}

Expand Down Expand Up @@ -556,6 +559,17 @@ pub mod stable_pool {
ensure!(amount > 0, StablePoolError::InsufficientInputAmount);
Ok(amount)
}

fn check_min_reserve(&self, token_id: usize, reserve: u128) -> Result<(), StablePoolError> {
if self.pool.precisions[token_id]
.checked_mul(reserve)
.ok_or(MathError::MulOverflow(115))?
< MIN_RESERVE
{
return Err(StablePoolError::MinReserve);
}
Ok(())
}
}

impl StablePool for StablePoolContract {
Expand All @@ -566,6 +580,14 @@ pub mod stable_pool {
amounts: Vec<u128>,
to: AccountId,
) -> Result<(u128, u128), StablePoolError> {
//check amounts if it is initial liquidity supply
if self.total_supply() == 0 {
amounts
.iter()
.enumerate()
.try_for_each(|(id, &amount)| self.check_min_reserve(id, amount))?;
deuszx marked this conversation as resolved.
Show resolved Hide resolved
}

// calc lp tokens (shares_to_mint, fee)
let (shares, fee_part) = self.get_mint_liquidity_for_amounts(amounts.clone())?;

Expand Down
2 changes: 2 additions & 0 deletions amm/drink-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ mod stable_pool_contract;
#[cfg(test)]
mod stable_swap_tests;
#[cfg(test)]
mod stable_min_reserve_tests;
#[cfg(test)]
mod utils;
83 changes: 83 additions & 0 deletions amm/drink-tests/src/stable_min_reserve_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use drink::{runtime::MinimalRuntime, session::Session};

use crate::stable_pool_contract::StablePoolError;

use super::{stable_swap_tests::setup_stable_swap, utils::*};

const USDT_DEC: u8 = 6;
const USDC_DEC: u8 = 6;
const DAI_DEC: u8 = 18;

fn test_min_initial_reserve(
session: &mut Session<MinimalRuntime>,
token_decimals: [u8; 2],
initial_reserves: [u128; 2],
expected_result: Result<(u128, u128), StablePoolError>,
deuszx marked this conversation as resolved.
Show resolved Hide resolved
) {
let (stable_swap, _, _) =
setup_stable_swap(session, token_decimals, initial_reserves, 1000, 25, 6);
let res = handle_ink_error(stable_swap::add_liquidity(
session,
stable_swap,
BOB,
1,
initial_reserves.to_vec(),
bob(),
));
assert_eq!(expected_result, res, "Unexpected result");
}

#[drink::test]
fn test_01(session: &mut Session) {
// one 1 usdt, 1 usdc
test_min_initial_reserve(
&mut session,
[USDT_DEC, USDC_DEC],
[1_000_000u128, 1_000_000u128],
Ok((2000000000000000000, 0)),
);
}

#[drink::test]
fn test_02(session: &mut Session) {
// one 0.1 usdt, 0.1 usdc
test_min_initial_reserve(
&mut session,
[USDT_DEC, USDC_DEC],
[100_000u128, 100_000u128],
Err(StablePoolError::MinReserve()),
);
}

#[drink::test]
fn test_03(session: &mut Session) {
// one 1 usdt, 0.1 usdc
test_min_initial_reserve(
&mut session,
[USDT_DEC, USDC_DEC],
[1_000_000u128, 100_000u128],
Err(StablePoolError::MinReserve()),
);
}

#[drink::test]
fn test_04(session: &mut Session) {
// one 1 usdt, 1 dai
test_min_initial_reserve(
&mut session,
[USDT_DEC, DAI_DEC],
[1_000_000u128, 1_000_000_000_000_000_000u128],
Ok((2000000000000000000, 0)),
);
}

#[drink::test]
fn test_05(session: &mut Session) {
// one 1 usdt, 0.1 dai
deuszx marked this conversation as resolved.
Show resolved Hide resolved
test_min_initial_reserve(
&mut session,
[USDT_DEC, DAI_DEC],
[100_000u128, 100_000_000_000_000_000u128],
Err(StablePoolError::MinReserve()),
);
}
2 changes: 1 addition & 1 deletion amm/drink-tests/src/stable_swap_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ink_wrapper_types::{Connection, ToAccountId};

const FEE_BPS_DENOM: u128 = 10_000;

fn setup_stable_swap(
pub fn setup_stable_swap(
session: &mut Session<MinimalRuntime>,
token_decimals: [u8; 2],
token_supply: [u128; 2],
Expand Down
1 change: 1 addition & 0 deletions amm/traits/stable_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ pub enum StablePoolError {
IdenticalTokenId,
IncorrectAmountsCount,
InvalidAmpCoef,
MinReserve,
InsufficientLiquidityMinted,
InsufficientLiquidityBurned,
InsufficientOutputAmount,
Expand Down
3 changes: 3 additions & 0 deletions helpers/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ pub mod stable_pool {
pub const MIN_AMP: u128 = 1;
/// Max amplification coefficient.
pub const MAX_AMP: u128 = 1_000_000;

/// Min reserve
pub const MIN_RESERVE: u128 = TOKEN_TARGET_PRECISION;
}
3 changes: 0 additions & 3 deletions helpers/stable_swap_math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,6 @@ fn compute_lp_amount_for_deposit(
amp_coef: u128,
) -> Result<(u128, u128), MathError> {
if pool_token_supply == 0 {
if deposit_amounts.contains(&0) {
return Err(MathError::DivByZero(8));
}
Ok((
compute_d(deposit_amounts, amp_coef)?
.try_into()
Expand Down
Loading