Skip to content

Commit ec74da4

Browse files
committed
min liquidity math fix
1 parent 514f300 commit ec74da4

File tree

4 files changed

+33
-19
lines changed

4 files changed

+33
-19
lines changed

src/contract.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -543,21 +543,21 @@ mod test {
543543
let pool_mockup = PoolMockup::new(100_000, 200_000);
544544
let vault_mockup = VaultMockup::new(&pool_mockup, vault_params("2", "1.45", "0.55"));
545545

546-
vault_mockup.deposit(42, 0, &pool_mockup.user1).unwrap();
546+
vault_mockup.deposit(10_123, 0, &pool_mockup.user1).unwrap();
547547
vault_mockup.rebalance(&pool_mockup.deployer).unwrap();
548548

549549
// Dual case
550550
let pool_mockup = PoolMockup::new(100_000, 200_000);
551551
let vault_mockup = VaultMockup::new(&pool_mockup, vault_params("2", "1.45", "0.55"));
552552

553-
vault_mockup.deposit(0, 42, &pool_mockup.user1).unwrap();
553+
vault_mockup.deposit(0, 10_123, &pool_mockup.user1).unwrap();
554554
vault_mockup.rebalance(&pool_mockup.deployer).unwrap();
555555

556556
// Combined case
557557
let pool_mockup = PoolMockup::new(100_000, 200_000);
558558
let vault_mockup = VaultMockup::new(&pool_mockup, vault_params("2", "1.45", "0.55"));
559559

560-
vault_mockup.deposit(42, 0, &pool_mockup.user1).unwrap();
560+
vault_mockup.deposit(10_123, 0, &pool_mockup.user1).unwrap();
561561
vault_mockup.rebalance(&pool_mockup.deployer).unwrap();
562562
assert!(vault_mockup.vault_state_query().limit_position_id.is_some());
563563
assert!(vault_mockup.vault_state_query().full_range_position_id.is_none());
@@ -642,7 +642,7 @@ mod test {
642642
let pool_mockup = PoolMockup::new(100_000, 200_000);
643643
let vault_mockup = VaultMockup::new(&pool_mockup, vault_params("2", "1.45", "0.55"));
644644

645-
let (vault_x, vault_y) = (1_000, 1_000);
645+
let (vault_x, vault_y) = (10_000, 10_000);
646646
vault_mockup.deposit(vault_x, vault_y, &pool_mockup.user1).unwrap();
647647
vault_mockup.rebalance(&pool_mockup.deployer).unwrap();
648648

@@ -657,7 +657,7 @@ mod test {
657657
let pool_mockup = PoolMockup::new(100_000, 200_000);
658658
let vault_mockup = VaultMockup::new(&pool_mockup, vault_params("2", "1.45", "0.55"));
659659

660-
let (vault_x, vault_y) = (1_000, 1_500);
660+
let (vault_x, vault_y) = (10_000, 15_000);
661661
vault_mockup.deposit(vault_x, vault_y, &pool_mockup.user1).unwrap();
662662
let shares_got = vault_mockup.shares_query(&pool_mockup.user1.address());
663663
vault_mockup.rebalance(&pool_mockup.deployer).unwrap();
@@ -682,8 +682,8 @@ mod test {
682682

683683
assert_eq!(vault_bals_before_withdrawal.bal0, Uint128::new(vault_x));
684684
assert_eq!(vault_bals_before_withdrawal.bal1, Uint128::new(vault_y));
685-
assert_approx_eq!(vault_bals_after_withdrawal.bal0, Uint128::zero(), MIN_LIQUIDITY);
686-
assert_approx_eq!(vault_bals_after_withdrawal.bal1, Uint128::zero(), MIN_LIQUIDITY);
685+
assert_approx_eq!(vault_bals_after_withdrawal.bal0, Uint128::zero(), MIN_LIQUIDITY + Uint128::one());
686+
assert_approx_eq!(vault_bals_after_withdrawal.bal1, Uint128::zero(), MIN_LIQUIDITY + Uint128::one());
687687
}
688688

689689

@@ -703,7 +703,7 @@ mod test {
703703
vault_mockup.withdraw(shares_got, &pool_mockup.user1).unwrap();
704704

705705
assert!(vault_mockup.vault_balances_query().bal0.is_zero());
706-
assert_approx_eq!(vault_mockup.vault_balances_query().bal1, Uint128::zero(), MIN_LIQUIDITY);
706+
assert_approx_eq!(vault_mockup.vault_balances_query().bal1, Uint128::zero(), MIN_LIQUIDITY + Uint128::one());
707707
}
708708

709709
#[test]
@@ -756,8 +756,8 @@ mod test {
756756
&ExecuteMsg::Withdraw(
757757
WithdrawMsg {
758758
shares: shares_got,
759-
amount0_min: vault_balances_before_withdrawal.bal0 + Uint128::one(),
760-
amount1_min: vault_balances_before_withdrawal.bal1 + Uint128::one(),
759+
amount0_min: vault_balances_before_withdrawal.bal0 - MIN_LIQUIDITY,
760+
amount1_min: vault_balances_before_withdrawal.bal1 - MIN_LIQUIDITY,
761761
to: pool_mockup.user1.address()
762762
}
763763
),
@@ -771,8 +771,8 @@ mod test {
771771
&ExecuteMsg::Withdraw(
772772
WithdrawMsg {
773773
shares: shares_got,
774-
amount0_min: vault_balances_before_withdrawal.bal0 - MIN_LIQUIDITY,
775-
amount1_min: vault_balances_before_withdrawal.bal1 - MIN_LIQUIDITY,
774+
amount0_min: vault_balances_before_withdrawal.bal0 - MIN_LIQUIDITY - Uint128::one(),
775+
amount1_min: vault_balances_before_withdrawal.bal1 - MIN_LIQUIDITY - Uint128::one(),
776776
to: pool_mockup.user1.address()
777777
}
778778
),
@@ -782,8 +782,8 @@ mod test {
782782

783783
let vault_balances_after_withdrawal = vault_mockup.vault_balances_query();
784784

785-
assert_approx_eq!(vault_balances_after_withdrawal.bal0, Uint128::zero(), MIN_LIQUIDITY);
786-
assert_approx_eq!(vault_balances_after_withdrawal.bal1, Uint128::zero(), MIN_LIQUIDITY);
785+
assert_approx_eq!(vault_balances_after_withdrawal.bal0, Uint128::zero(), MIN_LIQUIDITY + Uint128::one());
786+
assert_approx_eq!(vault_balances_after_withdrawal.bal1, Uint128::zero(), MIN_LIQUIDITY + Uint128::one());
787787
assert!(vault_balances_after_withdrawal.protocol_unclaimed_fees0.is_zero());
788788
assert!(vault_balances_after_withdrawal.protocol_unclaimed_fees1.is_zero());
789789
}
@@ -897,11 +897,13 @@ mod test {
897897
fn min_liquidity_attack() {
898898
let pool_mockup = PoolMockup::new(200_000, 100_000);
899899
let vault_mockup = VaultMockup::new(&pool_mockup, vault_params("2", "1.45", "0.55"));
900+
900901
vault_mockup.deposit(10_000, 10_000, &pool_mockup.user1).unwrap();
901902
let shares = vault_mockup.shares_query(&pool_mockup.user1.address());
902903
vault_mockup.withdraw(shares - Uint128::one(), &pool_mockup.user1).unwrap();
903-
let shares = vault_mockup.shares_query(&pool_mockup.user2.address());
904+
904905
vault_mockup.deposit(10_000, 10_000, &pool_mockup.user2).unwrap();
906+
let shares = vault_mockup.shares_query(&pool_mockup.user2.address());
905907
vault_mockup.withdraw(shares - Uint128::one(), &pool_mockup.user2).unwrap();
906908
}
907909

src/error.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ pub enum DepositError {
7070
InvalidShareholderAddress(String),
7171

7272
#[error("Used amounts below min wanted amounts: used: {used}, wanted: {wanted}")]
73-
DepositedAmontsBelowMin { used: String, wanted: String }
73+
DepositedAmountsBelowMin { used: String, wanted: String },
74+
75+
#[error("Deposit must be above {min_liquidity}, got: {got}")]
76+
DepositedAmountBelowMinLiquidity { min_liquidity: String, got: String }
7477
}
7578

7679
#[derive(Error, Debug, PartialEq)]

src/execute.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ pub fn deposit(
6969
return Err(ShareholderCantBeContract(new_holder.into()));
7070
}
7171

72+
if !(amount0 > MIN_LIQUIDITY || amount1 > MIN_LIQUIDITY) {
73+
return Err(DepositedAmountBelowMinLiquidity {
74+
min_liquidity: MIN_LIQUIDITY.into(),
75+
got: format!("({}, {})", amount0, amount1)
76+
})
77+
}
78+
7279
let CalcSharesAndUsableAmountsResponse {
7380
shares,
7481
usable_amount0: amount0_used,
@@ -89,7 +96,7 @@ pub fn deposit(
8996
assert!(!shares.is_zero());
9097

9198
if amount0_used < amount0_min || amount1_used < amount1_min {
92-
return Err(DepositedAmontsBelowMin {
99+
return Err(DepositedAmountsBelowMin {
93100
used: format!("({}, {})", amount0_used, amount1_used),
94101
wanted: format!("({}, {})", amount0_min, amount1_min),
95102
});

src/query.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use cosmwasm_std::{Deps, Uint128, Uint256};
44
use cw20_base::state::TOKEN_INFO;
55
use osmosis_std::types::osmosis::concentratedliquidity::v1beta1::PositionByIdRequest;
66

7-
use crate::{do_me, do_ok, msg::{CalcSharesAndUsableAmountsResponse, PositionBalancesWithFeesResponse, VaultBalancesResponse}, state::{FundsInfo, PositionType, FEES_INFO, FUNDS_INFO, VAULT_INFO, VAULT_STATE}};
7+
use crate::{constants::MIN_LIQUIDITY, do_me, do_ok, msg::{CalcSharesAndUsableAmountsResponse, PositionBalancesWithFeesResponse, VaultBalancesResponse}, state::{FundsInfo, PositionType, FEES_INFO, FUNDS_INFO, VAULT_INFO, VAULT_STATE}};
88

99
/// Partition available balances to the vault in 3 sets:
1010
/// - Balances available for business logic, e.g., for creating new positions.
@@ -173,8 +173,10 @@ pub fn calc_shares_and_usable_amounts(
173173
let total_supply = TOKEN_INFO.load(deps.storage).unwrap().total_supply;
174174

175175
if total_supply.is_zero() {
176+
// Invariant: Wont overflow. See [`DepositError::DepositedAmountBelowMinLiquidity`].
176177
CalcSharesAndUsableAmountsResponse {
177-
shares: cmp::max(input_amount0, input_amount1),
178+
shares: cmp::max(input_amount0, input_amount1)
179+
.checked_sub(MIN_LIQUIDITY).unwrap(),
178180
usable_amount0: input_amount0,
179181
usable_amount1: input_amount1,
180182
}

0 commit comments

Comments
 (0)