Allowance

An ERC20 mechanism that permits a third party to spend tokens on behalf of the token owner, up to a specified limit.

An allowance is a core mechanism in the ERC20 token standard that enables one address to authorize another address to spend tokens on their behalf. This delegation pattern is fundamental to DeFi, enabling smart contracts to move user tokens for swaps, lending deposits, and other operations. However, the traditional allowance mechanism has known security vulnerabilities, particularly race conditions that enable front-running attacks.

How Allowances Work

The allowance system consists of three main functions in the ERC20 standard:

approve: Sets the amount a spender can transfer on behalf of the owner.

1function approve(address spender, uint256 amount) external returns (bool);

allowance: Queries the current allowance for a spender.

1function allowance(address owner, address spender) external view returns (uint256);

transferFrom: Transfers tokens from one address to another, using the caller's allowance.

1function transferFrom(address from, address to, uint256 amount) external returns (bool);

When Alice wants to use a DEX, she first approves the DEX contract to spend her tokens. The DEX can then call transferFrom to move tokens from Alice's wallet during a swap.

The Allowance Security Problem

The standard approve function has a well-documented vulnerability. When changing an existing allowance, a race condition allows the spender to exploit both the old and new allowance values.

If Alice has approved Bob for 100 tokens and wants to reduce it to 50, Bob can:

  1. Watch the mempool for Alice's approval transaction
  2. Front-run with a transferFrom for 100 tokens
  3. After Alice's transaction confirms, transfer another 50 tokens

Bob extracts 150 tokens when Alice intended to limit him to 50. This vulnerability exists in every standard ERC20 token.

Safe Allowance Patterns

Several patterns mitigate allowance vulnerabilities:

Increase/Decrease Allowance: Adjust allowances incrementally rather than setting absolute values.

1function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
2 _approve(msg.sender, spender, allowance(msg.sender, spender) + addedValue);
3 return true;
4}
5
6function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
7 uint256 currentAllowance = allowance(msg.sender, spender);
8 require(currentAllowance >= subtractedValue);
9 _approve(msg.sender, spender, currentAllowance - subtractedValue);
10 return true;
11}

Approve to zero first: Always set allowance to zero before setting a new value. This requires two transactions but eliminates the race.

Minimum necessary approvals: Approve only the exact amount needed for each operation rather than unlimited approvals.

Permit: The Modern Alternative

EIP-2612 introduces the permit function, allowing approval via cryptographic signature rather than on-chain transaction:

1function permit(
2 address owner,
3 address spender,
4 uint256 value,
5 uint256 deadline,
6 uint8 v, bytes32 r, bytes32 s
7) external;

Benefits of permit:

  • No approval transaction needed: Users sign a message off-chain; the signature accompanies the actual operation.
  • Atomic operations: Approval and transfer happen in the same transaction, eliminating the race window.
  • Gas savings: Users don't pay gas for a separate approval transaction.
  • Deadline protection: Signatures expire, limiting their exploitation window.

Many modern DeFi protocols support permit, though not all tokens implement it.

Unlimited Approvals

For convenience, many DeFi interfaces request unlimited approvals (type(uint256).max). This creates ongoing risk:

Convenience: Users only approve once per token per protocol. Risk: If the protocol is compromised, all approved tokens can be stolen.

Best practices:

  • Approve only what you need for each operation
  • Revoke unused approvals periodically
  • Use approval management tools to monitor outstanding approvals

Allowance in Protocol Security

When auditing protocols that handle user tokens:

Check transferFrom usage: Ensure the protocol correctly handles tokens transferred via transferFrom, accounting for fees and rebasing.

Review approval requests: Protocols shouldn't request more approval than necessary for their operations.

Consider permit support: Modern protocols should support permit-style approvals when possible.

Handle approval failures: Some tokens return false instead of reverting on approval failure. Use SafeERC20 patterns.

User Protection

Users can protect themselves from allowance-related risks:

  1. Review approval amounts before signing transactions
  2. Use hardware wallets that display approval details
  3. Revoke unnecessary approvals via tools like revoke.cash
  4. Prefer permit when available to avoid separate approval transactions
  5. Set reasonable slippage to make front-running unprofitable

Understanding the allowance mechanism and its vulnerabilities is essential for both DeFi users and developers. While the basic mechanism is simple, its security implications require careful consideration in protocol design and user behavior.

Need expert guidance on Allowance?

Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.

Get a Quote

oog
zealynx

Subscribe to Our Newsletter

Stay updated with our latest security insights and blog posts

© 2024 Zealynx