Waffle say hello world tutorial with hardhat and ethers
In this Waffle(opens in a new tab) tutorial, we will learn how to set up a simple "Hello world" smart contract project, using hardhat(opens in a new tab) and ethers.js(opens in a new tab). Then we will learn how to add a new functionality to our smart contract and how to test it with Waffle.
Let's start by creating a new project:
yarn init
or
npm init
and installing required packages:
yarn add -D hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai
or
npm install -D hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai
Next step is creating a sample hardhat project by running npx hardhat
.
888 888 888 888 888888 888 888 888 888888 888 888 888 8888888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888888 888 "88b 888P" d88" 888 888 "88b "88b 888888 888 .d888888 888 888 888 888 888 .d888888 888888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888👷 Welcome to Hardhat v2.0.3 👷? What do you want to do? …❯ Create a sample projectCreate an empty hardhat.config.jsQuitKyerɛ biribiara
Select Create a sample project
Our project's structure should look like this:
1MyWaffleProject2├── contracts3│ └── Greeter.sol4├── node_modules5├── scripts6│ └── sample-script.js7├── test8│ └── sample-test.js9├── .gitattributes10├── .gitignore11├── hardhat.config.js12└── package.jsonKyerɛ biribiara
Now let's talk about some of these files:
- Greeter.sol - our smart contract written in solidity;
1contract Greeter {2string greeting;34constructor(string memory _greeting) public {5console.log("Deploying a Greeter with greeting:", _greeting);6greeting = _greeting;7}89function greet() public view returns (string memory) {10return greeting;11}1213function setGreeting(string memory _greeting) public {14console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);15greeting = _greeting;16}17}Kyerɛ biribiaraHwɛ so kyerɛw bi
Our smart contract can be divided into three parts:
- constructor - where we declare a string type variable called
greeting
, - function greet - a function that will return the
greeting
when called, - function setGreeting - a function that allows us to change the
greeting
value.
- sample-test.js - our tests file
1describe("Greeter", function () {2 it("Should return the new greeting once it's changed", async function () {3 const Greeter = await ethers.getContractFactory("Greeter")4 const greeter = await Greeter.deploy("Hello, world!")56 await greeter.deployed()7 expect(await greeter.greet()).to.equal("Hello, world!")89 await greeter.setGreeting("Hola, mundo!")10 expect(await greeter.greet()).to.equal("Hola, mundo!")11 })12})Kyerɛ biribiaraHwɛ so kyerɛw bi
Next step consists of compiling our contract and running tests:
Waffle tests use Mocha (a test framework) with Chai (an assertion library). All you have to do is run npx hardhat test
and wait for the following message to appear.
✓ Should return the new greeting once it's changed
Everything looks great so far, let's add some more complexity to our project
Imagine a situation where someone adds an empty string as a greeting. It wouldn't be a warm greeting, right?
Let's make sure that doesn't happen:
We want to use solidity's revert
when someone passes an empty string. A good thing is that we can easily test this functionality with Waffle's chai matcher to.be.revertedWith()
.
1it("Should revert when passing an empty string", async () => {2 const Greeter = await ethers.getContractFactory("Greeter")3 const greeter = await Greeter.deploy("Hello, world!")45 await greeter.deployed()6 await expect(greeter.setGreeting("")).to.be.revertedWith(7 "Greeting should not be empty"8 )9})Kyerɛ biribiaraHwɛ so kyerɛw bi
Looks like our new test didn't pass:
Deploying a Greeter with greeting: Hello, world!Changing greeting from 'Hello, world!' to 'Hola, mundo!'✓ Should return the new greeting once it's changed (1514ms)Deploying a Greeter with greeting: Hello, world!Changing greeting from 'Hello, world!' to ''1) Should revert when passing an empty string1 passing (2s)1 failingKyerɛ biribiara
Let's implement this functionality into our smart contract:
1require(bytes(_greeting).length > 0, "Greeting should not be empty");Hwɛ so kyerɛw bi
Now, our setGreeting function looks like this:
1function setGreeting(string memory _greeting) public {2require(bytes(_greeting).length > 0, "Greeting should not be empty");3console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);4greeting = _greeting;5}Hwɛ so kyerɛw bi
Let's run tests again:
✓ Should return the new greeting once it's changed (1467ms)✓ Should revert when passing an empty string (276ms)2 passing (2s)
Congrats! You made it :)
Conclusion
We made a simple project with Waffle, Hardhat and ethers.js. We learned how to set up a project, add a test and implement new functionality.
For more great chai matchers to test your smart contracts, check official Waffle's docs(opens in a new tab).
Nsakraeɛ edi akyire: @pettinarip(opens in a new tab), December 8, 2023