contracts: revive SuperchainTokenBridge + add SuperchainERC20Factory (wrap/unwrap) - #22087
Draft
opsuperchain wants to merge 2 commits into
Draft
contracts: revive SuperchainTokenBridge + add SuperchainERC20Factory (wrap/unwrap)#22087opsuperchain wants to merge 2 commits into
opsuperchain wants to merge 2 commits into
Conversation
Restores the SuperchainTokenBridge predeploy (0x4200...0028), the abstract SuperchainERC20, and the IERC7802 interface that were removed in ethereum-optimism#19999 / ethereum-optimism#20141, byte-for-byte where possible (the bridge's semver-lock initCodeHash matches the pre-deletion value). Adaptations to the current tree: - Registered in the Predeploys.getAllRecords() registry and the L2ContractsManager deploy/upgrade flow (interop-gated, like SuperchainETHBridge and ETHLiquidity), which replaced the old per-setter genesis wiring after the deletion. - SuperchainERC20 imports the vendored solady (v0.0.158); the versioned @solady-v0.0.245 remapping no longer exists. IERC20Solady is restored without the Permit2 error that solady v0.0.158 predates. - L2ContractsManager semver bumped to 1.14.0. The legacy OptimismSuperchainERC20 lane (beacon, factory, L2StandardBridgeInterop) is intentionally not revived. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds a factory that wraps any existing ERC20 into a SuperchainERC20 so it can move across the Superchain through the SuperchainTokenBridge. New interop-gated predeploy at 0x4200...0026 (the slot freed by the old OptimismSuperchainERC20Factory). - deploy(chainId, token, name, symbol, decimals) CREATE2-deploys a SuperchainWrappedERC20 with salt = keccak256(chainId, token). The wrapped token's constructor takes no arguments and reads its parameters back from the factory, so the initcode is constant and the wrapped token address is identical on every chain, derived purely from the [chain_id, address] identity of the original token. - On the original token's chain, metadata is read from the token itself (with a fallback to caller-supplied values for tokens without the metadata extension); on remote chains the deployer supplies it, or uses propagation: - propagate(token, toChainId) sends the canonical wrapped metadata from the token's home chain to the factory on another chain via the L2ToL2CrossDomainMessenger (the factory is the same predeploy address on every chain). relayDeploy requires the messenger, the factory itself as cross-domain sender, and message source chain == the token's claimed home chain, so remote chains receive authentic metadata without trusting any caller. - wrap(token, amount) escrows original tokens in the factory and mints wrapped tokens 1:1 against the actually-received amount (so fee-on-transfer tokens cannot inflate supply beyond backing); unwrap(token, amount) burns and releases escrow. Both are only possible on the token's home chain; everywhere else supply moves exclusively through the SuperchainTokenBridge, so home-chain escrow always equals global wrapped supply. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
opsuperchain
force-pushed
the
feat/superchain-erc20-factory
branch
from
July 28, 2026 22:05
4532d34 to
24cc925
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR revives the
SuperchainTokenBridgeand adds a newSuperchainERC20Factorythat lets any existing ERC20 be wrapped into aSuperchainERC20and moved across the Superchain.Commit 1: revive the SuperchainTokenBridge
SuperchainTokenBridge,SuperchainERC20, andIERC7802were removed in #19999 (and #20141) as unused interop contracts. This commit restores them from history at their original semvers and predeploy slot (0x4200...0028), adapted to the predeploy machinery that has landed since (Predeploys.getAllRecords()registry,L2ContractsManagerdeploy/upgrade flow, gate assertions inL2Genesis). The bridge is gated behind interop exactly likeSuperchainETHBridge/ETHLiquidity. The legacyOptimismSuperchainERC20lane (beacon, factory,L2StandardBridgeInterop) is intentionally not revived; the new factory below replaces it.Commit 2: SuperchainERC20Factory
A minimal wrap/unwrap factory, added as an interop-gated predeploy at
0x4200...0026(the slot freed by the oldOptimismSuperchainERC20Factory):deploy(chainId, token, name, symbol, decimals)deploys aSuperchainWrappedERC20via CREATE2 withsalt = keccak256(chainId, token). The wrapped token's constructor takes no arguments (metadata is read back from the factory during construction), so its initcode is constant and the wrapped token address is identical on every chain, derived purely from the[chain_id, address]identity of the original token.propagate(token, toChainId)sends the canonical wrapped metadata from the token's home chain to the factory on another chain via theL2ToL2CrossDomainMessenger(the factory is the same predeploy address everywhere, mirroringSuperchainTokenBridge.sendERC20/relayERC20).relayDeployon the destination requires the messenger, the factory itself as cross-domain sender, and message source chain == the token's claimed home chain, so remote chains get authentic metadata without trusting any caller.wrap(token, amount)escrows original tokens in the factory and mints the wrapped token 1:1 (mints the actually-received amount, so fee-on-transfer tokens can't inflate supply beyond backing). Only possible on the token's home chain.unwrap(token, amount)burns wrapped tokens and releases escrow.SuperchainERC20:crosschainMint/crosschainBurnare gated to theSuperchainTokenBridge, so once deployed on two chains,sendERC20/relayERC20move it between them. Escrow on the home chain always equals global wrapped supply.Notes for reviewers
@solady-v0.0.245remapping no longer exists; the vendored solady is v0.0.158) and registration in the new predeploy registry.L2ContractsManagersemver bumped 1.13.0 → 1.14.0.Tests
SuperchainTokenBridgeandSuperchainERC20unit tests.🤖 Generated with Claude Code