skills/vulnerability-patterns/fee-on-transfer-tokens/SKILL.md
Fee-on-transfer and deflationary token integration pitfalls that break protocol accounting.
npx skillsauth add apegurus/solidity-argus fee-on-transfer-tokensInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Protocols that assume transferFrom(sender, recipient, amount) delivers exactly amount tokens to the recipient will break when interacting with fee-on-transfer (deflationary) tokens. These tokens deduct a fee during transfer, so the actual received amount is less than the specified amount. This creates accounting mismatches that can lead to insolvency, stuck funds, or exploitation.
Severity: Informational to Medium (depends on whether the protocol explicitly supports or excludes these tokens)
Prevalence: Found in 5 independent BailSec audits: Gamma UniswapV4, Gamma Vaults, Meuna, Moebius Finance, Terminal Finance DEX.
// VULNERABLE: Assumes amount received == amount transferred
function deposit(address token, uint256 amount) external {
IERC20(token).transferFrom(msg.sender, address(this), amount);
// If token has 2% fee, contract only received 0.98 * amount
// but records the full amount — accounting is now wrong
balances[msg.sender] += amount; // Overstated!
}
// SECURE: Measures actual received amount
function deposit(address token, uint256 amount) external {
uint256 balanceBefore = IERC20(token).balanceOf(address(this));
IERC20(token).transferFrom(msg.sender, address(this), amount);
uint256 received = IERC20(token).balanceOf(address(this)) - balanceBefore;
balances[msg.sender] += received; // Correct accounting
}
| Token | Fee Mechanism | Notes | |-------|--------------|-------| | SAFEMOON | 10% tax on transfer | Reflection + burn + liquidity | | STA (Statera) | 1% deflationary burn | Destroyed on each transfer | | PAXG | 0.02% transfer fee | Gold-backed, fee goes to Paxos | | USDT (potential) | Configurable fee (currently 0) | Has fee infrastructure built-in |
transferFrom() or safeTransferFrom() and then use the amount parameter directly?balanceOf(address(this)) check before and after the transfer?balanceOf to determine the actual amount receivedtesting
Specialist profile for mechanically applying the attack-vector deck and classifying vectors as skip, drop, or investigate.
tools
Specialist profile for libraries, helpers, base contracts, adapters, encoders, wrappers, and integration glue.
testing
Specialist profile for rounding, scale, decimal, downcast, and arithmetic accounting edge cases.
testing
Specialist profile for extracting conservation laws and state couplings, then searching for violating paths.