Skip to content

Why must some token approvals be reset to zero first?

Some ERC-20 tokens reject a direct change from one non-zero allowance to another. Learn when a zero-first approval is required, how the two confirmed transactions work, and what risks remain.

Updated

For educational purposes only; not investment advice. Investing may result in loss.

Direct answer

Some ERC-20 implementations reject approve(spender, newAmount) when the existing allowance and newAmount are both non-zero. For those tokens, first submit approve(spender, 0), wait for it to confirm, and only then submit the new non-zero approval.

This restriction is not required of every ERC-20 token. ERC-20 defines approve as replacing the current allowance and recommends zero-first behavior in client interfaces to mitigate an approval-change race, while also saying token contracts should not enforce it for compatibility. Some deployed tokens nevertheless do enforce it. Zero-first is therefore both a compatibility procedure and a useful checkpoint, not a guarantee that the old allowance cannot be spent before the zeroing transaction confirms.

Why must some token approvals be reset to zero first?
0 / 5
0 items reviewed; 5 items still unresolved

Completing this review does not prove an asset, transaction, or system is safe.

How it works

  1. Verify the chain, token contract, owner, spender and intended amount. Read allowance(owner, spender) from the token contract rather than relying only on a wallet label.
  2. If the allowance is already 0, submit the desired approval once. If it is non-zero, a direct non-zero replacement may succeed on a standard implementation or revert on a zero-first token.
  3. For a zero-first flow, submit approve(spender, 0) and wait for a successful receipt. Then read the same owner-spender allowance again and confirm it is 0.
  4. Recheck the token balance, spender and purpose. Only then submit approve(spender, newAmount) and wait for confirmation before treating the new allowance as active.
  5. Verify the final allowance and review any intervening Transfer and Approval events. A successful transaction receipt proves execution, while the current contract state shows the permission that remains.

OpenZeppelin’s SafeERC20.forceApprove implements a compatibility fallback for contracts: it tries the desired value, and if that call fails, it tries 0 followed by the desired value. This helper changes the calling contract’s own allowance; it does not automatically fix a user’s wallet approval or remove the need to verify transaction ordering and final state.

Example

An owner has an allowance of 1000 tokens for a spender and wants to reduce it to 100. On a zero-first token, a direct approve(spender, 100) reverts, so the on-chain allowance remains 1000; a reverted call does not partially update it.

The owner instead submits approve(spender, 0). Before that transaction confirms, the spender uses 400, leaving 600; the confirmed zeroing transaction then replaces the remainder with 0. After checking the lower token balance, the owner can decide whether to grant the new 100. If granted, the spender has already used 400 and can later use up to 100 more. Zero-first exposed the intervening spend before the new permission was granted, but it did not undo that spend.

Risks

  • The old allowance remains usable until the zeroing transaction executes. A spender may race a pending revocation or reduction.
  • Broadcasting the zeroing and replacement transactions without waiting for the first confirmation removes the intended checkpoint and can hide an intervening spend.
  • A wrong chain, token address or spender address can create or revoke a different permission from the one intended. Token symbols are not unique identifiers.
  • The two-step flow costs two transactions when both are needed, and either can fail, be replaced or remain pending. Do not infer state from a submitted signature alone.
  • Unlimited approvals and upgradeable or compromised spenders can expose future deposits. Use the smallest practical amount and verify the remaining allowance after use.
  • Contract integrations must handle non-standard return values and approval behavior deliberately. A compatibility wrapper cannot make an untrusted spender safe.

Common misconceptions

  • Every ERC-20 requires zero-first. The standard recommends the client-side sequence but says token contracts should not enforce it; only some implementations reject non-zero-to-non-zero changes.
  • Zero-first completely fixes the approval race. The spender can still use the old allowance before the zeroing transaction confirms.
  • A reverted replacement cleared the old allowance. A revert rolls back the attempted state change, so the prior allowance normally remains.
  • Two transactions sent together are equivalent to waiting. The safety checkpoint comes from confirming and inspecting the zero state before deciding on the replacement.
  • Disconnecting a website revokes its approval. Wallet connection state is separate from the token contract’s on-chain allowance.

Sources

Navigation

Search the wiki...