Final ERC standard. A simplified, callback-free alternative to ERC-1155 for managing many token IDs in one contract. Adopted by Uniswap v4 for pool-token claims and increasingly used wherever ERC-1155's receiver hooks and batch ops are unwanted overhead.
- 01Uniswap v4 hook accounting
- 02DEX / AMM internal balances
- 03high-frequency multi-token bookkeeping
- 04cases where ERC-1155 receiver callbacks are a footgun
- 05lightweight per-id allowance flows
- pnpm add solady
Implement ERC-6909 by extending `ERC6909` from Solady (`solady/src/tokens/ERC6909.sol`) — Solady is the canonical reference; OpenZeppelin does not yet ship one. The interface combines per-id allowances and operator approvals: `balanceOf(owner,id)`, `allowance(owner,spender,id)`, `isOperator(owner,spender)`, `transfer(receiver,id,amount)`, `transferFrom(sender,receiver,id,amount)`, `approve(spender,id,amount)`, `setOperator(spender,approved)`. Events: `Transfer`, `OperatorSet`, `Approval`. There are NO `onReceived` callbacks and NO batch functions — simpler, cheaper, and safer against reentrancy than ERC-1155. Pair with `supportsInterface` (ERC-165) and the ERC-6909 metadata extension if exposing `name`, `symbol`, `decimals`, `tokenURI` per id.
- ⚑No receiver callback means tokens CAN be sent to contracts that don't know how to handle them — add explicit receiver checks in your protocol layer if needed.
- ⚑Operator approval (`setOperator`) is per-(owner, operator) across ALL ids — there's no operator-per-id middle ground like ERC-1155's all-or-nothing-by-collection.
- ⚑No batch transfer in the spec — composing multiple transfers off-chain and submitting via multicall is the idiomatic replacement.
- ⚑Not all infrastructure indexes ERC-6909 yet (some explorers still treat it as 'unknown token'); confirm subgraph / Dune / Alchemy support before committing.
- ⚑Mixing ERC-6909 with ERC-1155 in the same contract is technically possible but creates ambiguous `supportsInterface` behavior — pick one.