As a web3 developer, you can play with Ethereum blockchain using Ethers.js
to get a deeper understanding. This 3-parts tutorial lists 12 tasks for you.
Ethers.js
is a Javascript API for Ethereum blockchain which can work with Mainnet, testnet such as Ropsten, Rinkeby, local testnet, Layer 2 and sidechains.
We will use Hardhat Ethereum development environment to set up a playground as it can provide all the components we need:
- local testnet: Hardhat Network based on
@ethereumjs/vm
- interactive console: Hardhat console
- solidity development tools: Hardhat
- Ethers.js: Ethereum Javascript API
Hardhat brings in Ethers.js
with plugin hardhat-ethers
.
Ethers.js documents: https://docs.ethers.io/v5/
Task 1: Setup Ethers.js playground with Hardhat
You need to have node.js
and yarn
installed in your computer.
Task 1.1 Install Hardhat
Run in command line:
mkdir playeth && cd playeth
yarn add hardhat
Task 1.2 Init Hardhat project
You can init a Hardhat project by running:
yarn hardhat
Choose Option "Create an advanced sample project that uses TypeScript". A sample hardhat project will be created.
Task 1.3 Run a stand-alone local testnet
In another terminal, run a stand-alone local testnet "Hardhat Network" by running:
yarn hardhat node
More about in-process and stand-alone mode of Hardhat Network can be found here.
Task 1.4 Enter Hardhat console
Run Hardhat console connecting to blockchain testnet localhost:
yarn hardhat console --network localhost
Check Ethers.js
version and get the current blocknumber in console:
ethers.version
//'ethers/5.5.3'
await ethers.provider.getBlockNumber()
//0
Now, you have an Ethers.js playground with an interactive console and a local testnet.
Task 2: Have a look at blockchain
Currently Hardhat console is connected to a local blockchain testnet at http://localhost:8545. Let's have a look at the blockchain with Ethers.js
.
Ethers.js
provide "Provider" and "Signer" for interaction with blockchain. Its document explains:
A Provider in ethers is a read-only abstraction to access the blockchain data.
A Signer in ethers is an abstraction of an Ethereum Account, which can be used to sign messages and transactions and send signed transactions to the Ethereum Network to execute state changing operations.
Task 2.1 check connection
We can access provider ether.provider
,an Ethers.js wrapped Ethereum RPC provider.
const provider = ethers.provider
ethers.provider.connection
// { url: 'http://localhost:8545' }
Task 2.2 check network of provider
await provider.getNetwork()
//{ chainId: 31337, name: 'unknown' }
Ethereum network with chainId 31337 is local testnet at 127.0.0.1:8545
.
Task 2.3 get signer
The big difference between ethers.js
and web3.js
is that it separate signer from provider. Provider can only read data from blockchain while signer can send transactions to change data on blockchain. Ethers.js docs explain signer:
const signer = await provider.getSigner()
//this is a JsonRpcSigner
await signer.getAddress()
//'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
Task 2.4 get all the accounts with Hardhat console
Hardhat console is running with 20 test accounts.
accounts = await ethers.getSigners();
accounts.length
//20
for (const account of accounts) console.log(account.address)
Result:
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
0x70997970C51812dc3A010C7d01b50e0d17dc79C8
0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC
0x90F79bf6EB2c4f870365E785982E1f101E93b906
...
There is a sample hardhat plugin accounts
, you can run it in command line:
yarn hardhat accounts
Task 3: Get ETH balance of an address
We can use getBalance()
to get ETH balance of an address (reference link). Since we only need to read data from blockchain, we will use provider
instead of signer
.
Task 3.1 getBalance
firstaddress = accounts[0].address
balance = await provider.getBalance(firstaddress)
//BigNumber { value: "10000000000000000000000" }
The return result is BigNumber, which means 10000.0 ethers. Every account has 10000.0 test ethers in Hardhat local testnet.
Task 3.2 formatEther
We can use ethers.js utilities for Display Logic and Input to display it in a friendly manner.
ethers.utils.formatEther(balance)
//'10000.0'
Task 3.3 parseEther
We can also transfer from string to Bignumber easily.
ethers.utils.parseEther("0.5");
//BigNumber { value: "500000000000000000" }
Task 4: Send ETH from one address to another
Task 4.1 Send ETH using MetaMask
You can use MetaMask to transfer test ethers between accounts:
- Switch network to Localhost8545 in MetaMask
- Import account #0 with privateKey
- Transfer 100 test ETH from Account #0 to Account #1
Accounts #0: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
privateKey: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
Accounts #1: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
Address #00 and privateKey to add account to MetaMask. Address #1 is the receiver.
Note: Remember to change chainId from "1337" to "31337" in MetaMask network setting.
You can check the results in console:
provider = ethers.provider
acccount_1='0x70997970C51812dc3A010C7d01b50e0d17dc79C8'
await provider.getBalance(acccount_1).then((r)=>console.log(ethers.utils.formatEther(r)))
//'10100.0'
Send ETH from one address to another can be done by call sendTransaction
using Ethers.js. Related Ether.js docs is here.
Detailed explanation of Transaction can be found in Andreas M. Antonopoulos's book Mastering Ethereum Chapter 6 Transactions.
Task 4.2 Prepare for sendTransaction
signer = await ethers.provider.getSigner()
send_address = await signer.getAddress()
accounts = await ethers.getSigners();
to_address = accounts[1].address
nonce = await signer.getTransactionCount()
gas_price = await signer.getGasPrice()
gas_limit = ethers.utils.hexlify(21000)
value = ethers.utils.parseUnits('100.0')
Task 4.3 Format transaction
tx = {
from: send_address,
to: to_address,
value: value,
nonce: nonce,
gasLimit: gas_limit,
gasPrice: gas_price,
}
Task 4.4 Call sendTransaction
Send transaction:
await signer.sendTransaction(tx)
Task 4.5 Check results
provider = ethers.provider
await provider.getBalance(to_address).then((r)=>console.log(ethers.utils.formatEther(r)))
//'10200.0'
await provider.getBalance(send_address).then((r)=>console.log(ethers.utils.formatEther(r)))
//'9799.999923543659375'
The balance of send_address is a little less than 9800.0 because it paid some ether as gas fee for the transactions.
When sendTransaction
called, it returns receipt of the transaction executed on the blockchain.
{
hash: '0x8915f9df88e4f2af2eefe05922e026c66723678b7df3de11e525a03c11b391a2',
type: 0,
accessList: null,
blockHash: '0xfae5411b597d02b1c36a6842f14db5aad7ac2b974474f06355bd1b4eb5d438ed',
blockNumber: 1,
transactionIndex: 0,
confirmations: 1,
from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
gasPrice: BigNumber { value: "1875000000" },
gasLimit: BigNumber { value: "135168" },
to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
value: BigNumber { value: "100000000000000000000" },
nonce: 0,
data: '0x',
r: '0x116a4e2acba174b04a6f44248fef0170012d956d20e03d93b1b3368fce09c8e8',
s: '0x14f1104a1fa98fed53a06a4a7a6464503d1f8a822191c022a2180e45c258809b',
v: 62710,
creates: null,
chainId: 31337,
wait: [Function (anonymous)]
}
You can also have a look at the terminal running yarn hardhat node
. Transaction details are logged on the screen:
Transaction: 0x8915f9df88e4f2af2eefe05922e026c66723678b7df3de11e525a03c11b391a2
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
To: 0x70997970c51812dc3a010c7d01b50e0d17dc79c8
Value: 100 ETH
Gas used: 21000 of 135168
Block #1: 0xfae5411b597d02b1c36a6842f14db5aad7ac2b974474f06355bd1b4eb5d438ed
Tutorial List:
1. A Concise Hardhat Tutorial(3 parts)
https://dev.to/yakult/a-concise-hardhat-tutorial-part-1-7eo
2. Understanding Blockchain with ethers.js
(5 parts)
https://dev.to/yakult/01-understanding-blockchain-with-ethersjs-4-tasks-of-basics-and-transfer-5d17
3. Tutorial : build your first DAPP with Remix and Etherscan (7 Tasks)
https://dev.to/yakult/tutorial-build-your-first-dapp-with-remix-and-etherscan-52kf
4. Tutorial: build DApp with Hardhat, React and ethers.js (6 Tasks)
https://dev.to/yakult/a-tutorial-build-dapp-with-hardhat-react-and-ethersjs-1gmi
5. Tutorial: build DAPP with Web3-React and SWR
https://dev.to/yakult/tutorial-build-dapp-with-web3-react-and-swr-1fb0
6. Tutorial: write upgradeable smart contract (proxy) using OpenZeppelin(7 Tasks)
7. Tutorial: Build a NFT marketplace DApp like Opensea(5 Tasks)
https://dev.to/yakult/tutorial-build-a-nft-marketplace-dapp-like-opensea-3ng9
If you find this tutorial helpful, follow me at Twitter @fjun99
Top comments (2)
Running
npx hardhat node
and trying to accesshttp://127.0.0.1:8545/
gets me this error:it there something wrong with your config.js?
maybe you can download hardhat in another directory and run again.