# Create2 in Solidity **Published by:** [DeFi Simon](https://paragraph.com/@defi-simon/) **Published on:** 2024-03-28 **URL:** https://paragraph.com/@defi-simon/create2-in-solidity ## Content 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 addressSmart 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 addressThe 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 CREATEcreator's addresssalt: a value given by creatorThe bytecode of contract to be deployednew 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​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​Let’s use Create2 to implement a minimalist Uniswap.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​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​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​The exchange reserves addresses for new users to create wallet contracts.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​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. ## Publication Information - [DeFi Simon](https://paragraph.com/@defi-simon/): Publication homepage - [All Posts](https://paragraph.com/@defi-simon/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@defi-simon): Subscribe to updates - [Twitter](https://twitter.com/SicongLu): Follow on Twitter