The ERC20Internals::_balanceOf function uses a low-level return inside an assembly block, which immediately exits the entire call frame. When called internally, this bypasses any subsequent Solidity code in the caller, potentially skipping important logic or checks. This behavior can break internal control flow, violate assumptions in higher-level ERC-20 functions, and reduce compatibility with contracts or tools expecting standard ERC-20 balanceOf semantics. Additionally, the function reverts for address(0), which is inconsistent with ERC-20 expectations of returning a zero balance.
Likelihood:
Occurs when _balanceOf is called internally from another function or contract, because the assembly return immediately exits the entire call frame.
Occurs during contract extensions or hooks that rely on _balanceOf for checks, calculations, or accounting before completing their logic.
Impact:
Internal control flow is bypassed, potentially skipping critical checks or updates in higher-level ERC-20 functions such as transferFrom, hooks, or custom extensions.
Compatibility with wallets, contracts, and tools that rely on standard ERC-20 balanceOf behavior is broken, leading to unexpected failures or incorrect accounting.
balanceOf function is expected to trigger the caller-specific logic inside ERC20Internals, but the implementation bypasses it completely, returning the raw balance without executing the intended checks. To validate this behaviour, a temporary hook was added in Token.sol:bool public afterBalanceOfRan;
function testHook() external returns (uint256) {
afterBalanceOfRan = false;
This hook allows us to detect whether control flow continues after _balanceOf.
It should execute the final line and set afterBalanceOfRan = true, but due to the assembly-level early return inside balanceOf, the function exits before reaching this line.
0 for address(0). This restores ERC-20 semantics and ensures internal callers continue execution.return inside assembly: compute and load the slot in assembly, store into a local uint256, and return via Solidity.The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.