Background
Morph lets users pay gas in ERC20 fee tokens. During EVM execution we rely on the token contract's transfer and/or read user balances directly from a registered storage slot (balanceSlot in L2TokenRegistry). Both depend on assumptions about the token captured at registration time (storage layout, behavior).
Fee tokens are not controlled by Morph. If a registered token is an upgradeable proxy, the project can upgrade the implementation after registration — changing the storage layout (the registered balanceSlot then points to the wrong slot → wrong balance reads → fee-accounting corruption) or its behavior. Registration is onlyOwner, but that only vets the token at the moment of registration; there is no constraint or detection afterward.
Goal
- Record an implementation fingerprint per fee token at registration.
- Detect when a token's implementation changes.
- On detected change, auto-deactivate the token (
TokenInfo.isActive = false) — fail closed, stop using it for gas payment.
- Re-activation requires a manual re-audit (owner action after review).
Open design points (for tech design)
- Fingerprint choice is non-trivial:
extcodehash(tokenAddress) does not catch proxy upgrades (the proxy's own bytecode is unchanged; only the implementation slot changes). Catching upgrades requires resolving the implementation (e.g. EIP-1967 impl slot → extcodehash(impl)), which is proxy-pattern-specific and not generically resolvable (UUPS / transparent / beacon / diamond / custom slots, and can be deliberately hidden). Must define the policy for tokens whose implementation can't be reliably resolved (reject at registration vs accept with monitoring).
- Detection timing / location: on-chain at use-time vs off-chain monitor triggering deactivation; on-chain check cost.
balanceSlot reliance: consider restricting direct slot reads to non-upgradeable / fingerprint-pinned tokens, with standard transfer/balanceOf as fallback.
- Existing mechanism to reuse:
TokenInfo.isActive, batchUpdateTokenStatus, isTokenActive.
Non-goals
- Preventing project teams from upgrading their own token contracts (outside Morph's control).
Background
Morph lets users pay gas in ERC20 fee tokens. During EVM execution we rely on the token contract's
transferand/or read user balances directly from a registered storage slot (balanceSlotinL2TokenRegistry). Both depend on assumptions about the token captured at registration time (storage layout, behavior).Fee tokens are not controlled by Morph. If a registered token is an upgradeable proxy, the project can upgrade the implementation after registration — changing the storage layout (the registered
balanceSlotthen points to the wrong slot → wrong balance reads → fee-accounting corruption) or its behavior. Registration isonlyOwner, but that only vets the token at the moment of registration; there is no constraint or detection afterward.Goal
TokenInfo.isActive = false) — fail closed, stop using it for gas payment.Open design points (for tech design)
extcodehash(tokenAddress)does not catch proxy upgrades (the proxy's own bytecode is unchanged; only the implementation slot changes). Catching upgrades requires resolving the implementation (e.g. EIP-1967 impl slot →extcodehash(impl)), which is proxy-pattern-specific and not generically resolvable (UUPS / transparent / beacon / diamond / custom slots, and can be deliberately hidden). Must define the policy for tokens whose implementation can't be reliably resolved (reject at registration vs accept with monitoring).balanceSlotreliance: consider restricting direct slot reads to non-upgradeable / fingerprint-pinned tokens, with standardtransfer/balanceOfas fallback.TokenInfo.isActive,batchUpdateTokenStatus,isTokenActive.Non-goals