SSSwap

First Flight #41
Beginner FriendlyRust
100 EXP
View results
Submission Details
Severity: low
Valid

No Validation for Non-Standard Token Behavior in the `transfer::transfer_tokens` function

Description: The AMM doesn't validate or handle non-standard token behaviors like fee-on-transfer tokens or rebasing tokens. The AMM assumes all tokens follow standard SPL token behavior. However, some tokens implement custom behaviors like taking fees on transfers or rebasing (changing total supply). The AMM doesn't validate actual amounts received after transfers, which could lead to accounting inconsistencies.

Impact:

  1. Pools with fee-on-transfer tokens would have incorrect accounting

  2. Rebasing tokens could cause unexpected behavior in pools

  3. Potential for economic exploits using non-standard tokens

Proof of Concept: With a fee-on-transfer token:

// User transfers 100 tokens, but due to 5% transfer fee, only 95 arrive
// AMM still records 100 tokens in calculations
transfer_tokens(
&context.accounts.user_token_a,
&mut context.accounts.token_vault_a,
&amount_a, // 100 tokens
&context.accounts.token_a_mint,
&context.accounts.user,
&context.accounts.token_program,
);
// Actual balance increase is only 95, but AMM uses 100 in calculations

Recommended Mitigation: Implement balance checking before and after transfers to validate actual amounts received in the liquidity_operations::provide_liquidity function:

pub fn provide_liquidity(context: Context<ModifyLiquidity>, amount_a: u64) -> Result<()> {
// Record balances before transfer
let vault_a_balance_before = context.accounts.vault_a.amount;
let vault_b_balance_before = context.accounts.vault_b.amount;
// Calculate expected amount_b
let expected_amount_b = calculate_token_b_provision_with_a_given(
&mut context.accounts.vault_a,
&mut context.accounts.vault_b,
amount_a
)?;
// Perform transfers
transfer_tokens(/* params for token A */)?
transfer_tokens(/* params for token B */)?
// Reload accounts and check actual amounts received
context.accounts.vault_a.reload()?;
context.accounts.vault_b.reload()?;
let actual_amount_a = context.accounts.vault_a.amount - vault_a_balance_before;
let actual_amount_b = context.accounts.vault_b.amount - vault_b_balance_before;
// Use actual amounts for LP calculation
let lp_to_mint: u64 = liquidity_calculation(actual_amount_a, actual_amount_b)?;
// Rest of function...
Ok(())
}
Updates

Lead Judging Commences

0xtimefliez Lead Judge 13 days ago
Submission Judgement Published
Validated
Assigned finding tags:

weird T22s

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.