Introduction to Ethereum Contract Creation
Ethereum offers two primary methods for deploying smart contracts:
- Direct creation by Externally Owned Accounts (EOAs)
Creation via other smart contracts:
- Using
CREATEopcode (0xf0) - Using
CREATE2opcode (0xf5)
- Using
The choice between these methods impacts address predictability, upgradeability, and cross-chain security considerations.
EOA-Created Contracts: Address Calculation
When an EOA creates a contract, the address is deterministically calculated using:
address = keccak256(rlp_encode(sender_address, nonce))[12:]Key characteristics:
- The nonce represents the sender's transaction count
- Address changes if the same sender deploys multiple contracts
- Simple implementation but vulnerable to chain replays
Solidity Implementation Examples
Basic Implementation (Solidity 0.8+):
function addressFrom(address _origin, uint _nonce) public pure returns (address) {
bytes memory data;
if (_nonce == 0x00) data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80));
else if (_nonce <= 0x7f) data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, uint8(_nonce));
// Additional cases for larger nonce values...
return address(uint160(uint256(keccak256(data))));
}Gas-Optimized Assembly Version:
function addressFrom(address _origin, uint _nonce) external pure returns (address _address) {
bytes memory data;
if(_nonce == 0x00) data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80));
else if(_nonce <= 0x7f) data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, uint8(_nonce));
// Additional cases...
assembly {
mstore(0, keccak256(data, add(data, 0x20), mload(data)))
_address := mload(0)
}
}Contract-Created Contracts: CREATE vs CREATE2
CREATE (0xf0) Operation
- Uses sender-and-nonce-hash formula:
keccak256(sender, nonce) - Simple but creates chain-specific addresses
- Vulnerable to replay attacks across networks
CREATE2 (0xf5) Operation
Introduced in EIP-1014 with the formula:
address = keccak256(0xff ++ sender ++ salt ++ keccak256(init_code))[12:]Key advantages:
- Enables metamorphic contracts (redeploying different code to same address)
- Predictable addresses before deployment
- Better cross-chain security when using proper salt derivation
๐ Learn more about advanced contract deployment strategies
Security Considerations
Cross-chain protection: Derive new salts using:
bytes20 newSalt = bytes20(keccak256(abi.encodePacked(_initializerData, _salt)));- Address collisions: The 0xff prefix prevents CREATE/CREATE2 collisions
- Upgrade patterns: CREATE2 enables interesting upgrade architectures
Practical Examples
CREATE2 Deployment Code Example
function deployWithCREATE2(
bytes memory bytecode,
bytes32 salt
) public returns (address) {
address addr;
assembly {
addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
if iszero(extcodesize(addr)) {
revert(0, 0)
}
}
return addr;
}FAQ Section
Q: Why would I use CREATE2 instead of CREATE?
A: CREATE2 provides address predictability, enables advanced upgrade patterns, and offers better cross-chain deployment safety when proper salt derivation is used.
Q: How does the 0xff prefix prevent address collisions?
A: The 0xff byte makes RLP-encoded CREATE addresses impossibly large (petabyte-scale) if they were to collide with CREATE2 addresses, effectively preventing practical collisions.
Q: Can I redeploy different code to the same CREATE2 address?
A: Yes, through metamorphic contract patterns, but only if you control the original deployment and use the same salt/bytecode hash combination.
๐ Explore real-world CREATE2 applications
Conclusion
Understanding Ethereum contract address calculation is crucial for:
- Building upgradeable systems
- Implementing secure cross-chain deployments
- Developing advanced smart contract patterns
The choice between CREATE and CREATE2 depends on your specific requirements for address predictability, upgradeability, and security considerations.