For educational purposes only; not investment advice. Investing may result in loss.
Direct answer
The ERC-20 approval race condition can occur when an owner replaces one non-zero allowance with another by calling approve(spender, newAmount). A spender can see the pending change, spend the old allowance first with transferFrom, and then spend from the replacement allowance after it is confirmed.
The ERC-20 specification therefore recommends that client interfaces first set the allowance to 0 before setting a new value for the same spender. Each transaction must be confirmed in order. Where a token supports them, atomic increaseAllowance or decreaseAllowance calls avoid replacing a non-zero allowance directly.
Completing this review does not prove an asset, transaction, or system is safe.
How it works
ERC-20 defines approve as an overwrite: a successful approve(spender, amount) sets the spender’s allowance to amount. Separately, transferFrom(owner, recipient, amount) lets that spender move the owner’s tokens and normally reduces the remaining allowance. Pending transactions do not reserve an execution order, so a spender may submit a transfer that executes before the owner’s approval change.
The risky transition is N -> M, where both N > 0 and M > 0. If the spender consumes N before the replacement approval executes, the later approval installs a fresh allowance of M. The maximum spent across that sequence can therefore be N + M, subject to the owner’s token balance and the token’s implementation.
Example
Alice has approved a protocol to spend 100 tokens. She submits approve(protocol, 50), intending to lower the remaining allowance to 50. Before that transaction confirms, the protocol’s spender submits transferFrom(Alice, recipient, 100) and gets it executed first. Alice’s approval then sets the allowance to 50, which the spender can use in another transfer. The two transfers total 150 tokens.
A safer replacement flow is approve(protocol, 0), wait for confirmation, inspect the resulting allowance and balance, and only then submit approve(protocol, 50) if the new approval is still appropriate. If the spender uses the old allowance before the zeroing transaction confirms, Alice can see the changed balance and stop before granting the new 50.
Risks
- Setting the allowance to
0does not revoke spending that has already executed or prevent use of the old allowance before the zeroing transaction confirms. - Sending the zeroing and replacement approvals together, without waiting for the first confirmation, reintroduces ordering risk.
increaseAllowanceanddecreaseAllowanceare not part of the base ERC-20 standard; use them only when the verified token contract supports them.- An unlimited allowance can expose the owner’s full token balance while it remains active. Verify the chain, token contract, spender, and amount before signing.
- Some tokens have non-standard approval behavior. Read the wallet simulation and transaction calldata, and confirm the on-chain allowance after each step.
Common misconceptions
- “The latest approval transaction replaces the old one immediately.” It changes state only when executed on-chain.
- “Lowering an allowance caps total future spending at the new amount.” A spender may use the old allowance before the change executes.
- “Zero-first guarantees that no more tokens can leave.” The old allowance remains usable until the zeroing transaction confirms.
- “Every ERC-20 has
increaseAllowanceanddecreaseAllowance.” They are optional extensions, not ERC-20 requirements. - “Revoking the website connection revokes token approval.” Wallet connection state and the token contract’s on-chain allowance are separate.
Related topics
- How to distinguish between canonical and wrapped tokens
- Mempool
- Permit2 signature risk
- Reduce-only orders
- Wallet approval
Sources
- ERC-20: Token Standard - Ethereum Improvement Proposals (accessed: 2026-08-20)
- ERC20 | OpenZeppelin Docs - OpenZeppelin (accessed: 2026-08-20)