Skip to content

Commit

Permalink
Disallow deposit/withdrawal when all amounts are 0 (#34)
Browse files Browse the repository at this point in the history
* add check for amounts

* fix tests

* add tests for zero amounts deposit and withdrawal

* rename error
  • Loading branch information
JanKuczma authored Aug 19, 2024
1 parent 270acaa commit a82659b
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 11 deletions.
37 changes: 29 additions & 8 deletions amm/contracts/stable_pool/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,11 @@ pub mod stable_pool {
amounts.len() == self.pool.tokens.len(),
StablePoolError::IncorrectAmountsCount
);
// Check that at least one amount is non-zero
ensure!(
amounts.iter().any(|&amount| amount > 0),
StablePoolError::ZeroAmounts
);

// Make sure rates are up to date before we attempt any calculations
let rates = self.get_scaled_rates()?;
Expand All @@ -559,12 +564,14 @@ pub mod stable_pool {

// transfer amounts
for (id, &token) in self.pool.tokens.iter().enumerate() {
self.token_by_address(token).transfer_from(
self.env().caller(),
self.env().account_id(),
amounts[id],
vec![],
)?;
if amounts[id] > 0 {
self.token_by_address(token).transfer_from(
self.env().caller(),
self.env().account_id(),
amounts[id],
vec![],
)?;
}
}

// mint shares
Expand Down Expand Up @@ -620,10 +627,17 @@ pub mod stable_pool {
.all(|(amount, min_amount)| amount >= min_amount),
StablePoolError::InsufficientOutputAmount
);
// Check that at least one amount is non-zero
ensure!(
amounts.iter().any(|&amount| amount > 0),
StablePoolError::ZeroAmounts
);

// transfer tokens
for (&token, &amount) in self.pool.tokens.iter().zip(amounts.iter()) {
self.token_by_address(token).transfer(to, amount, vec![])?;
if amount > 0 {
self.token_by_address(token).transfer(to, amount, vec![])?;
}
}

// update reserves
Expand Down Expand Up @@ -658,6 +672,11 @@ pub mod stable_pool {
amounts.len() == self.pool.tokens.len(),
StablePoolError::IncorrectAmountsCount
);
// Check that at least one amount is non-zero
ensure!(
amounts.iter().any(|&amount| amount > 0),
StablePoolError::ZeroAmounts
);

let rates = self.get_scaled_rates()?;

Expand Down Expand Up @@ -689,7 +708,9 @@ pub mod stable_pool {
}
// transfer tokens
for (&token, &amount) in self.pool.tokens.iter().zip(amounts.iter()) {
self.token_by_address(token).transfer(to, amount, vec![])?;
if amount > 0 {
self.token_by_address(token).transfer(to, amount, vec![])?;
}
}
// update reserves
for (i, &amount) in amounts.iter().enumerate() {
Expand Down
144 changes: 144 additions & 0 deletions amm/drink-tests/src/stable_swap_tests/tests_add_remove_lp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,3 +1225,147 @@ fn test_lp_withdraw_all_but_no_more() {
)
.expect_err("Should not successfully remove liquidity");
}

#[drink::test]
fn test_for_zero_deposit(mut session: Session) {
seed_account(&mut session, CHARLIE);
seed_account(&mut session, DAVE);
seed_account(&mut session, EVA);

let initial_reserves = vec![100000 * ONE_DAI, 100000 * ONE_USDT, 100000 * ONE_USDC];
let initial_supply = initial_reserves
.iter()
.map(|amount| amount * 100_000_000_000)
.collect::<Vec<u128>>();
let (stable_swap, tokens) = setup_stable_swap_with_tokens(
&mut session,
vec![18, 6, 6],
initial_supply.clone(),
10_000,
2_500_000,
200_000_000,
BOB,
vec![],
);

_ = stable_swap::add_liquidity(
&mut session,
stable_swap,
BOB,
1,
initial_reserves.clone(),
bob(),
)
.expect("Should successfully add liquidity");

// setup max allowance for stable swap contract on both tokens
transfer_and_increase_allowance(
&mut session,
stable_swap,
tokens.clone(),
CHARLIE,
vec![500 * ONE_DAI, 500 * ONE_USDT, 500 * ONE_USDC],
BOB,
);

let err = stable_swap::add_liquidity(
&mut session,
stable_swap,
CHARLIE,
0,
vec![0, 0, 0],
charlie(),
)
.expect_err("Should return an error");

assert_eq!(
err,
StablePoolError::ZeroAmounts(),
"Should return appropriate error"
);

_ = stable_swap::add_liquidity(
&mut session,
stable_swap,
CHARLIE,
0,
vec![1, 0, 0],
charlie(),
)
.expect("Should min liqudity");
}

#[drink::test]
fn test_for_zero_withdrawal(mut session: Session) {
seed_account(&mut session, CHARLIE);
seed_account(&mut session, DAVE);
seed_account(&mut session, EVA);

let initial_reserves = vec![100000 * ONE_DAI, 100000 * ONE_USDT, 100000 * ONE_USDC];
let initial_supply = initial_reserves
.iter()
.map(|amount| amount * 100_000_000_000)
.collect::<Vec<u128>>();
let (stable_swap, _) = setup_stable_swap_with_tokens(
&mut session,
vec![18, 6, 6],
initial_supply.clone(),
10_000,
2_500_000,
200_000_000,
BOB,
vec![],
);

_ = stable_swap::add_liquidity(
&mut session,
stable_swap,
BOB,
1,
initial_reserves.clone(),
bob(),
)
.expect("Should successfully add liquidity");

let err = stable_swap::remove_liquidity_by_shares(
&mut session,
stable_swap,
BOB,
1,
vec![0, 0, 0],
bob(),
)
.expect_err("Should return an error");

assert_eq!(
err,
StablePoolError::ZeroAmounts(),
"Should return appropriate error"
);

let err = stable_swap::remove_liquidity_by_amounts(
&mut session,
stable_swap,
BOB,
0,
vec![0, 0, 0],
bob(),
)
.expect_err("Should return an error");

assert_eq!(
err,
StablePoolError::ZeroAmounts(),
"Should return appropriate error"
);

_ = stable_swap::remove_liquidity_by_amounts(
&mut session,
stable_swap,
BOB,
1,
vec![1, 0, 0],
bob(),
)
.expect("Should burn liquidity");
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ fn test_swap_exact_in(
[0, expected_protocol_fee_part].to_vec(),
bob(),
)
.expect("swap_exact_in: Should remove liquidity");
.unwrap_or((0, 0));
assert_eq!(
total_lp_required - lp_fee_part,
protocol_fee_lp,
Expand All @@ -181,7 +181,7 @@ fn test_swap_exact_in(
[0, expected_protocol_fee_part].to_vec(),
bob(),
)
.expect("swap_received: Should remove liquidity");
.unwrap_or((0, 0));
assert_eq!(
total_lp_required - lp_fee_part,
protocol_fee_lp,
Expand Down
2 changes: 1 addition & 1 deletion amm/traits/stable_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ pub enum StablePoolError {
InvalidTokenId(AccountId),
IdenticalTokenId,
IncorrectAmountsCount,
InvalidAmpCoef,
ZeroAmounts,
InsufficientLiquidityMinted,
InsufficientLiquidityBurned,
InsufficientOutputAmount,
Expand Down

0 comments on commit a82659b

Please sign in to comment.