Probably for those who are just starting to learn Ethereum in particular as well as EVM-based platforms in general know Truffle
(a framework supporting compile, deploy smart contract). However, when it comes to developing larger, more complex smart contracts, it exposes some limitations such as consuming a lot of gas, long deploying time, … With Hardhat
, the framework gives us options, somewhat superior features to do with more complex smart contract systems.
1. General introduction
Like Truffle , Hardhat is a development environment for compiling, deploying, testing and debugging Ethereum Dapps.
Some of Hardhat ‘s standout feature points
- Integrated local
hardhat
network, easy to run and debug code on local. - Debug is easier: With Hardhat , we can debug Solidity code more easily when we can console.log out variables (Solidity doesn’t support console.log)
- Plugins system: Help developers to add functionality, depending on each specific project
- TypeScript support
2. Installation
We also set up a trial of a small sample project with hardhat
. We perform the operations below
1 2 3 4 5 | <span class="token function">mkdir</span> hardhat-tutorial <span class="token builtin class-name">cd</span> hardhat-tutorial <span class="token function">npm</span> init --yes <span class="token function">npm</span> <span class="token function">install</span> --save-dev hardhat |
1 2 | npx hardhat |
We will choose option 1 (create a sample project)
Continue to select the necessary options
In the end, Hardhat ‘s sample project directory structure should look like this
Here we take the corresponding structure of the Truffle Box
Basically the project structure of the 2 tools is relatively similar
- The
contracts
folder contains the source code of the smart contracts - The
scripts
andmigrations
directory contains scripts written in Javascript for compiling and deploying smart contracts. - The
test
directory contains the unit tests written for the contract - 2 The files
hardhat.config.js
andtruffle-config.js
containhardhat.config.js
such as networks, wallet address, compiler …
3. Use
Greeter.sol
We have a smart contract Greeter.sol
file in the contracts
folder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | pragma solidity <span class="token operator">^</span> <span class="token number">0.7</span> <span class="token number">.0</span> <span class="token punctuation">;</span> <span class="token comment">// Thư viện giúp sử dụng console.log trong solidity để debug</span> <span class="token keyword">import</span> <span class="token string">"hardhat/console.sol"</span> <span class="token punctuation">;</span> contract Greeter <span class="token punctuation">{</span> string greeting <span class="token punctuation">;</span> <span class="token function">constructor</span> <span class="token punctuation">(</span> <span class="token parameter">string memory _greeting</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">"Deploying a Greeter with greeting:"</span> <span class="token punctuation">,</span> _greeting <span class="token punctuation">)</span> <span class="token punctuation">;</span> greeting <span class="token operator">=</span> _greeting <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">greet</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">public</span> view <span class="token function">returns</span> <span class="token punctuation">(</span> <span class="token parameter">string memory</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> greeting <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">function</span> <span class="token function">setGreeting</span> <span class="token punctuation">(</span> <span class="token parameter">string memory _greeting</span> <span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">"Changing greeting from '%s' to '%s'"</span> <span class="token punctuation">,</span> greeting <span class="token punctuation">,</span> _greeting <span class="token punctuation">)</span> <span class="token punctuation">;</span> greeting <span class="token operator">=</span> _greeting <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
hardhat.config.js
The hardhat.config.js
file is where we define networks, the compiler, the build file directory, …
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'@nomiclabs/hardhat-waffle'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">task</span> <span class="token punctuation">(</span> <span class="token string">"accounts"</span> <span class="token punctuation">,</span> <span class="token string">"Prints the list of accounts"</span> <span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> accounts <span class="token operator">=</span> <span class="token keyword">await</span> ethers <span class="token punctuation">.</span> <span class="token function">getSigners</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span> <span class="token keyword">const</span> account <span class="token keyword">of</span> accounts <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> account <span class="token punctuation">.</span> address <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> solidity <span class="token operator">:</span> <span class="token string">'0.7.3'</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
A more complete version
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> defaultNetwork <span class="token operator">:</span> <span class="token string">'hardhat'</span> <span class="token punctuation">,</span> networks <span class="token operator">:</span> <span class="token punctuation">{</span> hardhat <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> development <span class="token operator">:</span> <span class="token punctuation">{</span> url <span class="token operator">:</span> <span class="token string">'http://127.0.0.1:8545'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> quorum <span class="token operator">:</span> <span class="token punctuation">{</span> url <span class="token operator">:</span> <span class="token string">'http://127.0.0.1:22000'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> solidity <span class="token operator">:</span> <span class="token punctuation">{</span> version <span class="token operator">:</span> <span class="token string">'0.6.2'</span> <span class="token punctuation">,</span> settings <span class="token operator">:</span> <span class="token punctuation">{</span> optimizer <span class="token operator">:</span> <span class="token punctuation">{</span> enabled <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> runs <span class="token operator">:</span> <span class="token number">200</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> paths <span class="token operator">:</span> <span class="token punctuation">{</span> sources <span class="token operator">:</span> <span class="token string">'./contracts'</span> <span class="token punctuation">,</span> tests <span class="token operator">:</span> <span class="token string">'./test'</span> <span class="token punctuation">,</span> cache <span class="token operator">:</span> <span class="token string">'./cache'</span> <span class="token punctuation">,</span> artifacts <span class="token operator">:</span> <span class="token string">'./artifacts'</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> mocha <span class="token operator">:</span> <span class="token punctuation">{</span> timeout <span class="token operator">:</span> <span class="token number">20000</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
scripts/sample-script.js
Unlike Truffle , Hardhat does not need to deploy “buffer” to add contract Migration.sol
, so it can save 1 amount of gas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">const</span> hre <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">"hardhat"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// load contract Greeter</span> <span class="token keyword">const</span> Greeter <span class="token operator">=</span> <span class="token keyword">await</span> hre <span class="token punctuation">.</span> ethers <span class="token punctuation">.</span> <span class="token function">getContractFactory</span> <span class="token punctuation">(</span> <span class="token string">"Greeter"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Truyền tham số cho hàm constructor</span> <span class="token keyword">const</span> greeter <span class="token operator">=</span> <span class="token keyword">await</span> Greeter <span class="token punctuation">.</span> <span class="token function">deploy</span> <span class="token punctuation">(</span> <span class="token string">"Vui Tet Cung Viblo"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// deploy contract</span> <span class="token keyword">await</span> greeter <span class="token punctuation">.</span> <span class="token function">deployed</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">"Greeter deployed to:"</span> <span class="token punctuation">,</span> greeter <span class="token punctuation">.</span> address <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">main</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> process <span class="token punctuation">.</span> <span class="token function">exit</span> <span class="token punctuation">(</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">catch</span> <span class="token punctuation">(</span> <span class="token parameter">error</span> <span class="token operator">=></span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">error</span> <span class="token punctuation">(</span> error <span class="token punctuation">)</span> <span class="token punctuation">;</span> process <span class="token punctuation">.</span> <span class="token function">exit</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Deploy
1 2 | npx hardhat run scripts/sample-script.js |
If we want to deploy the code contract in other networks, we add the --network
option
1 2 | npx hardhat run scripts/sample-script.js --network development |
So the console.log we put in the constructor
function has been executed
4. More advanced features
Compile contracts in different Solidity versions
hardhat.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> solidity <span class="token operator">:</span> <span class="token punctuation">{</span> compilers <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> version <span class="token operator">:</span> <span class="token string">"0.5.5"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> version <span class="token operator">:</span> <span class="token string">"0.6.7"</span> <span class="token punctuation">,</span> settings <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Hardhat in this case would use the 0.5.5
compiler for pragma solidity ^0.5.0
and 0.6.7
contracts with pragma solidity ^0.6.0
contracts
In TH contract defines the compiler pragma solidity >=0.5.0
, Hardhat will choose the highest compiler 0.6.7
Or we can configure details for which contracts to use which compiler
1 2 3 4 5 6 7 8 9 10 11 12 | module <span class="token punctuation">.</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span> solidity <span class="token operator">:</span> <span class="token punctuation">{</span> compilers <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token operator">...</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> overrides <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string">"contracts/Foo.sol"</span> <span class="token operator">:</span> <span class="token punctuation">{</span> version <span class="token operator">:</span> <span class="token string">"0.5.5"</span> <span class="token punctuation">,</span> settings <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Run a private blockchain network such as ganache
In the past, I used to use ganache to deploy smart contract locally with truffle for testing, of course I can use truffle develop
but ganache has more options and ways to configure parameters. With Hardhat , I can also use Hardhat , it also supports the simulation of local versions of hardforks of Ethereum.
1 2 | npx hardhat node |
By default the network will run at port 8545
, we can add parameters to adjust as desired
1 2 3 4 5 | --fork --fork-block-number --hostname --port |
Conclude
In general, Hardhat is a very powerful, full-featured tool needed to help developers deploy smart contracts on Ethereum. Hardhat usage is quite similar to Truffle , in addition it also overcomes some bad points from the opponent.