Token-0x

First Flight #54
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: low
Likelihood: medium

View Functions Revert on Zero Address

Author Revealed upon completion

Root + Impact

Description

  • The _balanceOf() and _allowance() functions revert when queried with zero address instead of returning 0.

  • Standard ERC20 implementations return 0 for these edge cases.

function _balanceOf(address owner) internal view returns (uint256) {
assembly {
// @> Reverts instead of returning 0
if iszero(owner) {
revert(0, 0)
}
// ...
}
}
function _allowance(address owner, address spender) internal view returns (uint256) {
assembly {
// @> Reverts instead of returning 0
if or(iszero(owner), iszero(spender)) {
revert(0, 0)
}
// ...
}
}

Risk

Likelihood:

  • Protocols querying balanceOf(address(0)) for burn tracking will fail

  • Some integrations check zero address allowances

Impact:

  • Breaks compatibility with protocols expecting standard behavior

  • View functions should not revert on valid (if unusual) inputs

  • No direct fund loss, but integration failures possible

Proof of Concept

These tests confirm that querying balance or allowance with zero address causes a revert rather than returning 0. Some protocols use balanceOf(address(0)) to track burned tokens (tokens sent to the zero address). This non-standard behavior breaks such integrations.

Place these tests in test/ViewFunctionsRevertPOC.t.sol and run with forge test --match-contract ViewFunctionsRevertPOC -vv:

function test_BalanceOfZeroAddressReverts() public {
vm.expectRevert();
token.balanceOf(address(0));
// Reverts instead of returning 0
}
function test_AllowanceZeroAddressReverts() public {
vm.expectRevert();
token.allowance(address(0), alice);
// Reverts instead of returning 0
}

Recommended Mitigation

Instead of reverting when the zero address is passed, return 0. This matches OpenZeppelin's behavior and maintains compatibility with protocols that may query these edge cases. The zero address cannot hold tokens or have allowances, so returning 0 is semantically correct.

function _balanceOf(address owner) internal view returns (uint256) {
assembly {
- if iszero(owner) {
- revert(0, 0)
- }
+ // Return 0 for zero address instead of reverting
+ if iszero(owner) {
+ mstore(0x00, 0)
+ return(0x00, 0x20)
+ }
// ...
}
}

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!