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.
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.
Edit the ExampleERC20.sol contract in contracts/. ExampleERC20.sol is an Open ZeppelinERC20 contract. ERC20 is a popular smart contract interface. You can also add your own contracts.
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.
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.
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:
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.
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]
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.