Account Addresses
Learn the foundational concepts of the CREATE2 opcode and how smart contract wallets generate counterfactual addresses.
A contract account can be programmed to support many different use cases for your users. In order for those use cases to be live, the code
that implements it must be deployed to the EVM under its own address.
Want an example?
If you're after more concrete examples, check out github.com/stackup-wallet/erc-4337-examples.
Smart contract code
code
Every smart contract address has a code
attached to it that implements the logic. Anyone can retrieve this code by calling the eth_getCode
RPC method. On a tool like ethers.js this can be as simple as calling:
const code = await provider.getCode(address);
An ERC-4337 smart contract account is no different. Before the account can do common things, like validate a signature, its code
must be deployed otherwise the EVM will not know how to handle the request. A quick way to check if a smart contract account is deployed is to verify if the code
field is null or not:
const code = await provider.getCode(accountAddress);
const isDeployed = code !== "0x";
Deterministic addresses
With EOAs, the address is consistent across all EVM networks. As long as a user has access to the private key they can access the same address on any network. Ideally we would also like to create the same user experience with contract accounts too.
A user should be able to deterministically know their account address and keep it consistent on every EVM network irrespective of whether the code
has been deployed or not. This means they can generate an account and start sending funds to it with full assurance that they'll be able to control those funds at any time given they have the correct verification method.
ERC-4337 does this by using the CREATE2
opcode through a Singleton Factory. Let's break this down to understand what that means in practice.
Generating an address
Below is an example of how you can calculate a CREATE2
address with ethers.js:
const accountAddress = ethers.utils.getCreate2Address(
fromAddress,
salt,
initCodeHash
);
A contract address would be determined by a fromAddress
, salt
, and initCodeHash
.
fromAddress
fromAddress
The fromAddress
is the address of the Singleton Factory. This factory receives the salt
and initCode
as input and uses CREATE2
to deploy the contract on-chain.
Because the factory address is the same on every chain, we can rely on it to also deploy our smart contract code
on all networks under the same address too.
salt
salt
For an ERC-4337 account, the salt
parameter is the first nonce
value. This is 0
.
initCodeHash
initCodeHash
The initCode
, which is also a field on the UserOperation
, is the smart contract code and arguments used for initializing it. It is hashed using keccak256
to derive the initCodeHash
.
Updated about 1 month ago