04 · No blacklist
No per-address switch decides whether a transfer reverts.
The question
Can one address be stopped from selling while everyone else can?
Blacklists are sold as anti-bot tools. They are also how a deployer picks who gets to exit. A whitelist that gates transfers during a "launch phase" is the same mechanism from the other side, and the check treats it the same way.
How it decides
A candidate is a state variable of type mapping(address => bool), whatever its name.
A guard read is a read of that mapping in a position that decides a revert: inside the argument of require(...), or inside the condition of an if whose body reverts (a revert statement, a call to revert or require). A read that only picks a branch, like isExcludedFromFee[from] ? 0 : fee, is not a guard.
The transfer path is every function reachable from transfer and transferFrom.
The check fails if a candidate has a guard read somewhere in the transfer path and an assignment to it in any function reachable from an entry point, constructor excluded.
- Found: fail.
blacklisted decides whether _transfer reverts, and setBlacklist can change it. - Otherwise: pass.
No per-address switch in the transfer path.
What passes
mapping(address => bool) public isExcludedFromFee;
function _transfer(address f, address t, uint256 v) internal {
uint256 fee = isExcludedFromFee[f] ? 0 : v * taxBps / 10000;
...
}
The mapping picks a fee, not a revert. Settable, and fine.
A blacklist set only in the constructor, with no setter, also passes: nobody can add to it.
What fails
mapping(address => bool) public bots;
function setBot(address a, bool v) external onlyOwner { bots[a] = v; }
function _transfer(...) internal { require(!bots[from] && !bots[to], "bot"); ... }
Whatever it is called: bots, blocked, isSniper, allowed. The name never enters the decision; the shape does.
Known edges
A guard expressed through a helper (require(canTransfer(from)) where canTransfer reads the mapping) is followed, because the helper is in the transfer path. A guard that reads the mapping through a view function on another contract is not seen; it would show as an external call in the review.