Migration: From Ethers v4

这份文件只涵盖了v4中存在的、在v5中发生了一些重要变化的功能。

它没有涵盖所有已添加的新特性,主要目的是帮助那些更新他们的旧脚本和应用程序的人保持功能的一致性。

如果你遇到任何遗漏的变化,请告诉我,我将更新本指南。

BigNumber

命名空间

由于大数(BigNumber)使用的相当频繁, 它已经被移到the top level of the umbrella package.

// v4 ethers.utils.BigNumber ethers.utils.BigNumberish // v5 ethers.BigNumber ethers.BigNumberish

创建实例

bigNumberify总是优先于构造函数,因为它可以缩短[[BigNumber]对象的对象实例化(因为它们是不可变的)这已经被移动到了静态的from类方法中.

// v4 new ethers.utils.BigNumber(someValue) ethers.utils.bigNumberify(someValue); // v5 // - Constructor 是私有的 // - 移除 `bigNumberify` ethers.BigNumber.from(someValue)

合约

ENS 名称解析

解析的地址的名称已更改。如果传递给构造函数的地址是一个ENS名称,那么在对合约进行任何调用之前,该地址将被解析。

解析地址的属性名称从addressPromise改为了resolvedAddress

解析 ENS 名称
// v4 contract.addressPromise // v5 contract.resolvedAddress

Gas 估算

The only difference in gas estimation is that the bucket has changed its name from estimate to estimateGas.

Gas Estimation
// v4 contract.estimate.transfer(toAddress, amount) // v5 contract.estimateGas.transfer(toAddress, amount)

函数

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 contact.foo and 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.

如果一个方法返回多个项,则没有区别。

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.

Functions Bucket
const abi = [ // 返回一个值 "function single() view returns (uint8)", // 返回两个值 "function double() view returns (uint8, uint8)", ]; // v4 await contract.single() // 123 await contract.functions.single() // 123 // v5 (notice the change in the .function variant) await contract.single() // 123 await contract.functions.single() // [ 123 ] // v4 await contract.double() // [ 123, 5 ] await contract.functions.double() // [ 123, 5 ] // v5 (no difference from v4) await contract.double() // [ 123, 5 ] await contract.functions.double() // [ 123, 5 ]

错误

命名空间

所有错误现在属于Logger类,相关的函数已经转移到Logger实例中, 它可以包括每个包的版本字符串

全局错误函数已经被移至Logger类方法中。

// v4 ethers.errors.UNKNOWN_ERROR ethers.errors.* errors.setCensorship(censorship, permanent) errors.setLogLevel(logLevel) errors.checkArgumentCount(count, expectedCount, suffix) errors.checkNew(self, kind) errors.checkNormalize() errors.throwError(message, code, params) errors.warn(...) errors.info(...) // v5 ethers.utils.Logger.errors.UNKNOWN_ERROR ethers.utils.Logger.errors.* Logger.setCensorship(censorship, permanent) Logger.setLogLevel(logLevel) const logger = new ethers.utils.Logger(version); logger.checkArgumentCount(count, expectedCount, suffix) logger.checkNew(self, kind) logger.checkNormalize() logger.throwError(message, code, params) logger.warn(...) logger.info(...)

接口

[[接口]]对象经历了最具戏剧性的变化。

它不再是一个元类,现在有一些方法可以简化处理合约接口操作,而不需要进行对象检查和特殊的临界情况

函数

// v4 (example: "transfer(address to, uint amount)") interface.functions.transfer.encode(to, amount) interface.functions.transfer.decode(callData) // v5 interface.encodeFunctionData("transfer", [ to, amount ]) interface.decodeFunctionResult("transfer", data) // 或者你可以使用任何兼容的签名或Fragment对象。 // Notice that signature normalization is performed for you, // e.g. "uint"和"uint256"将被自动转换 interface.encodeFunctionData("transfer(address,uint)", [ to, amount ]) interface.decodeFunctionResult("transfer(address to, uint256 amount)", data)

事件

// v4 (example: Transfer(address indexed, address indexed, uint256) interface.events.Transfer.encodeTopics(values) interface.events.Transfer.decode(data, topics) // v5 interface.encodeFilterTopics("Transfer", values) interface.decodeEventLog("Transfer", data, topics)

Inspection

现在(大部分)关于一个函数或者事件的查询可以直接在Fragment对象上完成

// v4 interface.functions.transfer.name interface.functions.transfer.inputs interface.functions.transfer.outputs interface.functions.transfer.payable interface.functions.transfer.gas // v5 const functionFragment = interface.getFunction("transfer") functionFragment.name functionFragment.inputs functionFragment.outputs functionFragment.payable functionFragment.gas // v4; type is "call" or "transaction" interface.functions.transfer.type // v5; constant is true (i.e. "call") or false (i.e. "transaction") functionFragment.constant // v4 interface.events.Transfer.anonymous interface.events.Transfer.inputs interface.events.Transfer.name // v5 const eventFragment = interface.getEvent("Transfer"); eventFragment.anonymous eventFragment.inputs eventFragment.name // v4 const functionSig = interface.functions.transfer.signature const sighash = interface.functions.transfer.sighash const eventSig = interface.events.Transfer.signature const topic = interface.events.Transfer.topic // v5 const functionSig = functionFragment.format() const sighash = interface.getSighash(functionFragment) const eventSig = eventFragment.format() const topic = interface.getTopic(eventFragment)

钱包

助记短语

mnemonic短语和相关属性已经合并为一个mnemonic对象,它现在也包括locale.

// v4 wallet.mnemonic wallet.path // v5 // - 助记符语法和路径是一个助记符对象 // - 注意: 如果没有助记符,wallet.mnemonic为空 wallet.mnemonic.phrase wallet.mnemonic.path