Token-0x

First Flight #54
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: low
Valid

`balanceOf`/`allowance` Revert on Zero Address

Description

  • OpenZeppelin's balanceOf(address(0)) returns 0, and allowance(address(0), x) or allowance(x, address(0)) returns 0.

  • Token-0x reverts on these calls, which may break integrations that query zero address balances for various reasons.

function _balanceOf(address owner) internal view returns (uint256) {
assembly {
// @> Reverts on zero address
if iszero(owner) {
revert(0, 0)
}
// ...
}
}
function _allowance(address owner, address spender) internal view returns (uint256 remaining) {
assembly {
// @> Reverts if either is zero
if or(iszero(owner), iszero(spender)) {
revert(0, 0)
}
// ...
}
}

Risk

Likelihood:

  • Uncommon but some protocols may query zero address

  • Some token tracking tools check balanceOf(address(0)) for burned tokens

Impact:

  • Behavioral difference from standard implementations

  • May cause unexpected reverts in edge cases

Proof of Concept

function test_zero_address_revert() public {
// Token-0x reverts
vm.expectRevert();
token.balanceOf(address(0));
// OpenZeppelin returns 0
assertEq(token2.balanceOf(address(0)), 0);
}

Recommended Mitigation

function _balanceOf(address owner) internal view returns (uint256) {
assembly {
+ // Return 0 for zero address instead of reverting
if iszero(owner) {
- revert(0, 0)
+ mstore(0x00, 0)
+ return(0x00, 0x20)
}
let baseSlot := _balances.slot
let ptr := mload(0x40)
mstore(ptr, owner)
mstore(add(ptr, 0x20), baseSlot)
let dataSlot := keccak256(ptr, 0x40)
let amount := sload(dataSlot)
mstore(ptr, amount)
mstore(add(ptr, 0x20), 0)
return(ptr, 0x20)
}
}

Similar change for _allowance:

function _allowance(address owner, address spender) internal view returns (uint256 remaining) {
assembly {
+ // Return 0 for zero addresses instead of reverting
- if or(iszero(owner), iszero(spender)) {
- revert(0, 0)
- }
+ if iszero(owner) {
+ mstore(0x00, 0)
+ return(0x00, 0x20)
+ }
+
+ if iszero(spender) {
+ mstore(0x00, 0)
+ return(0x00, 0x20)
+ }
let ptr := mload(0x40)
let baseSlot := _allowances.slot
mstore(ptr, owner)
mstore(add(ptr, 0x20), baseSlot)
let initialHash := keccak256(ptr, 0x40)
mstore(ptr, spender)
mstore(add(ptr, 0x20), initialHash)
let allowanceSlot := keccak256(ptr, 0x40)
remaining := sload(allowanceSlot)
}
}
Updates

Lead Judging Commences

gaurangbrdv Lead Judge 18 days ago
Submission Judgement Published
Validated
Assigned finding tags:

accounting

accounting related issue in token-0x

Support

FAQs

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

Give us feedback!