solady-erc20-permit2-assumptionslisted
Install: claude install-skill iktok90-design/ai-smart-contract-auditor
# Solady ERC20 / permit / DN404 assumption detection
## When this applies
Trigger on any of:
- `import {ERC20} from "solady/tokens/ERC20.sol";` or `ERC2612`, `DN404`, `DN404Mirror`, `ERC4626` from solady
- Integrations calling `permit(...)` and assuming a fixed EIP-712 domain / version string
- Code relying on Solady's revert *reasons* (Solady reverts with custom errors / 4-byte selectors, not strings)
- DN404 tokens treated as plain ERC20 (the NFT mirror has separate transfer semantics)
- Off-chain indexers decoding events / revert data assuming OZ layout
- Overriding `name()`, `symbol()`, `_constantNameHash`, `_versionHash`, or `_domainNameAndVersion`
## Detection patterns
### Hardcoded permit domain separator (MEDIUM)
```solidity
bytes32 DOMAIN = keccak256(abi.encode(
TYPE_HASH, keccak256("MyToken"), keccak256("1"), block.chainid, token
));
// ← assumes version "1"; Solady ERC2612 default version is "1" but DN404/overrides may differ
```
Solady derives the domain via `_domainNameAndVersion()` (default version `"1"`). If the token overrides `_versionHash` or `name()`, a hand-rolled separator mismatches and every `permit` reverts `InvalidPermit`.
**Signal:** off-chain or on-chain code reconstructs the EIP-712 domain instead of reading `DOMAIN_SEPARATOR()` from the token.
### Relying on revert strings (MEDIUM)
```solidity
try token.transferFrom(a, b, amt) returns (bool) {}
catch Error(string memory reason) { // ← Solady reverts with custom errors,
if (