The ERC-20 standard is DeFi's lingua franca — but it's also a minefield. Fee-on-transfer tokens break lending protocols. Rebasing tokens corrupt vault accounting. The approve/transferFrom pattern enables frontrunning attacks. And hundreds of tokens deviate from the standard in ways that silently break integrations. If your protocol handles ERC-20 tokens, you need to know these pitfalls.
1. Approval Frontrunning (The Double-Spend)
When a user calls approve(spender, newAmount), a frontrunner can spend the old allowance AND the new one in the same block.
// Attack scenario:
// Alice approved Bob for 100 tokens
// Alice calls approve(Bob, 50) to reduce allowance
// Bob frontruns: transferFrom(Alice, Bob, 100) using old allowance
// Alice's tx executes: approve(Bob, 50)
// Bob calls: transferFrom(Alice, Bob, 50) using new allowance
// Total stolen: 150 tokens instead of 50
// SOLUTION: Use increaseAllowance/decreaseAllowance
// Or: Set to 0 first, then set new amount in separate tx
2. Fee-on-Transfer Tokens
Some tokens (STA, PAXG, certain deflationary tokens) deduct a fee on every transfer. If your contract expects to receive exactly the amount transferred, accounting will be wrong.
// VULNERABLE: Assumes received amount == transferred amount
function deposit(uint256 amount) external {
token.transferFrom(msg.sender, address(this), amount);
balances[msg.sender] += amount; // Overstated if token has transfer fee!
}
// SECURE: Check actual received amount
function deposit(uint256 amount) external {
uint256 before = token.balanceOf(address(this));
token.transferFrom(msg.sender, address(this), amount);
uint256 received = token.balanceOf(address(this)) - before;
balances[msg.sender] += received;
}
3. Rebasing Tokens
Tokens like stETH and AMPL change balances automatically. Vault contracts that cache balances will have stale accounting. Use wrapped versions (wstETH) in DeFi protocols.
4. Non-Standard Return Values
USDT, BNB, and ~300+ tokens don't follow the standard bool return on transfer(). Always use OpenZeppelin's SafeERC20 library.
5. Tokens with Hooks (ERC-777)
ERC-777 tokens have tokensReceived callbacks that can trigger reentrancy. Multiple DeFi protocols were drained by ERC-777 reentrancy.
ERC-20 Integration Checklist
- ✅ Use SafeERC20 for all token operations
- ✅ Check actual received balance for fee-on-transfer support
- ✅ Use wrapped versions of rebasing tokens
- ✅ Guard against ERC-777 reentrancy with nonReentrant
- ✅ Handle tokens with >18 and <18 decimals
- ✅ Test with USDT, USDC, WBTC, stETH, and deflationary tokens
How Vultbase Detects ERC-20 Issues
- Pattern DB — 32 ERC-20 integration patterns covering all non-standard behaviors
- Static Analysis — Flags missing SafeERC20, unchecked returns, and balance assumptions
- DeFi Challenge — Tests with adversarial token implementations
ERC-20 compatibility is harder than it looks. Audit your token integration before one non-standard token breaks everything.