- Create and Deploy Your First Smart Contract on the XDC Network Using OpenZeppelin and Hardhat
- π§ Table of contents
- π° Overview
- β Starting a new Hardhat Project
- π΅ Write Smart Contract Using OpenZeppelin
OpenZeppelin is an open-source framework that helps to build secure smart contracts to automate your decentralized applications.
OpenZeppelin contracts are written in solidity and use ERC standards for Ethereum-based tokens.
In this tutorial, you will learn how to set up Hardhat and use it to build, test, and deploy a smart contract build with OpenZeppelin on both the XDC Network mainnet and XDC Apothem testnet.
The complete tutorial code can be found here.
- Install and setup Hardhat
- Create a smart contract with the help of openzeppelin
- Compile the smart contract
- Deploy the smart contract
- Interact with the smart contract
- Check the deployment status on xinfin.network
Metamask wallet (Extension link) or XDC Pay wallet (Extension link)
Don't know how to create a wallet? Click here
Node.js. (Download link)
First, you'll need to setup your hardhat project. Open the terminal and follow these commands.
Make a folder with you project name and go to the project directory:
mkdir xdc-openzeppelin
cd xdc-openzeppelin
Initialize the project and install Hardhat:
npm init --yes
npm install --save-dev hardhat
In the same directory, run:
npx hardhat
- Select
Create a Javascript project
orCreate a Typescript project
according to your requirement. - Specify Hardhat Project root or press enter for already specified path.
- Specify
y
for yes andn
for no for adding a .gitignore - Press enter for
Do you want to install this sample project's dependencies with npm (@nomicfoundation/hardhat-toolbox)?
Note: If you are on windows, install this:
npm install --save-dev @nomicfoundation/hardhat-toolbox
Now, you will have a folder structure as below
To use OpenZeppelin contracts, install the package in the project using:
npm install @openzeppelin/contracts
In the contract folder, create a new file and write your contract inside it. In this example, we are creating MyToken.sol
for reference.
You'll use the ERC20.sol of OpenZeppelin to create and mint tokens.
1] You'll import ERC20.sol from OpenZeppelin using import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
2] You'll inherit all the methods and variable from OpenZeppelin's ERC20.sol and use it in your contract, by simply adding is ERC20
after the contract name
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// inherit ERC20 from OpenZeppelin by simply adding 'is ERC20'
contract MyToken is ERC20 {
//...to be continued
}
3] If you see the constructor of OpenZeppelin's ERC20.sol file, it takes in 2 parameters - name and symbol.
The _mint function of OpenZeppelin's ERC20.sol file also takes in 2 parameters - account(the address you want to send tokens to) and the amount of tokens you want to send.
Next, add it to out contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// inherit ERC20 from openzeppelin by simply adding 'is ERC20'
contract MyToken is ERC20 {
constructor() ERC20("MyToken", "MTK") {
// premint 1000 tokens to the owner of the contract.
_mint(msg.sender, 1000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public {
_mint(to, amount);
}
}
4] Since we want the mint function to be called only by the owner, you'll use an owner variable in the contract, and set a require statement in the mint function:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// inherit ERC20 from openzeppelin by simply adding 'is ERC20'
contract MyToken is ERC20 {
address public owner;
constructor() ERC20("MyToken", "MTK") {
owner = msg.sender;
// premint 1000 tokens to the owner of the contract.
_mint(msg.sender, 1000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public {
require(owner == msg.sender, "Only owner can mint the token!");
_mint(to, amount);
}
}
- To compile the contract, write the following in the terminal:
npx hardhat compile
If this returns errors, check your contract and rectify them.
If everything is correctly configured and there is no errors, you should see the following message on your console:
Compiled 5 Solidity files successfully
For writing the script to deploy the contract, create deploy.js
in scripts
folder, if it is already not there. Copy the following code in the deploy.js
:
const hre = require("hardhat");
async function main() {
// make sure to change the name of your contract
const MyToken = await hre.ethers.getContractFactory("MyToken");
const myToken = await MyToken.deploy();
await myToken.deployed();
console.log("My token contract address:", myToken.address);
}
// Call the main function and catch if there is any error
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
- To add the XDC Testnet network to metamask: (If you are using XDCPay, you don't have to follow this step)
- To add XDC mainnet network to metamask: (If you are using XDCPay you don't have to follow this step)
Make sure you do not push this file to github.
- Make a
.env
at the root of the project to store the private key and network url.
XINFIN_NETWORK_URL="enter-network-rpc-url-here"
XINFIN_PRIVATE_KEY="enter-your-private-key-here"
.env file that I have used for this project.
XINFIN_NETWORK_URL=https://erpc.xinfin.network
APOTHEM_NETWORK_URL=https://erpc.apothem.network
PRIVATE_KEY=202e3c9d30bbeca38d6578659919d4c3dc989ae18c16756690877fdc4dfa607f
π¨ Do not use the Private Key in the example above in production or you can risk losing your assets! π¨
- Dont know how to get your private key? Open your XDCPay wallet extension and click on the three dots on the top-left. This will open a popup.
Click on the Export Private key
inside the popup.
Enter the password that you used while creating the account.
Copy your private key. This key will be used to sign transactions when deploying the contract through hardhat.
- To be able to import env file variables, please install
dotenv
from your terminal:
npm install dotenv
- Open the
hardhat.config.js
file. Now we will add the network url and private key of our wallet to this file, so that we can deploy our contract. Yourharhat.config.js
should look like this.
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
module.exports = {
solidity: "0.8.16",
networks: {
xinfin: {
url: process.env.XINFIN_NETWORK_URL,
accounts: [process.env.PRIVATE_KEY],
},
apothem: {
url: process.env.APOTHEM_NETWORK_URL,
accounts: [process.env.PRIVATE_KEY],
},
},
};
After writing code for the setup and contract, go back to the terminal. Make sure you are in your project directory and type:
For the XDC mainnet:
npx hardhat run scripts/deploy.js --network xinfin
For the testnet:
npx hardhat run scripts/deploy.js --network apothem
In either case, you need to have enough funds to pay gas fees on the address that is being used for development.
If the deployment is sucessful, the console should log the following message after migrations complete processing:
My token contract address: 0xc8Ac88d77b9870D289806F54AfF9057f170bAb21
When importing third-party libraries like OpenZeppelin, it becomes necessary to flatten your smart contract and then verify it on the blockscan, because blockscan doesn't have access to the OpenZeppelin's code. When we flatten the code, the OpenZeppelin's code will be included in the same file as your samrt contract.
To flatten the contract using Hardhat, write the following in the terminal:
npx hardhat flatten ./path-to-file/contractName.sol > flattenedContractName.sol
In this case, you'll write:
npx hardhat flatten ./contracts/MyToken.sol > flattenedMyToken.sol
This will create a new file flattenedMyToken.sol
which would include flattened code for your smart contract.
Once you have successfully deployed your smart contract to the blockchain, it might be interesting to verify your contract on XinFin Block Explorer.
Change the prefix 0x
to xdc
to look for your contract on XinFin Block Explorer
In this example, there is a MyToken
contract deployed on XDC Mainnet at the 0x802555081f6AAcE51559d0650Bf15f242aBe7fd7
. You could search for your newly deployed contract on XinFin Block Explorer:
Click in the Verify And Publish
Option.
You will be redirected to the contract verification page where we need to fill out:
- Contract Name: MyToken
- Compiler: Check your
hardhat-config.js
file for Compiler Version - Contract Code: Just paste everything from your
flattenedMyToken.sol
file
Once everything is filled out, press Submit!
If everything is correctly filled out, your contract page on the block explorer should display a new tab called Contract
:
In this page you can Read from, Write to, or simply read the information tied to your Smart Contract on the blockchain:
For more information about Hardhat, Please Visit Hardhat Documentation.
For more information about XinFin Network, Please Visit XDC Network Documentation on GitBook.
Resources used during the deployment of the openzeppelin ERC20 Token can be found here.