Zero Amount Operation Remediation
How to fix missing zero-amount validation in token operations.
Zero Amount Operation Remediation
Overview
Related Detector: Zero Amount Operation
Missing zero-amount validation allows token operations with zero values, which can bypass fee logic, cause accounting errors, or enable griefing. The fix adds explicit non-zero checks before token operations.
Recommended Fix
Before (Vulnerable)
pub fn transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
// No amount validation -- zero is accepted
spl_token::instruction::transfer(..., amount)?;
Ok(())
}
After (Fixed)
pub fn transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
if amount == 0 {
return Err(ProgramError::InvalidArgument);
}
spl_token::instruction::transfer(..., amount)?;
Ok(())
}
Alternative Mitigations
1. Anchor constraint
pub fn transfer(ctx: Context<Transfer>, amount: u64) -> Result<()> {
require!(amount > 0, ErrorCode::InvalidAmount);
// ...
}
2. Minimum amount threshold
const MIN_TRANSFER_AMOUNT: u64 = 1000; // Minimum meaningful amount
pub fn transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
if amount < MIN_TRANSFER_AMOUNT {
return Err(ProgramError::Custom(ErrorCode::AmountBelowMinimum as u32));
}
// ...
}
3. Fee-aware minimum
Ensure the amount exceeds the fee so the net amount is positive:
let fee = calculate_fee(amount);
require!(amount > fee, ErrorCode::AmountTooSmallForFee);
Common Mistakes
Mistake 1: Checking amount after fee deduction only
// WRONG: fee might equal amount, making net = 0
let net = amount - fee;
require!(net > 0); // Should also check: require!(amount > 0) first
Mistake 2: Using >= 0 instead of > 0
// WRONG: u64 is always >= 0, this check is meaningless
require!(amount >= 0); // Always true for unsigned integers
// CORRECT:
require!(amount > 0);