Signers

ethersSigner是以太坊账户的抽象,可以用来签名消息和交易,如将签名的交易发送到以太坊网络以执行状态更改的操作。

可用的操作里在很大程度上取决于所使用的子类。

例如,一个来自MetaMask的Signer可以发送交易和签名消息,但不能签名一个不广播的交易。

你会遇到的最常见的Signers有:

Signer

Signer类是抽象的,不能直接实例化,而是应该使用一个具体的子类,如 Wallet, VoidSignerJsonRpcSigner

signer.connect( provider ) Signer

子类必须实现这个,但是如果更改后的providers是不被支持的话,它们可能仅仅只抛出一个错误。

signer.getAddress( ) Promise< string< 地址(Address) > >

返回一个解析为帐户地址的Promise。

这是一个Promise,因此一个Signer可以围绕一个异步源进行设计,如硬钱包。

子类必须实现这个。

Signer.isSigner( object ) boolean

当且仅当 object 是一个Signer时返回true。

Blockchain Methods

signer.getBalance( [ blockTag = "latest" ] ) Promise< 大数(BigNumber) >

在指定的blockTag下返回这个钱包的余额。

signer.getChainId( ) Promise< number >

返回这个钱包连接的链 ID。

signer.getGasPrice( ) Promise< 大数(BigNumber) >

返回当前的gas price。

signer.getTransactionCount( [ blockTag = "latest" ] ) Promise< number >

返回此帐户曾经发送的交易数量,交易中的中nonce依赖这个值。

signer.call( transactionRequest ) Promise< string< DataHexString > >

返回transactionRequest调用的结果,此帐户地址用作from 字段。

signer.estimateGas( transactionRequest ) Promise< 大数(BigNumber) >

返回发送transactionRequest的估算费用,在使用这个方法之前先用账户地址填充from字段。

signer.resolveName( ensName ) Promise< string< 地址(Address) > >

返回与ensName关联的地址。

Signing

signer.signMessage( message ) Promise< string< RawSignature > >

这将返回一个解析为消息Raw SignaturePromise。

由于使用的是hashMessage方法,因此它是EIP-191兼容的。 如果在Solidity中恢复地址,则需要这个前缀来创建一个匹配的哈希。

子类必须实现这个方法。 如果不支持签名消息可能会抛出错误,比如在基于合约的钱包或基于元交易的钱包中使用时。

Note

如果message是一个字符串,它将被视为一个字符串并转换为UTF8字节的表示形式。

当且仅当消息是Bytes时,它将被视为二进制数据。

例如,字符串"0x1234"是6个字符长(在本例中是6字节长)。 这与数组[ 0x12, 0x34 ]不同,数组长度为2字节。

一种常见的情况是对哈希签名。在本例中,如果哈希是一个字符串,则必须首先使用arrayifyutility函数将其转换为数组。

signer.signTransaction( transactionRequest ) Promise< string< DataHexString > >

返回一个解析为transactionRequest中已签名的交易的Promise。 此方法不填充任何缺少的字段。

子类必须实现这个,如果不支持签名消息可能会抛出错误,出于安全这在许多客户端中是常见的。

signer.sendTransaction( transactionRequest ) Promise< TransactionResponse >

该方法使用populateTransaction填充缺少字段的transactionRequest,并返回一个解析成交易的Promise。

子类必须实现这个,如果不支持发送交易可能会抛出错误,比如VoidSigner或者如果钱包没有联网且没有连接Provider

signer._signTypedData( domain , types , value ) Promise< string< RawSignature > >

<<<<<<< Updated upstream 签名使用EIP-712规范,在作用域中采用类型数据结构作为类型化的数据值。 ======= 使用EIP-712规范,采用类型数据结构作为领域签署类型化的数据值。 >>>>>>> Stashed changes

Experimental feature (方法名称会做更改)

这仍然是一个实验中的功能。如果使用它,请指定您正在使用的ethers的确切版本(例如指定"5.0.18",而不是"^5.0.18"), 因为方法名将从_signTypedData重命名为signTypedData

Typed Data Example
// 作用域中的所有属性都是可选的 const domain = { name: 'Ether Mail', version: '1', chainId: 1, verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC' }; // 所有类型定义的name列表 const types = { Person: [ { name: 'name', type: 'string' }, { name: 'wallet', type: 'address' } ], Mail: [ { name: 'from', type: 'Person' }, { name: 'to', type: 'Person' }, { name: 'contents', type: 'string' } ] }; // 待签名的数据 const value = { from: { name: 'Cow', wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826' }, to: { name: 'Bob', wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB' }, contents: 'Hello, Bob!' }; signature = await signer._signTypedData(domain, types, value); // '0x463b9c9971d1a144507d2e905f4e98becd159139421a4bb8d3c9c2ed04eb401057dd0698d504fd6ca48829a3c8a7a98c1c961eae617096cb54264bbdd082e13d1c'

Sub-Classes

Signer的所有重要属性都是不可变的,这一点非常重要。由于以太坊是异步的,并处理关键数据(如ether和其他潜在有价值的加密资产), 整个Signer的生命周期中保持provideraddress等属性是静态的有助于防止严重的问题的出现, 而且许多其他类和库也是认定provideraddress等属性是静态的。

子类必须扩展Signer,并且必须调用super()

signer.checkTransaction( transactionRequest ) TransactionRequest

这通常不需要重写,但可能需要在子类中提供自定义操作。

这应该返回一个transactionRequest的副本,包含callestimateGaspopulateTransaction (sendTransaction使用的)所需的任何属性。 如果指定了任何未知的key,它会抛出一个错误。

默认的实现只验证有效的TransactionRequest属性是否存在,如果不存在,则将from添加到交易中。

如果存在from字段,则必须验证它与 Signer的地址是否相等。

signer.populateTransaction( transactionRequest ) Promise< TransactionRequest >

这通常不需要重写,但可能需要在子类中提供自定义操作。

这应该返回一个transactionRequest的副本,遵循与checkTransaction相同的过程, 并填写发送交易所需的任何属性。返回的结果都是promises,可以使用resolvePropertiesutility函数来解析。

默认实现调用checkTransaction,如果它是一个ENS name就会解析它,并根据Signer上的相关操作添加gasPrice, nonce, gasLimitchainId

Wallet inherits ExternallyOwnedAccount and Signer

Wallet类继承了Signer,可以使用私钥作为外部拥有帐户(EOA)的标准对交易和消息进行签名。

new ethers.Wallet( privateKey [ , provider ] )

privateKey创建一个新的钱包实例,并可选地连接到provider

ethers.Wallet.createRandom( [ options = {} ] ) Wallet

返回一个带有随机私钥的新钱包,由加密安全的熵源生成。如果当前环境没有安全的熵源,则会抛出错误。

使用此方法创建的钱包将具有助记词。

ethers.Wallet.fromEncryptedJson( json , password [ , progress ] ) Promise< Wallet >

从加密的JSON钱包创建一个实例。

如果提供了进度,它将在解密期间被调用,其值介于0到1之间,表示一个完成进度。

ethers.Wallet.fromEncryptedJsonSync( json , password ) Wallet

从加密的JSON钱包创建一个实例。

此操作将同步操作,从而锁定用户界面一段时间。 大多数应用程序应该使用异步的fromEncryptedJson

ethers.Wallet.fromMnemonic( mnemonic [ , path , [ wordlist ] ] ) Wallet

从助记短语中创建实例。

如果没有指定path,则使用以太坊的默认path路径(如m/44'/60'/0'/0/0).

如果不指定wordlist,则使用English Wordlist。

Properties

wallet.address string< 地址(Address) >

此钱包表示的帐户的地址。

wallet.provider Provider

这个钱包所连接的provider,它将用于任何Blockchain Methods的方法,它也可以是null。

注意

一个钱包实例是不可变的,因此如果您希望更改Provider,您可以使用connect方法创建一个连接到所需的provider的新实例。

wallet.publicKey string< DataHexString< 65 > >

此钱包的未压缩的公钥。

Methods

wallet.encrypt( password , [ options = {} , [ progress ] ] ) Promise< string >

加密钱包,使用password返回一个解析为JSON钱包的Promise。

如果提供了进度,它将在解密期间被调用,其值介于0到1之间,表示一个完成进度。

Wallet Examples
// 通过助记词创建一个钱包实例 mnemonic = "announce room limb pattern dry unit scale effort smooth jazz weasel alcohol" walletMnemonic = Wallet.fromMnemonic(mnemonic) // 或者通过私钥创建一个钱包实例 walletPrivateKey = new Wallet(walletMnemonic.privateKey) walletMnemonic.address === walletPrivateKey.address // true // 有着每个Signer API的地址,是一个Promise对象 await walletMnemonic.getAddress() // '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1' // 一个钱包地址,也可用同步的方式获得 walletMnemonic.address // '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1' // 内部加密组件 walletMnemonic.privateKey // '0x1da6847600b0ee25e9ad9a52abbd786dd2502fa4005dd5af9310b7cc7a3b25db' walletMnemonic.publicKey // '0x04b9e72dfd423bcf95b3801ac93f4392be5ff22143f9980eb78b3a860c4843bfd04829ae61cdba4b3b1978ac5fc64f5cc2f4350e35a108a9c9a92a81200a60cd64' // 钱包助记词 walletMnemonic.mnemonic // { // locale: 'en', // path: "m/44'/60'/0'/0/0", // phrase: 'announce room limb pattern dry unit scale effort smooth jazz weasel alcohol' // } // Note: 通过私钥创建的钱包实例没有助记词,因为从数学上无法推导 walletPrivateKey.mnemonic // null // 签名消息 await walletMnemonic.signMessage("Hello World") // '0x14280e5885a19f60e536de50097e96e3738c7acae4e9e62d67272d794b8127d31c03d9cd59781d4ee31fb4e1b893bd9b020ec67dfa65cfb51e2bdadbb1de26d91c' tx = { to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72", value: utils.parseEther("1.0") } // 签名交易 await walletMnemonic.signTransaction(tx) // '0xf865808080948ba1f109551bd432803012645ac136ddd64dba72880de0b6b3a7640000801ca0918e294306d177ab7bd664f5e141436563854ebe0a3e523b9690b4922bbb52b8a01181612cec9c431c4257a79b8c9f0c980a2c49bb5a0e6ac52949163eeb565dfc' // connect方法返回一个连接到provider的新钱包实例 wallet = walletMnemonic.connect(provider) // 从网络中查询 await wallet.getBalance(); // { BigNumber: "6846" } await wallet.getTransactionCount(); // 3 // 发送 ether await wallet.sendTransaction(tx) // { // accessList: [], // chainId: 31337, // confirmations: 0, // data: '0x', // from: '0x894ed91B666FacCe5a4D2FF8261924b4754A5759', // gasLimit: { BigNumber: "21001" }, // gasPrice: null, // hash: '0x1b4a95e9d23bd96d5429c535148eb3eaed326d89118b118e44cc05c26703224e', // maxFeePerGas: { BigNumber: "1572346688" }, // maxPriorityFeePerGas: { BigNumber: "1500000000" }, // nonce: 5, // r: '0x5e32c2741700a9120cfa186bc74e88b3d9488393be796a5124fddf08ffdbfdc6', // s: '0x2431f3e3274cd22d6de63ed6e23a5c6839c1fabeb97b6683fb15584b9bf1f29d', // to: '0x8ba1f109551bD432803012645Ac136ddd64DBA72', // type: 2, // v: 0, // value: { BigNumber: "1000000000000000000" }, // wait: [Function] // }

VoidSigner inherits Signer

一个VoidSigner是一个简单的Signer,它不能签名。

当API需要signer作为参数时,它作为只读的signer是有用的,但它只能携带只读的操作。

比如,在call函数调用期间会自动传递所提供的地址。

new ethers.VoidSigner( address [ , provider ] ) VoidSigner

为一个地址创建VoidSigner实例。

voidSigner.address string< 地址(Address) >

VoidSigner的地址。

VoidSigner Pre-flight Example
address = "0x8ba1f109551bD432803012645Ac136ddd64DBA72" signer = new ethers.VoidSigner(address, provider) // The DAI token contract abi = [ "function balanceOf(address) view returns (uint)", "function transfer(address, uint) returns (bool)" ] contract = new ethers.Contract("dai.tokens.ethers.eth", abi, signer) // 获取此帐户的token数量 tokens = await contract.balanceOf(signer.getAddress()) // { BigNumber: "2413468059122458201631" } // // Pre-flight (check for revert) on DAI from the signer // // 注意: 我们现在还没有私钥,这仅仅允许我们检查这样做时会发生什么。这是前端界面中发出请求进行检查是很有用的。 // 当 token 余额可用时将会正确执行转账 await contract.callStatic.transfer("donations.ethers.eth", tokens) // true // 当转账的数量大于 token 余额时将会失败 await contract.callStatic.transfer("donations.ethers.eth", tokens.add(1)) // [Error: call revert exception; VM Exception while processing transaction: reverted with reason string "Dai/insufficient-balance" [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ]] { // address: 'dai.tokens.ethers.eth', // args: [ // 'donations.ethers.eth', // { BigNumber: "2413468059122458201632" } // ], // code: 'CALL_EXCEPTION', // data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000184461692f696e73756666696369656e742d62616c616e63650000000000000000', // errorArgs: [ // 'Dai/insufficient-balance' // ], // errorName: 'Error', // errorSignature: 'Error(string)', // method: 'transfer(address,uint256)', // reason: 'Dai/insufficient-balance', // transaction: { // data: '0xa9059cbb000000000000000000000000643aa0a61eadcc9cc202d1915d942d35d005400c000000000000000000000000000000000000000000000082d598fcab89948e20', // from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72', // to: '0x6B175474E89094C44Da98b954EedeAC495271d0F' // } // }

ExternallyOwnedAccount

这个接口包含外部拥有帐户(EOA)所需的最小属性集,可以执行某些操作,比如将其编码为JSON钱包。

eoa.address string< 地址(Address) >

地址(Address)EOA的地址

eoa.privateKey string< DataHexString< 32 > >

EOA的私钥

eoa.mnemonic 助记词

可选的。帐户HD的助记词,如果有的话可以打印出来。EOA账户源不编码助记符,如HD extended keys。