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
- CPI identification: Locates all CPI calls that could be token operations.
- Zero validation scan: Checks the entire function for comparison operations against zero (
> 0,!= 0,< amount). - Explicit zero detection: Flags CPI calls that use an explicit zero constant as the instruction parameter at high severity.
- 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.
Related Detectors
- Input Validation — general input validation issues
- Token Balance Invariant — detects balance invariant violations