Skip to main content
Sigvex

Zero Amount Operation

Detects token operations that may accept zero amounts without explicit validation.

Zero Amount Operation

Overview

Remediation Guide: How to Fix Zero Amount Operation

The zero-amount operation detector identifies SPL token operations (transfers, mints, burns) that may accept zero amounts without explicit rejection. Zero-amount operations can bypass validation or fee logic that assumes non-zero amounts, cause accounting inconsistencies in DeFi protocols, and lead to unintended behavior.

Why This Is an Issue

While the SPL Token program technically allows zero-amount operations, they can cause problems in application logic:

  • Validation bypass: Fee calculations, slippage checks, or minimum amount validations may assume non-zero amounts
  • Accounting inconsistencies: Zero-amount transfers can create transaction entries without meaningful value movement, confusing accounting systems
  • Liquidity tracking errors: DeFi protocols tracking liquidity may produce incorrect metrics from zero-value operations
  • Gas griefing: Repeatedly submitting zero-amount operations consumes compute units without productive work

CWE mapping: CWE-20 (Improper Input Validation).

How to Resolve

pub fn transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    // Validate non-zero amount at function entry
    if amount == 0 {
        msg!("Transfer amount must be greater than zero");
        return Err(ProgramError::InvalidArgument);
    }

    let ix = spl_token::instruction::transfer(
        &spl_token::id(), accounts[0].key, accounts[1].key,
        accounts[2].key, &[], amount,
    )?;
    invoke(&ix, accounts)?;
    Ok(())
}

Examples

Vulnerable Code

pub fn process_transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    // VULNERABLE: no zero-amount check
    // If amount == 0, fee calculation may divide by zero or produce wrong result
    let fee = calculate_fee(amount); // What if amount == 0?
    let net = amount - fee;

    let ix = spl_token::instruction::transfer(
        &spl_token::id(), accounts[0].key, accounts[1].key,
        accounts[2].key, &[], net,
    )?;
    invoke(&ix, accounts)?;
    Ok(())
}

Fixed Code

pub fn process_transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    require!(amount > 0, ErrorCode::InvalidAmount);

    let fee = calculate_fee(amount);
    let net = amount.checked_sub(fee).ok_or(ProgramError::ArithmeticOverflow)?;
    require!(net > 0, ErrorCode::AmountTooSmall);

    let ix = spl_token::instruction::transfer(
        &spl_token::id(), accounts[0].key, accounts[1].key,
        accounts[2].key, &[], net,
    )?;
    invoke(&ix, accounts)?;
    Ok(())
}

Sample Sigvex Output

{
  "detector_id": "zero-amount-operation",
  "severity": "medium",
  "confidence": 0.40,
  "description": "CPI call (potentially a token operation) is performed without any explicit zero-amount validation in the function.",
  "location": { "function": "process_transfer", "offset": 2 }
}

Detection Methodology

  1. CPI identification: Locates all CPI calls that could be token operations.
  2. Zero validation scan: Checks the entire function for comparison operations against zero (> 0, != 0, < amount).
  3. Explicit zero detection: Flags CPI calls that use an explicit zero constant as the instruction parameter at high severity.
  4. Missing validation: At lower confidence, flags CPI calls in functions lacking any zero-amount checks.

Limitations

  • CPI calls are identified broadly; not all CPIs are token operations, leading to potential false positives.
  • Functions that validate amounts through indirect means (e.g., enum discriminator checks) may not be recognized.
  • Intentional zero-amount operations (e.g., to trigger state updates) will be flagged.

References