💻Setup a local environment
It's recommended to get familiar with the basic tooling and technologies that are used by Solidity developers before diving into the challenges.
Tip Some instructions are unclear? it's probably intentional - deciphering technical instructions is a major skill needed by professionals. Still struggling? we'd be happy to support in our Discord.
Install Hardhat
Hardhat is our preferred ethereum development environment to use. If you are already used to another environment, it wouldn't hurt learning a new techonology. It's quite simple and supports multiple plugins. ( See example hardhat-foundry ). Install Hardhat globally (from your terminal, anywhere):
npm i -g hardhat --save-dev
npm i -g hardhat-shorthand
Run hardhat
and quit immediately, just to ensure it is installed properly.
Play with Hardhat
Create a new folder with an Hardhat project by running hardhat init
Follow the options/questions based on your intuition, if something doesn't seem right - retry.
You should end up with a folder structure similar to this:
.
├── artifacts // Compiled contract bytecode and metadata
├── cache // Ignore
├── contracts // The source code of the contracts
├── hardhat.config.js // Hardhat configuration
├── node_modules // Node.js packages
├── package-lock.json // Packages index
├── package.json // Packages index
├── scripts // Developer scripts or snippets
└── test // Unit tests, and easy interaction with the contract
Our focus at the start should be the contracts
, and the test
folders.
contracts
- where the source code is, the actual contract and logic, and where auditors mostly work their magic.
test
- JavaScript unit tests. You might wonder now - why JavaScript? how is this code related to the code deployed to the blockchain? etc.
Don't worry - it is only used for local testing during the smart contract developement phase. Hardhat provides an abstraction layer which makes our lives much easier, by giving us many tools to interact with a fake local ethereum network embedded inside of it. Hardhat also abstracts `ethers.js`, and others, to give us convenient JavaScript interaction capabilities with our fake local network.
So for example:
const LockContract = await ethers.getContractFactory("Lock")
getContractFactory
takes the Lock.sol
contract's name as a parameter and returns a factory object that can be used to deploy or interact with instances of the contract.
We will now try a more complicated example, in which we will:
We deploy a simple token contract (
SimpleToken
) with an initial supply.We transfer some amount of tokens from the deployer to
user1
.Finally, we check
user1
's balance to ensure the transfer was successful.
Follow the comments to ensure you understand.
const { ethers } = require('hardhat');
const { expect } = require('chai');
describe('Basic Token Interaction', function () {
let deployer, user1, user2;
let token;
const INITIAL_SUPPLY = 1000000n * 10n ** 18n;
const TRANSFER_AMOUNT = 100n * 10n ** 18n;
before(async function () {
// Setup scenario
[deployer, user1, user2] = await ethers.getSigners();
// Deploy a simple token contract
const TokenContract = await ethers.getContractFactory('SimpleToken', deployer);
token = await TokenContract.deploy(INITIAL_SUPPLY);
// Check the total supply of the token
expect(await token.totalSupply()).to.eq(INITIAL_SUPPLY);
});
it('Token Transfer', async function () {
// Transfer tokens from deployer to user1
await token.connect(deployer).transfer(user1.address, TRANSFER_AMOUNT);
// Check user1's token balance
expect(await token.balanceOf(user1.address)).to.eq(TRANSFER_AMOUNT);
});
it('Check Balance', async function () {
// User1 checks their balance
const balance = await token.balanceOf(user1.address);
// Expect balance to be equal to the transferred amount
expect(balance).to.eq(TRANSFER_AMOUNT);
});
});
After we've gotten a grasp for what hardhat is, we can go through a few more commands:
Compiling the contract
This one is quite simple, try to run hh compile
and inspect what happened.
Hardhat Tasks
To get a grasp of what hardhat tasks are, try pasting this task into hardhat.config.js
:
task("accounts", "Prints the list of accounts", async () => {
const accounts = await ethers.getSigners();
for (const account of accounts) {
console.log(account.address)
}
})
Then run hh acounts
- you know you're good when you see a bunch of hex addresses.
Hardhat tests
hh test
- try to figure out what it did
Then navigate to the main contract code (e.g. contracts/Lock.sol
) and utilize hardhat's logging "hack":
Add
import "hardhat/console.sol"
to the contract, if not already presentFind a decent place to add
console.log("hi")
hh test
Try to see your logged string
Although simple, this is a powerful utility which will help us down the line a lot.
Fork Mainnet
This is a powerful feature, instructing hardhat to use mainnet contracts on our fake hardhat blockchain - allowing us to benefit real data in our fake environment.
Get free API key from https://app.infura.io
In the dashboard, where the API key is, copy the ethereum network url and paste as follows in
hardhat.config.js
:
module.exports = {
solidity: "0.8.19",
networks: {
hardhat: {
forking: {
url: "https://mainnet.infura.io/v3/<YOUR-kEY>"
}
}
}
};
Then run
hh test
You should see a warning about running from a fork to indicate success.
Debugging Hardhat tests in VSCode
We've already demonstrated above how to make use of the hardhat/console.sol
functionality to increase understanding of contracts during runtime.
Since the hardhat unit tests are just JavaScript, they are very trivial to debug.
Here's a typical vscode launch.json
configuration, in yarn + hardhat based projects:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Yarn Hardhat Debugging",
"console": "integratedTerminal",
"runtimeExecutable": "yarn",
"runtimeArgs": [
"hardhat",
"test",
"${workspaceFolder}/test/SomeTest.js"
]
}
]
}
Pressing the debug button on a test JavaScript file should prompt you to manually enter a launch.json
configuration. You will then have to customize it once to your own project, and debugging the tests would be a breeze!
Last updated