A guide to deploying and linking multi-chain smart contracts on Quai Network.
NodeJS | Javascript runtime environment. Use the LTS version. |
hardhat-example | A Hardhat project with sample contracts and deploy scripts for Quai Network. |
Quais.js | A JavaScript library for interacting with Quai Network. |
quai-hardhat-plugin | A plugin built for Hardhat that provides support for the SolidityX compiler. |
hardhat-example
repository, navigating to the SolidityX/
directory we’ll be using for this tutorial, and installing the dependencies via npm
.
hardhat-example
repository for the Single-Chain Deployment Tutorial, you
can skip the cloning step. Just navigate to the SolidityX/
directory and run npm install
.SolidityX
directory comes with 2 sample contracts: QRC20.sol
and QRC721.sol
inside of the contracts/
directory. Both of the included contracts are the initial SolidityX/cross-chain implementations of existing token standards. Source code for the contracts can be found in the SolidityX-Contracts Repository
As mentioned above, we’ll be deploying the QRC721 smart contract. Before configuring and deploying the QRC721, we recommend getting familiar with the contract specs.
hardhat-example
repo to hold token details, private keys, and RPC URLs in a secure fashion.
.env.dist
file is a template file and should not be used as is. You should copy the .env.dist
file to a new .env
file in the repository root using the following command:This file lives at the root of the hardhat-example
repository and serves as the config file for both the Solidity
and SolidityX
directories..env.dist
file in the root to a new .env
file in the repository root using the following command:
.env
file and add your private keys, RPC URLs, and token args for the contract you’d like to deploy. The .env
file should look like this:
PK
values must all be for unique addresses and correspond to the zone name, i.e. your CYPRUS1PK
should be the private key of your
Cyprus1 address.hardhat-example
repository uses the Quais SDK to configure network connections using only a single RPC URL. To learn more about how the SDK configures network providers, visit the SDK provider examples section.
After filling in your private keys, RPC URL, we’re now ready to securely consume them inside of hardhat.config.js
.
hardhat.config.js
to configure smart contract deployments. The config file allows you to define deployment networks, tasks, compilers, etc. hardhat-example/SolidityX
contains a prebuilt hardhat.config.js
file with configurations for compiling, deploying, verifying SolidityX smart contracts on Quai.
The below configuration file has two main differences from the hardhat.config.js
file use for basic Solidity contract deployment:
quai-hardhat-plugin
to handle SolidityX compiler downloadsolidityx
object to specify a locally built SolidityX compiler (if you don’t want to use the plugin to download the compiler)Sample hardhat configuration file
hardhat-example
repository.cyprus1
cyprus2
cyprus3
paxos1
paxos2
paxos3
hydra1
hydra2
hydra3
hardhat.config.js
will pull your private keys and RPC URLs from the .env
file and use them to deploy and verify your contracts.
hardhat.config.js
file already includes the quai-hardhat-plugin
to handle the SolidityX compiler download. If you’ve followed the above steps, you’re already set up to use the plugin to download the SolidityX compiler.Compile with SolidityX
npx
in the CLI.Compile all of the contracts inside the contracts/
directory with:Configure deployment scripts
scripts/
directory, you’ll find a deploy script for both QRC20 and QRC721 contracts: deployQRC20.js
and deployQRC721.js
. For this tutorial, we’ll be using the QRC721 contract.The deployQRC721.js
script works by pulling your specified network/accounts config from hardhat.config.js
and the QRC721 arguments specified in the .env
file at the root of the repository and uses them to deploy your contract.Token arguments are consumed via the tokenArgs
array:provider
and wallet
variables in tandem with the compiled contract ABI and bytecode to create a new contract instance:Deploy contracts
cyprus1
as the network flag in the deployment command like below:cyprus2
as the network flag in the deployment command.baseURI
variable for each chain to prevent duplicate mints or additionally modifying
the QRC721 contract to handle minting on different shards. This variable can be changed in the .env
file at the root of the repository.AddApprovedAddresses
method. It accepts 2 arrays as arguments: chain indexes and approved addresses.
The AddApprovedAddresses
method seen below can be used to add as few as 1 or as many as 8 sister contracts to the approvedAddresses
array of a QRC721 or QRC20 contract.
ApprovedAddresses
of each of the QRC721 contracts, the cross-chain functionality of the transferFrom
method becomes available, which allows anyone who owns a token from the collection to trustlessly send their it between shards that the contracts are deployed to.
quais.js
and some of the Hardhat Runtime Environment that we used in the deploy script. Start by creating another file in the scripts directory named addApprovedAddresses.js
.
addApprovedAddresses.js
:
addApprovedAddresses.js
script uses the QRC721.sol
ABI to compose and send a transaction that inserts new addresses to the approvedAddresses
array in any deployed QRC721 contract.
How the linking script works
provider
with our specified network configuration from Hardhat 2. Creating a quais wallet
with our
provider
and key config from Hardhat 3. Defining the contract we’d like to add an approved address to with the imported QRC721.sol
ABI, contract address, and wallet
4. Composing the addApprovedAddresses
transaction with the inputs - chainIndex
array: integer
chain indices corresponding to the addresses we’d like to add to approvedAddresses
- address
array: the contract addresses that we’d
like to add to approvedAddresses
5. Sending the transaction and waiting for inclusion in a block.addApprovedAddresses.js
file, we’re ready to start linking our sister contracts.
Build linking transactions
addApprovedAddresses
method.addApprovedAddresses
method can take in and
handle its own contract address as an argument. This removes the need to alter the transaction data for each contract you want to link.addApprovedAddresses
method is (notice the order of the arrays):chainIndex
array: [0, 1]
address
array: ['0x00735E9B2c731Fd3eCC8129a3653ACb99dF969cC', '0x0172F38EC31f58B1419E2CcE2B05B095625218ea']
Send linking transactions
contractAddress
variable to our Cyprus 1 contract address in the addApprovedAddresses.js
script:--network cyprus1
flag when sending transactions to the Cyprus 1 contract.addApprovedAddresses.js
script, change the contractAddress
variable to our Cyprus 2 contract address:--network cyprus2
flag:addApprovedAddresses
method. You now have the tools to deploy and link contracts across all zone chains within Quai Network.