Ethers
Ethers is a Javascript library for building on EVM-compatible networks.
It allows developers to interact with smart contracts, send transactions, and retrieve data from the network.
Installation​
This guide assumes you have the latest version of Node.js installed.
To install ethers
in your project, run the following command:
_10npm install ethers
Initializing Ethers With Flow​
To use ethers
in your project, start by importing the module and initializing a new Provider with Flow's JSON-RPC endpoint. We are specifying Flow Previewnet in this example.
_10const { ethers } = require('ethers')_10const provider = new ethers.providers.JsonRpcProvider('https://previewnet.evm.nodes.onflow.org')
Currently, only Flow Previewnet is available. More networks are coming soon - see here for more info.
Querying The Blockchain​
ethers
provides a number of methods for querying the blockchain, such as getting the latest block number, querying account balances, and more.
You can try using some of these methods to verify that your ethers
provider is working correctly.
_16// Look up the current block number (i.e. height)_16await provider.getBlockNumber()_16// 19227915_16_16// Get the current balance of an account_16balance = await provider.getBalance("0x1234")_16// 4085267032476673080n_16_16// Since the balance is in attoFlow, you may wish to display it_16// in FLOW instead._16ethers.formatEther(balance)_16// '4.08526703247667308'_16_16// Get the next nonce required to send a transaction_16await provider.getTransactionCount("ethers.eth")_16// 2
For more information about other queries you can make ethers
, please see the official documentation.
Interacting With Smart Contracts​
The ethers
library allows developers to interact with smart contracts via the Contract
object.
For this example we will use the following Storage
contract, deployed on the Flow Previewnet to the address 0x4c7784ae96e7cfcf0224a95059573e96f03a4e70
. Note that anyone can interact with this contract, as it is deployed on a public network, so state may not always be as expected.
We recommend deploying your own contract, which can be done using Hardhat or Remix.
_14// SPDX-License-Identifier: MIT_14pragma solidity ^0.8.0;_14_14contract Storage {_14 uint256 public storedData;_14_14 function store(uint256 x) public {_14 storedData = x;_14 }_14_14 function retrieve() public view returns (uint256) {_14 return storedData;_14 }_14}
The ABI for this contract can be generated using the solc
compiler, or another tool such as Hardhat or Remix.
Now that we have both the ABI and address of the contract, we can create a new Contract
object for use in our application.
_40// Replace with the ABI of the deployed contract_40const abi = [_40 {_40 "inputs": [],_40 "stateMutability": "nonpayable",_40 "type": "constructor"_40 },_40 {_40 "inputs": [_40 {_40 "internalType": "uint256",_40 "name": "x",_40 "type": "uint256"_40 }_40 ],_40 "name": "store",_40 "outputs": [],_40 "stateMutability": "nonpayable",_40 "type": "function"_40 },_40 {_40 "inputs": [],_40 "name": "retrieve",_40 "outputs": [_40 {_40 "internalType": "uint256",_40 "name": "",_40 "type": "uint256"_40 }_40 ],_40 "stateMutability": "view",_40 "type": "function"_40 }_40]_40_40// Replace with the address of the deployed contract_40const contractAddress = "0x4c7784ae96e7cfcf0224a95059573e96f03a4e70"_40_40// Create a new contract object with the ABI and address connected to the provider_40const contract = new ethers.Contract(contractAddress, abi, provider)
We can now interact with the contract on the network by using the contract
object.
Reading State​
State can be read from the contract by calling the contract's "constant" methods (i.e. those which do not modify the state of the contract). This will not not send a transaction.
_10// Retrieve the current value stored in the contract_10// (this is using the `retrieve` method from the contract with no arguments)_10const result = await contract.retrieve()_10_10console.log(result) // Current value stored in the contract
Changing State​
We can mutate the state of the contract by sending a transaction to the network.
In order to send a transaction to the network, you will need an account with sufficient funds to pay for the transaction.
If you do not have an account yet, you can create one using the following command from your project's root directory:
_10node -e "console.log(require('ethers').Wallet.createRandom())"
Note that this is not a secure way to generate an account, and you should use a more secure method in a production environment.
For Flow Previewnet, you can fund your account using the Flow Faucet.
For this demonstration, we will use a private key to create an ethers Signer
object.
_10// You must replace this with the private key of the account you wish to use_10const signer = new ethers.Wallet('0x1234', provider)
Then, we can sign a transaction using the user's account and send it to the network.
_13const newValue = 1337 // Replace with any value you want to store_13_13// We must connect the signer to the contract to send a transaction_13const connectedContract = contract.connect(signer)_13_13// Send a transaction to the contract to store a new value_13const tx = await connectedContract.store(newValue)_13_13// Wait for the transaction to be mined_13await tx.wait()_13_13// Show the transaction_13console.log(tx) // { hash: '0x1234', ... }
Now that the transaction has been sent, the contract's state should have updated. We an verify this by querying the contract's state again:
_10const result = await contract.retrieve()_10console.log(result) // New value stored in the contract
For more information about using smart contracts in ethers
, see the official documentation.