Create and deploy your Smart Contract using Hardhat.
Requirements
To complete the tutorial npm has to be installed.
npm install -g npm
Step 1: Project init
First, we’ll need to create a folder for our project. Navigate to your command line and type
mkdir hello-world
cd hello-world
Now that we’re inside our project folder, we’ll use npm init to initialize the project.
npm init # (or npm init --yes)
It doesn’t matter how you answer the installation questions.
Approve the package.json, and we’re good to go!
Step 2: Install Hardhat
Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software. It helps developers build smart contracts and dApps locally before deploying to the live chain.
This command will generate a hardhat.config.js file, where we’ll specify all the configurations for our project (in step 13).
You can choose to create the project in JavaScript or TypeScript, but remember that the deployment and interaction files will have to be changed accordingly!
If the installation does not require you to install the plugin @nomicfoundation/hardhat-toolbox, which has everything you need to develop smart contracts, install it with the following command:
Create a folder to keep our smart contract code file. In the command line, type:
mkdir contracts
cd contracts
Open the hello-world project in your favourite editor (e.g., VSCode, IntelliJ IDEA). Smart contracts are written in a language called Solidity, which we will use to write our smart contract.
Below, there are three sample smart contracts that we can choose for this tutorial.
Navigate to the “contracts” folder and create a new file with the name of the smart contract you choose (e.g., Greeter.sol).
Copy and paste the contents below into your file, and be sure to read the comments to understand what this contract does:
// SPDX-License-Identifier: GPL-3.0pragmasolidity >=0.7.0 <0.9.0;/** * @title Storage * @dev Store & retrieve value in a variable * @custom:dev-run-script ./scripts/deploy_with_ethers.ts */contract Storage {uint256 number;/** * @dev Store value in variable * @param num value to store */functionstore(uint256 num) public { number = num; }/** * @dev Return value * @return value of 'number' */functionretrieve() publicviewreturns (uint256){return number; }}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.3;contract Payable {// Payable address can receive Etheraddresspayablepublic owner;address User;// Payable constructor can receive Etherconstructor() payable { owner =payable(msg.sender); }// Function to deposit Ether into this contract.// Call this function along with some Ether.// The balance of this contract will be automatically updated.functiondeposit(address u) publicpayable { User=u; }// Call this function along with some Ether.// The function will throw an error since this function is not payable.functionnotPayable() public {}functionretrieveAdd() publicviewreturns (address){ return User; }functionGetBalance() publicviewreturns (uint256){returnaddress(this).balance; }receive() externalpayable {}// Function to withdraw all Ether from this contract.functionwithdraw() public {// get the amount of Ether stored in this contractuint amount =address(this).balance;// send all Ether to owner// Owner can receive Ether since the address of owner is payable (bool success, ) = owner.call{value: amount}("");require(success,"Failed to send Ether"); }// Function to transfer Ether from this contract to address from inputfunctiontransfer(address payable _to,uint_amount) public {// Note that "to" is declared as payable (bool success, ) = _to.call{value: _amount}("");require(success,"Failed to send Ether"); }}
// SPDX-License-Identifier: UNLICENSEDpragma solidity ^0.8.9;// Import this file to use console.logimport"hardhat/console.sol";contract Lock { uint public unlockTime; address payable public owner; event Withdrawal(uint amount, uint when);constructor(uint _unlockTime) payable {require(block.timestamp < _unlockTime,"Unlock time should be in the future" ); unlockTime = _unlockTime; owner =payable(msg.sender); }functionwithdraw() public {// Uncomment this line to print a log in your terminal// console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp);require(block.timestamp >= unlockTime,"You can't withdraw yet");require(msg.sender == owner,"You aren't the owner"); emit Withdrawal(address(this).balance,block.timestamp);owner.transfer(address(this).balance); }}
We need to update hardhat.config.js so that our project knows the details about the 1DLT node.
Add the 1DLT node information into the network list in hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");/** @type import('hardhat/config').HardhatUserConfig */module.exports= { solidity:"0.8.15", networks: { node_1DLT: { url:"http://20.224.30.75:8545", chainId:637707033,//change it with your node chainID accounts: ["YOUR ACCOUNT PRIVATE KEY"], }, },};
Step 6: Write the deployment script
Now that our contract is written and our configuration file is good to go, it’s time to write our contract deploy script.
Navigate to the scripts/ folder and create a new file called deploy.js, adding the following contents to it:
cd ..
mkdir scripts
cd scripts
const {ethers} =require("hardhat");asyncfunctionmain() {constGreeter=awaitethers.getContractFactory("Greeter");// Start deployment, returning a promise that resolves to a contract objectconstgreeter=awaitGreeter.deploy("Hello World!"); console.log("Contract deployed to address:",greeter.address);}main().then(() =>process.exit(0)).catch(error => {console.error(error);process.exit(1); });
asyncfunctionmain() {constStorage=awaitethers.getContractFactory("Storage");// Start deployment, returning a promise that resolves to a contract objectconststorage=awaitStorage.deploy("Hello World!"); console.log("Contract deployed to address:",storage.address);}main().then(() =>process.exit(0)).catch(error => {console.error(error);process.exit(1); });
asyncfunctionmain() {constPayable=awaitethers.getContractFactory("Payable");// Start deployment, returning a promise that resolves to a contract objectconstpayable=awaitPayable.deploy("Hello World!"); console.log("Contract deployed to address:",payable.address);}main().then(() =>process.exit(0)).catch(error => {console.error(error);process.exit(1); });
Hardhat does an amazing job explaining each of these lines of code in their Contracts tutorial. We’ve adopted their explanations here.
A ContractFactory in ethers.js is an abstraction used to deploy new smart contracts, so Greeter here is a factory for instances of our hello world contract. When using the hardhat-ethers plugin ContractFactory andContract, instances are connected to the first signer (owner) by default.
constgreeter=awaitGreeter.deploy();
Calling deploy() on a ContractFactory will start the deployment and return a Promise that resolves to a Contract object. This object has a method for each of our smart contract functions.
Step 7: Deploy the contract
Let's compile our contract to make sure everything is working so far. The compile task is one of the built-in Hardhat tasks.
From the command line, run:
npxhardhatcompile
You might be warned about the SPDX license identifier not provided in the source file, but there is no need to worry about that.
We're finally ready to deploy our smart contract! Navigate to the command line and run: