Add checks for 0 token output and tests (#595)
This commit is contained in:
parent
a965c4aa68
commit
423d8b1ae9
|
@ -29,9 +29,12 @@ impl SwapResult {
|
||||||
let invariant = swap_source_amount.checked_mul(swap_destination_amount)?;
|
let invariant = swap_source_amount.checked_mul(swap_destination_amount)?;
|
||||||
|
|
||||||
// debit the fee to calculate the amount swapped
|
// debit the fee to calculate the amount swapped
|
||||||
let fee = source_amount
|
let mut fee = source_amount
|
||||||
.checked_mul(fee_numerator)?
|
.checked_mul(fee_numerator)?
|
||||||
.checked_div(fee_denominator)?;
|
.checked_div(fee_denominator)?;
|
||||||
|
if fee == 0 {
|
||||||
|
fee = 1; // minimum fee of one token
|
||||||
|
}
|
||||||
let new_source_amount_less_fee = swap_source_amount
|
let new_source_amount_less_fee = swap_source_amount
|
||||||
.checked_add(source_amount)?
|
.checked_add(source_amount)?
|
||||||
.checked_sub(fee)?;
|
.checked_sub(fee)?;
|
||||||
|
@ -48,6 +51,14 @@ impl SwapResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn map_zero_to_none(x: u64) -> Option<u64> {
|
||||||
|
if x == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The Uniswap invariant calculator.
|
/// The Uniswap invariant calculator.
|
||||||
pub struct ConstantProduct {
|
pub struct ConstantProduct {
|
||||||
/// Token A
|
/// Token A
|
||||||
|
@ -72,7 +83,7 @@ impl ConstantProduct {
|
||||||
)?;
|
)?;
|
||||||
self.token_a = result.new_source_amount;
|
self.token_a = result.new_source_amount;
|
||||||
self.token_b = result.new_destination_amount;
|
self.token_b = result.new_destination_amount;
|
||||||
Some(result.amount_swapped)
|
map_zero_to_none(result.amount_swapped)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Swap token b to a
|
/// Swap token b to a
|
||||||
|
@ -86,7 +97,7 @@ impl ConstantProduct {
|
||||||
)?;
|
)?;
|
||||||
self.token_b = result.new_source_amount;
|
self.token_b = result.new_source_amount;
|
||||||
self.token_a = result.new_destination_amount;
|
self.token_a = result.new_destination_amount;
|
||||||
Some(result.amount_swapped)
|
map_zero_to_none(result.amount_swapped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,18 +134,20 @@ impl PoolTokenConverter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A tokens for pool tokens
|
/// A tokens for pool tokens, returns None if output is less than 0
|
||||||
pub fn token_a_rate(&self, pool_tokens: u64) -> Option<u64> {
|
pub fn token_a_rate(&self, pool_tokens: u64) -> Option<u64> {
|
||||||
pool_tokens
|
pool_tokens
|
||||||
.checked_mul(self.token_a)?
|
.checked_mul(self.token_a)?
|
||||||
.checked_div(self.supply)
|
.checked_div(self.supply)
|
||||||
|
.and_then(map_zero_to_none)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// B tokens for pool tokens
|
/// B tokens for pool tokens, returns None is output is less than 0
|
||||||
pub fn token_b_rate(&self, pool_tokens: u64) -> Option<u64> {
|
pub fn token_b_rate(&self, pool_tokens: u64) -> Option<u64> {
|
||||||
pool_tokens
|
pool_tokens
|
||||||
.checked_mul(self.token_b)?
|
.checked_mul(self.token_b)?
|
||||||
.checked_div(self.supply)
|
.checked_div(self.supply)
|
||||||
|
.and_then(map_zero_to_none)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1938,6 +1938,33 @@ mod tests {
|
||||||
accounts.pool_mint_account = old_pool_account;
|
accounts.pool_mint_account = old_pool_account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deposit 1 pool token fails beacuse it equates to 0 swap tokens
|
||||||
|
{
|
||||||
|
let (
|
||||||
|
token_a_key,
|
||||||
|
mut token_a_account,
|
||||||
|
token_b_key,
|
||||||
|
mut token_b_account,
|
||||||
|
pool_key,
|
||||||
|
mut pool_account,
|
||||||
|
) = accounts.setup_token_accounts(&user_key, &depositor_key, deposit_a, deposit_b, 0);
|
||||||
|
assert_eq!(
|
||||||
|
Err(SwapError::CalculationFailure.into()),
|
||||||
|
accounts.deposit(
|
||||||
|
&depositor_key,
|
||||||
|
&pool_key,
|
||||||
|
&mut pool_account,
|
||||||
|
&token_a_key,
|
||||||
|
&mut token_a_account,
|
||||||
|
&token_b_key,
|
||||||
|
&mut token_b_account,
|
||||||
|
1,
|
||||||
|
deposit_a,
|
||||||
|
deposit_b / 10,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// slippage exceeeded
|
// slippage exceeeded
|
||||||
{
|
{
|
||||||
let (
|
let (
|
||||||
|
@ -2435,6 +2462,39 @@ mod tests {
|
||||||
accounts.pool_mint_account = old_pool_account;
|
accounts.pool_mint_account = old_pool_account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// withdrawing 1 pool token fails because it equates to 0 output tokens
|
||||||
|
{
|
||||||
|
let (
|
||||||
|
token_a_key,
|
||||||
|
mut token_a_account,
|
||||||
|
token_b_key,
|
||||||
|
mut token_b_account,
|
||||||
|
pool_key,
|
||||||
|
mut pool_account,
|
||||||
|
) = accounts.setup_token_accounts(
|
||||||
|
&user_key,
|
||||||
|
&withdrawer_key,
|
||||||
|
initial_a,
|
||||||
|
initial_b,
|
||||||
|
initial_pool,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Err(SwapError::CalculationFailure.into()),
|
||||||
|
accounts.withdraw(
|
||||||
|
&withdrawer_key,
|
||||||
|
&pool_key,
|
||||||
|
&mut pool_account,
|
||||||
|
&token_a_key,
|
||||||
|
&mut token_a_account,
|
||||||
|
&token_b_key,
|
||||||
|
&mut token_b_account,
|
||||||
|
1,
|
||||||
|
minimum_a_amount * 10,
|
||||||
|
minimum_b_amount,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// slippage exceeeded
|
// slippage exceeeded
|
||||||
{
|
{
|
||||||
let (
|
let (
|
||||||
|
@ -2820,6 +2880,32 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// output token value 0
|
||||||
|
{
|
||||||
|
let (
|
||||||
|
token_a_key,
|
||||||
|
mut token_a_account,
|
||||||
|
token_b_key,
|
||||||
|
mut token_b_account,
|
||||||
|
_pool_key,
|
||||||
|
_pool_account,
|
||||||
|
) = accounts.setup_token_accounts(&user_key, &swapper_key, initial_a, initial_b, 0);
|
||||||
|
assert_eq!(
|
||||||
|
Err(SwapError::CalculationFailure.into()),
|
||||||
|
accounts.swap(
|
||||||
|
&swapper_key,
|
||||||
|
&token_b_key,
|
||||||
|
&mut token_b_account,
|
||||||
|
&swap_token_b_key,
|
||||||
|
&swap_token_a_key,
|
||||||
|
&token_a_key,
|
||||||
|
&mut token_a_account,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// slippage exceeeded: minimum out amount too high
|
// slippage exceeeded: minimum out amount too high
|
||||||
{
|
{
|
||||||
let (
|
let (
|
||||||
|
|
Loading…
Reference in New Issue