Smart contract deployment on Ethereum has evolved significantly since its inception. One of the most powerful advancements is the CREATE2 opcode, introduced during the 2019 Constantinople upgrade. This feature allows developers to predict and control the address of a newly deployed contract—offering unprecedented flexibility for decentralized applications (dApps), contract factories, and upgradeable systems.
In this guide, we’ll explore how to use CREATE2 in Solidity through two primary methods: the high-level new operator with a salt parameter, and low-level inline assembly. We'll also dive into how to precompute contract addresses, a crucial capability for improving user experience in real-world dApps like Uniswap.
Understanding CREATE vs CREATE2
Ethereum Virtual Machine (EVM) provides two opcodes for deploying contracts:
CREATECREATE2
While both serve the purpose of instantiating new contracts, their behavior differs fundamentally in how they determine the resulting contract address.
The Limitation of CREATE
When using CREATE, the address of the new contract is calculated as:
keccak256(rlp.encode([creator_address, nonce]))[12:]This means the address depends on:
- The creator’s address
- The creator’s current nonce (transaction count)
Since the nonce increases with each transaction, it's impossible to predict the next contract address without knowing how many transactions have been sent. This lack of determinism limits use cases where pre-known addresses are essential.
The Power of CREATE2
With CREATE2, the address is calculated using a deterministic formula that includes a user-defined salt value:
keccak256(0xff ++ address ++ salt ++ keccak256(init_code))[12:]Here:
0xff: A constant prefix to avoid collision withCREATEaddress: Deployer’s addresssalt: User-supplied 32-byte valueinit_code: The creation bytecode (constructor + code)
Because none of these depend on the nonce, you can precompute the contract address before deployment—a game-changer for UX and architecture design.
👉 Discover how leading blockchain platforms enable predictable smart contract deployment
Method 1: Using new with Salt in Solidity
Solidity offers a clean, high-level syntax to leverage CREATE2 using the new keyword with a {salt: ...} modifier.
Syntax
ContractType instance = new ContractType{salt: _salt}(constructor_args);Where:
_saltis abytes32value used in address derivation- The constructor arguments follow normally in parentheses
Example Implementation
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Callee {
string public value1;
string public value2;
constructor(string memory _value1, string memory _value2) {
value1 = _value1;
value2 = _value2;
}
}
contract ContractCreator {
address public contractAddress;
function newContract(string memory value1, string memory value2) external {
bytes32 salt = keccak256(abi.encodePacked(value1, value2));
Callee callee = new Callee{salt: salt}(value1, value2);
contractAddress = address(callee);
}
}In this example:
- The salt is derived from hashing the constructor parameters.
- This ensures that identical inputs always produce the same contract address.
- The contract can be redeployed at any time to the same address if needed (e.g., after migration or recovery).
Method 2: Inline Assembly with create2
For more control over gas usage and deployment logic, developers can use inline assembly to call the create2 opcode directly.
Syntax
addr := create2(value, offset, size, salt)Parameters:
value: Amount of ETH to send during creationoffset: Memory location of init codesize: Size of init code in bytessalt: 32-byte salt for deterministic addressing
Example with Assembly
function createContract(string memory value1, string memory value2) external {
bytes32 salt = keccak256(abi.encodePacked(value1, value2));
bytes memory bytecode = abi.encodePacked(
type(Callee).creationCode,
abi.encode(value1, value2)
);
address addr;
assembly {
addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
}
contractAddress = addr;
}Key points:
type(Callee).creationCoderetrieves the raw bytecode including constructor logic.abi.encode(...)appends constructor arguments.mload(bytecode)reads the length of the bytecode (stored in first 32 bytes).add(bytecode, 0x20)skips the length field to point to actual data.
This method gives full control and is often used in advanced patterns like minimal proxy contracts and factory designs.
👉 See how modern DeFi protocols utilize deterministic contract creation
Precomputing CREATE2 Contract Addresses
One of the most valuable features of CREATE2 is the ability to predict a contract’s address before deployment. This is especially useful in dApp frontends where immediate feedback improves user experience.
Address Prediction Formula
address predicted = address(uint160(uint(
keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
salt,
keccak256(bytecode)
))
)));Full Prediction Example
function predictCreate2Address(string memory value1, string memory value2)
external view returns (address)
{
bytes32 salt = keccak256(abi.encodePacked(value1, value2));
bytes memory bytecode = abi.encodePacked(
type(Callee).creationCode,
abi.encode(value1, value2)
);
bytes32 hash = keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
salt,
keccak256(bytecode)
));
return address(uint160(uint(hash)));
}You can test this in Remix:
- Call
predictCreate2Address("a", "b")→ get predicted address - Deploy via
newContract("a", "b") - Compare addresses — they will match exactly
This capability powers real-world use cases:
- Uniswap V2: Predicts pair addresses so users can immediately interact with new trading pairs.
- Wallet recovery systems: Re-deploy lost contracts at known addresses.
- Gasless meta-transactions: Pre-register handler contracts.
Frequently Asked Questions (FAQ)
Q: What happens if two contracts are deployed with the same salt and init code?
A: Only the first deployment succeeds. The second attempt fails because a contract already exists at that address. This prevents duplication while enabling safe re-deployment attempts.
Q: Can I change the salt after computing an address?
A: No — changing the salt changes the resulting address. To maintain predictability, all inputs (salt, bytecode, deployer) must remain consistent between prediction and deployment.
Q: Is CREATE2 more expensive than CREATE in terms of gas?
A: Slightly. CREATE2 uses more gas due to additional hashing operations. However, this cost is usually negligible compared to the benefits of deterministic addressing.
Q: Can I use CREATE2 without knowing the constructor arguments ahead of time?
A: No. Since constructor arguments are part of the init_code, they must be known when computing the bytecode hash — which is required for both deployment and prediction.
Q: Are there security risks with predictable addresses?
A: Yes. Predictable addresses can expose contracts to front-running or pre-deployment attacks. Always ensure salts are sufficiently random or based on secure input when privacy matters.
Core Keywords for SEO Optimization
- CREATE2 Ethereum
- predict contract address
- deterministic contract deployment
- Solidity create2
- smart contract factory
- inline assembly create2
- Uniswap pair address
- EVM opcode create2
These keywords reflect high-intent searches from developers building scalable dApps and protocol infrastructure.
👉 Explore developer tools that support CREATE2-based smart contract patterns
By mastering CREATE2, you unlock advanced architectural capabilities in Ethereum development — from gas-efficient factories to seamless user experiences in DeFi and identity systems. Whether using high-level Solidity syntax or fine-tuning with assembly, deterministic deployment is now a cornerstone of modern smart contract engineering.