How to determine the address of a smart contract before the deployment: using CREATE2 for the crypto exchange

The topic of blockchain does not cease to be a source of not only all kinds of hype, but also ideas that are very valuable from a technological point of view. Therefore, she did not bypass the inhabitants of the sunny city. People are eyeing, studying, trying to shift their expertise in the traditional informational approach to blockchain systems. So far, just a point: one of the Rostelecom-Solar developments is able to check the security of software based on the blockchain. And along the way, some thoughts arise on solving the applied problems of the blockchain community. One of these life hacks - how to determine the address of a smart contract before the deployment using CREATE2 - today I want to share with you under the cut.



image

The CREATE2 opcode was added to the hard fork of Constantinople on February 28 this year. As indicated in the EIP, this opcode was introduced primarily for state channels. However, we used it to solve another problem.



There are users on the exchange with balances. We must provide each user with an Ethereum address to which anyone can send tokens, thereby replenishing their account. Let's call these addresses "wallets." When tokens come to wallets, we must send them to a single wallet (hotwallet).



In the following sections, I analyze solutions to this problem without CREATE2 and explain why we abandoned them. If you are only interested in the end result, you can find it in the “Final Solution” section.



Ethereum Addresses



The easiest solution is to generate new ethereum addresses for new users. These addresses will be wallets. To transfer tokens from a wallet to a hotwallet, you need to sign the transaction by calling the transfer () function with the wallet’s private key from the backend.



This approach has the following advantages:





However, we abandoned this approach because it has one significant drawback: you need to store private keys somewhere. And the point is not only that they can be lost, but also that you need to carefully control access to these keys. If at least one of them is compromised, then the tokens of a certain user will not reach a hot wallet.



image



Create a separate smart contract for each user



Deploying a separate smart contract for each user eliminates the need to store private wallet keys on the server. The exchange will call this smart contract to transfer tokens to the hotwallet.



We also refused this decision, since the user cannot be shown the address of his wallet without deploying a smart contract (this is actually possible, but in a rather complicated way with other shortcomings that we will not discuss here). On the exchange, a user can create as many accounts as he needs, and everyone needs their own wallet. This means that we need to spend money on the deployment of the contract, not even being sure that the user will use this account.



Opcode CREATE2



To fix the problem of the previous method, we decided to use the CREATE2 opcode. CREATE2 allows you to pre-determine the address at which the smart contract will be deployed. The address is calculated using the following formula:



keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
      
      





where:



This ensures that the address that we provide to the user will indeed contain the desired bytecode. In addition, this smart contract can be deployed when we need. For example, when a user decides to use his wallet for the first time.

image

Moreover, you can calculate the address of a smart contract every time instead of storing it, since:





More improvements



The previous solution still has one drawback: you have to pay to deploy a smart contract. However, you can get rid of this. To do this, you can call the transfer () function, and then selfdestruct () in the wallet constructor. And then the gas for the deployment of the smart contract will be returned.



Contrary to popular belief, you can deploy a smart contract at the same address several times with the CREATE2 opcode. This is because CREATE2 checks that the nonce of the target address is zero (it is assigned the value “1” at the beginning of the constructor). In this case, the selfdestruct () function resets nonce addresses each time. That way, if you call CREATE2 again with the same arguments, the check for nonce will pass.



Note that this solution is similar to the ethereum address option, but without the need to store private keys. The cost of transferring money from a wallet to a hotwallet is approximately equal to the cost of calling the transfer () function, since we do not pay for the deployment of a smart contract.



Final decision



image



Initially prepared by:





 constructor () { address hotWallet = 0x…; address token = 0x…; token.transfer (hotWallet, token.balanceOf (address (this))); selfdestruct (address (0)); }
      
      





For each new user, we show his / her wallet address by calculating



 keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
      
      





When a user transfers tokens to the corresponding wallet address, our backend sees the Transfer event with the _to parameter equal to the wallet address. At this point, it is already possible to increase the user's balance on the exchange before deploying the wallet.



When a sufficient number of tokens accumulate at the wallet address, we can transfer them all at once to a hotwallet. To do this, the backend calls the function of the smart contract factory, which performs the following actions:



 function deployWallet ( uint256) { bytes memory walletBytecode =…; // invoke CREATE2 with wallet bytecode and salt }
      
      





Thus, the constructor of the smart wallet contract is called, which transfers all its tokens to the hotwallet address and then self-destructs.



Full code can be found here . Please note that this is not our production code, since we decided to optimize the wallet bytecode and wrote it in the opcodes.



Posted by Pavel Kondratenkov, Ethereum Specialist



All Articles