Migration: From Ethers v4
This document only covers the features present in v4 which have changed in some important way in v5.
It does not cover all the new additional features that have been added and mainly aims to help those updating their older scripts and applications to retain functional parity.
If you encounter any missing changes, please let me know and I'll update this guide.
Since BigNumber is used quite frequently, it has been moved to the top level of the umbrella package.
bigNumberify method was always preferred over the constructor since it could short-circuit an object instantiation for [[BigNumber] objects (since they are immutable). This has been moved to a static
from class method.
The name of the resolved address has changed. If the address passed into the constructor was an ENS name, the address will be resolved before any calls are made to the contract.
The name of the property where the resolved address has changed from
The only difference in gas estimation is that the bucket has changed its name from
In a contract in ethers, there is a
functions bucket, which exposes all the methods of a contract.
All these functions are available on the root contract itself as well and historically there was no difference between
contract.functions.foo. The original reason for the
functions bucket was to help when there were method names that collided with other buckets, which is rare.
In v5, the
functions bucket is now intended to help with frameworks and for the new error recovery API, so most users should use the methods on the root contract.
The main difference will occur when a contract method only returns a single item. The root method will dereference this automatically while the
functions bucket will preserve it as an Result.
If a method returns multiple items, there is no difference.
This helps when creating a framework, since the result will always be known to have the same number of components as the Fragment outputs, without having to handle the special case of a single return value.
const abi = [
"function single() view returns (uint8)",
"function double() view returns (uint8, uint8)",
All errors now belong to the Logger class and the related functions have been moved to Logger instances, which can include a per-package version string.
Global error functions have been moved to Logger class methods.
errors.checkArgumentCount(count, expectedCount, suffix)
errors.throwError(message, code, params)
const logger = new ethers.utils.Logger(version);
logger.checkArgumentCount(count, expectedCount, suffix)
logger.throwError(message, code, params)
The Interface object has undergone the most dramatic changes.
It is no longer a meta-class and now has methods that simplify handling contract interface operations without the need for object inspection and special edge cases.
interface.encodeFunctionData("transfer", [ to, amount ])
interface.encodeFunctionData("transfer(address,uint)", [ to, amount ])
interface.decodeFunctionResult("transfer(address to, uint256 amount)", data)
interface.decodeEventLog("Transfer", data, topics)
Interrogating properties about a function or event can now (mostly) be done directly on the Fragment object.
const functionFragment = interface.getFunction("transfer")
// v4; type is "call" or "transaction"
// v5; constant is true (i.e. "call") or false (i.e. "transaction")
const eventFragment = interface.getEvent("Transfer");
const functionSig = interface.functions.transfer.signature
const sighash = interface.functions.transfer.sighash
const eventSig = interface.events.Transfer.signature
const topic = interface.events.Transfer.topic
const functionSig = functionFragment.format()
const sighash = interface.getSighash(functionFragment)
const eventSig = eventFragment.format()
const topic = interface.getTopic(eventFragment)
The mnemonic phrase and related properties have been merged into a single
mnemonic object, which also now includes the