Skip to main content

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​

info

This guide assumes you have the latest version of Node.js installed.

To install ethers in your project, run the following command:


_10
npm 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.


_10
const { ethers } = require('ethers')
_10
const provider = new ethers.providers.JsonRpcProvider('https://previewnet.evm.nodes.onflow.org')

info

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)
_16
await provider.getBlockNumber()
_16
// 19227915
_16
_16
// Get the current balance of an account
_16
balance = await provider.getBalance("0x1234")
_16
// 4085267032476673080n
_16
_16
// Since the balance is in attoFlow, you may wish to display it
_16
// in FLOW instead.
_16
ethers.formatEther(balance)
_16
// '4.08526703247667308'
_16
_16
// Get the next nonce required to send a transaction
_16
await 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
_14
pragma solidity ^0.8.0;
_14
_14
contract 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
_40
const 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
_40
const contractAddress = "0x4c7784ae96e7cfcf0224a95059573e96f03a4e70"
_40
_40
// Create a new contract object with the ABI and address connected to the provider
_40
const 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)
_10
const result = await contract.retrieve()
_10
_10
console.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.

info

If you do not have an account yet, you can create one using the following command from your project's root directory:


_10
node -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
_10
const signer = new ethers.Wallet('0x1234', provider)

Then, we can sign a transaction using the user's account and send it to the network.


_13
const newValue = 1337 // Replace with any value you want to store
_13
_13
// We must connect the signer to the contract to send a transaction
_13
const connectedContract = contract.connect(signer)
_13
_13
// Send a transaction to the contract to store a new value
_13
const tx = await connectedContract.store(newValue)
_13
_13
// Wait for the transaction to be mined
_13
await tx.wait()
_13
_13
// Show the transaction
_13
console.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:


_10
const result = await contract.retrieve()
_10
console.log(result) // New value stored in the contract

For more information about using smart contracts in ethers, see the official documentation.