// SPDX-License-Identifier: MIT pragma solidity 0.8.26; /** * Probe — the measurement, run from inside a real holder's address. * * HOW IT GETS THERE. `eth_call` takes a third parameter, a state override, and * one of the things it can override is an account's CODE. So this runtime is * installed at the address of an account that genuinely owns the token, for the * duration of one call that changes nothing, and `msg.sender` inside the * token's `transfer` is therefore the address that actually holds the units. * * That is the whole reason this works without a funded key, an approval, or a * fork. A probe deployed the ordinary way — through `eth_call` with no `to`, * which is how the property suite runs — lands at a fresh address that owns * nothing, and every token in the census would refuse it for lack of balance. * The finding would be "no token on this chain will let you move anything", * which is a statement about the probe. * * WHAT IT RETURNS, and why all five numbers rather than a verdict: * * shape how the call ENDED — true, silence, false, a half-word, a revert * sent how far the holder's own balance FELL * recv how far the recipient's balance ROSE * retLen the length of the return buffer, kept because 0 and 32 are the * difference between a pre-ABI token and a modern one * retWord the first word of it, so `false` is a fact and not a deduction * * `sent` and `recv` are read separately and are not assumed to be equal — they * are the two numbers the entire sweep is about. A fee-on-transfer token makes * them differ; a truncating token makes both differ from the request; a token * that reports success and moves nothing makes both zero. * * NOTHING HERE REVERTS ON A FINDING. A probe that throws when the token * misbehaves destroys the measurement it was sent to take: the caller learns * only that something went wrong, and every distinct failure arrives looking * the same. */ contract Probe { uint8 constant OK_TRUE = 0; /* returned a word, non-zero */ uint8 constant OK_EMPTY = 1; /* returned nothing at all — the pre-ABI shape */ uint8 constant OK_FALSE = 2; /* returned a word, zero — a refusal, reported as a value */ uint8 constant OK_SHORT = 3; /* returned something that is not a word */ uint8 constant REVERTED = 4; uint8 constant NO_CODE = 5; /* not a token: every call to it "succeeds" */ function run(address token, address to, uint256 amount) external returns (uint8 shape, uint256 sent, uint256 recv, uint256 retLen, bytes32 retWord, bytes memory ret) { /* An address with no code accepts every call and returns an empty buffer, which is byte-for-byte what a correct pre-ABI token returns. Checked first, because after the call the two are indistinguishable. */ if (token.code.length == 0) return (NO_CODE, 0, 0, 0, bytes32(0), ""); uint256 s0 = _bal(token, address(this)); uint256 r0 = _bal(token, to); bool ok; (ok, ret) = token.call( abi.encodeWithSelector(bytes4(0xa9059cbb), to, amount) /* transfer(address,uint256) */ ); retLen = ret.length; if (ret.length >= 32) { assembly ("memory-safe") { retWord := mload(add(ret, 32)) } } /* The balances are read again even after a revert. A reverted call cannot have moved anything, but reading it is what makes that a measurement rather than an assumption. */ uint256 s1 = _bal(token, address(this)); uint256 r1 = _bal(token, to); unchecked { sent = s0 > s1 ? s0 - s1 : 0; recv = r1 > r0 ? r1 - r0 : 0; } /* THE REFUSAL IS RETURNED WHOLE, and this is not a nicety. Seven tokens in the first run of this sweep refused the probe, and "seven refused" is not a finding — it is a prompt to ask whether the probe broke them. Overriding a holder's code makes that address a CONTRACT, and a token with an anti-bot check on `msg.sender.code.length` will refuse it for a reason that has nothing to do with the token being wrong. Only the token's own words separate the two, so they are carried back. */ if (!ok) return (REVERTED, sent, recv, retLen, retWord, ret); if (ret.length == 0) shape = OK_EMPTY; else if (ret.length < 32) shape = OK_SHORT; else shape = retWord == bytes32(0) ? OK_FALSE : OK_TRUE; } /** The holder's balance, as this token reports it. A token that cannot answer `balanceOf` at all reads as zero here, and the caller sees a request that moved nothing — which is the correct account of it. */ function _bal(address token, address who) private view returns (uint256 v) { (bool ok, bytes memory d) = token.staticcall( abi.encodeWithSelector(bytes4(0x70a08231), who) /* balanceOf(address) */ ); if (ok && d.length >= 32) { assembly ("memory-safe") { v := mload(add(d, 32)) } } } }