Hardhat Setup for NFT Token¶
Now that we have implemented our token in Truffle, surely, you're eager to know how Hardhat can be of service.
It's framework or toolkit #2 that we're trying. Since we already have some experience with Truffle, we can also make some comparison here.
Let's start with the setup.
Install Hardhat¶
Hardhat is, like Truffle, JavaScript (node) based. That means, you install it via the node package manager.
But, unlike Truffle, it is project dependent and installed as a dev-dependency.
Create a new folder in our nft-project folder called hardhat.
mkdir -p nft-project/hardhat
code nft-project/hardhat
Now we initialize an empty npm project:
npm init -y
and then install Hardhat as a dev-dependency:
npm install --save-dev hardhat
Setup Hardhat¶
Now hardhat is installed as a dev-dependency. To setup a new hardhat project, you can run
npx hardhat
which will run some sort of wizard.
Cool thing about hardhat, you can also integrate it into a Typescript Project. That might be a big plus on one hand, but at the end, you just need the ABI and the address.
For this one, we will still start with a general JavaScript project. So, from the selection, select "Create a JavaScript project"
Select the right folder, and for .gitignore
and hardhat-toolbox
say "y".
What you'll end up with is a sample project with a contract, a deploy script in scripts and a test in the test folder.
You could now run
npx hardhat test
to run the tests, and it looks very much like in truffle. The reason is, hardhat also uses Mocha as a test-runner. The difference is, there isn't so much magic happening behind the scenes.
Compilation and the ABI Array¶
Similar to Truffle, when you run
npx hardhat compile
Hardhat will see which compiler it needs to use from the hardhat.config.js
file in the root folder of the project, then compile the contracts and put the artifacts in the artifacts/contracts
folder. There are two files actually, an artifact with ABI and bytecode. And a debug file, that either contains the source, compiled source and more info, or a pointer to a debug file.
However, it does not contain an address or any more info. So, how is deployment working with Hardhat now?!
Deployment with Hardhat¶
In hardhat you have, at least by default, no Address management like in Truffle. It's a lot more transparent, especially for newcomers, for the better or for worse. Hardhat puts a lot more responsibility into the developers hand and doesn't give you a clear structure. With one exception: Scripts are in the scripts folder.
Hardhat also comes with a development node, which looks and feels very much like Ganache.
Start it in one terminal with
npx hardhat node
Then run in the other terminal
npx hardhat run --network localhost scripts/deploy.js
If you inspect the deploy.js script, you will see, Hardhat uses by default ethers.js. We haven't really used Ethers.js yet, so, its a good time to start using it by example.
Add our NFT to HardHat¶
Let's add our NFT and remove the existing Lock contract.
rm contracts/Lock.sol
rm scripts/deploy.js
rm test/Lock.js
rm -rf artifacts
rm -rf cache
Let's start with a blank Project.
Add a Spacebear.sol file in the contracts folder with the same content as the one from Truffle, except the console.log - more on that in a second:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract Spacebear is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("Spacebear", "SBR") {}
function _baseURI() internal pure override returns (string memory) {
return "https://ethereum-blockchain-developer.com/2022-06-nft-truffle-hardhat-foundry/nftdata/";
}
function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
}
function buyToken() public payable {
uint256 tokenId = _tokenIdCounter.current();
require(msg.value == tokenId * 0.1 ether, "Not enough funds sent");
_tokenIdCounter.increment();
_safeMint(msg.sender, tokenId);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
pure
override(ERC721)
returns (string memory)
{
return string(abi.encodePacked(_baseURI(),"_",tokenId+1,".json"));
}
}
If you run
npx hardhat compile
you'll see that openzeppelin is missing the contracts, so let's install them too:
npm install @openzeppelin/contracts
and then again
npx hardhat compile
One thing you might have witnessed: compilation is about a bazillion times faster than in Truffle. And you are right. Hardhat is blazing fast. Consistently. Something a lot of people like over Truffle.
Let's see in the next lab how we can deploy our smart contract.