Proxy contract designed for EIP-7702 accounts.
These contracts are unaudited and simple prototypes. Use at your own risk.
- Protect initializers with chain-agnostic EOA signatures
- Use existing Smart Account contracts without changes
- Unify contract implementation upgrades using ERC-1967 storage slots
- Deploy an instance of
EIP7702Proxy
pointing to a specific smart account implementation. - Sign an EIP-7702 authorization with the EOA
- Sign an initialization hash with the EOA
- Submit transaction with EIP-7702 authorization and call to
account.initialize(bytes args, bytes signature)
bytes args
: arguments to the smart account implementation's actual initializer functionbytes signature
: ECDSA signature over the initialization hash from the EOA
Now the EOA has been upgraded to the smart account implementation and had its state initialized.
If the smart account implementation supports UUPS upgradeability, it will work as designed by submitting upgrade calls to the account.
EIP7702Proxy
is constructed with aninitalImplementation
that it will delegate all calls to by defaultEIP7702Proxy
is constructed with aguardedInitializer
, the initializer selector of theinitialImplementation
- Calls to the account on
guardedInitializer
revert and do not delegate the call to the smart account implementation EIP7702Proxy
defines a new, static selector compatible with all initializers:initialize(bytes args, bytes signature)
- Calls to the account on
initialize
have their signature validated via ECDSA and the proxy delegates a call combining theguardedInitializer
and providedargs
to theinitialImplementation
- The
initialImplementation
is responsible for handling replay protection, which is standard practice among smart accounts - All other function selectors are undisturbed and this proxy functions akin to a simple ERC-1967 proxy
This repository contains scripts that can be used to perform an EIP-7702 upgrade to a EIP7702Proxy
with a CoinbaseSmartWallet
implementation and initialize the smart account. The Odyssey testnet by Ithaca has EIP-7702 enabled. If testing locally, you can use the Anvil testnet with Odyssey enabled.
The upgrade process happens in two steps:
-
UpgradeEOA.s.sol: Deploys the implementation and proxy template, then performs the EIP-7702 upgrade
- Outputs the proxy template address which is needed for the initialization step
- For Odyssey: Save this address to use in the next step
-
Initialize.s.sol: Initializes the smart account with a new owner and tests the upgrade
- For Odyssey: Requires the proxy template address from step 1
ℹ️ See the scripts themselves for additional comments and documentation.
- Foundry installed
- If you're using the Odyssey testnet, you'll need three private keys funded with some Odyssey ETH (see
.env.example
):EOA_PRIVATE_KEY
: The private key of the EOA to be upgradedDEPLOYER_PRIVATE_KEY
: The private key of the EOA that will perform the upgradeNEW_OWNER_PRIVATE_KEY
: The private key of another EOA that will be added as an ownerPROXY_TEMPLATE_ADDRESS_ODYSSEY
: Address of the proxy template (from UpgradeEOA.s.sol output)
Odyssey Chain Info: https://hub.conduit.xyz/odyssey
- Start a local Anvil node with Odyssey enabled:
anvil --odyssey
- Run the UpgradeEOA script to upgrade your EOA:
forge script script/UpgradeEOA.s.sol --rpc-url http://localhost:8545 --broadcast --ffi
- Run the Initialize script to set up ownership:
forge script script/Initialize.s.sol --rpc-url http://localhost:8545 --broadcast
-
Set up environment variables (see
.env.example
) -
Run the UpgradeEOA script with Odyssey RPC:
forge script script/UpgradeEOA.s.sol --rpc-url https://odyssey.ithaca.xyz --broadcast --ffi
# Note the proxy template address from the output
export PROXY_TEMPLATE_ADDRESS_ODYSSEY=<address from output>
- Run the Initialize script:
forge script script/Initialize.s.sol --rpc-url https://odyssey.ithaca.xyz --broadcast
Below are the commands to verify the implementation contract and proxy template. While we can verify the implementation contract and proxy template, we've been unable to verify the upgraded EOA address directly. We suspect it might be related to EIP-7702's deployment mechanism being different from traditional contract deployments, but this needs to be confirmed with the Blockscout and/or Ithaca teams.
In the meantime, you can check correctness by:
- Comparing your EOA's code with the verified proxy template
- Checking that the proxy delegates to the verified implementation
- Using the provided scripts to test interactions
forge verify-contract \
--verifier blockscout \
--verifier-url "https://odyssey-explorer.ithaca.xyz/api" \
--watch \
--compiler-version "v0.8.23" \
--num-of-optimizations 200 \
<IMPLEMENTATION_ADDRESS> \
lib/smart-wallet/src/CoinbaseSmartWallet.sol:CoinbaseSmartWallet
forge verify-contract \
--verifier blockscout \
--verifier-url "https://odyssey-explorer.ithaca.xyz/api" \
--watch \
--compiler-version "v0.8.23" \
--num-of-optimizations 200 \
<PROXY_TEMPLATE_ADDRESS> \
src/EIP7702Proxy.sol:EIP7702Proxy