Ethereum’s CREATE2 opcode, introduced in February 2019 via EIP-1014, revolutionized how smart contracts can be deployed by enabling predictable contract addresses before deployment. Unlike the traditional CREATE opcode, CREATE2 allows developers to compute a contract’s future address off-chain, opening doors to advanced use cases like state channels, wallet recovery, and gas-efficient contract factories.
This guide explores how CREATE2 works, compares it with CREATE, and demonstrates its practical application through a real-world challenge from Capture the Ether.
Understanding CREATE vs. CREATE2
How CREATE Works
By default, Ethereum uses the CREATE opcode to deploy contracts. The resulting contract address is determined by:
- Deployer’s address
- Deployer’s nonce (transaction count)
The formula:
keccak256(rlp.encode(deployerAddress, nonce))[12:]This means the address changes every time a new contract is deployed from the same account—because the nonce increments. As a result, you cannot predict the next contract address without knowing the exact transaction sequence.
👉 Discover how blockchain developers use predictable addresses for secure dApp design.
How CREATE2 Enhances Control
CREATE2 introduces a more flexible and deterministic method. Instead of relying on the nonce, it calculates the contract address using:
- Deployer’s address
- Hash of the contract bytecode (
keccak256(bytecode)) - A user-defined 32-byte salt value
The formula:
keccak256(0xff ++ deployerAddress ++ salt ++ keccak256(bytecode))[12:]The 0xff prefix ensures separation between addresses generated by CREATE and CREATE2. Because all inputs are known in advance, you can calculate the contract address before deployment, even years ahead.
This capability unlocks powerful patterns such as:
- Pre-registering interactions with future contracts
- Building trustless escrow or proxy systems
- Deploying identical logic at deterministic addresses across chains
Practical Use Case: Solving Capture the Ether’s Fuzzy Identity Challenge
Let’s apply CREATE2 to solve the Fuzzy Identity challenge. The goal? Deploy a contract that meets two conditions:
- Has a
name()function returningbytes32("smarx") - Is deployed at an address containing the hex string
badc0de
While brute-forcing private keys with CREATE is theoretically possible, it's inefficient. With CREATE2, we can iterate over salt values instead—dramatically reducing computational overhead.
Step 1: Get the Contract Bytecode
We start by writing the target contract:
pragma solidity ^0.5.12;
contract BadCodeSmarx {
function name() external pure returns (bytes32) {
return bytes32("smarx");
}
}Compile this using Truffle or Remix to obtain the bytecode:
0x608060405234801561001057600080fd...Store this hex string in your deployment script. This bytecode hash will remain constant throughout our calculations.
Step 2: Build the CREATE2 Deployer Contract
Next, create a factory-like contract that uses CREATE2 to deploy instances of BadCodeSmarx. In modern Solidity (v0.8+), you can use high-level syntax:
function deploy(bytes32 _salt) public returns (address) {
BadCodeSmarx instance = new BadCodeSmarx{salt: _salt}();
return address(instance);
}Alternatively, use inline assembly for full control:
assembly {
addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
}Here:
- First parameter:
0wei sent - Second and third: memory pointer and length of bytecode
- Fourth: user-provided salt
Deploy this deployer contract to the Ropsten testnet (or any network). For this example, assume its address is: 0xca4dfd86a86c48c5d9c228bedbeb7f218a29c94b
Now we have everything needed to compute potential addresses off-chain.
Step 3: Brute-Force the Salt Off-Chain
We need a salt that makes the final address contain badc0de. Write a Node.js script using ethereumjs-util:
const eth = require('ethereumjs-util');
const deployingAddress = 'ca4dfd86a86c48c5d9c228bedbeb7f218a29c94b';
const bytecodeHash = '4670da3f633e838c2746ca61c370ba3dbd257b86b28b78449f4185480e2aba51';
const prefix = 'ff' + deployingAddress;
for (let i = 0; i < Number.MAX_SAFE_INTEGER; i++) {
const salt = i.toString(16).padStart(64, '0');
const payload = prefix + salt + bytecodeHash;
const hash = eth.bufferToHex(eth.keccak256(Buffer.from(payload, 'hex')));
const address = '0x' + hash.slice(-40);
if (address.includes('badc0de')) {
console.log('Found salt:', '0x' + salt);
console.log('Deployed address:', address);
break;
}
}After about 30 seconds, it outputs:
Found salt: 0x000000000000000000000000000000000000000000000000000000005b2bfe
Deployed address: 0xa905a3922a4ebfbc7d257cecdb1df04a3badc0deExecute deploy(0x...5b2bfe) on-chain—and your contract lands exactly where intended.
👉 Learn how developers leverage deterministic deployments for cross-chain interoperability.
FAQ
What is the main advantage of CREATE2 over CREATE?
CREATE2 enables predictable contract addresses independent of transaction order or nonce. This allows pre-deployment planning and interaction with future contracts.
Can I use CREATE2 without writing assembly code?
Yes. Starting in Solidity 0.8, you can use {salt: ...} syntax directly: new Contract{salt: _salt}();
Does CREATE2 cost more gas than CREATE?
Slightly. The CREATE2 opcode has a higher base gas cost due to additional hashing operations, but this is usually negligible compared to overall deployment costs.
Is brute-forcing salts secure?
Yes—for finding specific substrings like badc0de, iterating salts is safe and common in challenges. However, never expose sensitive logic based on predictable salts in production.
Can I reuse the same salt for multiple deployments?
No. Using the same salt and deployer will result in only one successful deployment; subsequent attempts revert because the address is already occupied.
Where is CREATE2 commonly used in real-world applications?
Popular use cases include:
- Counterfactual wallet deployments (e.g., Argent)
- Universal login systems
- Gas-optimized contract factories
- Layer 2 state channel participants
Core Keywords
- Ethereum CREATE2 opcode
- Predictable contract address
- Smart contract deployment
- Deterministic address generation
- CREATE vs CREATE2
- Off-chain address calculation
- Solidity salt parameter
- Capture the Ether challenge
By mastering CREATE2, developers gain fine-grained control over contract deployment logic—enabling innovative architectures that were previously impossible on Ethereum. Whether building scalable dApps or solving blockchain puzzles, understanding this opcode is essential for modern smart contract engineering.
👉 Explore tools that simplify CREATE2-based deployments and testing environments.