If you are a smart contract developer, you might have wondered how to deploy your contract to different networks, such as Ethereum, Polygon, Arbitrum, etc., but keep the same address for each deployment. This can be useful for testing purposes and for users who want to interact with your contract across various networks.
In this article, I will explain how to achieve this using a simple example and some tools that can make your life easier.
When you deploy a smart contract to the Ethereum network, the address of the contract is derived from your wallet address, your wallet's transaction count (also known as nonce), and your contract's bytecode. This ensures that each contract deployed to Ethereum has a unique address.
However, this also means that if you deploy the same contract to another network, such as Polygon or Arbitrum, the address will be different, because the nonce of your wallet will be different on each network.
For example, let's say you have a wallet address 0x1a2b3c4d and you want to deploy a smart contract called Vault. If you deploy it on Ethereum with a nonce of 2, the address of the Vault contract might be 0x5d5d5d. But if you deploy it on Polygon with a nonce of 4, the address might be 0x6e6e6e. And if you deploy it on Arbitrum with a nonce of 7, the address might be 0x7f7f7f.
This can be confusing and inconvenient for users who want to use your contract on different networks. They will have to remember different addresses for each network and make sure they are using the right one.
To solve this problem, we need to make sure that the nonce of our wallet is the same on each network before we deploy our contract. This way, the address of the contract will be the same on each network.
One way to do this is to manually send some transactions from our wallet on each network until we reach the desired nonce. For example, if we want our nonce to be 7 on each network, we can send 0 ETH to ourselves or to another address 5 times on Ethereum (since our nonce is already 2), 3 times on Polygon (since our nonce is already 4), and 0 times on Arbitrum (since our nonce is already 7).
This method works, but it is tedious and costly. We have to pay gas fees for each transaction and wait for them to be confirmed. Moreover, we have to keep track of our nonce on each network and make sure we don't send any other transactions that would change it.
Fortunately, there is a better way to do this using a tool called Hardhat and an opcode called CREATE2.
Hardhat is a development environment for Ethereum that allows you to write, test, debug, and deploy smart contracts with ease. It has many features and plugins that can help you with various tasks, such as compiling, testing, debugging, deploying, etc.
One of the plugins that we will use in this tutorial is @nomiclabs/hardhat-ethers , which allows us to interact with Ethereum nodes using the ethers.js library.
To use Hardhat, we need to install it and some other dependencies in our project folder:
Then we need to create a hardhat.config.js file in our project root and configure it with some settings:
In this file, we require the plugin and dotenv , which allows us to load environment variables from a .env file. Then we export an object with some properties:
• solidity : the version of Solidity compiler we want to use
• networks : an object with the names and settings of the networks we want to connect to
• url : the RPC URL of each network (we will use BuildBear for this)
• accounts : an array with our private key (we will use the same key for all networks)
We also need to create a .env file in our project root and store our API URLs and private key there:
To get the BuildBear API URLs, we need to create an account on BuildBear and create an endpoint for each network we want to use. BuildBear is a service that provides fast and reliable RPC URLs for various networks, such as Ethereum Mainnet, Polygon Mainnet, Arbitrum Mainnet, etc. It also provides analytics and monitoring tools for your transactions and contracts.
To create an endpoint on BuildBear , follow these steps:
• Log in with your GitHub account
• Click on Create an endpoint
• Name your endpoint and select the chain and network of your choice
• Click on Create endpoint
• Copy the RPC URL from the dashboard
Repeat these steps for each network you want to use and paste the URLs in your .env file.
CREATE2 is an opcode that allows us to deploy a smart contract with a deterministic address based on some parameters:
• bytecode : the compiled version of our smart contract
• salt : an arbitrary value that we can choose
• sender : the address that deploys the contract
The formula for calculating the address of a contract deployed with CREATE2 is:
As you can see, this formula does not depend on the nonce of the sender , so we don't have to worry about syncing our nonces across different networks. We just have to make sure that we use the same bytecode , salt , and sender on each network.
To use CREATE2 , we need to write a smart contract that implements this opcode and calls it with our desired parameters. For example:
This contract has a function called deploy that takes two arguments: _bytecode and _salt . It then uses assembly code to call CREATE2 with these arguments and returns the address of the deployed contract.
We can deploy this Deployer contract once on each network using Hardhat , and then use it to deploy our Vault contract with the same address on each network.
The Vault contract is a simple example of a smart contract that allows users to deposit and withdraw ETH . It has two functions: deposit and withdraw :
We can compile this contract using Hardhat :
This will generate a folder called artifacts with some files inside. One of them is artifacts/contracts/Vault.sol/Vault.json , which contains some information about our compiled Vault contract , such as its ABI (Application Binary Interface) and bytecode .
We can use these information to deploy our Vault contract using CREATE2 .
Vault Deploy Script
To deploy our Vault contract using CREATE2 , we need to write a script that does the following:
• Connects to each network using Hardhat
• Deploys the Deployer contract using Hardhat
• Gets the bytecode of the Vault contract from artifacts
• Chooses a salt value (we can use any value we want)
• Calls the deploy function of the Deployer contract with the bytecode and salt as arguments
• Prints out the address of the deployed Vault contract
Here is an example script that does these steps:
This script will deploy our Vault contract to Ethereum, Polygon, and Arbitrum networks using BuildBear RPC URLs and our private key. It will print out the address of the deployed contract on each network, which should be the same.
In this article, we learned how to deploy a smart contract to different networks with the same address using Hardhat and CREATE2 . This can be useful for testing purposes and for users who want to interact with your contract across various networks.
We also learned how to use BuildBear , a service that provides fast and reliable RPC URLs for various networks, such as Ethereum Mainnet, Polygon Mainnet, Arbitrum Mainnet, etc. It also provides analytics and monitoring tools for your transactions and contracts.
I hope you found this article helpful and informative. If you have any questions or feedback, please let me know in the comments. Thank you for reading!