# Create2 in Solidity

By [DeFi Simon](https://paragraph.com/@defi-simon) · 2024-03-28

---

`CREATE2` opcode helps us to predict the address of smart contract before it is deployed on Ethereum network, and `Uniswap` created `Pair` contract with `CREATE2` instead of `CREATE`.

In this blog, I will introduce the use of `CREATE2`.

**How does** `CREATE` calculate address
---------------------------------------

Smart contracts can be created by other contracts and regular accounts using the `CREATE` opcode.

In both cases, the address of new contract is calculated in the same way: the hash of creator's address (usually wallet address which will deploy or contract address) and the nonce(the total number of transactions sent from this address or, for contract account, the total number of contracts created. Every time a contract is created, the nonce will plus one).

    new address = hash(creator's address, nonce)
    

creator's address won't change, but the nonce may change over time, so it's difficult to predict the address of contract created with CREATE.

**How does** `CREATE2` calculate address
----------------------------------------

The purpose of `CREATE2` is to make contract address independent of future events. No matter what happens on blockchain in the future, you can deploy the contract to a pre-calculated address.

The address of contract created with `CREATE2` is determined by four parts:

*   `0xFF`: a constant to avoid conflict with `CREATE`
    
*   creator's address
    
*   salt: a value given by creator
    
*   The bytecode of contract to be deployed
    

    new address = hash("0xFF", creator's address, salt, bytecode)
    

`CREATE2` ensures that if creator deploys a given contract bytecode with `CREATE2` and given `salt`, it will be stored at `new address`.

**How to use** `CREATE2`[**​**](https://www.wtf.academy/en/docs/solidity-102/Create2/#how-to-use-create2)
---------------------------------------------------------------------------------------------------------

`CREATE2` is used in the same way as `Create`. It also `new` a new contract and passes in parameters which is needed for the new contract constructor, except with an extra `salt` parameter.

    Contract x = new Contract{salt: _salt, value: _value}(params)
    

`Contract` is the name of contract to be created, `x` is the contract object (address), and `_salt` is the specified salt; If the constructor is `payable`, a number of(`_value`) `ETH` can be transferred to the contract at creation, and `params` is the parameter of new contract constructor.

**Minimalist Uniswap2**[**​**](https://www.wtf.academy/en/docs/solidity-102/Create2/#minimalist-uniswap2)
---------------------------------------------------------------------------------------------------------

Let’s use `Create2` to implement a minimalist `Uniswap`.

### `Pair`[**​**](https://www.wtf.academy/en/docs/solidity-102/Create2/#pair)

    contract Pair{
        address public factory; // factory contract address
        address public token0; // token1
        address public token1; // token2
    
        constructor() payable {
            factory = msg.sender;
        }
    
        // called once by the factory at time of deployment
        function initialize(address _token0, address _token1) external {
            require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
            token0 = _token0;
            token1 = _token1;
        }
    }
    

`Pair` contract is simple and contains three state variables: `factory`, `token0` and `token1`.

Constructor assigns the `factory` to factory contract address at deployment time. `initialize` function is called once by factory contract when the `Pair` contract is created, updating `token0` and `token1` to the addresses of two tokens in the token pair.

### `PairFactory2`[**​**](https://www.wtf.academy/en/docs/solidity-102/Create2/#pairfactory2)

    contract PairFactory2{
            mapping(address => mapping(address => address)) public getPair; // Find the Pair address by two token addresses
            address[] public allPairs; // Save all Pair addresses
    
            function createPair2(address tokenA, address tokenB) external returns (address pairAddr) {
                require(tokenA != tokenB, 'IDENTICAL_ADDRESSES'); //Avoid conflicts when tokenA and tokenB are the same
                // Calculate salt with tokenA and tokenB addresses
                (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); //Sort tokenA and tokenB by size
                bytes32 salt = keccak256(abi.encodePacked(token0, token1));
                //Deploy new contract with create2
                Pair pair = new Pair{salt: salt}(); 
                // call initialize function of the new contract
                pair.initialize(tokenA, tokenB);
                // Update address map
                pairAddr = address(pair);
                allPairs.push(pairAddr);
                getPair[tokenA][tokenB] = pairAddr;
                getPair[tokenB][tokenA] = pairAddr;
            }
    

Factory contract(`PairFactory2`) has two state variables. `getPair` is a map of two token addresses to the token pair address. It is convenient to find the token pair address according to tokens. `allPairs` is an array of token pair address, storing all token pair addresses.

`PairFactory2` contract has only one `createPair2` function, which uses `CREATE2` to create a new `Pair` contract based on the two token addresses `tokenA` and `tokenB` entered. Inside

        Pair pair = new Pair{salt: salt}(); 
    

It's the above code that uses `CREATE2` to create contract, which is very simple, and `salt` is the hash of `token1` and `token2`.

        bytes32 salt = keccak256(abi.encodePacked(token0, token1));
    

### **Calculate** `Pair` address beforehand

            // Calculate Pair contract address beforehand
            function calculateAddr(address tokenA, address tokenB) public view returns(address predictedAddress){
                require(tokenA != tokenB, 'IDENTICAL_ADDRESSES'); //Avoid conflicts when tokenA and tokenB are the same
                // Calculate salt with tokenA and tokenB addresses
                (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); //Sort tokenA and tokenB by size
                bytes32 salt = keccak256(abi.encodePacked(token0, token1));
                // Calculate contract address
                predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
                    bytes1(0xff),
                    address(this),
                    salt,
                    keccak256(type(Pair).creationCode)
                )))));
            }
    

We write a `calculateAddr` function to precompute the address of `Pair` that `tokenA` and `tokenB` will generate. With it, we can verify whether the address we calculated in advance is the same as actual address.

You can deploy `PairFactory2` contract and call `createPair2` with the following two addresses as parameters to see what is the address of token pair created and whether it is the same as the precomputed address.

    WBNB address: 0x2c44b726ADF1963cA47Af88B284C06f30380fC78
    PEOPLE address on BSC:
    0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
    

#### **If there are parameters in deployment contract constructor**[**​**](https://www.wtf.academy/en/docs/solidity-102/Create2/#if-there-are-parameters-in-deployment-contract-constructor)

For example, when `create2` contract:

> **_Pair pair = new Pair{salt: salt}(address(this));_**

When calculating, you need to package parameters and bytecode together:

> **_keccak256(type(Pair).creationCode) => keccak256(abi.encodePacked(type(Pair).creationCode, abi.encode(address(this))))_**
> 
>     predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
>                     bytes1(0xff),
>                     address(this),
>                     salt,
>                     keccak256(abi.encodePacked(type(Pair).creationCode, abi.encode(address(this))))
>                 )))));
>     

**Application scenario of** `CREATE2`[**​**](https://www.wtf.academy/en/docs/solidity-102/Create2/#application-scenario-of-create2)
-----------------------------------------------------------------------------------------------------------------------------------

1.  The exchange reserves addresses for new users to create wallet contracts.
    
2.  `Factory` contract driven by `CREATE2`. The creation of trading pairs in `UniswapV2` is done by calling `create2` in `Factory`. The advantage is: It can get a certain `pair` address, so that the Router can calculate `pair` address through `(tokenA, tokenB)`, no longer need to perform a `Factory.getPair(tokenA, tokenB)` cross-contract call.
    

**Summary**[**​**](https://www.wtf.academy/en/docs/solidity-102/Create2/#summary)
---------------------------------------------------------------------------------

In this blog, we introduced the principle of `CREATE2` opcode and how to use it. Besides, we used it to create a minimalist version of `Uniswap` and calculate token pair contract address in advance. `CREATE2` helps us to determine contract address before deploying the contract, which is basis for some `layer2` projects.

---

*Originally published on [DeFi Simon](https://paragraph.com/@defi-simon/create2-in-solidity)*
