Mastering CREATE2: How to Predictably Deploy Smart Contracts in Solidity

·

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:

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:

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:

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:

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:


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:

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:

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:

  1. Call predictCreate2Address("a", "b") → get predicted address
  2. Deploy via newContract("a", "b")
  3. Compare addresses — they will match exactly

This capability powers real-world use cases:


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

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.