Hardhat
Learn how to write, test and deploy smart contracts to Avalanche's C-Chain with Hardhat.
The goal of this guide is to lay out best practices regarding writing, testing and deployment of smart contracts to Avalanche's C-Chain. We'll be building smart contracts with Hardhat.
Prerequisites
NodeJS and Yarn
First, install the LTS (long-term support) version of NodeJS. This is 18.x
at the time of writing. NodeJS bundles npm
.
Next, install yarn.
AvalancheGo and Avalanche Network Runner
AvalancheGo is an Avalanche node implementation written in Go. Avalanche Network Runner is a tool to quickly deploy local test networks. Together, you can deploy local test networks and run tests on them.
Solidity and Avalanche
It is also helpful to have a basic understanding of Solidity and Avalanche.
Dependencies
Clone the quickstart repository and install the necessary packages via yarn
.
Note
The repository cloning method used is HTTPS, but SSH can be used too:
git clone git@github.com:ava-labs/avalanche-smart-contract-quickstart.git
You can find more about SSH and how to use it here.
Write Contracts
Edit the ExampleERC20.sol
contract in contracts/
. ExampleERC20.sol
is an Open Zeppelin ERC20 contract. ERC20 is a popular smart contract interface. You can also add your own contracts.
Hardhat Config
Hardhat uses hardhat.config.js
as the configuration file. You can define tasks, networks, compilers and more in that file. For more information see here.
Here is an example pre-configured hardhat.config.ts
.
This configures necessary network information to provide smooth interaction with Avalanche. There are also some pre-defined private keys for testing on a local test network.
Note
The port in this tutorial uses 9650. Depending on how you start your local network, it could be different.
Hardhat Tasks
You can define custom hardhat tasks in hardhat.config.ts
. There are two tasks included as examples: accounts
and balances
.
npx hardhat accounts
prints the list of accounts.npx hardhat balances
prints the list of AVAX account balances.
As with other yarn
scripts, you can pass in a --network
flag to hardhat tasks.
Accounts
Prints a list of accounts on the local Avalanche Network Runner network.
Balances
Prints a list of accounts and their corresponding AVAX balances on the local Avalanche Network Runner network.
Notice that the first account is already funded. This is because this address is pre-funded in the local network genesis file.
ERC20 Balances
This will return the result in wei. If you want to know the exact amount of token with its token name then you need to divide it with its decimal. erc20.abi.json
can be found here.
The example uses the C-Chain Public API for the provider. For a local Avalanche network use http://127.0.0.1:9650/ext/bc/C/rpc
and for Fuji Testnet use https://api.avax-test.network/ext/bc/C/rpc
.
Hardhat Help
Run yarn hardhat
to list Hardhat's version, usage instructions, global options and available tasks.
Typical Avalanche Network Runner Workflow
Run Avalanche Network Runner
First confirm you have the latest AvalancheGo built.
(Note that you can also download pre-compiled AvalancheGo binaries rather than building from source.)
Confirm you have Avalanche Network Runner installed by following the steps listed here
Start Avalanche Network Runner and run a script to start a new local network.
Start the Server
Start a New Avalanche Network with Five Nodes
Now you're running a local Avalanche network with 5 nodes.
Fund Accounts
Transfer 1,000 AVAX from the X-Chain to each of the 10 accounts in hardhat.config.ts
with the script fund-cchain-addresses
. Funding these accounts is a prerequisite for deploying and interacting with smart contracts.
Note: If you see Error: Invalid JSON RPC response: "API call rejected because chain is not done bootstrapping"
, you need to wait until network is bootstrapped and ready to use. It should not take too long.
Confirm each of the accounts are funded with 1000 AVAX.
Send each of the accounts some AVAX from the first account.
Confirm that the balances are updated
Note: If you see Error HH108: Cannot connect to the network local. Please make sure your node is running, and check your internet connection and networks config
, ensure that you are using a valid Node Port. See which ports the Nodes are using by running the command:
Compile Smart Contracts
In package.json
there's a compile
script.
Run yarn compile
to make sure your project compiles.
Deploy Smart Contracts
Hardhat enables deploying to multiple environments. In package.json there is a script for deploying.
Edit the deployment script in scripts/deploy.ts
You can choose which environment that you want to deploy to by passing in the --network
flag with local
(for example a local network created with Avalanche Network Runner), fuji
, or mainnet
for each respective environment. If you don't pass in --network
then it will default to the hardhat network. For example, if you want to deploy to Mainnet:
Deploy the contract to your local network:
We now have a token deployed at 0x17aB05351fC94a1a67Bf3f56DdbB941aE6
.
Interact with Smart Contract
Hardhat has a developer console to interact with contracts and the network. For more information about Hardhat's console see here. Hardhat console is a NodeJS-REPL, and you can use different tools in it. Ethers is the library that we'll use to interact with our network.
You can open console with:
Get the contract instance with factory and contract address to interact with our contract:
The first line retrieves contract factory with ABI & bytecode. The second line retrieves an instance of that contract factory with given contract address. Recall that our contract was already deployed to 0x17aB05351fC94a1a67Bf3f56DdbB941aE6
in the previous step.
Fetch the accounts:
This is exactly the same account list as in yarn accounts
.
Now we can interact with our ERC-20
contract:
account[0]
has a balance because account[0]
is the default account. The contract is deployed with this account. The constructor of ERC20.sol mints TOTAL_SUPPLY
of 123456789 token to the deployer of the contract.
accounts[1]
currently has no balance. Send some tokens to accounts[1]
, which is 0x9632a79656af553F58738B0FB750320158495942
.
Note: Since this is a local network, we did not need to wait until transaction is accepted. However for other networks like fuji
or mainnet
you need to wait until transaction is accepted with: await result.wait()
.
Now we can ensure that tokens are transferred:
As you might noticed there was no "sender" information in await coin.transfer(accounts[1], 100)
; this is because ethers
uses the first signer as the default signer. In our case this is account[0]
. If we want to use another account we need to connect with it first.
Now we can call the contract with signer1
, which is account[1]
.
Let's check balances now:
We've successfully transferred 5 tokes from accounts[1]
to accounts[0]
Summary
Now you have the tools you need to launch a local Avalanche network, create a Hardhat project, as well as create, compile, deploy and interact with Solidity contracts.
Join our Discord Server to learn more and ask any questions you may have.