Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 042da2b

Browse files
authored
token-swap: Allow for huge swaps that almost entirely drain one side (#3334)
1 parent 62ede32 commit 042da2b

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

token-swap/program/src/curve/stable.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ fn compute_new_destination_amount(
123123
let leverage: U256 = leverage.into();
124124
let new_source_amount: U256 = new_source_amount.into();
125125
let d_val: U256 = d_val.into();
126+
let zero = U256::from(0u128);
127+
let one = U256::from(1u128);
126128

127129
// sum' = prod' = x
128130
// c = D ** (n + 1) / (n ** (2 * n) * prod' * A)
@@ -135,8 +137,18 @@ fn compute_new_destination_amount(
135137
// Solve for y by approximating: y**2 + b*y = c
136138
let mut y = d_val;
137139
for _ in 0..ITERATIONS {
138-
let (y_new, _) = (checked_u8_power(&y, 2)?.checked_add(c)?)
139-
.checked_ceil_div(checked_u8_mul(&y, 2)?.checked_add(b)?.checked_sub(d_val)?)?;
140+
let numerator = checked_u8_power(&y, 2)?.checked_add(c)?;
141+
let denominator = checked_u8_mul(&y, 2)?.checked_add(b)?.checked_sub(d_val)?;
142+
// checked_ceil_div is conservative, not allowing for a 0 return, but we can
143+
// ceiling to 1 token in this case since we're solving through approximation,
144+
// and not doing a constant product calculation
145+
let (y_new, _) = numerator.checked_ceil_div(denominator).unwrap_or_else(|| {
146+
if numerator == U256::from(0u128) {
147+
(zero, zero)
148+
} else {
149+
(one, zero)
150+
}
151+
});
140152
if y_new == y {
141153
break;
142154
} else {
@@ -630,4 +642,24 @@ mod tests {
630642
);
631643
}
632644
}
645+
646+
// this test comes from a failed proptest
647+
#[test]
648+
fn withdraw_token_conversion_huge_withdrawal() {
649+
let pool_token_supply: u64 = 12798273514859089136;
650+
let pool_token_amount: u64 = 12798243809352362806;
651+
let swap_token_a_amount: u64 = 10000000000000000000;
652+
let swap_token_b_amount: u64 = 6000000000000000000;
653+
let amp = 72;
654+
let curve = StableCurve { amp };
655+
check_withdraw_token_conversion(
656+
&curve,
657+
pool_token_amount as u128,
658+
pool_token_supply as u128,
659+
swap_token_a_amount as u128,
660+
swap_token_b_amount as u128,
661+
TradeDirection::AtoB,
662+
CONVERSION_BASIS_POINTS_GUARANTEE,
663+
);
664+
}
633665
}

0 commit comments

Comments
 (0)