Vite is a modern, frontend build tool and open source project that offers an alternative to Webpack. You can use it to create a new project with the Vite React template that is very similar to the type of project created by
create-react-app. We’ll use it to connect to the smart contract deployed later in the tutorial.
Open a Terminal window and run the following commands to set it up:
yarn create vite getting-started-with-avalanche --template react
cd getting-started-with-avalanche
yarn create vite getting-started-with-avalanche --template react
cd getting-started-with-avalanche
yarn create vite getting-started-with-avalanche --template react
cd getting-started-with-avalanche
After generating the boilerplate app, install dependencies for hardhat, ethers, @nomiclabs/hardhat-ethers, and dotenv to manage environment variables:
yarn add -D dotenv hardhat ethers @nomiclabs/hardhat-ethers
yarn add -D dotenv hardhat ethers @nomiclabs/hardhat-ethers
yarn add -D dotenv hardhat ethers @nomiclabs/hardhat-ethers
Create the directories and files for your smart contract, Hardhat deployment script, and Hardhat configuration:
mkdir contracts scripts
echo > contracts/HelloWorld.sol
echo > scripts/deploy.js
echo > hardhat.config.js
mkdir contracts scripts
echo > contracts/HelloWorld.sol
echo > scripts/deploy.js
echo > hardhat.config.js
mkdir contracts scripts
echo > contracts/HelloWorld.sol
echo > scripts/deploy.js
echo > hardhat.config.js
Create a .env file in the root directory of your project to hold environment variables for our endpoint URL, private key, and contract address.
echo 'QUICKNODE_URL=\nPRIVATE_KEY=\nVITE_CONTRACT_ADDRESS=' > .env
echo 'QUICKNODE_URL=\nPRIVATE_KEY=\nVITE_CONTRACT_ADDRESS=' > .env
echo 'QUICKNODE_URL=\nPRIVATE_KEY=\nVITE_CONTRACT_ADDRESS=' > .env
Add .env to .gitignore so you do not commit any private information.
echo '.env' >> .gitignore
echo '.env' >> .gitignore
echo '.env' >> .gitignore
Create a Hello World Solidity Contract
Next, we’ll add a boilerplate smart contract, HelloWorld, to deploy to Avalanche. Open a code editor of choice and paste this code into contracts/HelloWorld.sol:
// contracts/HelloWorld.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.6;
import "hardhat/console.sol";
contract HelloWorld {
string private helloMessage;
constructor(string memory _helloMessage) {
console.log(_helloMessage);
helloMessage = _helloMessage;
}
function hello() public view returns (string memory) {
return helloMessage;
}
function setHello(string memory _helloMessage) public {
console.log("Changing helloMessage from '%s' to '%s'", helloMessage, _helloMessage);
helloMessage = _helloMessage;
}
}
// contracts/HelloWorld.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.6;
import "hardhat/console.sol";
contract HelloWorld {
string private helloMessage;
constructor(string memory _helloMessage) {
console.log(_helloMessage);
helloMessage = _helloMessage;
}
function hello() public view returns (string memory) {
return helloMessage;
}
function setHello(string memory _helloMessage) public {
console.log("Changing helloMessage from '%s' to '%s'", helloMessage, _helloMessage);
helloMessage = _helloMessage;
}
}
// contracts/HelloWorld.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.6;
import "hardhat/console.sol";
contract HelloWorld {
string private helloMessage;
constructor(string memory _helloMessage) {
console.log(_helloMessage);
helloMessage = _helloMessage;
}
function hello() public view returns (string memory) {
return helloMessage;
}
function setHello(string memory _helloMessage) public {
console.log("Changing helloMessage from '%s' to '%s'", helloMessage, _helloMessage);
helloMessage = _helloMessage;
}
}
The contract has a string variable called helloMessage. It contains a hello function which returns the value set to helloMessage. Another function, setHello, changes the value of helloMessage to whatever argument is passed into the function.
Now that we have created our smart contract, let’s deploy it to Avalanche!
Write the Deployment Script
Add the following deployment script to scripts/deploy.js:
// scripts/deploy.js
async function main() {
const HelloWorldFactory = await ethers.getContractFactory("HelloWorld")
const helloMessage = await HelloWorldFactory.deploy("Hello from QuickNode")
await helloMessage.deployed()
console.log("Contract deployed to:", helloMessage.address)
console.log("Contract deployed by " + JSON.stringify(helloMessage.signer) + " signer")
process.exit(0)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
// scripts/deploy.js
async function main() {
const HelloWorldFactory = await ethers.getContractFactory("HelloWorld")
const helloMessage = await HelloWorldFactory.deploy("Hello from QuickNode")
await helloMessage.deployed()
console.log("Contract deployed to:", helloMessage.address)
console.log("Contract deployed by " + JSON.stringify(helloMessage.signer) + " signer")
process.exit(0)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
// scripts/deploy.js
async function main() {
const HelloWorldFactory = await ethers.getContractFactory("HelloWorld")
const helloMessage = await HelloWorldFactory.deploy("Hello from QuickNode")
await helloMessage.deployed()
console.log("Contract deployed to:", helloMessage.address)
console.log("Contract deployed by " + JSON.stringify(helloMessage.signer) + " signer")
process.exit(0)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
The main function calls the getContractFactory method on the ethers library and passes in HelloWorld as the name of the contract. HelloWorldFactory is deployed with the message "Hello from QuickNode" and set to helloMessage. This is then called on the next line with the deployed method. Lastly, the address and signer for the contract are logged to the console.
Hardhat Configuration
Now that we have our contract and a script to deploy it, the last step is to write our Hardhat configuration. The configuration specifies where the contract artifacts are placed in the project and what network the contract is deployed to.
The code for it looks like this:
// hardhat.config.js
require("dotenv").config()
require("@nomiclabs/hardhat-ethers")
module.exports = {
solidity: "0.8.6",
paths: {
artifacts: './src/artifacts',
},
networks: {
fuji: {
url: process.env.QUICKNODE_URL,
accounts: [`0x` + process.env.PRIVATE_KEY],
chainId: 43113,
},
},
}
// hardhat.config.js
require("dotenv").config()
require("@nomiclabs/hardhat-ethers")
module.exports = {
solidity: "0.8.6",
paths: {
artifacts: './src/artifacts',
},
networks: {
fuji: {
url: process.env.QUICKNODE_URL,
accounts: [`0x` + process.env.PRIVATE_KEY],
chainId: 43113,
},
},
}
// hardhat.config.js
require("dotenv").config()
require("@nomiclabs/hardhat-ethers")
module.exports = {
solidity: "0.8.6",
paths: {
artifacts: './src/artifacts',
},
networks: {
fuji: {
url: process.env.QUICKNODE_URL,
accounts: [`0x` + process.env.PRIVATE_KEY],
chainId: 43113,
},
},
}
Here we specify the Solidity version, the path for the contract artifacts, and the network information for Fuji. Add this code to the hardhat.config.js file.
Before we can deploy this contract, we need to include two environment variables in .env . Navigate to the Coinbase Wallet extension and click on "Show Recovery Phrase". Copy your private key and set it to the PRIVATE_KEY variable.
Next, visit the QuickNode dashboard and copy the HTTP provider URL for your endpoint. Paste the URL into your .env file and include /ext/bc/C/rpc at the very end of the URL to specify that you want to connect to the C-Chain. This chain is an instance of the Ethereum Virtual Machine that allows for creating smart contracts with the C-Chain’s API.
Deploy Contract to Fuji
Before deploying the contract, we need to first compile the contract. Run the following command:
yarn hardhat compile
yarn hardhat compile
Then, deploy the contract and include a --network flag to specify the Fuji test network.
yarn hardhat run scripts/deploy.js --network fuji
yarn hardhat run scripts/deploy.js --network fuji
yarn hardhat run scripts/deploy.js --network fuji
If everything in your project is set up correctly, after running this script your terminal outputs the following message but with your own addresses:
Contract deployed to: 0x873E3BB2A752DBDFA06017CC5a709600Ac3c0153
Contract deployed by "<SignerWithAddress 0x6b492Ef06CA3b462f20db50EB288fAbB1E3e8Bfc>" signer
Include the contract address in .env, so it can be accessed from our frontend client in the next section.