function _balanceOf(address owner) internal view returns (uint256) {
assembly {
@> if iszero(owner) {
@> revert(0, 0)
@> }
}
}
function _allowance(address owner, address spender) internal view returns (uint256 remaining) {
assembly {
@> if or(iszero(owner), iszero(spender)) {
@> revert(0, 0)
@> }
}
}
pragma solidity ^0.8.24;
import {ERC20} from "./ERC20.sol";
contract VulnerableIntegration is ERC20 {
constructor() ERC20("Test", "TST") {
_mint(msg.sender, 1000e18);
}
function batchCheckBalances(address[] calldata users) external view returns (uint256 total) {
for (uint256 i = 0; i < users.length; i++) {
total += this.balanceOf(users[i]);
}
}
function testZeroAddressDoS() external view {
address[] memory users = new address[](3);
users[0] = address(0x1);
users[1] = address(0);
users[2] = address(0x2);
this.batchCheckBalances(users);
}
}
function _balanceOf(address owner) internal view returns (uint256) {
assembly {
- if iszero(owner) {
- revert(0, 0)
- }
+ if iszero(owner) {
+ 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)
}
}
function _allowance(address owner, address spender) internal view returns (uint256 remaining) {
assembly {
- if or(iszero(owner), iszero(spender)) {
- revert(0, 0)
- }
+ if or(iszero(owner), 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)
}
}