├── .gitignore ├── Makefile ├── Readme.md ├── make.bat ├── source ├── _static │ ├── ethers.css │ └── z_stat.js ├── _templates │ ├── breadcrumbs.html │ ├── footer.html │ └── layout.html ├── api-advanced.rst ├── api-contract.rst ├── api-providers.rst ├── api-utils.rst ├── api-wallet.rst ├── api.rst ├── conf.py ├── cookbook-accounts.rst ├── cookbook-contracts.rst ├── cookbook-providers.rst ├── cookbook-react.rst ├── cookbook-signing.rst ├── cookbook-testing.rst ├── cookbook.rst ├── getting-started.rst ├── glossaries.rst ├── index.rst ├── migration.rst ├── notes.rst └── testing.rst └── status.md /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | .vscode/* 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # [ethers.js中文文档](https://learnblockchain.cn/docs/ethers.js/) 2 | 3 | ============= 4 | 5 | 6 | ethers.js 有逐步取代 web3.js 的趋势,希望这份中文文档可以帮到大家,文档Web地址托管在[登链社区-文档中心](https://learnblockchain.cn/docs/ethers.js/)。 7 | 8 | 9 | This is the documentation for the various Ethers projects. 10 | 11 | The current projects documented here are: 12 | 13 | - **ethers.js** - The Ethereum JavaScript library 14 | - **ethers-app** - The application library and toolchain for ethers.io and ethers.space. 15 | 16 | **Coming soon:** 17 | 18 | - **ethers.objc** - The Ethereum Objective-C library 19 | - **ethers.ino** - The Ethereum Arduino C library 20 | - **ethers-ens** - The ENS registration library and command-line tools 21 | - **ethers-build** - The testing, debugging and deployment library and tools; this is largely covered in the **ethers-app** documentation above, but this will be the low-level API for hacking into the framework 22 | 23 | 24 | ## 贡献 25 | 26 | 本文档由[登链社区](https://learnblockchain.cn)社区成员翻译整理。 27 | 欢迎大家加入,申请成为贡献者,微信添加Tiny熊(xlbxiong),或者发邮件:xlb@upchain.pro 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ### Sphinx 安装 36 | 37 | ``` 38 | sudo pip install -U Sphinx 39 | pip install sphinx_rtd_theme 40 | pip install --upgrade recommonmark 41 | ``` 42 | 43 | ### 支持 RST 及Markdown格式 44 | 45 | RST文档格式的一个[中文说明](http://www.cnblogs.com/seayxu/p/5603876.html) 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /source/_static/ethers.css: -------------------------------------------------------------------------------- 1 | /* Unbold the leading package names */ 2 | dt sup { 3 | font-weight: normal; 4 | font-style: italic; 5 | opacity: 0.85; 6 | vertical-align: baseline; 7 | top: auto; 8 | font-size: small; 9 | } 10 | 11 | dt { 12 | padding-bottom: 5px; 13 | } 14 | 15 | .rst-content dl dd { 16 | margin-bottom: 20px; 17 | } 18 | 19 | .code-block-caption { 20 | text-align: right; 21 | margin-bottom: 4px; 22 | } 23 | 24 | .code-block-caption .headerlink { 25 | display: none; 26 | } 27 | 28 | /* Simulate :maxdepth: 2 only for api-advanced */ 29 | /* .toctree-l2 > a[href^=api-advanced] + ul { 30 | display: none; 31 | } */ 32 | -------------------------------------------------------------------------------- /source/_static/z_stat.js: -------------------------------------------------------------------------------- 1 | var cnzz_protocol = (("https:" == document.location.protocol) ? "https://" : "http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1265946080'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s22.cnzz.com/z_stat.php%3Fid%3D1265946080' type='text/javascript'%3E%3C/script%3E")); 2 | -------------------------------------------------------------------------------- /source/_templates/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | {%- extends "sphinx_rtd_theme/breadcrumbs.html" %} 2 | 3 | {% block breadcrumbs_aside %} 4 |
  • 5 | {{ _('Edit on GitHub') }} 6 |
  • 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /source/_templates/footer.html: -------------------------------------------------------------------------------- 1 | {% extends "!footer.html" %} 2 | 3 | {% block extrafooter %} 4 | 5 | {% endblock %} 6 | 7 | -------------------------------------------------------------------------------- /source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% set css_files = css_files + [ "_static/ethers.css" ] %} 3 | {% block htmltitle %} 4 | {{ title }} — ethers.js v4中文文档 — 登链社区 5 | {% endblock %} 6 | 7 | {% block sidebartitle %} 8 | {{ super() }} 9 | 10 | {% endblock %} 11 | {% block menu %} 12 | {{ super() }} 13 |

    相关文档

    14 |
  • ethers.js v5中文文档
  • 15 |
  • Solidity 中文文档
  • 16 |
  • Foundry 中文文档
  • 17 |
  • Hardhat 中文文档
  • 18 |
  • Truffle 中文文档
  • 19 |
  • Web3.js 中文文档
  • 20 |
  • Etherscan API 中文文档
  • 21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /source/api-advanced.rst: -------------------------------------------------------------------------------- 1 | .. include:: glossaries.rst 2 | .. |nbsp| unicode:: U+00A0 .. non-breaking space 3 | 4 | 低级 API 5 | ************** 6 | 7 | These are advanced, low-level API features that should, for most people not be 8 | necessary to worry about. 9 | 10 | They are lightly documented here, and in the future will have more documentation, 11 | but the emphasis at this point is documenting the more :ref:`common methods `. 12 | 13 | ----- 14 | 15 | ABI编码器 AbiCoder 16 | ===================== 17 | 18 | 创建 AbiCoder 19 | ------------------ 20 | 21 | new :sup:`ethers . utils` **. AbiCoder** ( [ coerceFunc ] ) 22 | Create a new ABI Coder object, which calls *coerceFunc* for each parsed value 23 | during decoding. The *coerceFunc* should have the signature: ``function(type, value)``. 24 | 25 | 静态属性 26 | ----------------- 27 | 28 | :sup:`ethers . utils` **. defaultAbiCoder** 29 | A default instance of the coder which can be used, which has a *coerceFunc* 30 | which will call ``toNumber()`` on BigNumbers whose **type** is less than 31 | 53 bits and is safe for JavaScript Number instances. 32 | 33 | Prototype属性 34 | ---------------- 35 | 36 | :sup:`prototype` . encode ( types , values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 37 | Returns a :ref:`hex string ` of the *values* encoded as the *types*. 38 | Throws if a value is invalid for the type. 39 | 40 | :sup:`prototype` . decode ( types , data ) |nbsp| :sup:`=>` |nbsp| :sup:`Result` 41 | Returns an Object by parsing *data* assuming *types*, with each parameter 42 | accessible as a positional parameters. Throws if *data* is invalid 43 | for the *types*. 44 | 45 | 46 | ----- 47 | 48 | .. _api-hdnode: 49 | 50 | HDNode (分层推导) 51 | ====================== 52 | 53 | A *Hierarchical Deterministic Wallet* represents a large tree of private keys 54 | which can reliably be reproduced from an initial seed. Each node in the tree 55 | is represented by an HDNode which can be descended into. 56 | 57 | A *mnemonic phrase* represents a simple way to generate the initial seed. 58 | 59 | See the `BIP 32 Specification`_ to learn more about HD Wallets and hardened vs 60 | non-hardened nodes. 61 | 62 | See the `BIP 39 Specification`_ to learn more about Mnemonic Phrases. 63 | 64 | 创建HDNode实例 65 | ------------------ 66 | 67 | :sup:`ethers . utils . HDNode` **. fromMnemonic** ( mnemonic ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode` 68 | Create an HDNode from a *mnemonic* phrase. 69 | 70 | :sup:`ethers . utils . HDNode` **. fromSeed** ( seed ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode` 71 | Create an HDNode from a seed. 72 | 73 | :sup:`ethers . utils . HDNode` **. fromExtendedKey** ( extendedKey ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode` 74 | Create an HDNode from an extended private key (xpriv) or extended public key (xpub). 75 | 76 | 77 | Prototype属性 78 | --------------- 79 | 80 | :sup:`prototype` **. privateKey** 81 | The :ref:`hex string ` private key for this node. 82 | 83 | :sup:`prototype` **. publicKey** 84 | The (compressed) public key for this node. 85 | 86 | :sup:`prototype` **. chainCode** 87 | The chain code for this node. 88 | 89 | :sup:`prototype` **. index** 90 | The index (from the parent) of this node (0 for the master node). 91 | 92 | :sup:`prototype` **. depth** 93 | The depth within the hierarchy of this node. 94 | 95 | :sup:`prototype` **. fingerprint** 96 | The fingerprint of this node. This can be used to identify a node, but wallets 97 | should handle collisions. 98 | 99 | :sup:`prototype` **. parentFingerprint** 100 | The fingerprint of this node's parent (or 0x00000000 for the master node). 101 | 102 | :sup:`prototype` **. extendedKey** 103 | The extended private key (xpriv) of the node, or the extended public key (xpub) 104 | if the node has been neutered. 105 | 106 | 107 | 子节点及最终节点 推导 108 | --------------------------------- 109 | 110 | :sup:`prototype` **. derivePath** ( path ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode` 111 | Derive the path from this node. Path is slash (**/**) delimited path components. 112 | The first component may be "m" for master (which enforces the starting node is 113 | in fact a master node) and each subsequent path component should be a positive 114 | integer (up to 31 bits), which can optionally include an apostrophe (**'**) to 115 | indicate hardened derivation for that path components. See below for some examples. 116 | 117 | :sup:`prototype` **. neuter** ( ) |nbsp| :sup:`=>` |nbsp| :sup:`HDNode` 118 | Returns a new instance of the node without a private key. This can be used to 119 | derive an extended public key. See the BIP32 standard for more details. 120 | 121 | 122 | 静态方法 123 | -------------- 124 | 125 | :sup:`ethers . utils . HDNode` **. mnemonicToEntropy** ( mnemonic ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 126 | Convert a *mnemonic* to its binary entropy. (throws an error if the checksum 127 | is invalid) 128 | 129 | :sup:`ethers . utils . HDNode` **. entropyToMnemonic** ( entropy ) |nbsp| :sup:`=>` |nbsp| :sup:`string` 130 | Convert the binary *entropy* to the mnemonic phrase. 131 | 132 | :sup:`ethers . utils . HDNode` **. mnemonicToSeed** ( mnemonic ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 133 | Compute the BIP39 seed from *mnemonic*. 134 | 135 | :sup:`ethers . utils . HDNode` **. isValidMnemonic** ( string ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 136 | Returns true if and only if the string is a valid mnemonic (including 137 | the checksum) 138 | 139 | .. code-block:: javascript 140 | :caption: *HDNode derivation* 141 | 142 | let HDNode = require('ethers').utils.HDNode; 143 | 144 | let mnemonic = "radar blur cabbage chef fix engine embark joy scheme fiction master release"; 145 | 146 | let masterNode = HDNode.fromMnemonic(mnemonic); 147 | 148 | let standardEthereum = masterNode.derivePath("m/44'/60'/0'/0/0"); 149 | 150 | // Get the extended private key 151 | let xpriv = node.extendedKey; 152 | 153 | // Get the extended public key 154 | let xpub = node.neuter().extnededKey; 155 | 156 | ----- 157 | 158 | .. _api-interface: 159 | 160 | 抽象接口对象 Interface 161 | ======================== 162 | 163 | The Interface Object is a meta-class that accepts a Solidity (or compatible) 164 | Application Binary Interface (ABI) and populates functions to deal with encoding 165 | and decoding the parameters to pass in and results returned. 166 | 167 | 创建Interface实例 168 | -------------------- 169 | 170 | new :sup:`ethers . utils` . Interface ( abi ) 171 | Returns a new instance and populates the properties with the ABI constructor, 172 | methods and events. The *abi* may be either a JSON string or the parsed JSON 173 | Object. 174 | 175 | 176 | Prototype属性 177 | ----------------- 178 | 179 | :sup:`prototype` . abi 180 | A **copy** of the ABI is returned, modifying this object will not alter the ABI. 181 | 182 | :sup:`prototype` . deployFunction 183 | A DeployDesciption for the constructor defined in the ABI, or the default constructor 184 | if omitted. 185 | 186 | :sup:`prototype` . events 187 | An object of all the events available in the ABI, by name and signature, which map 188 | to a EventDescription. 189 | 190 | :sup:`prototype` . functions 191 | An object of all the functions available in the ABI, by name and signature, which map 192 | to a FunctionDescription. 193 | 194 | 195 | 解析(交易/日志)对象 196 | ----------------------- 197 | 198 | :sup:`prototype` . parseTransaction ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`TransactionDescription` 199 | Parse *transaction* and return a description of the call it represents. 200 | 201 | :sup:`prototype` . parseLog ( log ) |nbsp| :sup:`=>` |nbsp| :sup:`LogDescription` 202 | Parse *log* and return a description of the event logs it represents. 203 | 204 | 205 | 对象测试方法 206 | --------------------- 207 | 208 | :sup:`prototype` . isInterface ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 209 | Returns true if *value* is an Interface. 210 | 211 | :sup:`prototype` . isIndexed ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 212 | Returns true if *value* is a dynamic Indexed value, which means the actual 213 | value of *value* is the hash of the actual value. 214 | 215 | 216 | 描述 217 | ------------ 218 | 219 | **Deploy Description** 220 | 221 | ============================== ====================================== 222 | name description 223 | ============================== ====================================== 224 | inputs The description of the constructor input parameters 225 | payable Whether the constructor can accept *Ether* 226 | encode(params) A function which encodes *params* 227 | ============================== ====================================== 228 | 229 | **Event Description** 230 | 231 | ============================== ====================================== 232 | name description 233 | ============================== ====================================== 234 | name The event name (e.g. "Transfer") 235 | signature The event signature (e.g. "Transfer(address indexed,address indexed,uint256)") 236 | inputs The event input parameters 237 | anonymous Whether the event is an anonymous event 238 | topic The topic for this event signature 239 | encodeTopics(params) A function which computes filter topics for given *params* 240 | decode(data, topics) A function to parse the log result *data* and *topics* 241 | ============================== ====================================== 242 | 243 | **Function Description** 244 | 245 | ============================== ====================================== 246 | name description 247 | ============================== ====================================== 248 | name The method name (e.g. "transfer") 249 | type The method type (i.e. "call" or "transaction") 250 | signature The method signature (e.g. "transfer(address to, uint256 amount)") 251 | sighash The signature hash of the signature (4 bytes) 252 | inputs The description of the method input parameters 253 | outputs The description of the method output parameters 254 | payable Whether the method can accept *Ether* 255 | gas The maximum gas this method will consume (null if unknown) 256 | encode(params) A function which encodes *params* 257 | decode(data) A function which decodes the result *data* 258 | ============================== ====================================== 259 | 260 | **Log Description** 261 | 262 | ============================== ====================================== 263 | name description 264 | ============================== ====================================== 265 | name The event name (e.g. "Transfer") 266 | signature The event signature (e.g. "Transfer(address indexed,address indexed,uint256)") 267 | topics The event topics 268 | decode(data, topics) A function to parse the logs 269 | values The decoded values of the event 270 | ============================== ====================================== 271 | 272 | **Transaction Description** 273 | 274 | ============================== ====================================== 275 | name description 276 | ============================== ====================================== 277 | name The method name (e.g. "transfer") 278 | args The arguments passed to the method 279 | signature The method signature (e.g. "transfer(address to, uint256 amount)") 280 | sighash The signature hash of the signature (4 bytes) 281 | decode(data) A function to parse the result data 282 | value The value (in wei) of the transaction 283 | ============================== ====================================== 284 | 285 | ----- 286 | 287 | |provider| 及子类 288 | ======================= 289 | 290 | See the :ref:`Provider API ` for more common usage. This documentation 291 | is designed for developers that are sub-classing BaseProvider. 292 | 293 | 静态方法 294 | -------------- 295 | 296 | :sup:`BaseProvider` . inherits ( childProvider ) |nbsp| :sup:`=>` |nbsp| :sup:`void` 297 | Set up *childProvider* as an provider, inheriting the parent prototype and 298 | set up a prototype.inherits on the *childProvider*. 299 | 300 | Prototype属性 301 | ------------------ 302 | 303 | :sup:`prototype` . perform ( method , params ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 304 | The only method needed to override in a subclass. All values are sanitized 305 | and defaults populated in params and the result is sanitized before returning. 306 | Returns a :ref:`Promise `, see the example below for overview of 307 | *method* and *params*. 308 | 309 | .. code-block:: javascript 310 | :caption: *BaseProvider Sub-Class Stub* 311 | 312 | const ethers = require('ethers'); 313 | 314 | // The new provider Object 315 | function DemoProvider(something) { 316 | 317 | let network = getNetworkSomehow() 318 | 319 | // The super must be called with either a Network or a Promise 320 | // that resolves to a Network 321 | ethers.providers.BaseProvider.call(this, network); 322 | 323 | ethers.utils.defineReadOnly(this, 'somethingElse', somethingElse); 324 | } 325 | 326 | // Inherit the Provider 327 | ethers.providers.BaseProvider.inherits(DemoProvider); 328 | 329 | // Override perform 330 | DemoProvider.prototype.perform = function(method, params) { 331 | switch (method) { 332 | case 'getBlockNumber': 333 | // Params: 334 | // { } 335 | 336 | case 'getGasPrice': 337 | // Params: 338 | // { } 339 | 340 | case 'getBalance': 341 | // Params: 342 | // { 343 | // address: address, 344 | // blockTag: blockTag 345 | // } 346 | 347 | case 'getTransactionCount': 348 | // Params: 349 | // { 350 | // address: address, 351 | // blockTag: blockTag 352 | // } 353 | 354 | case 'getCode': 355 | // Params: 356 | // { 357 | // address: address, 358 | // blockTag: blockTag 359 | // } 360 | 361 | case 'getStorageAt': 362 | // Params: 363 | // { 364 | // address: address, 365 | // position: hexString, 366 | // blockTag: blockTag 367 | // } 368 | 369 | case 'sendTransaction': 370 | // Params: 371 | // { 372 | // signedTransaction: hexString 373 | // } 374 | 375 | case 'getBlock': 376 | // Params: 377 | // Exactly one of the following will be specified, the other will be absent 378 | // { 379 | // blockHash: blockHash, 380 | // blockTag: blockTag 381 | // } 382 | 383 | case 'getTransaction': 384 | // Params: 385 | // { 386 | // transactionHash: hexString 387 | // } 388 | 389 | case 'getTransactionReceipt': 390 | // Params: 391 | // { 392 | // transactionHash: hexString 393 | // } 394 | 395 | case 'call': 396 | // Params: 397 | // { 398 | // transaction: See Transaction Requests (on Providers API) 399 | // } 400 | 401 | case 'estimateGas': 402 | // Params: 403 | // { 404 | // transaction: See Transaction Requests (on Providers API) 405 | // } 406 | 407 | case 'getLogs': 408 | // Params: 409 | // { 410 | // address: address, 411 | // fromBlock: blockTag, 412 | // toBlock: blockTag, 413 | // topics: array (possibly nested) of topics 414 | // } 415 | 416 | default: 417 | break; 418 | } 419 | 420 | return Promise.reject(new Error('not implemented - ' + method)); 421 | }; 422 | 423 | ----- 424 | 425 | 递归长度前缀编码 (RLP) 426 | ======================================== 427 | 428 | Recursive-Length Prefixed Encoding,This encoding method is used internally for several aspects of Ethereum, such as 429 | encoding transactions and determining contract addresses. For most developers this 430 | should not be necessary to use. 431 | 432 | RLP can encode nested arrays, with data as :ref:`hex strings ` and Uint8Array (or other non-Array 433 | :ref:`arrayish ` objects). A decoded object will always have data represented as :ref:`hex strings ` and 434 | Arrays. 435 | 436 | See: https://github.com/ethereum/wiki/wiki/RLP 437 | 438 | 静态方法 439 | -------------- 440 | 441 | :sup:`ethers . utils . RLP` . encode( object ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 442 | Encodes an object as an RLP :ref:`hex string `. (throws an Error if the object contains 443 | invalid items) 444 | 445 | :sup:`ethers . utils . RLP` . decode( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`any` 446 | Decode *hexStringOrArrayish* into the encoded object. (throws an Error if 447 | invalid RLP-coded data) 448 | 449 | .. code-block:: javascript 450 | :caption: *RLP coder* 451 | 452 | let object = [ ["0x42"], "0x1234", [ [], [] ] ]; 453 | 454 | let encoded = ethers.utils.RLP.encode(object); 455 | console.log(encoded); 456 | // 0xc8c142821234c2c0c0 457 | 458 | let decoded = ethers.utils.RLP.decode(encoded); 459 | console.log(decoded); 460 | // [ [ '0x42' ], '0x1234', [ [], [] ] ] 461 | 462 | ----- 463 | 464 | Signing Key 465 | =============== 466 | 467 | The SigningKey interface provides an abstraction around the 468 | *secp256k1 elliptic curve cryptography* library, which signs digests, 469 | computes public keys from private keys and performs *ecrecover* which 470 | computes a public key from a digest and a signature. 471 | 472 | 473 | 创建 SigningKey 实例 474 | ----------------------- 475 | 476 | new :sup:`ethers . utils` . SigningKey ( privateKey ) 477 | Create a new SigningKey and compute the corresponding public key and address. 478 | A private key may be a any :ref:`hex string ` or an 479 | :ref:`Arrayish ` representing 32 bytes. 480 | 481 | 482 | Prototype属性 483 | ------------------ 484 | 485 | :sup:`prototype` . address 486 | The Ethereum checksum address for this key pair. 487 | 488 | :sup:`prototype` . privateKey 489 | The private key for the key pair. 490 | 491 | :sup:`prototype` . publicKey 492 | The uncompressed public key for the key pair. 493 | 494 | 495 | 加密操作 496 | ------------------------ 497 | 498 | :sup:`prototype` . signDigest ( messageDigest ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 499 | The :ref:`flat-format Signature ` for the digests, signed 500 | by this key pair. 501 | 502 | :sup:`prototype` . computeSharedSecret ( publicOrPrivateKey ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 503 | Compute the ECDH shared secret from this keys private key and the 504 | *publicOrPrivateKey*. In is generally considered good practice to 505 | further hash this value before using it as a key. 506 | 507 | 508 | .. code-block:: javascript 509 | :caption: *Signing Key* 510 | 511 | const ethers = require('ethers'); 512 | 513 | let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123'; 514 | let signingKey = new ethers.utils.SigningKey(privateKey); 515 | 516 | console.log('Address: ' + signingKey.address); 517 | // "Address: 0x14791697260E4c9A71f18484C9f997B308e59325" 518 | 519 | let message = "Hello World"; 520 | let messageBytes = ethers.utils.toUtf8Bytes(message); 521 | let messageDigest = ethers.utils.keccak256(messageBytes); 522 | 523 | console.log("Digest: " + messageDigest); 524 | // "Digest: 0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba" 525 | 526 | let signature = signingKey.signDigest(messageDigest); 527 | 528 | console.log(signature); 529 | // { 530 | // recoveryParam: 0, 531 | // r: "0x79f56f3422dc67f57b2aeeb0b20295a99ec90420b203177f83d419c98beda7fe", 532 | // s: "0x1a9d05433883bdc7e6d882740f4ea7921ef458a61b2cfe6197c2bb1bc47236fd" 533 | // } 534 | 535 | let recovered = ethers.utils.recoverAddress(messageDigest, signature); 536 | 537 | console.log("Recovered: " + recovered); 538 | // "Recovered: 0x14791697260E4c9A71f18484C9f997B308e59325" 539 | 540 | let publicKey = signingKey.publicKey; 541 | 542 | console.log('Public Key: ' + publicKey); 543 | // "Public Key: 0x026655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a3515" 544 | 545 | let compressedPublicKey = ethers.utlis.computePublicKey(publicKey, true); 546 | let uncompressedPublicKey = ethers.utils.computePublicKey(publicKey, false); 547 | 548 | console.log(compressedPublicKey); 549 | // "0x026655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a3515" 550 | 551 | console.log(uncompressedPublicKey); 552 | // "0x046655feed4d214c261e0a6b554395596f1f1476a77d999560e5a8df9b8a1a35" + 553 | // "15217e88dd05e938efdd71b2cce322bf01da96cd42087b236e8f5043157a9c068e" 554 | 555 | let address = ethers.utils.computeAddress(publicKey); 556 | 557 | console.log('Address: ' + address); 558 | // "Address: 0x14791697260E4c9A71f18484C9f997B308e59325" 559 | 560 | 561 | ----- 562 | 563 | .. _BIP 32 Specification: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki 564 | .. _BIP 39 Specification: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki 565 | 566 | .. EOF 567 | -------------------------------------------------------------------------------- /source/api-contract.rst: -------------------------------------------------------------------------------- 1 | .. include:: glossaries.rst 2 | .. |nbsp| unicode:: U+00A0 .. non-breaking space 3 | 4 | .. _api-contract: 5 | 6 | 合约 7 | ********* 8 | 9 | 合约是在以太坊区块链上的可执行程序的抽象。合约具有代码 (称为字节代码) 以及分配的长期存储 (storage)。每个已部署的合约都有一个地址, 用它连接到合约, 可以向其发送消息来调用合约方法。 10 | 11 | 合约可以发出 **事件**, 它可以被应用程序监听(订阅), 当合约执行了特定操作时, 应用程序将收到通知。事件是无法在合约内读取的。 12 | 13 | 在合约上可以调用两种类型的方法: 14 | 15 | `视图方法 `_ : 不能添加、移除或更改存储中的任何数据,也不能记录任何事件,并且只能调用其他合约上**视图方法**。 16 | 这些方法是免费的(不需要以太)调用。 结果也可以返回给调用者。 17 | 18 | **非视图方法**: 需要支付费用(用Ether),但可以执行任何所需的状态更改操作,记录事件,发送ether并在其他合约上调用非视图方法。 19 | 这些方法**不能**将其结果返回给调用者。 这些方法必须由交易触发,由外部拥有的账户(EOA)直接或间接发送(如从另一个合约调用),并且只有在交易被打包(挖矿)后才会产生效果。 20 | 因此,这些操作所需的持续时间可能变化很大,并且取决于交易Gas价格、网络拥塞和矿工优先选择方法。 21 | 22 | 23 | 合约 API 提供了简单的方法来连接到一个合约并调用它的方法,它作为 JavaScript 对象上的函数,处理所有的二进制协议转换,内部名称修改和主题构造。 24 | 这使得合约对象可以像任何标准的JavaScript对象一样使用,而不必担心以太坊虚拟机或区块链的低级细节。 25 | 26 | 合约Contract对象是一个元类,它是一个在运行时定义类的类。 可以提供合约定义(称为应用程序二进制接口或ABI)以及可用的方法和事件可以动态添加到对象中。 27 | 28 | 在本文档中,我们将参考以下合约。 29 | 30 | 31 | .. code-block:: javascript 32 | :caption: *SimpleStorage 合约* 33 | 34 | pragma solidity ^0.4.24; 35 | 36 | contract SimpleStorage { 37 | 38 | event ValueChanged(address indexed author, string oldValue, string newValue); 39 | 40 | string _value; 41 | 42 | constructor(string value) public { 43 | emit ValueChanged(msg.sender, _value, value); 44 | _value = value; 45 | } 46 | 47 | function getValue() view public returns (string) { 48 | return _value; 49 | } 50 | 51 | function setValue(string value) public { 52 | emit ValueChanged(msg.sender, _value, value); 53 | _value = value; 54 | } 55 | } 56 | 57 | ----- 58 | 59 | .. _contract-deployment: 60 | 61 | 部署合约 62 | ==================== 63 | 64 | 为了将合约部署到以太坊网络,可以创建一个 **ContractFactory** 来管理合约字节码和 **应用程序二进制接口** (ABI),ABI通常由 *Solidity* 编译器生成。 65 | 66 | 67 | 创建 ContractFactory 68 | --------------------------- 69 | 70 | new :sup:`ethers` . ContractFactory ( abi , bytecode [ , signer ] ) 71 | 创建合约工厂,通过部署合约的 *字节码* 以及在 *abi* 中定义的构造函数来创建合约工厂。 *签名器 singer* 将用于发送任何部署交易 72 | 73 | :sup:`ethers` . ContractFactory . fromSolidity ( compilerOutput [ , signer ] ) 74 | 从Solidity编译器的 *compilerOutput* 或从 *Truffle* JSON (如: ``output.contracts['SimpleStorage.sol'].SimpleStorage``) 创建合约工厂 ContractFactory。 75 | 76 | 77 | :sup:`prototype` . connect ( signer ) |nbsp| :sup:`=>` |nbsp| :sup:`ContractFactory` 78 | 创建连接到新 *签名器signer* 的ContractFactory **新实例** 。 79 | 80 | 81 | Prototype属性 82 | ------------------ 83 | 84 | :sup:`prototype` . bytecode 85 | 返回合约的可执行字节码。 86 | 87 | :sup:`prototype` . interface 88 | 返回合约应用程序二进制接口(ABI)。 89 | 90 | :sup:`prototype` . signer 91 | 返回 :ref:`签名器Signer ` 用来发送交易到网络。 92 | 如果为空,则 ``deploy()`` 不可以调用。 93 | 94 | 95 | 关联地址 96 | ---------- 97 | 98 | :sup:`prototype` . attach ( address ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract` 99 | 使用合约接口和签名器Singer 连接到现有合约实例。参数为合约 **地址** 100 | 101 | 102 | 部署合约 103 | ---------- 104 | 105 | :sup:`prototype` . deploy ( ... ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 106 | 创建一个部署合约的交易,并使用合约 :ref:`Signer ` 将其发送到网络,并返回合约对象的 :ref:`Promise ` 。 交易记录通过 contract.deployTransaction 获取。 107 | 参数将传递给合约构造函数constructor。 108 | 请记住,合约可能不会立即挖出。 ``contract.deployed()`` 函数将返回一个 :ref:`Promise ` ,将在部署合约后获取实例,或者在部署被拒绝时生成一个错误。 109 | 110 | :sup:`prototype` . getDeployTransaction ( ... ) |nbsp| :sup:`=>` |nbsp| :sup:`UnsignedTransaction` 111 | 返回部署合约(提供了构造参数)的交易。 通常可用于离线签名交易或分析工具。 112 | 113 | .. code-block:: javascript 114 | :caption: *部署合约* 115 | 116 | const ethers = require('ethers'); 117 | 118 | // The Contract interface 119 | let abi = [ 120 | "event ValueChanged(address indexed author, string oldValue, string newValue)", 121 | "constructor(string value)", 122 | "function getValue() view returns (string value)", 123 | "function setValue(string value)" 124 | ]; 125 | 126 | // The bytecode from Solidity, compiling the above source 127 | let bytecode = "0x608060405234801561001057600080fd5b506040516105bd3803806105bd8339" + 128 | "8101604081815282518183526000805460026000196101006001841615020190" + 129 | "91160492840183905293019233927fe826f71647b8486f2bae59832124c70792" + 130 | "fba044036720a54ec8dacdd5df4fcb9285919081906020820190606083019086" + 131 | "9080156100cd5780601f106100a2576101008083540402835291602001916100" + 132 | "cd565b820191906000526020600020905b815481529060010190602001808311" + 133 | "6100b057829003601f168201915b505083810382528451815284516020918201" + 134 | "9186019080838360005b838110156101015781810151838201526020016100e9" + 135 | "565b50505050905090810190601f16801561012e578082038051600183602003" + 136 | "6101000a031916815260200191505b5094505050505060405180910390a28051" + 137 | "610150906000906020840190610157565b50506101f2565b8280546001816001" + 138 | "16156101000203166002900490600052602060002090601f0160209004810192" + 139 | "82601f1061019857805160ff19168380011785556101c5565b82800160010185" + 140 | "5582156101c5579182015b828111156101c55782518255916020019190600101" + 141 | "906101aa565b506101d19291506101d5565b5090565b6101ef91905b80821115" + 142 | "6101d157600081556001016101db565b90565b6103bc806102016000396000f3" + 143 | "0060806040526004361061004b5763ffffffff7c010000000000000000000000" + 144 | "0000000000000000000000000000000000600035041663209652558114610050" + 145 | "57806393a09352146100da575b600080fd5b34801561005c57600080fd5b5061" + 146 | "0065610135565b60408051602080825283518183015283519192839290830191" + 147 | "85019080838360005b8381101561009f57818101518382015260200161008756" + 148 | "5b50505050905090810190601f1680156100cc57808203805160018360200361" + 149 | "01000a031916815260200191505b509250505060405180910390f35b34801561" + 150 | "00e657600080fd5b506040805160206004803580820135601f81018490048402" + 151 | "8501840190955284845261013394369492936024939284019190819084018382" + 152 | "80828437509497506101cc9650505050505050565b005b600080546040805160" + 153 | "20601f6002600019610100600188161502019095169490940493840181900481" + 154 | "0282018101909252828152606093909290918301828280156101c15780601f10" + 155 | "610196576101008083540402835291602001916101c1565b8201919060005260" + 156 | "20600020905b8154815290600101906020018083116101a457829003601f1682" + 157 | "01915b505050505090505b90565b604080518181526000805460026000196101" + 158 | "00600184161502019091160492820183905233927fe826f71647b8486f2bae59" + 159 | "832124c70792fba044036720a54ec8dacdd5df4fcb9285918190602082019060" + 160 | "60830190869080156102715780601f1061024657610100808354040283529160" + 161 | "200191610271565b820191906000526020600020905b81548152906001019060" + 162 | "200180831161025457829003601f168201915b50508381038252845181528451" + 163 | "60209182019186019080838360005b838110156102a557818101518382015260" + 164 | "200161028d565b50505050905090810190601f1680156102d257808203805160" + 165 | "01836020036101000a031916815260200191505b509450505050506040518091" + 166 | "0390a280516102f49060009060208401906102f8565b5050565b828054600181" + 167 | "600116156101000203166002900490600052602060002090601f016020900481" + 168 | "019282601f1061033957805160ff1916838001178555610366565b8280016001" + 169 | "0185558215610366579182015b82811115610366578251825591602001919060" + 170 | "01019061034b565b50610372929150610376565b5090565b6101c991905b8082" + 171 | "1115610372576000815560010161037c5600a165627a7a723058202225a35c50" + 172 | "7b31ac6df494f4be31057c7202b5084c592bdb9b29f232407abeac0029"; 173 | 174 | 175 | // 连接网络 176 | let provider = ethers.getDefaultProvider('ropsten'); 177 | 178 | // 加载钱包以部署合约 179 | let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123'; 180 | let wallet = new ethers.Wallet(privateKey, provider); 181 | 182 | // 部署是异步的,所以我们使用异步IIFE 183 | (async function() { 184 | 185 | // 常见合约工厂实例 186 | let factory = new ethers.ContractFactory(abi, bytecode, wallet); 187 | 188 | // 请注意,我们将 "Hello World" 作为参数传递给合约构造函数constructor 189 | let contract = await factory.deploy("Hello World"); 190 | 191 | // 部署交易有一旦挖出,合约地址就可用 192 | // 参考: https://ropsten.etherscan.io/address/0x2bd9aaa2953f988153c8629926d22a6a5f69b14e 193 | console.log(contract.address); 194 | // "0x2bD9aAa2953F988153c8629926D22A6a5F69b14E" 195 | 196 | // 发送到网络用来部署合约的交易 197 | // 查看: https://ropsten.etherscan.io/tx/0x159b76843662a15bd67e482dcfbee55e8e44efad26c5a614245e12a00d4b1a51 198 | console.log(contract.deployTransaction.hash); 199 | // "0x159b76843662a15bd67e482dcfbee55e8e44efad26c5a614245e12a00d4b1a51" 200 | 201 | //合约还没有部署;我们必须等到它被挖出 202 | await contract.deployed() 203 | 204 | // 好了 合约已部署。 205 | })(); 206 | 207 | 208 | ----- 209 | 210 | 连接已有合约 211 | ================================= 212 | 213 | 一旦合约被部署,就可以连接它,使用 **Contract** 对象。 214 | 215 | Once a Contract has been deployed, it can be connected to using 216 | the **Contract** object. 217 | 218 | 连接合约 219 | ------------------------ 220 | 221 | new :sup:`ethers` . Contract ( addressOrName , abi , providerOrSigner ) 222 | 通过 **abi** 及 **addressOrName** 连接合约,连接作为 **providerOrSigner**。 223 | 224 | 有关 **abi** 支持的格式,请参阅 :ref:`合约 ABI ` 。 225 | 226 | 有关访问能力和限制,请参阅 :ref:`提供者与签名器 ` 227 | 228 | .. code-block:: javascript 229 | :caption: *连接已有合约* 230 | 231 | const ethers = require('ethers'); 232 | 233 | // The Contract interface 234 | let abi = [ 235 | "event ValueChanged(address indexed author, string oldValue, string newValue)", 236 | "constructor(string value)", 237 | "function getValue() view returns (string value)", 238 | "function setValue(string value)" 239 | ]; 240 | 241 | // Connect to the network 242 | let provider = ethers.getDefaultProvider(); 243 | 244 | // 地址来自上面部署的合约 245 | let contractAddress = "0x2bD9aAa2953F988153c8629926D22A6a5F69b14E"; 246 | 247 | // 使用Provider 连接合约,将只有对合约的可读权限 248 | let contract = new ethers.Contract(contractAddress, abi, provider); 249 | 250 | 251 | .. code-block:: javascript 252 | :caption: *调用只读的视图方法* 253 | 254 | // 获取当前的值 255 | let currentValue = await contract.getValue(); 256 | 257 | console.log(currentValue); 258 | // "Hello World" 259 | 260 | .. code-block:: javascript 261 | :caption: *调用非视图方法方法* 262 | 263 | // 从私钥获取一个签名器 Signer 264 | let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123'; 265 | let wallet = new ethers.Wallet(privateKey, provider); 266 | 267 | // 使用签名器创建一个新的合约实例,它允许使用可更新状态的方法 268 | let contractWithSigner = contract.connect(wallet); 269 | // ... 或 ... 270 | // let contractWithSigner = new Contract(contractAddress, abi, wallet) 271 | 272 | // 设置一个新值,返回交易 273 | let tx = await contractWithSigner.setValue("I like turtles."); 274 | 275 | // 查看: https://ropsten.etherscan.io/tx/0xaf0068dcf728afa5accd02172867627da4e6f946dfb8174a7be31f01b11d5364 276 | console.log(tx.hash); 277 | // "0xaf0068dcf728afa5accd02172867627da4e6f946dfb8174a7be31f01b11d5364" 278 | 279 | // 操作还没完成,需要等待挖矿 280 | await tx.wait(); 281 | 282 | // 再次调用合约的 getValue() 283 | let newValue = await contract.getValue(); 284 | 285 | console.log(currentValue); 286 | // "I like turtles." 287 | 288 | .. code-block:: javascript 289 | :caption: *监听事件Event* 290 | 291 | contract.on("ValueChanged", (author, oldValue, newValue, event) => { 292 | // 在值变化的时候被调用 293 | 294 | console.log(author); 295 | // "0x14791697260E4c9A71f18484C9f997B308e59325" 296 | 297 | console.log(oldValue); 298 | // "Hello World" 299 | 300 | console.log(newValue); 301 | // "Ilike turtles." 302 | 303 | // 查看后面的事件触发器 Event Emitter 了解事件对象的属性 304 | console.log(event.blockNumber); 305 | // 4115004 306 | }); 307 | 308 | .. code-block:: javascript 309 | :caption: *过滤事件Events* 310 | 311 | // 使用签名器地址作为事件触发者进行过滤 312 | let filter = contract.filters.ValueChanged(wallet.address); 313 | 314 | contract.on(filter, (author, oldValue, newValue, event) => { 315 | // 只有当我们的账号(签名器地址)更改的数据才回调 316 | }); 317 | 318 | ----- 319 | 320 | Prototype 属性 321 | --------------- 322 | 323 | :sup:`prototype` . address 324 | 返回合约地址或 ENS 名称。 325 | 326 | :sup:`prototype` . deployTransaction 327 | 如果合约通过ContractFactory部署,返回部署的交易,否则为null 。 328 | 329 | :sup:`prototype` . interface 330 | 解析的ABI的 :ref:`接口 ` 元类,通常不需要直接访问。 331 | 332 | 根据提供的ABI,附加属性将在运行时添加到原型 Prototype 中,请参阅:ref:`合约元类 Meta-Class ` 。 333 | 334 | ----- 335 | 336 | 等待部署 337 | ---------------------- 338 | 339 | :sup:`prototype` . deployed ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 340 | 如果该合约是通过 ``deploy()`` 产生,则返回一个 :ref:`Promise ` ,一旦部署被挖掘,从 :ref:`Promise ` 可以获得该合约,如果该合约未能部署,则无法获取。 341 | 如果是已经部署的合约,一旦链上的代码被确认,:ref:`Promise ` 就会resolve 。 342 | 343 | ----- 344 | 345 | .. _contract-metaclass: 346 | 347 | 元类 Meta-Class 属性 348 | ========================= 349 | 350 | Since a Contract is dynamic and loaded at run-time, many of the properties 351 | that will exist on a Contract are determined at run-time from 352 | the :ref:`Contract ABI `. 353 | 354 | 合约方法 355 | ---------------- 356 | 357 | All functions populated from the ABI are also included on the contract object 358 | directly, for example ``contract.functions.getValue()`` can also be called 359 | using ``contract.getValue()``. 360 | 361 | :sup:`prototype` . functions . *functionName* 362 | An object that maps each ABI function name to a function that will 363 | either call (for constant functions) or sign and send a transaction 364 | (for non-constant functions) 365 | 366 | Calling a **Constant** function requires either a :ref:`Provider ` or 367 | a Signer with a :ref:`Provider `. 368 | 369 | Calling a **Non-Constant** function (i.e. sending a transaction) requires a 370 | :ref:`Signer `. 371 | 372 | :sup:`prototype` . estimate . *functionName* 373 | An object that maps each ABI function name to a function that will 374 | estimate the cost the provided parameters. 375 | 376 | 377 | 合约事件过滤器 378 | ---------------------- 379 | 380 | Filters allow for a flexible and efficient way to fetch only a subset of the 381 | events that match specific criteria. The ``filters`` property contains a 382 | function for every Event in the ABI that computes a Filter for a given 383 | set of values. The ``null`` matches any value. 384 | 385 | :sup:`prototype` . filters . *eventname* 386 | A function that generates filters that can be listened to, using the 387 | ``on(eventName, ...)`` function, filtered by the Event values. 388 | 389 | .. code-block:: javascript 390 | :caption: *Filtering Events* 391 | 392 | // A filter from me to anyone 393 | let filterFromMe = contract.filters.Transfer(myAddress); 394 | 395 | // A filter from anyone to me 396 | let filterToMe = contract.filters.Transfer(null, myAddress); 397 | 398 | // A filter from me AND to me 399 | let filterFromMeToMe = contract.filters.Transfer(myAddress, myAddress); 400 | 401 | contract.on(filterFromMe, (fromAddress, toAddress, value, event) => { 402 | console.log('I sent', value); 403 | }); 404 | 405 | contract.on(filterToMe, (fromAddress, toAddress, value, event) => { 406 | console.log('I received', value); 407 | }); 408 | 409 | contract.on(filterFromMeToMe, (fromAddress, toAddress, value, event) => { 410 | console.log('Myself to me', value); 411 | }); 412 | 413 | 414 | ----- 415 | 416 | .. _contract-overrides: 417 | 418 | override 指定交易附加信息 419 | ============================== 420 | 421 | Every Contract method may take one additional (optional) parameter which specifies the 422 | transaction (or call) overrides. 423 | 424 | .. code-block:: javascript 425 | :caption: *Contract Transaction Overrides* 426 | 427 | // All overrides are optional 428 | let overrides = { 429 | 430 | // The maximum units of gas for the transaction to use 431 | gasLimit: 23000, 432 | 433 | // The price (in wei) per unit of gas 434 | gasPrice: utils.parseUnits('9.0', 'gwei'), 435 | 436 | // The nonce to use in the transaction 437 | nonce: 123, 438 | 439 | // The amount to send with the transaction (i.e. msg.value) 440 | value: utils.parseEther('1.0'), 441 | 442 | // The chain ID (or network ID) to use 443 | chainId: 1 444 | 445 | }; 446 | 447 | // Solidity: function someFunction(address addr) public 448 | let tx = contract.someFunction(addr, overrides) 449 | 450 | .. code-block:: javascript 451 | :caption: *Contract Call Overrides* 452 | 453 | let overrides = { 454 | 455 | // The address to execute the call as 456 | from: "0x0123456789012345678901234567890123456789", 457 | 458 | // The maximum units of gas for the transaction to use 459 | gasLimit: 23000, 460 | 461 | }; 462 | 463 | // Solidity: function someFunction(address addr) public pure returns (bytes32 result) 464 | let result = contract.someFunction(addr, overrides) 465 | 466 | ----- 467 | 468 | .. _contract-event-emitter: 469 | 470 | 事件触发器Event Emitter 471 | ========================= 472 | 473 | Each Contract supports many of the operations available from the `Event Emitter API`_. 474 | 475 | To listen for Events, the contract requires either a :ref:`Provider ` or 476 | a Signer with a :ref:`Provider `. 477 | 478 | 479 | Event Names 480 | ----------- 481 | 482 | The available eventNames are: 483 | 484 | - **string** -- The name of an event (e.g. "TestEvent" or "TestEvent(string, uint)") 485 | - **filter** -- See :ref:`Contract Filters ` 486 | - **\*** -- All events 487 | 488 | 489 | Event Object 490 | ------------ 491 | 492 | All event callbacks receive the parameters specified in the ABI as well as one additional 493 | Event Object with 494 | 495 | - **blockNumber**, **blockHash**, **transactionHash** -- The Block and Transaction of the Log 496 | - **address** -- The contract address for the Log 497 | - **data** -- The Log data 498 | - **topics** -- An array of the Log topics 499 | - **args** -- An array of the parsed arguments for the event 500 | - **event** -- the name of the event (e.g. "Transfer") 501 | - **eventSignature** -- the full signature of the event (e.g. "Transfer(address,address,uint256)") 502 | - **getBlock()** -- A function that resolves to the Block containing the Log 503 | - **getTransaction()** -- A function that resolves to the Transaction containing the Log 504 | - **getTransactionReceipt()** -- A function that resolves to the Transaction Receipt containing the Log 505 | - **removeListener()** -- A function that removes this callack as a listener 506 | - **decode(data, topics)** -- A function that decodes data and topics into parsed arguments 507 | 508 | 509 | Configuring Events 510 | ------------------ 511 | 512 | :sup:`prototype` . on ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract` 513 | Registers *callback* to be called on every *eventName*. Returns the contract, so calls may be chained. 514 | 515 | :sup:`prototype` . addEventListner ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract` 516 | An alias for ``on``. 517 | 518 | :sup:`prototype` . once ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract` 519 | Register *callback* to be called at most once, for *eventName*. Returns the contract, so calls may be chained. 520 | 521 | :sup:`prototype` . emit ( eventName , ... ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 522 | Trigger all callbacks for *eventName*, returning true if there was at 523 | least one listener. This should generally not be called directly. 524 | 525 | :sup:`prototype` . listenerCount ( [ eventName ] ) |nbsp| :sup:`=>` |nbsp| :sup:`number` 526 | Returns the number of callbacks registered for *eventName*. 527 | 528 | :sup:`prototype` . listeners ( eventName ) |nbsp| :sup:`=>` |nbsp| :sup:`Listeners[]` 529 | Returns a list of callbacks for *eventName*. 530 | 531 | :sup:`prototype` . removeAllListeners ( eventName ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract` 532 | De-registers all listeners for *eventName*. Returns the contract, so calls may be chained. 533 | 534 | :sup:`prototype` . removeListener ( eventName , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Contract` 535 | De-registers the specific *callback* for *eventName*. Returns the contract, so calls may be chained. 536 | 537 | .. code-block:: javascript 538 | :caption: *Events* 539 | 540 | contract.on("ValueChanged", (oldValue, newValue, event) => { 541 | console.log(oldValue, newValue); 542 | }); 543 | 544 | 545 | ----- 546 | 547 | .. _providers-vs-signers: 548 | 549 | 用 Providers 还是 Signers 550 | =========================== 551 | 552 | A Contract object has a notion of an "frame of reference", which will determine 553 | what type of access and whom the Contract is enacted upon as. This is specified 554 | by the **providerOrSigner** parameter when connecting to a Contract. 555 | 556 | There are three possible cases for connecting a Contract using the providerOrSigner. 557 | 558 | ============================================ ======================================== 559 | providerOrSigner Operation Privileges 560 | ============================================ ======================================== 561 | :ref:`Provider ` Read-Only Access 562 | :ref:`Signer ` (without a provider) Write-Only Access (as account owner) 563 | :ref:`Signer ` (with a provider) Read and Write Access (as account owner) 564 | ============================================ ======================================== 565 | 566 | The **providerOrSigner** is immutable, so to change the "frame of reference" to 567 | another account or provider, use the ``connect`` function. 568 | 569 | :sup:`prototype` . connect ( providerOrSigner ) 570 | Create a **new instance** of the Contract object connected as *providerOrSigner*. 571 | 572 | 573 | 类型在合约与 JavaScript 之间的转换 574 | ======================================== 575 | 576 | There are many variable types available in *Solidity*, some which convert 577 | to and from JavaScript gracefully, and others that do not. Here are some 578 | note regarding passing and returning values in Contracts. 579 | 580 | 581 | Bytes 582 | ----- 583 | 584 | Bytes are available in fixed-length or dynamic-length variants. In both cases, the 585 | values are returned as a hex string and may be passed in as either a hex string or 586 | as an :ref:`arrayish `. 587 | 588 | To convert the string into an array, use the :ref:`arrayify() ` utility function. 589 | 590 | 591 | Integers 592 | -------- 593 | 594 | Integers in *solidity* are a fixed number of bits (aligned to the nearest byte) 595 | and are available in signed and unsigned variants. 596 | 597 | For example, a **uint256** is 256 bits (32 bytes) and unsigned. An **int8** 598 | is 8 bits (1 byte) and signed. 599 | 600 | When the type is 48 bits (6 bytes) or less, values are returned as a JavaScript 601 | Number, since Javascript Numbers are safe to use up to 53 bits. 602 | 603 | Any types with 56 bits (7 bytes) or more will be returned as a BigNumber, 604 | even if the *value* is within the 53 bit safe range. 605 | 606 | When passing numeric values in, JavaScript Numbers, hex strings or any BigNumber 607 | is acceptable (however, take care when using JavaScript Numbers and performing 608 | mathematical operations on them). 609 | 610 | The **uint** and **int** types are aliases for **uint256** and **int256**, 611 | respectively. 612 | 613 | 614 | Strings 615 | ------- 616 | 617 | For short strings, many Contracts use a bytes32 to encode a null-terminated 618 | string representation, rather than a length-prefixed representation, so the 619 | :ref:`formatBytes32String ` and :ref:`parseBytes32String ` 620 | utility functions can be used to handle this conversion. 621 | 622 | To convert between the two dynamic types, strings and bytes, the 623 | :ref:`toUtf8Bytes() ` and :ref:`toUtf8String() ` 624 | utility functions can be used. 625 | 626 | 627 | Structs 628 | ------- 629 | 630 | Structs can be specified as Objects with their named properties, or as an Array, 631 | the same length as the struct. 632 | 633 | **Constant** methods which return a single item, return that item directly. If the 634 | method returns multiple values then an object is returned which can be accessed by 635 | either the named properties or by their indices, in which case both point to the 636 | **same instance**. 637 | 638 | 639 | .. code-block:: javascript 640 | :caption: *Example Return Types* 641 | 642 | /** 643 | * Contract Methods 644 | * 645 | * function oneItem() public view returns (uint256 param1); 646 | * function twoItems() public view returns (uint256 param1, uint256 param2); 647 | * 648 | */ 649 | 650 | let resultOne = await oneItem(); 651 | console.log(resultOne); 652 | // 1337 653 | 654 | let resultTwo = await twoItems(); 655 | console.log(resultTwo); 656 | // { 657 | // "param1": 1337, 658 | // "param2": 42, 659 | // 0: 1337, 660 | // 1: 42, 661 | // length: 2 662 | // } 663 | 664 | assert.ok(resultTwo[0] === resultTwo.param1); 665 | assert.ok(resultTwo[1] === resultTwo.param2); 666 | 667 | 668 | ----- 669 | 670 | .. _contract-filter: 671 | 672 | 事件过滤 673 | ================ 674 | 675 | On every contract, there is a ``filters`` property, which can be used to 676 | generate an event filter. And event filter can be passed into the ``on(eventName)`` 677 | of a contract. 678 | 679 | .. code-block:: javascript 680 | :caption: *Find all ERC-20 transfers to myAddress* 681 | 682 | // The null field indicates any value matches, this specifies 683 | // "any Transfer from any to myAddress" 684 | let filter = contract.Transfer(null, myAddress); 685 | 686 | // Listen for our filtered results 687 | contract.on(filter, (from, to, value) => { 688 | console.log('I received ' + value.toString() + ' tokens from ' + from); 689 | }); 690 | 691 | ----- 692 | 693 | .. _contract-abi: 694 | 695 | |ABI| 696 | ================================== 697 | 698 | Each Contract has a description of its interface, which describes each function 699 | and event. 700 | 701 | The Solidity compiler generates the ABI in a JSON format, which can be used as 702 | a JSON string or parsed as a JavaScript Object. This is generated by the 703 | compiler and can be loaded as a file, or copied into the source code. 704 | 705 | The ABI may also be specified using `Human-Readable ABI`_, which is much easier 706 | to use when typing in an ABI by hand, for example, as well as easier to read. This 707 | is simply an array of strings, each of which is the Solidity function or event 708 | signature. 709 | 710 | .. code-block:: javascript 711 | :caption: *Human-Readable ABI* 712 | 713 | let ABI = [ 714 | "event Transfer(address from, address to, uint amount)", 715 | "function transfer(address to, uint amount)", 716 | "function symbol() view returns (string)" 717 | ] 718 | 719 | 720 | ----- 721 | 722 | .. _Human-Readable ABI: https://blog.ricmoo.com/human-readable-contract-abis-in-ethers-js-141902f4d917 723 | .. _Event Emitter API: https://nodejs.org/api/events.html#events_class_eventemitter 724 | 725 | .. EOF 726 | -------------------------------------------------------------------------------- /source/api-providers.rst: -------------------------------------------------------------------------------- 1 | .. include:: glossaries.rst 2 | .. |nbsp| unicode:: U+00A0 .. non-breaking space 3 | 4 | .. _api-provider: 5 | 6 | 提供者 Provider 7 | ***************** 8 | 9 | |provider| 是一个连接以太坊网络的抽象,用与查询以太坊网络状态或者发送更改状态的交易。 10 | 11 | *EtherscanProvider* 和 *InfuraProvider* 提供连接公开的第三方节点服务提供商,无需自己运行任何以太坊节点。 12 | 13 | *JsonRpcProvider* 和 *IpcProvider* 允许连接到我们控制或可以访问的以太坊节点(包括主网,测试网,权威证明(PoA)节点或Ganache)。 14 | 15 | 如果你已经有 Web3 应用程序或 Web3 兼容的 |provider| (例如 MetaMask 的 web3.currentProvider ),它可以用 *Web3Provider* 包装来使它与ethers的Provider API 兼容。 16 | 17 | 在大多数情况下,建议使用默认 |provider| , 它同时连接 Etherscan 和 INFURA 。 18 | 19 | 20 | .. code-block:: javascript 21 | :caption: *连接默认的 provider* 22 | 23 | // 可以使用任何标准网络名称做参数: 24 | // - "homestead" 25 | // - "rinkeby" 26 | // - "ropsten" 27 | // - "kovan" 28 | // - "goerli" 29 | 30 | let provider = ethers.getDefaultProvider('ropsten'); 31 | 32 | .. code-block:: javascript 33 | :caption: *连接 MetaMask* 34 | 35 | // 将自动检测网络; 36 | // 如果在MetaMask中更改了网络,则会导致页面刷新。 37 | 38 | let provider = new ethers.providers.Web3Provider(web3.currentProvider); 39 | 40 | ----- 41 | 42 | .. _provider-connect: 43 | 44 | 连接以太坊网络 45 | ====================== 46 | 47 | 有几种方法可以连接到以太坊提供的网络。如果你不是运行您自己的本地以太坊节点,建议使用 ``getDefaultProvider()`` 方法。 48 | 49 | 50 | :sup:`ethers` . getDefaultProvider( [ network :sup:`= "homestead"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Provider` 51 | 52 | 创建(返回)一个由多个后端(INFURA 和 Etherscan)支持的 FallbackProvider 。 53 | 如果你不是运行自己的以太坊节点,这是**推荐**的连接以太坊网络的方法 54 | 55 | new :sup:`ethers . providers` . EtherscanProvider( [ network :sup:`= "homestead"` ] [ , apiToken ] ) 56 | 连接 `Etherscan`_ blockchain `web 服务 API `_. 57 | 58 | **参考:** Etherscan 说明: :ref:`属性 ` 和 :ref:`方法 ` 59 | 60 | new :sup:`ethers . providers` . InfuraProvider( [ network :sup:`= "homestead"` ] [ , apiAccessToken ] ) 61 | 连接 `INFURA`_ 提供的以太坊节点。 62 | 63 | **参考:** INFURA 说明: :ref:`属性 ` 64 | 65 | new :sup:`ethers . providers` . JsonRpcProvider( [ urlOrInfo :sup:`= "http://localhost:8545"` ] [ , network ] ) 66 | 通过节点 *urlorInfo* 的 `JSON-RPC API`_ URL 进行连接, 如: `Parity`_ 或 `Geth`_ 。 67 | 68 | 参数: *urlOrInfo* 也可以作为一个对象,可以指定以下参数: 69 | 70 | - **url** --- JSON-RPC URL (必须) 71 | - **user** --- 用于基本身份验证的用户名 (可选) 72 | - **password** --- 用于基本身份验证的密码 (可选) 73 | - **allowInsecure** --- 允许通过不安全的HTTP网络进行基本身份验证 (默认值: false) 74 | 75 | **参考:** JSON-RPC 说明: :ref:`属性 ` 和 :ref:`方法 ` 76 | 77 | new :sup:`ethers . providers` . Web3Provider( web3Provider [ , network ] ) 78 | 连接到现有的 Web3 提供者 (如: `web3Instance.currentProvider`). 79 | 80 | 如果没指定参数 *network* ,也会自动检测网络 *network* (主网还是测试网); 有关详细信息见上文 JsonRpcProvider 的 *network* 说明。 81 | 82 | **参考:** Web3 说明: :ref:`属性 ` 和 :ref:`方法 ` 83 | 84 | new :sup:`ethers . providers` . FallbackProvider( providers ) 85 | 通过依次尝试每个 |provider| 来提高可靠性,如果遇到错误,则返回列表中的下一个提供程序。 网络由 |provider| 确定,**必须** 相互匹配。 86 | 87 | **参考:** Fallback 说明: :ref:`属性 ` 88 | 89 | new :sup:`ethers . providers` . IpcProvider( path [ , network ] ) 90 | 通过节点 IPC `JSON-RPC API`_ 连接节点, 如: `Parity`_ 或 `Geth`_ 。提供一个 IPC路径 *path* such 91 | 92 | 如果没指定参数 *network* ,也会自动检测网络 *network* (主网还是测试网); 有关详细信息见上文 JsonRpcProvider 的 *network* 说明。 93 | 94 | **参考:** IPC 说明: :ref:`属性 ` 和 :ref:`方法 ` 95 | 96 | .. code-block:: javascript 97 | :caption: *连接第三方提供者* 98 | 99 | // 可以使用任何标准网络名称做参数: 100 | // - "homestead" 101 | // - "rinkeby" 102 | // - "ropsten" 103 | // - "kovan" 104 | 105 | let defaultProvider = ethers.getDefaultProvider('ropsten'); 106 | 107 | // ... 或 ... 108 | 109 | let etherscanProvider = new ethers.providers.EtherscanProvider('ropsten'); 110 | 111 | // ... 或 ... 112 | 113 | let infuraProvider = new ethers.providers.InfuraProvider('ropsten'); 114 | 115 | .. code-block:: javascript 116 | :caption: *连接 Geth 或 Parity 节点* 117 | 118 | // 在使用JSON-RPC API时,将自动检测网络 119 | 120 | 121 | // 默认: http://localhost:8545 122 | let httpProvider = new ethers.providers.JsonRpcProvider(); 123 | 124 | 125 | // 通过定制 URL 连接 : 126 | let url = "http://something-else.com:8546"; 127 | let customHttpProvider = new ethers.providers.JsonRpcProvider(url); 128 | 129 | 130 | // 通过 IPC 命名管道 131 | let path = "/var/run/parity.ipc"; 132 | let ipcProvider = new ethers.providers.IpcProvider(path); 133 | 134 | 135 | .. code-block:: javascript 136 | :caption: *连接一个已有的 Web3 提供者* 137 | 138 | // 使用 Web3 provider 时, 自动检测网络 139 | 140 | // e.g. HTTP provider 141 | let currentProvider = new web3.providers.HttpProvider('http://localhost:8545'); 142 | 143 | let web3Provider = new ethers.providers.Web3Provider(currentProvider); 144 | 145 | ----- 146 | 147 | 属性 148 | ========== 149 | 150 | 除非另有说明,否则所有属性都是不可变的,如果未指定,则将采用默认值。 151 | 152 | .. _provider: 153 | 154 | 基类 Provider 属性 155 | ------------------- 156 | 157 | :sup:`prototype` . blockNumber 158 | 159 | 返回 |provider| 已经知晓的最新区块号(块高),如果没有同步到区块,则为 *null*。 160 | 161 | :sup:`prototype` . polling 162 | *可变的 mutable* 163 | 164 | 如果 |provider| 当前正在轮询,因为它活跃的观察事件。 165 | 轮询可以设置为临时启用/禁用或永久禁用以允许节点进程退出。 166 | 167 | :sup:`prototype` . pollingInterval 168 | *可变的 mutable* 169 | 170 | |provider| 的轮询频率(以毫秒为单位)。 默认时间间隔为4秒。 171 | 172 | 对于 PoA 网络本地节点时,更小的轮询间隔也许有意义。 不过但轮询Etherscan或INFURA时,设置得太低可能会导致服务阻止我们的IP地址或以其他方式限制API调用。 173 | 174 | .. _provider-etherscan-properties: 175 | 176 | EtherscanProvider (派生于Provider)属性 177 | ------------------------------------------------------- 178 | 179 | :sup:`prototype` . apiToken 180 | The Etherscan API Token (如果没有指定则为空) 181 | 182 | .. _provider-infura-properties: 183 | 184 | InfuraProvider (派生于 JsonRpcProvider )属性 185 | ------------------------------------------------------- 186 | 187 | :sup:`prototype` . apiAccessToken 188 | The INFURA API Access Token (如果没有指定则为空) 189 | 190 | 191 | .. _provider-jsonrpc-properties: 192 | 193 | JsonRpcProvider (派生于Provider)属性 194 | ----------------------------------------------------- 195 | 196 | :sup:`prototype` . connection 197 | 描述JSON-RPC 节点与属性的连接对象: 198 | 199 | - **url** --- the JSON-RPC URL 200 | - **user** --- 用于基本身份验证的用户名 (可选) 201 | - **password** --- 用于基本身份验证的密码 (可选) 202 | - **allowInsecure** --- 允许通过不安全的HTTP网络进行基本身份验证 203 | 204 | .. _provider-web3-properties: 205 | 206 | Web3Provider (派生于 JsonRpcProvider )属性 207 | ----------------------------------------------------- 208 | 209 | :sup:`prototype` . provider 210 | 与 Web3 库兼用的底层 |provider| 。 比如: `HTTPProvider`_ 或 `IPCProvider`_ 。 Web3 |provider| 唯一需要的方法是: 211 | 212 | - **sendAsync ( method , params , callback )** 213 | 214 | .. _provider-fallback-properties: 215 | 216 | FallbackProvider (派生于Provider)属性 217 | ------------------------------------------------------ 218 | 219 | :sup:`prototype` . providers 220 | 一组 |provider| 的拷贝(修改此变量不会影响关联的 |provider| )。 221 | 222 | 223 | .. _provider-ipc-properties: 224 | 225 | IpcProvider (派生于 JsonRpcProvider )属性 226 | ---------------------------------------------------- 227 | 228 | :sup:`prototype` . path 229 | 返回连接的 JSON-RPC IPC(命名管道)路径。 230 | 231 | 232 | ----- 233 | 234 | .. _provider-network: 235 | 236 | 获取网络 237 | ========= 238 | 239 | :sup:`prototype` . getNetwork ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 240 | 返回可获取 :ref:`网络 ` 对象的 :ref:`Promise ` ,包含了连接的网络和链信息。 241 | 242 | ----- 243 | 244 | .. _provider-account: 245 | 246 | 获取账号信息 247 | ============== 248 | 249 | :sup:`prototype` . getBalance ( addressOrName [ , blockTag :sup:`= "latest"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 250 | 返回参数 *addressOrName* 余额的(类型为 :ref:`BigNumber ` ) :ref:`Promise ` 对象。 251 | 可选参数 *blockTag* (参考: :ref:`Block Tags `) 指定一个区块。 252 | 253 | :sup:`prototype` . getTransactionCount ( addressOrName [ , blockTag :sup:`= "latest"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 254 | 返回参数 *addressOrName* 的所发送交易数量(Number对象)的 :ref:`Promise ` 对象,它用来作为发送交易的nonce。 255 | 可选参数 *blockTag* 指定一个区块, (参考: :ref:`Block Tags `) 。 256 | 257 | 258 | .. code-block:: javascript 259 | :caption: *获取账号余额* 260 | 261 | let address = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0"; 262 | 263 | provider.getBalance(address).then((balance) => { 264 | 265 | // 余额是 BigNumber (in wei); 格式化为 ether 字符串 266 | let etherString = ethers.utils.formatEther(balance); 267 | 268 | console.log("Balance: " + etherString); 269 | }); 270 | 271 | .. code-block:: javascript 272 | :caption: *获取账号所发送交易数量* 273 | 274 | let address = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0"; 275 | 276 | provider.getTransactionCount(address).then((transactionCount) => { 277 | console.log("发送交易总数: " + transactionCount); 278 | }); 279 | 280 | ----- 281 | 282 | .. _provider-blockchain: 283 | 284 | 获取以太坊状态 285 | ================= 286 | 287 | :sup:`prototype` . getBlockNumber ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 288 | 返回最新区块号(Number类型)的 :ref:`Promise ` 。 289 | 290 | :sup:`prototype` . getGasPrice ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 291 | 返回当前 gas 价格 (类型 :ref:`BigNumber `) 的 :ref:`Promise ` 。 292 | 293 | :sup:`prototype` . getBlock ( blockHashOrBlockNumber ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 294 | 返回给定参数对应的区块信息的 :ref:`Promise ` (参考: :ref:`区块回复 `) 。 295 | 296 | :sup:`prototype` . getTransaction ( transactionHash ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 297 | 根据交易hash获取交易信息的 :ref:`Promise ` 。 (参考: :ref:`交易回复 `) 298 | 299 | :sup:`prototype` . getTransactionReceipt ( transactionHash ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 300 | 根据交易hash获取交易收据的 :ref:`Promise ` 301 | (参考: :ref:`交易收据 `) 302 | 303 | 304 | .. code-block:: javascript 305 | :caption: *获取当前状态* 306 | 307 | provider.getBlockNumber().then((blockNumber) => { 308 | console.log("Current block number: " + blockNumber); 309 | }); 310 | 311 | provider.getGasPrice().then((gasPrice) => { 312 | // gasPrice is a BigNumber; convert it to a decimal string 313 | gasPriceString = gasPrice.toString(); 314 | 315 | console.log("Current gas price: " + gasPriceString); 316 | }); 317 | 318 | .. code-block:: javascript 319 | :caption: *区块* 320 | 321 | // 查看: https://ropsten.etherscan.io/block/3346773 322 | 323 | // 区块号 324 | provider.getBlock(3346773).then((block) => { 325 | console.log(block); 326 | }); 327 | 328 | // 区块 Hash 329 | let blockHash = "0x7a1d0b010393c8d850200d0ec1e27c0c8a295366247b1bd6124d496cf59182ad"; 330 | provider.getBlock(blockHash).then((block) => { 331 | console.log(block); 332 | }); 333 | 334 | .. code-block:: javascript 335 | :caption: *交易* 336 | 337 | // 查看: https://ropsten.etherscan.io/tx/0xa4ddad980075786c204b45ab8193e543aec4411bd94894abef47dc90d4d3cc01 338 | 339 | let transactionHash = "0xa4ddad980075786c204b45ab8193e543aec4411bd94894abef47dc90d4d3cc01" 340 | 341 | provider.getTransaction(transactionHash).then((transaction) => { 342 | console.log(transaction); 343 | }); 344 | 345 | provider.getTransactionReceipt(transactionHash).then((receipt) => { 346 | console.log(receipt); 347 | }); 348 | 349 | ----- 350 | 351 | .. _provider-ens: 352 | 353 | 以太坊域名服务 ENS 354 | ======================= 355 | 356 | `Ethereum Naming Service`_ (ENS:Ethereum Naming Service 以太坊域名服务) 允许使用一个容易记住的名称来关联一个以太坊地址。(译者注:类似于域名和IP地址) 357 | 任何提供者的可以针对地址也可以针对ENS名称 358 | 359 | ENS还提供反向查找功能,如果已经已配置,可以根据名称找到地址。 360 | 361 | :sup:`prototype` . resolveName ( ensName ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise
    ` 362 | 获取 *ensName* 对应地址的 :ref:`Promise ` ,如果没有则为null 。 363 | 364 | :sup:`prototype` . lookupAddress ( address ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 365 | 获取 *address* 对应的 ENS 名称的 :ref:`Promise ` ,如果没有则为null 。 366 | 367 | .. code-block:: javascript 368 | :caption: *将ENS名称解析为地址* 369 | 370 | provider.resolveName("registrar.firefly.eth").then(function(address) { 371 | console.log("Address: " + address); 372 | // "0x6fC21092DA55B392b045eD78F4732bff3C580e2c" 373 | }); 374 | 375 | .. code-block:: javascript 376 | :caption: *查找地址的ENS名称* 377 | 378 | let address = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c"; 379 | provider.lookupAddress(address).then(function(address) { 380 | console.log("Name: " + address); 381 | // "registrar.firefly.eth" 382 | }); 383 | 384 | ----- 385 | 386 | .. _provider-calling: 387 | 388 | 执行合约 389 | ================== 390 | 391 | 这些是相对低级别的调用。通常应该使用 :ref:`合约 API ` 392 | 393 | :sup:`prototype` . call ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 394 | Send the **read-only** (constant) *transaction* to a single Ethereum node and 395 | return a :ref:`Promise ` with the result (as a :ref:`hex string `) of executing it. 396 | (See :ref:`Transaction Requests `) 397 | 398 | 免费执行,因为它不会改变区块链上的任何状态。 399 | 400 | :sup:`prototype` . estimateGas ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 401 | Send a *transaction* to a single Ethereum node and return a :ref:`Promise ` with the 402 | estimated amount of gas required (as a :ref:`BigNumber `) to send it. 403 | (See :ref:`Transaction Requests `) 404 | 405 | 免费执行,但只是一个估算。 提供太少的 Gas 将导致交易被拒绝(同时仍然消耗掉所有提供的Gas)。 406 | 407 | :sup:`prototype` . sendTransaction ( signedTransaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 408 | Send the *signedTransaction* to the **entire** Ethereum network and 返回 :ref:`Promise ` 409 | that resolves to the :ref:`Transaction Response `. 410 | 411 | If an error occurs after the netowrk **may have** received the transaction, the 412 | promise will reject with the error, with the additional property ``transactionHash`` 413 | so that further processing may be done. 414 | 415 | **This will consume gas** from the account that signed the transaction. 416 | 417 | 418 | .. code-block:: javascript 419 | :caption: *calling constant functions* 420 | 421 | // See: https://ropsten.etherscan.io/address/0x6fc21092da55b392b045ed78f4732bff3c580e2c 422 | 423 | // Setup a transaction to call the FireflyRegistrar.fee() function 424 | 425 | // FireflyRegistrar contract address 426 | let address = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c"; 427 | 428 | // First 4 bytes of the hash of "fee()" for the sighash selector 429 | let data = ethers.utils.hexDataSlice(ethers.utils.id('fee()'), 0, 4); 430 | 431 | let transaction = { 432 | to: ensName, 433 | data: data 434 | } 435 | 436 | let callPromise = defaultProvider.call(transaction); 437 | 438 | callPromise.then((result) => { 439 | console.log(result); 440 | // "0x000000000000000000000000000000000000000000000000016345785d8a0000" 441 | 442 | console.log(ethers.utils.formatEther(result)); 443 | // "0.1" 444 | }); 445 | 446 | .. code-block:: javascript 447 | :caption: *sending a transaction* 448 | 449 | let privateKey = '0x0123456789012345678901234567890123456789012345678901234567890123'; 450 | let wallet = new ethers.Wallet(privateKey, provider); 451 | 452 | let transaction = { 453 | to: "ricmoo.firefly.eth", 454 | value: ethers.utils.parseEther("0.1") 455 | }; 456 | 457 | // Send the transaction 458 | let sendTransactionPromise = wallet.sendTransaction(transaction); 459 | 460 | sendTransactionPromise.then((tx) => { 461 | console.log(tx); 462 | }); 463 | 464 | ----- 465 | 466 | .. _provider-contract: 467 | 468 | 合约信息 469 | ============== 470 | 471 | :sup:`prototype` . getCode ( addressOrName ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 472 | 返回 :ref:`Promise ` with the bytecode (as a :ref:`hex string `) 473 | at *addressOrName*. 474 | 475 | :sup:`prototype` . getStorageAt ( addressOrName , position [ , blockTag :sup:`= "latest"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 476 | 返回 :ref:`Promise ` with the value (as a :ref:`hex string `) at 477 | *addressOrName* in *position* at *blockTag*. (参考 :ref:`Block Tags `) 478 | 479 | :sup:`prototype` . getLogs ( filter ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise< Log [ ] >` 480 | 返回 :ref:`Promise ` with an array (possibly empty) of the logs that 481 | match the *filter*. (参考 :ref:`Filters `) 482 | 483 | .. code-block:: javascript 484 | :caption: *get contract code* 485 | 486 | let contractEnsName = 'registrar.firefly.eth'; 487 | 488 | let codePromise = provider.getCode(contractEnsName); 489 | 490 | codePromise.then((result) => { 491 | console.log(result); 492 | }); 493 | 494 | .. code-block:: javascript 495 | :caption: *get contract storage value* 496 | 497 | let contractEnsName = 'registrar.firefly.eth'; 498 | 499 | // Position 0 in the FireflyRegistrar contract holds the ENS address 500 | 501 | let storagePromise = provider.getStorageAt(contractEnsName, 0); 502 | 503 | storagePromise.then((result) => { 504 | console.log(result); 505 | // "0x000000000000000000000000112234455c3a32fd11230c42e7bccd4a84e02010" 506 | }); 507 | 508 | .. code-block:: javascript 509 | :caption: *get contract event logs* 510 | 511 | let contractEnsName = 'registrar.firefly.eth'; 512 | 513 | let topic = ethers.utils.id("nameRegistered(bytes32,address,uint256)"); 514 | 515 | let filter = { 516 | address: contractEnsName, 517 | fromBlock: 3313425, 518 | toBlock: 3313430, 519 | topics: [ topic ] 520 | } 521 | 522 | provider.getLogs(filter).then((result) => { 523 | console.log(result); 524 | // [ { 525 | // blockNumber: 3313426, 526 | // blockHash: "0xe01c1e437ed3af9061006492cb07454eca8561479454a709809b7897f225387d", 527 | // transactionIndex: 5, 528 | // removed: false, 529 | // address: "0x6fC21092DA55B392b045eD78F4732bff3C580e2c", 530 | // data: "0x00000000000000000000000053095760c154a1531a69fc718119d14c4aa1506f" + 531 | // "000000000000000000000000000000000000000000000000016345785d8a0000", 532 | // topics: [ 533 | // "0x179ef3319e6587f6efd3157b34c8b357141528074bcb03f9903589876168fa14", 534 | // "0xe625ed7b108857745d1d9889a7ae05861d8aee38e0e92fd3a31191de01c2515b" 535 | // ], 536 | // transactionHash: "0x61d641aaf3dcf4cf6bafc3e79d332d8773ea0688f87eb00f8b60c3f0050e55f0", 537 | // logIndex: 5 538 | // } ] 539 | 540 | }); 541 | 542 | ----- 543 | 544 | .. _provider-events: 545 | 546 | 事件 547 | ====== 548 | 549 | These methods allow management of callbacks on certain events on the blockchain 550 | and contracts. They are largely based on the `EventEmitter API`_. 551 | 552 | :sup:`prototype` . on ( eventType , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`Provider` 553 | Register a callback for any future *eventType*; see below for callback parameters 554 | 555 | :sup:`prototype` . once ( eventType , callback) |nbsp| :sup:`=>` |nbsp| :sup:`Provider` 556 | Register a callback for the next (and only next) *eventType*; see below for callback parameters 557 | 558 | :sup:`prototype` . removeListener ( eventType , callback ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 559 | Unregister the *callback* for *eventType*; if the same callback is registered 560 | more than once, only the first registered instance is removed 561 | 562 | :sup:`prototype` . removeAllListeners ( eventType ) |nbsp| :sup:`=>` |nbsp| :sup:`Provider` 563 | Unregister all callbacks for *eventType* 564 | 565 | :sup:`prototype` . listenerCount ( [ eventType ] ) |nbsp| :sup:`=>` |nbsp| :sup:`number` 566 | Return the number of callbacks registered for *eventType*, or if ommitted, the 567 | total number of callbacks registered 568 | 569 | :sup:`prototype` . resetEventsBlock ( blockNumber ) |nbsp| :sup:`=>` |nbsp| :sup:`void` 570 | Begin scanning for events from *blockNumber*. By default, events begin at the 571 | block number that the provider began polling at. 572 | 573 | 事件类型 574 | ----------- 575 | 576 | "block" 577 | Whenever a new block is mined 578 | 579 | ``callback( blockNumber )`` 580 | 581 | "pending" 582 | Whenever a new transaction is added to the transaction pool. This is **NOT** 583 | available on Etherscan or INFURA providers and may not be reliable on any 584 | provider. 585 | 586 | ``callback( transactionHash )`` 587 | 588 | "error" 589 | Whenever an error occurs during an event. 590 | 591 | ``callback( error )`` 592 | 593 | any address 594 | When the balance of the corresponding address changes. 595 | 596 | ``callback( balance )`` 597 | 598 | any transaction hash 599 | When the corresponding transaction has been included in a block; 参考 600 | :ref:`Waiting for Transactions `. 601 | 602 | ``callback( transactionReceipt )`` 603 | 604 | a filtered event object 605 | When the an event is logged by a transaction to the *address* with the 606 | associated *topics*. The filtered event properties are: 607 | 608 | - **address** --- the contract address to filter by (可选) 609 | - **topics** --- the log topics to filter by (可选) 610 | 611 | ``callback( log )`` 612 | 613 | an array of topics 614 | When any of the topics are logs by a transaction to any address. This is 615 | equivalent to using a filter object with no *address*. 616 | 617 | ``callback( log )`` 618 | 619 | .. _waitForTransaction: 620 | 621 | 等待交易 622 | ------------------------ 623 | 624 | :sup:`prototype` . waitForTransaction ( transactionHash ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 625 | Return a :ref:`Promise ` 可以获取到 the 626 | :ref:`Transaction Receipt ` once *transactionHash* is 627 | mined. 628 | 629 | .. code-block:: javascript 630 | :caption: *new blocks* 631 | 632 | provider.on('block', (blockNumber) => { 633 | console.log('New Block: ' + blockNumber); 634 | }); 635 | 636 | .. code-block:: javascript 637 | :caption: *account balance changes* 638 | 639 | provider.on('0x46Fa84b9355dB0708b6A57cd6ac222950478Be1d', (balance) => { 640 | console.log('New Balance: ' + balance); 641 | }); 642 | 643 | .. code-block:: javascript 644 | :caption: *transaction mined* 645 | 646 | provider.once(transactionHash, (receipt) => { 647 | console.log('Transaction Minded: ' + receipt.hash); 648 | console.log(receipt); 649 | ); 650 | 651 | // ... OR ... 652 | 653 | provider.waitForTransaction(transactionHash).then((receipt) => { 654 | console.log('Transaction Mined: ' + receipt.hash); 655 | console.log(receipt); 656 | }); 657 | 658 | .. code-block:: javascript 659 | :caption: *a filtered event has been logged* 660 | 661 | let contractEnsName = 'registrar.firefly.eth'; 662 | 663 | let topic = ethers.utils.id("nameRegistered(bytes32,address,uint256)"); 664 | 665 | let filter = { 666 | address: contractEnsName, 667 | topics: [ topic ] 668 | } 669 | 670 | provider.on(filter, (result) => { 671 | console.log(result); 672 | // { 673 | // blockNumber: 3606106, 674 | // blockHash: "0x878aa7059c93239437f66baeec82332dcb2f9288bcdf6eb1ff3ba6998cdf8f69", 675 | // transactionIndex: 6, 676 | // removed: false, 677 | // address: "0x6fC21092DA55B392b045eD78F4732bff3C580e2c", 678 | // data: "0x00000000000000000000000006b5955a67d827cdf91823e3bb8f069e6c89c1d6" + 679 | // "000000000000000000000000000000000000000000000000016345785d8a0000", 680 | // topics: [ 681 | // "0x179ef3319e6587f6efd3157b34c8b357141528074bcb03f9903589876168fa14", 682 | // "0x90a4d0958790016bde1de8375806da3be227ff48e611aefea36303fb86bca5ad" 683 | // ], 684 | // transactionHash: "0x0d6f43accb067ca8e391666f37f8e8ad75f88ebd8036c9166fd2d0b93b214d2e", 685 | // logIndex: 6 686 | // } 687 | }); 688 | 689 | 690 | ----- 691 | 692 | 对象及类型(用于参数及返回值) 693 | ================================== 694 | 695 | There are several common objects and types that are commonly used as input parameters or 696 | return types for various provider calls. 697 | 698 | ----- 699 | 700 | .. _blocktag: 701 | 702 | Block Tag 703 | --------- 704 | 705 | A block tag is used to uniquely identify a block's position in the blockchain: 706 | 707 | a Number or :ref:`hex string `: 708 | Each block has a block number (eg. ``42`` or ``"0x2a``. 709 | 710 | "latest": 711 | The most recently mined block. 712 | 713 | "pending": 714 | The block that is currently being mined. 715 | 716 | ----- 717 | 718 | .. _blockresponse: 719 | 720 | Block Responses 721 | --------------- 722 | 723 | .. code-block:: javascript 724 | :caption: *Example* 725 | 726 | { 727 | parentHash: "0x3d8182d27303d92a2c9efd294a36dac878e1a9f7cb0964fa0f789fa96b5d0667", 728 | hash: "0x7f20ef60e9f91896b7ebb0962a18b8defb5e9074e62e1b6cde992648fe78794b", 729 | number: 3346463, 730 | 731 | difficulty: 183765779077962, 732 | timestamp: 1489440489, 733 | nonce: "0x17060cb000d2c714", 734 | extraData: "0x65746865726d696e65202d20555331", 735 | 736 | gasLimit: utils.bigNumberify("3993225"), 737 | gasUsed: utils.bigNuberify("3254236"), 738 | 739 | miner: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", 740 | transactions: [ 741 | "0x125d2b846de85c4c74eafb6f1b49fdb2326e22400ae223d96a8a0b26ccb2a513", 742 | "0x948d6e8f6f8a4d30c0bd527becbe24d15b1aba796f9a9a09a758b622145fd963", 743 | ... [ 49 more transaction hashes ] ... 744 | "0xbd141969b164ed70388f95d780864210e045e7db83e71f171ab851b2fba6b730" 745 | ] 746 | } 747 | 748 | ----- 749 | 750 | .. _network: 751 | 752 | 网络 753 | ------- 754 | 755 | A network repsents various properties of a network, such as mainnet (i.e. "homestead") or 756 | one of the testnets (e.g. "ropsten", "rinkeby" or "kovan") or alternative networks 757 | (e.g. "classic"). A Network has the following properties: 758 | 759 | - *name* --- the name of the network (e.g. "homestead", "rinkeby") 760 | - *chainId* --- the chain ID (network ID) of the connected network 761 | - *ensAddress* --- the address of ENS if it is deployed to the network, otherwise *null* 762 | 763 | If a network does not have the ENS contract deployed to it, names cannot be resolved to addresses. 764 | 765 | .. code-block:: javascript 766 | :caption: *get a standard network* 767 | 768 | let network = ethers.providers.getNetwork('homestead'); 769 | // { 770 | // chainId: 1, 771 | // ensAddress: "0x314159265dd8dbb310642f98f50c066173c1259b", 772 | // name: "homestead" 773 | // } 774 | 775 | .. code-block:: javascript 776 | :caption: *a custom development network* 777 | 778 | let network = { 779 | chainId: 1337, 780 | name: "dev" 781 | } 782 | 783 | ----- 784 | 785 | .. _transaction-request: 786 | 787 | 交易请求 788 | -------------------- 789 | 790 | Any property which accepts a number may also be specified as a :ref:`BigNumber ` 791 | or :ref:`hex string `. Any property may also be given as a :ref:`Promise ` 792 | 可以获取到 the expected type. 793 | 794 | .. code-block:: javascript 795 | :caption: *Example* 796 | 797 | { 798 | // Required unless deploying a contract (in which case omit) 799 | to: addressOrName, // the target address or ENS name 800 | 801 | // These are optional/meaningless for call and estimateGas 802 | nonce: 0, // the transaction nonce 803 | gasLimit: 0, // the maximum gas this transaction may spend 804 | gasPrice: 0, // the price (in wei) per unit of gas 805 | 806 | // These are always optional (but for call, data is usually specified) 807 | data: "0x", // extra data for the transaction, or input for call 808 | value: 0, // the amount (in wei) this transaction is sending 809 | chainId: 3 // the network ID; usually added by a signer 810 | } 811 | 812 | ----- 813 | 814 | .. _transaction-response: 815 | 816 | 交易回复 817 | -------------------- 818 | 819 | .. code-block:: javascript 820 | :caption: *Example* 821 | 822 | { 823 | // Only available for mined transactions 824 | blockHash: "0x7f20ef60e9f91896b7ebb0962a18b8defb5e9074e62e1b6cde992648fe78794b", 825 | blockNumber: 3346463, 826 | timestamp: 1489440489, 827 | 828 | // Exactly one of these will be present (send vs. deploy contract) 829 | // They will always be a properly formatted checksum address 830 | creates: null, 831 | to: "0xc149Be1bcDFa69a94384b46A1F91350E5f81c1AB", 832 | 833 | // The transaction hash 834 | hash: "0xf517872f3c466c2e1520e35ad943d833fdca5a6739cfea9e686c4c1b3ab1022e", 835 | 836 | // See above "Transaction Requests" for details 837 | data: "0x", 838 | from: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", 839 | gasLimit: utils.bigNumberify("90000"), 840 | gasPrice: utils.bigNumberify("21488430592"), 841 | nonce: 0, 842 | value: utils.parseEther(1.0017071732629267), 843 | 844 | // The chain ID; 0 indicates replay-attack vulnerable 845 | // (eg. 1 = Homestead mainnet, 3 = Ropsten testnet) 846 | chainId: 1, 847 | 848 | // The signature of the transaction (TestRPC may fail to include these) 849 | r: "0x5b13ef45ce3faf69d1f40f9d15b0070cc9e2c92f3df79ad46d5b3226d7f3d1e8", 850 | s: "0x535236e497c59e3fba93b78e124305c7c9b20db0f8531b015066725e4bb31de6", 851 | v: 37, 852 | 853 | // The raw transaction (TestRPC may be missing this) 854 | raw: "0xf87083154262850500cf6e0083015f9094c149be1bcdfa69a94384b46a1f913" + 855 | "50e5f81c1ab880de6c75de74c236c8025a05b13ef45ce3faf69d1f40f9d15b0" + 856 | "070cc9e2c92f3df79ad46d5b3226d7f3d1e8a0535236e497c59e3fba93b78e1" + 857 | "24305c7c9b20db0f8531b015066725e4bb31de6" 858 | } 859 | 860 | ----- 861 | 862 | .. _transaction-receipt: 863 | 864 | 交易收据 865 | -------------------- 866 | 867 | .. code-block:: javascript 868 | :caption: *Example* 869 | 870 | { 871 | transactionHash: "0x7dec07531aae8178e9d0b0abbd317ac3bb6e8e0fd37c2733b4e0d382ba34c5d2", 872 | 873 | // The block this transaction was mined into 874 | blockHash: "0xca1d4d9c4ac0b903a64cf3ae3be55cc31f25f81bf29933dd23c13e51c3711840", 875 | blockNumber: 3346629, 876 | 877 | // The index into this block of the transaction 878 | transactionIndex: 1, 879 | 880 | // The address of the contract (if one was created) 881 | contractAddress: null, 882 | 883 | // Gas 884 | cumulativeGasUsed: utils.bigNumberify("42000"), 885 | gasUsed: utils.bigNumberify("21000"), 886 | 887 | // Logs (an Array of Logs) 888 | log: [ ], 889 | logsBloom: "0x00" ... [ 256 bytes of 0 ] ... "00", 890 | 891 | // Post-Byzantium hard-fork 892 | byzantium: false 893 | 894 | //////////// 895 | // Pre-byzantium blocks will have a state root: 896 | root: "0x8a27e1f7d3e92ae1a01db5cce3e4718e04954a34e9b17c1942011a5f3a942bf4", 897 | 898 | //////////// 899 | // Post-byzantium blocks will have a status (0 indicated failure during execution) 900 | // status: 1 901 | } 902 | 903 | ----- 904 | 905 | .. _log: 906 | 907 | 日志 908 | ------ 909 | 910 | .. code-block:: javascript 911 | :caption: *Example* 912 | 913 | { 914 | // The block this log was emitted by 915 | blockNumber: 916 | blockHash: 917 | 918 | // The transaction this log was emiited by 919 | transactionHash: 920 | transactionIndex: 921 | logIndex: 922 | 923 | // Whether the log has been removed (due to a chain re-org) 924 | removed: false, 925 | 926 | // The contract emitting the log 927 | address: 928 | 929 | // The indexed data (topics) and non-indexed data (data) for this log 930 | topics: [] 931 | data: 932 | } 933 | 934 | ----- 935 | 936 | .. _filter: 937 | 938 | 过滤器 939 | --------- 940 | 941 | Filtering on topics supports a `somewhat complicated`_ specification, however, 942 | for the vast majority of filters, a single topic is usually sufficient (see the example below). 943 | 944 | The *EtherscanProvider* currently only supports a single topic. 945 | 946 | .. code-block:: javascript 947 | :caption: *Example* 948 | 949 | { 950 | // Optional; The range of blocks to limit querying (See: Block Tags above) 951 | fromBlock: "latest", 952 | toBlock: "latest", 953 | 954 | // Optional; The specific block to limit the query to 955 | // Note: This may NOT be used with fromBlock or toBlock 956 | // Note: EtherscanProvider does not support blockHash 957 | // Note: This may be used for getLogs, but not as a provider Event (i.e. .on) 958 | blockHash: blockHash, 959 | 960 | // Optional; An address (or ENS name) to filter by 961 | address: addressOrName, 962 | 963 | // Optional; A (possibly nested) list of topics 964 | topics: [ topic1 ] 965 | } 966 | 967 | @TODO: Link to cookbook entry for filtering ERC-20 events for an address 968 | 969 | ----- 970 | 971 | |provider| 额外的 API 972 | ================================= 973 | 974 | .. _provider-etherscan-extra: 975 | 976 | Etherscan 977 | --------- 978 | 979 | :sup:`prototype` . getEtherPrice ( ) 980 | 返回 :ref:`Promise ` with the price of ether in USD. 981 | 982 | :sup:`prototype` . getHistory ( addressOrName [ , startBlock :sup:`= 0` [ , endBlock :sup:`= "latest"` ] ] ) 983 | 返回 :ref:`Promise ` with an array of :ref:`Transaction Responses ` 984 | for each transaction to or from *addressOrName* between *startBlock* and *endBlock* (inclusive). 985 | 986 | .. code-block:: javascript 987 | :caption: *a filtered event has been logged* 988 | 989 | let etherscanProvider = new ethers.providers.EtherscanProvider(); 990 | 991 | // Getting the current Ethereum price 992 | etherscanProvider.getEtherPrice().then(function(price) { 993 | console.log("Ether price in USD: " + price); 994 | }); 995 | 996 | 997 | // Getting the transaction history of an address 998 | let address = '0xb2682160c482eB985EC9F3e364eEc0a904C44C23'; 999 | let startBlock = 3135808; 1000 | let endBlock = 5091477; 1001 | etherscanProvider.getHistory(address, startBlock, endBlock).then(function(history) { 1002 | console.log(history); 1003 | // [ 1004 | // { 1005 | // hash: '0x327632ccb6d7bb47b455383e936b2f14e6dc50dbefdc214870b446603b468675', 1006 | // blockHash: '0x0415f0d2741de45fb748166c7dc2aad9b3ff66bcf7d0a127f42a71d3e286c36d', 1007 | // blockNumber: 3135808, 1008 | // transactionIndex: 1, 1009 | // from: '0xb2682160c482eB985EC9F3e364eEc0a904C44C23', 1010 | // gasPrice: ethers.utils.bigNumberify('0x4a817c800'), 1011 | // gasLimit: ethers.utils.bigNumberify('0x493e0'), 1012 | // to: '0xAe572713CfE65cd7033774170F029B7219Ee7f70', 1013 | // value: ethers.utils.bigNumberify('0xd2f13f7789f0000'), 1014 | // nonce: 25, 1015 | // data: '0x', 1016 | // creates: null, 1017 | // chainId: 0 1018 | // }, 1019 | // { 1020 | // hash: '0x7c10f2e7125a1fa5e37b54f5fac5465e8d594f89ff97916806ca56a5744812d9', 1021 | // ... 1022 | // } 1023 | // ] 1024 | }); 1025 | 1026 | .. _provider-jsonrpc-extra: 1027 | 1028 | JsonRpcProvider 1029 | --------------- 1030 | 1031 | :sup:`prototype` . send ( method , params ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 1032 | Send the JSON-RPC *method* with *params*. This is useful for calling 1033 | non-standard or less common JSON-RPC methods. A :ref:`Promise ` is 1034 | returned which will resolve to the parsed JSON result. 1035 | 1036 | :sup:`prototype` . listAccounts ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise
    ` 1037 | 返回 :ref:`Promise ` with a list of all account addresses the 1038 | node connected to this Web3 controls. 1039 | 1040 | :sup:`prototype` . getSigner( [ indexOrAddress ] ) |nbsp| :sup:`=>` |nbsp| :sup:`JsonRpcSigner` 1041 | 返回 :ref:`JsonRpcSigner ` attached to an account on the 1042 | Ethereum node the Web3 object is connected to. If *indexOrAddress* is not specified, 1043 | the first account on the node is used. 1044 | 1045 | 1046 | .. code-block:: javascript 1047 | :caption: *send vendor specific JSON-RPC API* 1048 | 1049 | let hash = "0x2ddf6dd2ec23adf525dac59d7c9189b25b172d679aad951e59e232045f2c811f"; 1050 | jsonRpcProvider.send('debug_traceTransaction', [ hash ]).then((result) => { 1051 | console.log(result); 1052 | }); 1053 | 1054 | .. code-block:: javascript 1055 | :caption: *list accounts and load the second account* 1056 | 1057 | // Get a signer for the account at index 1 1058 | jsonRpcProvider.listAccounts().then((accounts) => { 1059 | let signer = jsonRpcProvider.getSigner(accounts[1]); 1060 | console.log(signer); 1061 | }); 1062 | 1063 | .. _signer-jsonrpc: 1064 | 1065 | JsonRpcSigner 1066 | ------------- 1067 | 1068 | An account from a JSON-RPC API connection the conforms to the :ref:`Signer API `. 1069 | The :ref:`getSigner ` method of a JsonRpcProvider should be 1070 | used to instantiate these. 1071 | 1072 | :sup:`prototype` . provider 1073 | The provider that this Signer is connected to. 1074 | 1075 | :sup:`prototype` . getAddress ( ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise
    ` 1076 | 返回 :ref:`Promise ` that resolves to the account address. 1077 | 1078 | :sup:`prototype` . getBalance ( [ blockTag :sup:`= "latest"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 1079 | 返回 :ref:`Promise ` for the account balance. 1080 | 1081 | :sup:`prototype` . getTransactionCount ( [ blockTag :sup:`= "latest"` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 1082 | 返回 :ref:`Promise ` for the account transaction count. This 1083 | can be used to determine the next nonce to use for a transaction. 1084 | 1085 | :sup:`prototype` . sendTransaction ( [ transactionRequest ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 1086 | 返回 :ref:`Promise ` that resolves to the Transaction Response for 1087 | the sent transaction. 1088 | 1089 | If an error occurs after the netowrk **may have** received the transaction, the 1090 | promise will reject with the error, with the additional property ``transactionHash`` 1091 | so that further processing may be done. 1092 | 1093 | :sup:`prototype` . signMessage ( message ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 1094 | 返回 :ref:`Promise ` that resolves the signature of a signed message, in the 1095 | :ref:`Flat Format `. 1096 | 1097 | :sup:`prototype` . unlock ( password ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 1098 | 返回 :ref:`Promise ` the resolves to true or false, depending 1099 | on whether the account unlock was successful. 1100 | 1101 | ----- 1102 | 1103 | .. _Ethereum Naming Service: https://ens.domains 1104 | .. _Etherscan: https://etherscan.io/apis 1105 | .. _web service API: https://etherscan.io/apis 1106 | .. _INFURA: https://infura.io 1107 | .. _Parity: https://ethcore.io/parity.html 1108 | .. _Geth: https://geth.ethereum.org 1109 | .. _JSON-RPC API: https://github.com/ethereum/wiki/wiki/JSON-RPC 1110 | .. _EventEmitter API: https://nodejs.org/dist/latest-v6.x/docs/api/events.html 1111 | .. _replay protection: https://github.com/ethereum/EIPs/issues/155 1112 | .. _somewhat complicated: https://github.com/ethereum/wiki/wiki/JSON-RPC#a-note-on-specifying-topic-filters 1113 | .. _HTTPProvider: https://github.com/ethereum/web3.js/blob/develop/lib/web3/httpprovider.js 1114 | .. _IPCProvider: https://github.com/ethereum/web3.js/blob/develop/lib/web3/ipcprovider.js 1115 | 1116 | .. EOF 1117 | -------------------------------------------------------------------------------- /source/api-utils.rst: -------------------------------------------------------------------------------- 1 | .. include:: glossaries.rst 2 | .. |nbsp| unicode:: U+00A0 .. non-breaking space 3 | 4 | 工具包 5 | ********* 6 | 7 | 工具包提供了大量的通用实用函数去编写 dapps、处理用户输入和格式化数据等功能。 8 | 9 | ----- 10 | 11 | 地址相关函数 12 | ================== 13 | 14 | There are :ref:`several formats ` available to represent Ethereum 15 | addresses and various ways they are determined. 16 | 17 | .. _utils-getaddress: 18 | 19 | :sup:`utils` . getAddress ( address ) |nbsp| :sup:`=>` |nbsp| :sup:`Address` 20 | Normalize any supported address-format to a :ref:`checksum address `. 21 | 22 | :sup:`utils` . getIcapAddress ( address ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 23 | Normalize any supported address-format to a :ref:`ICAP address `. 24 | 25 | :sup:`utils` . getContractAddress ( transaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Address` 26 | Computes the contract address of a contract deployed by *transaction*. The only 27 | properties used are *from* and *nonce*. 28 | 29 | .. code-block:: javascript 30 | :caption: *convert between address formats* 31 | 32 | let address = "0xd115bffabbdd893a6f7cea402e7338643ced44a6"; 33 | let icapAddress = "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI"; 34 | 35 | console.log(utils.getAddress(address)); 36 | // "0xD115BFFAbbdd893A6f7ceA402e7338643Ced44a6" 37 | 38 | console.log(utils.getAddress(icapAddress)); 39 | // "0xD115BFFAbbdd893A6f7ceA402e7338643Ced44a6" 40 | 41 | console.log(utils.getAddress(address, true)); 42 | // "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI" 43 | 44 | console.log(utils.getAddress(icapAddress, true)); 45 | // "XE93OF8SR0OWI6F4FO88KWO4UNNGG1FEBHI" 46 | 47 | 48 | .. code-block:: javascript 49 | :caption: *determine a contract address* 50 | 51 | // Ropsten: 0x5bdfd14fcc917abc2f02a30721d152a6f147f09e8cbaad4e0d5405d646c5c3e1 52 | let transaction = { 53 | from: '0xc6af6e1a78a6752c7f8cd63877eb789a2adb776c', 54 | nonce: 0 55 | }; 56 | 57 | console.log(utils.getContractAddress(transaction)); 58 | // "0x0CcCC7507aEDf9FEaF8C8D731421746e16b4d39D" 59 | 60 | 61 | ----- 62 | 63 | .. _arrayish: 64 | 65 | Arrayish 66 | ========== 67 | 68 | An arrayish object is used to describe binary data and has the following conditions met: 69 | 70 | - has a *length* property 71 | - has a value for each index from 0 up to (but excluding) *length* 72 | - has a valid byte for each value; a byte is an integer in the range [0, 255] 73 | - is **not** a string 74 | 75 | **Examples:** ``Buffer``, ``[ 1, 2, 3 ]``, ``Uint8Array`` 76 | 77 | :sup:`utils` . isArrayish ( object ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 78 | Returns true if *object* can be treated as an arrayish object. 79 | 80 | :sup:`utils` . arrayify ( hexStringOrBigNumberOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array` 81 | Returns a Uint8Array of a hex string, BigNumber or of an `Arrayish`_ object. 82 | 83 | :sup:`utils` . concat ( arrayOfHexStringsAndArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array` 84 | Return a Uint8Array of all *arrayOfHexStringsAndArrayish* concatenated. 85 | 86 | :sup:`utils` . padZeros ( typedUint8Array, length ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array` 87 | Return a Uint8Array of *typedUint8Array* with zeros prepended to *length* bytes. 88 | 89 | :sup:`utils` . stripZeros ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array` 90 | Returns a Uint8Array with all leading zero **bytes** striped. 91 | 92 | ----- 93 | 94 | .. _bignumber: 95 | 96 | 大数处理 97 | =========== 98 | 99 | A BigNumber is an immutable object which allow accurate math operations 100 | on values larger than :ref:`JavaScript can accurately handle ` 101 | can safely handle. Also see: :ref:`Constants ` 102 | 103 | :sup:`prototype` . add ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 104 | Return a new BigNumber of this plus *otherValue*. 105 | 106 | :sup:`prototype` . sub ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 107 | Return a new BigNumber of this minus *otherValue*. 108 | 109 | :sup:`prototype` . mul ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 110 | Return a new BigNumber of this times *otherValue*. 111 | 112 | :sup:`prototype` . div ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 113 | Return a new BigNumber of this divided by *otherValue*. 114 | 115 | :sup:`prototype` . mod ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 116 | Return a new BigNumber of this modulo *otherValue*. 117 | 118 | :sup:`prototype` . maskn ( bits ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 119 | Return a new BigNumber with the number of *bits* masked. 120 | 121 | :sup:`prototype` . eq ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 122 | Return true if this is equal to *otherValue*. 123 | 124 | :sup:`prototype` . lt ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 125 | Return true if this is less than *otherValue*. 126 | 127 | :sup:`prototype` . lte ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 128 | Return true if this is less or equal to *otherValue*. 129 | 130 | :sup:`prototype` . gt ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 131 | Return true if this is greater than *otherValue*. 132 | 133 | :sup:`prototype` . gte ( otherValue ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 134 | Return true if this is greater than or equal to *otherValue*. 135 | 136 | :sup:`prototype` . isZero ( ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 137 | Return true if this is equal to zero. 138 | 139 | :sup:`prototype` . toNumber ( ) |nbsp| :sup:`=>` |nbsp| :sup:`number` 140 | Return a JavaScript number of the value. 141 | 142 | An error is thrown if the value is outside the safe range for JavaScript 143 | IEEE 754 64-bit floating point numbers (over 53 bits of mantissa). 144 | 145 | :sup:`prototype` . toString () |nbsp| :sup:`=>` |nbsp| :sup:`string` 146 | Return a decimal string representation. 147 | 148 | :sup:`prototype` . toHexString ( ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 149 | Return a hexstring representation of the value. 150 | 151 | 152 | 创建 BigNumber 实例 153 | ----------------------- 154 | 155 | :sup:`utils` . bigNumberify ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 156 | Returns a BigNumber instance of *value*. The *value* may be anything that can 157 | reliably be converted into a BigNumber: 158 | 159 | ============================ ======================= ================================= 160 | Type Examples Notes 161 | ============================ ======================= ================================= 162 | decimal string ``"42"``, ``"-42"`` 163 | hexadecimal string ``"0x2a"``, ``"-0x2a"`` case-insensitive 164 | numbers ``42``, ``-42`` must be witin the `safe range`_ 165 | :ref:`Arrayish ` ``[ 30, 252 ]`` big-endian encoding 166 | BigNumber any other BigNumber returns the same instance 167 | ============================ ======================= ================================= 168 | 169 | .. code-block:: javascript 170 | :caption: *examples* 171 | 172 | let gasPriceWei = utils.bigNumberify("20902747399"); 173 | let gasLimit = utils.bigNumberify(3000000); 174 | 175 | let maxCostWei = gasPriceWei.mul(gasLimit) 176 | console.log("Max Cost: " + maxCostWei.toString()); 177 | // "Max Cost: 62708242197000000" 178 | 179 | console.log("Number: " + maxCostWei.toNumber()); 180 | // throws an Error, the value is too large for JavaScript to handle safely 181 | 182 | ----- 183 | 184 | .. _bytes32string: 185 | 186 | Bytes32 字符串 187 | ================== 188 | 189 | Often for short strings, it is far more efficient to store them as 190 | a fixed, null-terminated bytes32, instead of a dynamic length-prefixed 191 | bytes. 192 | 193 | :sup:`utils` . formatBytes32String ( text ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 194 | Returns a :ref:`hex string ` representation of *text*, exactly 195 | 32 bytes wide. Strings **must** be 31 bytes or shorter, or an exception 196 | is thrown. 197 | 198 | **NOTE:** Keep in mind that UTF-8 characters outside the ASCII range can 199 | be multiple bytes long. 200 | 201 | :sup:`utils` . parseBytes32String ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`string` 202 | Returns *hexStringOrArrayish* as the original string, as generated by ``formatBytes32String``. 203 | 204 | .. code-block:: javascript 205 | :caption: *example* 206 | 207 | let text = "Hello World!" 208 | 209 | let bytes32 = ethers.utils.formatBytes32String(text) 210 | // "0x48656c6c6f20576f726c64210000000000000000000000000000000000000000" 211 | 212 | let originalText = ethers.utils.parseBytes32String(bytes32) 213 | // "Hello World!" 214 | 215 | 216 | ----- 217 | 218 | .. _constants: 219 | 220 | 常量 221 | ========= 222 | 223 | :sup:`ethers . constants` . AddressZero 224 | The address ``0x0000000000000000000000000000000000000000``. 225 | 226 | :sup:`ethers . constants` . HashZero 227 | The bytes32 ``0x0000000000000000000000000000000000000000000000000000000000000000``. 228 | 229 | :sup:`ethers . constants` . MaxUint256 230 | The bytes32 ``0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff``. 231 | 232 | :sup:`ethers . constants` . NegativeOne 233 | The :ref:`BigNumber ` ``bigNumberify(-1)``. 234 | 235 | :sup:`ethers . constants` . Zero 236 | The :ref:`BigNumber ` ``bigNumberify(0)``. 237 | 238 | :sup:`ethers . constants` . One 239 | The :ref:`BigNumber ` ``bigNumberify(1)``. 240 | 241 | :sup:`ethers . constants` . Two 242 | The :ref:`BigNumber ` ``bigNumberify(2)``. 243 | 244 | :sup:`ethers . constants` . WeiPerEther 245 | The :ref:`BigNumber ` ``bigNumberify("1000000000000000000")``. 246 | 247 | :sup:`ethers . constants` . EtherSymbol 248 | The Greek character Xi, used as the symbol for *ether*. 249 | 250 | ----- 251 | 252 | 加解密相关方法 253 | ======================= 254 | 255 | 椭圆曲线 256 | -------------- 257 | 258 | :sup:`utils` . computeAddress ( publicOrPrivateKey ) |nbsp| :sup:`=>` |nbsp| :sup:`Address` 259 | Computes the Ethereum address given a public key or private key. 260 | 261 | :sup:`utils` . computePublicKey ( publicOrPrivateKey [ , compressed :sup:`= false` ] ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 262 | Compute the public key for *publicOrPrivateKey*, optionally *compressed*. If 263 | *publicOrPrivateKey* is a public key, it may be either compressed or uncompressed. 264 | 265 | :sup:`utils` . recoverAddress ( digest , signature ) |nbsp| :sup:`=>` |nbsp| :sup:`Address` 266 | Returns the Ethereum address by using ecrecover with the *digest* for the 267 | *signature*. 268 | 269 | :sup:`utils` . recoverPublicKey ( digest , signature ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 270 | Returns the public key by using ecrecover with the *digest* for the *signature*. 271 | 272 | :sup:`utils` . verifyMessage ( messageStringOrArrayish , signature ) |nbsp| :sup:`=>` |nbsp| :sup:`Addresss` 273 | Returns the address of the account that signed *messageStringOrArrayish* to 274 | generate *signature*. 275 | 276 | .. code-block:: javascript 277 | :caption: *verify a message signature* 278 | 279 | let signature = "0xddd0a7290af9526056b4e35a077b9a11b513aa0028ec6c9880948544508f3c63" + 280 | "265e99e47ad31bb2cab9646c504576b3abc6939a1710afc08cbf3034d73214b8" + 281 | "1c"; 282 | 283 | let signingAddress = Wallet.verifyMessage('hello world', signature); 284 | 285 | console.log(signingAddress); 286 | // "0x14791697260E4c9A71f18484C9f997B308e59325" 287 | 288 | Hash 方法 289 | -------------- 290 | 291 | :sup:`utils` . keccak256 ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 292 | Compute the keccak256 cryptographic hash of a value, returned as a hex string. (Note: 293 | often Ethereum documentation refers to this, **incorrectly**, as SHA3) 294 | 295 | :sup:`utils` . sha256 ( hexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 296 | Compute the SHA2-256 cryptographic hash of a value, returned as a hex string. 297 | 298 | .. code-block:: javascript 299 | :caption: *hashing binary data* 300 | 301 | console.log(utils.keccak256([ 0x42 ])); 302 | // '0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111' 303 | 304 | console.log(utils.keccak256("0x42")); 305 | // '0x1f675bff07515f5df96737194ea945c36c41e7b4fcef307b7cd4d0e602a69111' 306 | 307 | 308 | console.log(utils.sha256([ 0x42 ])); 309 | // '0xdf7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c' 310 | 311 | console.log(utils.sha256("0x42")); 312 | // '0xdf7e70e5021544f4834bbee64a9e3789febc4be81470df629cad6ddb03320a5c' 313 | 314 | 315 | Hash 帮助方法 316 | --------------------- 317 | 318 | :sup:`utils` . hashMessage ( stringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 319 | Compute the prefixed message hash of a stringOrArrayish, by converting the 320 | message to bytes (as necessary) and prefixing with ``\x19Ethereum Signed Message\n`` 321 | and the length of the message. See the `eth_sign`_ JSON-RPC method for more information. 322 | 323 | :sup:`utils` . id ( utf8String ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 324 | Compute the keccak256 cryptographic hash of a UTF-8 string, returned as a hex string. 325 | 326 | .. code-block:: javascript 327 | :caption: *hashing utf-8 strings* 328 | 329 | // Convert the string to binary data 330 | let message = "Hello World"; 331 | let messageBytes = utils.toUtf8Bytes(message); 332 | utils.keccak256(messageBytes); 333 | // '0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba' 334 | 335 | // Which is equivalent to using the id function 336 | utils.id("Hello World"); 337 | // '0x592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba' 338 | 339 | 340 | // Compute the sighash for a Solidity method 341 | console.log(utils.id("addr(bytes32)")); 342 | // '0x3b3b57de213591bb50e06975ea011e4c8c4b3e6de4009450c1a9e55f66e4bfa4' 343 | 344 | Key 衍生 345 | -------------- 346 | 347 | :sup:`utils` . pbkdf2 ( password , salt , iterations , keylen , hashAlgorithm ) 348 | Return the pbkdf2 derived key from *password* and *salt* with *iterations* of 349 | *length* using the *hashAlgorithm*. The supported hash algorithms are ``sha256`` 350 | and ``sha512``. 351 | 352 | 随机数 353 | -------- 354 | 355 | :sup:`utils` . randomBytes ( length ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array` 356 | Return a Uint8Array of cryptographically secure random bytes 357 | 358 | .. code-block:: javascript 359 | :caption: *generate random bytes* 360 | 361 | let randomBytes3 = utils.randomBytes(3) 362 | // Uint8Array [ 194, 22, 140 ] 363 | 364 | let randomBytes32 = utils.randomBytes(32) 365 | // Uint8Array [ 162, 131, 117, 110, 196, 73, 144, 177, 201, 75, 88, 366 | // 105, 227, 210, 104, 226, 82, 65, 103, 157, 36, 170, 367 | // 214, 92, 190, 141, 239, 54, 96, 39, 240, 95 ] 368 | 369 | 370 | .. code-block:: javascript 371 | :caption: *generate a random number* 372 | 373 | let randomNumber = utils.bigNumberify(utils.randomBytes(32)); 374 | // BigNumber { _hex: 0x617542634156966e0bbb6c673bf88015f542c96eb115186fd93881518f05f7ff } 375 | 376 | Solidity 377 | -------- 378 | 379 | Solidity uses a `non-standard packed mode`_ to encode parameters that are passed 380 | into its hashing functions. The parameter types and values can be used to compute 381 | the result of the hash functions as would be performed by Solidity. 382 | 383 | :sup:`utils` . solidityKeccak256 ( types, values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 384 | Compute the keccak256 cryptographic hash using the Solidity non-standard (tightly) 385 | packed data for *values* given the *types*. 386 | 387 | :sup:`utils` . soliditySha256 ( types, values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 388 | Compute the SHA256 cryptographic hash using the Solidity non-standard (tightly) 389 | packed data for *values* given the *types*. 390 | 391 | :sup:`utils` . solidityPack ( types, values ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 392 | Compute the Solidity non-standard (tightly) packed data for *values* given the *types*. 393 | 394 | .. code-block:: javascript 395 | :caption: *examples* 396 | 397 | let result = utils.solidityKeccak256([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]); 398 | console.log(result); 399 | // '0x52d7e6a62ca667228365be2143375d0a2a92a3bd4325dd571609dfdc7026686e' 400 | 401 | result = utils.soliditySha256([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]); 402 | console.log(result); 403 | // '0x1eaebba7999af2691d823bf0c817e635bbe7e89ec7ed32a11e00ca94e86cbf37' 404 | 405 | result = utils.solidityPack([ 'int8', 'bytes1', 'string' ], [ -1, '0x42', 'hello' ]); 406 | console.log(result); 407 | // '0xff4268656c6c6f' 408 | 409 | ----- 410 | 411 | 412 | 以太币格式化与转换 413 | ===================== 414 | 415 | :sup:`utils` . etherSymbol 416 | 以太坊符号(希腊字母 *Xi* ) 417 | 418 | .. _parseEther: 419 | 420 | :sup:`utils` . parseEther ( etherString ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 421 | 将代表 ether 单位数的 *etherString* 解析为 wei 单位数的 BitNumber 实例。 422 | (译者注:ether、gwei、wei 等是以太坊的货币单位名称,下同。) 423 | .. _formatEther: 424 | 425 | :sup:`utils` . formatEther ( wei ) |nbsp| :sup:`=>` |nbsp| :sup:`string` 426 | 将代表 wei 单位数的 *wei* 格式化为代表 ether 单位数的十进制字符串。 427 | 输出值总是包含至少一个整数和一个小数位,否则将剪除前导和尾随的 0。 428 | 429 | .. _parseUnits: 430 | 431 | :sup:`utils` . parseUnits ( valueString , decimalsOrUnitName ) |nbsp| :sup:`=>` |nbsp| :sup:`BigNumber` 432 | 将代表某单位数的 *valueString* 解析为一个代表 wei 单位数的 BigNumber 实例。 433 | 参数 *decimalsOrUnitsName* 可以是 3 到 18 之间(3 的倍数)的小数位数, 434 | 或者是以太币单位名称,如:`gwei`。 435 | 436 | .. _formatUnits: 437 | 438 | :sup:`utils` . formatUnits ( wei , decimalsOrUnitName ) |nbsp| :sup:`=>` |nbsp| :sup:`string` 439 | 将 *wei* 单位数格式化为一个代表某单位数的十进制字符串。 440 | 输出值总是包含至少一个整数和一个小数位,否则将修剪前导和尾随的 0。 441 | 参数 *decimalsOrUnitsName* 可以是 3 到 18 之间(3 的倍数)的小数位数, 442 | 或者是单位名称,如:`gwei`。 443 | 444 | :sup:`utils` . commify ( numberOrString ) |nbsp| :sup:`=>` |nbsp| :sup:`string` 445 | 返回含有千分符的*numberOrString*。如果 *numberOrString* 包含小数点, 446 | 则输出值将至少具有一位整数和小数。如果不包含小数点,则输出值不会包含小数。 447 | 448 | .. code-block:: javascript 449 | :caption: *examples* 450 | 451 | let wei = utils.parseEther('1000.0'); 452 | console.log(wei.toString(10)); 453 | // "1000000000000000000000" 454 | 455 | console.log(utils.formatEther(0)); 456 | // "0.0" 457 | 458 | let wei = utils.bigNumberify("1000000000000000000000"); 459 | 460 | console.log(utils.formatEther(wei)); 461 | // "1000.0" 462 | 463 | console.log(utils.formatEther(wei, {commify: true})); 464 | // "1,000.0" 465 | 466 | console.log(utils.formatEther(wei, {pad: true})); 467 | // "1000.000000000000000000" (18 decimal places) 468 | 469 | console.log(utils.formatEther(wei, {commify: true, pad: true})); 470 | // "1,000.000000000000000000" (18 decimal places) 471 | 472 | 473 | ----- 474 | 475 | .. _hexstring: 476 | 477 | Hex 字符串 478 | =========== 479 | 480 | A hex string is **always** prefixed with "0x" and consists of the characters 481 | 0 -- 9 and a -- f. It is always returned lower case with even-length, but any hex 482 | string passed into a function may be any case and may be odd-length. 483 | 484 | :sup:`utils` . hexlify ( numberOrBigNumberOrHexStringOrArrayish ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 485 | Converts any number, :ref:`BigNumber `, hex string or 486 | `Arrayish`_ to a hex string. (otherwise, throws an error) 487 | 488 | :sup:`utils` . isHexString ( value ) |nbsp| :sup:`=>` |nbsp| :sup:`boolean` 489 | Returns true if *value* is a valid hexstring. 490 | 491 | :sup:`utils` . hexDataLength ( hexString ) |nbsp| :sup:`=>` |nbsp| :sup:`number` 492 | Returns the length (in bytes) of *hexString* if it is a valid data hexstring (even length). 493 | 494 | :sup:`utils` . hexDataSlice ( hexString , offset [ , endOffset ] ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 495 | Returns a string for the subdata of *hexString* from *offset* **bytes** 496 | (each byte is two nibbled) to *endOffset* **bytes**. If no *endOffset* is 497 | specified, the result is to the end of the *hexString* is used. Each byte is two nibbles. 498 | 499 | :sup:`utils` . hexStripZeros ( hexString ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 500 | Returns *hexString* with all leading zeros removed, but retaining at least 501 | one nibble, even if zero (e.g. ``0x0``). This may return an odd-length string. 502 | 503 | :sup:`utils` . hexZeroPad ( hexString , length ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 504 | Returns *hexString* padded (on the left) with zeros to length **bytes** (each 505 | byte is two nibbles). 506 | 507 | ----- 508 | 509 | Namehash 510 | ======== 511 | 512 | :sup:`utils` . namehash ( ensName ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 513 | Compute the namehash of *ensName*. Currently only supports the 514 | characters ``[a-z0-9.-]``. The concerns with fully supporting UTF-8 515 | are largely security releated, but `are open for discussion`_. 516 | 517 | .. code-block:: javascript 518 | :caption: *examples* 519 | 520 | let namehash = utils.namehash('ricmoo.firefly.eth'); 521 | // "0x0bcad17ecf260d6506c6b97768bdc2acfb6694445d27ffd3f9c1cfbee4a9bd6d" 522 | 523 | ----- 524 | 525 | .. _signature: 526 | 527 | 签名 528 | ========== 529 | 530 | There are two common formats for signatures in Ethereum. The **flat-format**, which 531 | is a hexstring with 65 bytes (130 nibbles); or an **expanded-format**, which is an object with 532 | the properties: 533 | 534 | - **r** and **s** --- the (r, s) public point of a signature 535 | - **recoveryParam** --- the recovery parameter of a signautre (either ``0`` or ``1``) 536 | - **v** --- the recovery param nomalized for Solidity (either ``27`` or ``28``) 537 | 538 | :sup:`utils` . splitSignature ( hexStringOrArrayishOrSignature ) |nbsp| :sup:`=>` |nbsp| :sup:`Signature` 539 | Returns an expanded-format signature object for *hexStringOrArrayishOrSignature*. 540 | Passing in an signature that is already in the expanded-format will ensure 541 | both *recoveryParam* and *v* are populated. 542 | 543 | :sup:`utils` . joinSignature ( signature ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 544 | Returns the flat-format signature hexstring of *signature*. The final *v* 545 | byte will always be normalized to ``0x1b`` of ``0x1c``. 546 | 547 | .. code-block:: javascript 548 | :caption: *To Expanded-Format* 549 | 550 | // Flat-format; this is the format provided by JSON-RPC responses 551 | let flat = "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16" + 552 | "3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466" + 553 | "1b" 554 | let expanded = utils.splitSignature(flat); 555 | 556 | console.log(expanded); 557 | // { 558 | // r: "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16", 559 | // s: "0x3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466", 560 | // recoveryParam: 0, 561 | // v: 27 562 | // } 563 | 564 | .. code-block:: javascript 565 | :caption: *To Flat-Format* 566 | 567 | // Expanded-format; this is the format Solidity and other tools often require 568 | let expanded = { 569 | r: "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16", 570 | s: "0x3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466", 571 | recoveryParam: 0, 572 | v: 27 573 | } 574 | let flat = utils.joinSignature(expanded); 575 | 576 | console.log(flat) 577 | // "0x0ba9770fd8778383f6d56faadc71e17b75f0d6e3ff0a408d5e6c4cee3bd70a16" + 578 | // "3574da0ebfb1eaac261698b057b342e52ea53f85287272cea471a4cda41e3466" + 579 | // "1b" 580 | 581 | 582 | ----- 583 | 584 | .. _transactions: 585 | 586 | 交易 587 | ============ 588 | 589 | :sup:`utils` . serializeTransaction ( transaction [ , signature ] ) |nbsp| :sup:`=>` |nbsp| :sup:`hex` 590 | Serialize *transaction* as a :ref:`hex-string `, optionally including 591 | the *signature*. 592 | 593 | If *signature* is provided, it may be either the :ref:`Flat Format ` 594 | or the :ref:`Expanded Format `, and the serialized transaction will 595 | be a signed transaction. 596 | 597 | :sup:`utils` . parseTransaction ( rawTransaction ) |nbsp| :sup:`=>` |nbsp| :sup:`Transaction` 598 | Parse the serialized transaction, returning an object with the properties: 599 | 600 | - **to** 601 | - **nonce** 602 | - **gasPrice** 603 | - **gasLimit** 604 | - **data** 605 | - **value** 606 | - **chainId** 607 | 608 | If the transactions is signed, addition properties will be present: 609 | 610 | - **r**, **s** and **v** --- the signature public point and recoveryParam (adjusted for the chainId) 611 | - **from** --- the address of the account that signed the transaction 612 | - **hash** --- the transaction hash 613 | 614 | ----- 615 | 616 | .. _utf8-strings: 617 | 618 | UTF-8 字符串 619 | ============= 620 | 621 | .. _utf8-to-bytes: 622 | 623 | :sup:`utils` . toUtf8Bytes ( string ) |nbsp| :sup:`=>` |nbsp| :sup:`Uint8Array` 624 | Converts a UTF-8 string to a Uint8Array. 625 | 626 | .. _utf8-to-string: 627 | 628 | :sup:`utils` . toUtf8String ( hexStringOrArrayish , [ ignoreErrors :sup:`= false` ) |nbsp| :sup:`=>` |nbsp| :sup:`string` 629 | Converts a hex-encoded string or array to its UTF-8 representation. 630 | 631 | .. code-block:: javascript 632 | :caption: *To UTF-8 Bytes* 633 | 634 | let text = "Hello World"; 635 | 636 | let bytes = utils.toUtf8Bytes(text); 637 | 638 | console.log(bytes); 639 | // Uint8Array [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100] 640 | 641 | .. code-block:: javascript 642 | :caption: *To UTF-8 String* 643 | 644 | let array = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]; 645 | 646 | let stringFromArray = utils.toUtf8String(array) 647 | 648 | console.log(stringFromArray); 649 | // "Hello World" 650 | 651 | let hexString = "0x48656c6c6f20576f726c64"; 652 | let stringFromHexString = utils.toUtf8String(hexString); 653 | 654 | console.log(stringFromHexString); 655 | // "Hello World" 656 | 657 | ----- 658 | 659 | Web 660 | === 661 | 662 | :sup:`utils` . fetchJson ( urlOrInfo [ , processFunc ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 663 | Returns a :ref:`Promise ` of the contents of *urlOrInfo*, processed by 664 | *processFunc*. 665 | 666 | The *urlOrInfo* may also be specified as an object with the properties: 667 | 668 | - **url** --- the JSON-RPC URL (required) 669 | - **user** --- a username to use for Basic Authentication (optional) 670 | - **password** --- a password to use for Basic Authentication (optional) 671 | - **allowInsecure** --- allow Basic Authentication over an insecure HTTP network (default: false) 672 | - **timeout** --- number of milliseconds to abort the request (default: 2 minutes) 673 | - **headers** --- additional headers to send to the server (case insensitive) 674 | 675 | :sup:`utils` . poll ( func , [ options ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Promise` 676 | Poll using the function *func*, resolving when it does not return ``undefined``. By 677 | default this method will use the `exponential back-off`_ algorithm. 678 | 679 | The *options* is an object with the properties: 680 | 681 | - **timeout** --- after this many millisecconds, the promise will reject with a ``timeout`` error (default: no timeout) 682 | - **floor** --- minimum amount of time between polling (default: 0) 683 | - **ceiling** --- minimum amount of time between polling (default: 10s) 684 | - **interval** --- the interval to use for exponential backoff (default: 250ms) 685 | - **onceBlock** --- a function which takes 2 parameters, the string ``block`` and a callback *func*; polling will occur everytime *func* is called; any provider can be passed in for this property 686 | 687 | ----- 688 | 689 | 690 | .. _are open for discussion: https://github.com/ethers-io/ethers.js/issues/42 691 | .. _eth_sign: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign 692 | .. _exponential back-off: https://en.wikipedia.org/wiki/Exponential_backoff 693 | .. _safe range: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger 694 | .. _non-standard packed mode: http://solidity.readthedocs.io/en/develop/abi-spec.html#non-standard-packed-mode 695 | 696 | .. EOF 697 | -------------------------------------------------------------------------------- /source/api-wallet.rst: -------------------------------------------------------------------------------- 1 | .. include:: glossaries.rst 2 | .. |nbsp| unicode:: U+00A0 .. non-breaking space 3 | 4 | .. _api-wallet: 5 | 6 | 在使用接口之前,需要先确保正确 引入了 `ethers.js `_ 。 7 | 8 | 9 | 钱包类 Wallet 和 签名器 Signer 10 | ************************************** 11 | 12 | |wallet| 类管理着一个公私钥对用于在以太坊网络上密码签名交易以及所有权证明。 13 | 14 | ----- 15 | 16 | .. _wallet: 17 | 18 | Wallet 19 | ====== 20 | 21 | **Wallet** 实现了 :ref:`Signer API ` ,因此可以在任何需要 |signer| 的地方使用 **Wallet** ,它包含了 |signer| 所有的属性。 22 | 23 | 24 | 创建 Wallet 实例 25 | ---------------------- 26 | 27 | new :sup:`Wallet` ( privateKey [ , provider ] ) 28 | 从参数 *privateKey* 私钥创建一个钱包实例, 还可以提供一个可选的 |provider| 参数用于连接节点。 29 | 30 | :sup:`Wallet` . createRandom ( [ options ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Wallet` 31 | 创建一个随机钱包实例。 确保钱包(私钥)存放在安全的位置,如果丢失了就**没有办法找回钱包**。 32 | 33 | 额外的参数 options 为: 34 | 35 | - **extraEntropy** --- 额外的熵加入随机源 36 | 37 | .. _fromEncryptedJson: 38 | 39 | :sup:`Wallet` . fromEncryptedJson ( json, password [ , progressCallback ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Wallet` 40 | 通过解密一个 `JSON 钱包文件`_ 创建钱包实例,JSON 钱包文件,即 keystore文件, 通常来自 Geth, parity, Crowdsale 等钱包或工具,或者通过钱包加密函数 *prototype.encrypt* 创建。 41 | 42 | :sup:`Wallet` . fromMnemonic ( mnemonic [ , path :sup:`= "m/44'/60'/0'/0/0"` [ , wordlist ] ] ) |nbsp| :sup:`=>` |nbsp| :sup:`Wallet` 43 | 通过助记词(及路径)创建钱包实例,助记词及路径由 `BIP-039`_ 和 `BIP-044`_ 定义,默认使用英文助记词。 44 | 这里有一篇介绍 `BIP39及BIP44非常棒的文章 `_ ,如果不了解 BIP39 及 BIP44 可以读一读。 45 | 46 | 注意压缩过的 min版本 ``dist/ethers.min.js`` 仅支持英文版本, 其他语言的支持可以通过添加 `` 49 | 50 | 51 | ----- 52 | 53 | .. _npm is installed: https://nodejs.org/en/ 54 | .. _ethers-v4.min.js: https://cdn.ethers.io/scripts/ethers-v4.min.js 55 | -------------------------------------------------------------------------------- /source/glossaries.rst: -------------------------------------------------------------------------------- 1 | 2 | .. |signer| raw:: html 3 | 4 | 签名器Signer 5 | 6 | .. |wallet| raw:: html 7 | 8 | 钱包Wallet 9 | 10 | .. |provider| raw:: html 11 | 12 | 提供者Provider 13 | 14 | .. |ABI| raw:: html 15 | 16 | 应用二进制接口Application Binary Interface(ABI) 17 | 18 | .. |Ether| raw:: html 19 | 20 | 以太Ether 21 | 22 | -------------------------------------------------------------------------------- /source/index.rst: -------------------------------------------------------------------------------- 1 | ethers.js v4 翻译及说明 2 | ************************** 3 | 4 | 翻译说明 5 | ========== 6 | 7 | 本文档基于 `官方文档 v4 版本 `_ 翻译, 最新的 v5 版本的翻译请前往 `ethers.js 中文文档 v5 `_ 。 8 | 9 | 由 `登链社区 `_ 成员翻译、整理、校队,尊重汗水,需转载请联系微信:xlbxiong 获取授权。 10 | 11 | 最近的的 12 | 13 | ethers.js 介绍 14 | ==================== 15 | 16 | ethers.js库旨在为以太坊区块链及其生态系统提供一个小而完整的 JavaScript API 库 17 | 它最初是与 `ethers.io`_ 一起使用,现在已经扩展为更通用的库。 18 | 19 | .. note:: 20 | 译者注:ethers.js 对比使用 web3.js 代码量更少,接口也更简洁,推荐优先使用 ethers.js 。 21 | 22 | .. note:: 23 | 译者注:Tiny熊 `用 ethers.js 开发了网页钱包`_ ,是一个很好的学习案例。 24 | 25 | 包含功能 26 | ========== 27 | 28 | - 将私钥保存在客户端,**安全** 可信赖 29 | - 可支持导入和导出的 **JSON钱包文件** (Geth,Parity和crowdsale) 30 | - 导入和导出 BIP39 **助记词** (12个词备份短语)和 HD(分层确定性)钱包(英语,意大利语,日语,韩语,简体中文,繁体中文; 更多即将推出) 31 | - 从任何合同ABI创建JavaScript 元类对象,包括 **ABIv2** 和 **可读的** ABI 32 | - 支持通过 `JSON-RPC`_ , `INFURA`_ , `Etherscan`_ 或 `MetaMask`_ 连接到以太坊节点。 33 | - **ENS名称** 是“一等公民”;它们可以在任何可以使用以太坊地址的地方使用 34 | - 库 **非常小** (压缩~88kb;未压缩284kb) 35 | - 功能 **完整** ,满足所有的以太坊相关需求 36 | - 文档全面: `中文文档`_ 及 `documentation`_ 37 | - 大量维护和添加的 **测试用例** 38 | - 完全支持 **TypeScript** 准备好,有定义文件和完整的TypeScript源文件 39 | - 宽松的 **MIT 协议许可** (包括所有依赖); 完全开源可以随意使用 40 | 41 | .. toctree:: 42 | :maxdepth: 4 43 | :caption: 开发手册目录 44 | 45 | getting-started 46 | api 47 | api-advanced 48 | cookbook 49 | migration 50 | notes 51 | testing 52 | 53 | 54 | .. _ethers.io: https://ethers.io 55 | .. _JSON-RPC: https://github.com/ethereum/wiki/wiki/JSON-RPC 56 | .. _INFURA: https://infura.io/ 57 | .. _Etherscan: https://etherscan.io/ 58 | .. _MetaMask: https://metamask.io/ 59 | .. _中文文档: https://learnblockchain.cn/ethers_v5/ 60 | .. _documentation: https://docs.ethers.io 61 | .. _用 ethers.js 开发了网页钱包: https://learnblockchain.cn/2019/04/11/wallet-dev-guide/#ethers.js 62 | 63 | Indices and tables 64 | ================== 65 | 66 | * :ref:`genindex` 67 | * :ref:`search` 68 | 69 | 70 | .. EOF 71 | -------------------------------------------------------------------------------- /source/migration.rst: -------------------------------------------------------------------------------- 1 | .. _migration: 2 | 3 | 迁移指南 4 | *************************** 5 | 6 | 从Web3 到 ethers v4 7 | ================================ 8 | 9 | Todo: This is coming soon. 10 | 11 | ----- 12 | 13 | 从 ethers v3 升级到 ethers v4 14 | ===================================== 15 | 16 | A lot of the functionality has remained the same, but there has been some 17 | slight refactoring and improved paradigms. 18 | 19 | ----- 20 | 21 | 常量变更 22 | --------- 23 | 24 | All constants have moved from the utils to the root ethers object. 25 | 26 | .. code-block:: javascript 27 | :caption: *Constants --- ethers v3* 28 | 29 | let one = ethers.utils.constants.One; 30 | 31 | .. code-block:: javascript 32 | :caption: *Constants --- ethers v4* 33 | 34 | let one = ethers.constants.One; 35 | 36 | ----- 37 | 38 | 合约部署变更 39 | ------------------- 40 | 41 | Deploying contracts has undergone some significant change. The new API is more 42 | seamless and reduces the amount of low-level understanding that is required, 43 | such as the details of how *init transaction* behave. 44 | 45 | More complex and complete objects are also returned through-out the 46 | process, so there are far less calls to utility functions after a deployment 47 | required to populate databases and track status. 48 | 49 | .. code-block:: javascript 50 | :caption: *ethers v3* 51 | 52 | let tx = Contract.getDeployTransaction(bytecode, abi, arg1, arg2); 53 | 54 | // overrides 55 | tx.gasLimit = 1500000; 56 | 57 | wallet.sendTransaction(tx).then((tx) => { 58 | let contractAddress = ethers.utils.getContractAddress(tx); 59 | let contract = new ethers.Contract(contractAddress, abi, wallet); 60 | provider.waitForTransaction(tx).then((tx) => { 61 | provider.getTransactionReceipt(tx.hash).then((receipt) => { 62 | if (receipt.status === 0) { 63 | throw new Error('failed to deploy'); 64 | } 65 | contract.someFunction(); 66 | }); 67 | }); 68 | }); 69 | 70 | .. code-block:: javascript 71 | :caption: *Deploy a Contract --- ethers v4* 72 | 73 | // Construct a Contract Factory 74 | let factory = new ethers.ContractFactory(abi, bytecode, signer); 75 | 76 | // Deploy automatically detects gasLimit and all other parameters 77 | // Overrides can optionally be passed as an extra parameter 78 | 79 | // Optional; all unspecified values will queried from the network 80 | let overrides = { }; 81 | 82 | factory.deploy(arg1, arg2, overrides).then((contract) => { 83 | // The contract is returned immediately; it has not been mined yet 84 | 85 | // The contract known its address (before it is even mined) 86 | console.log(contract.address); 87 | 88 | // You can access the in-flight transaction that is currently waiting to be mined 89 | console.log(contract.deployTransaction); 90 | // A full transaction with: 91 | // - from 92 | // - nonce 93 | // - hash 94 | // - all other Transaction Response fields 95 | // - wait() => Promise that resolves to the TransactionReceipt 96 | 97 | // The "deployed()" function will return a Promise that resolves 98 | // to the contract, once it has been mined. If the contract fails 99 | // to deploy, the Promise will reject. 100 | contract.deployed().then((contract) => { 101 | // The contract is now deployed 102 | contract.someFunction(); 103 | 104 | }, (error) => { 105 | // The transaction failed to deploy 106 | console.log('Failed to deploy in TX:', error.transactionHash); 107 | }); 108 | }); 109 | 110 | 111 | .. code-block:: javascript 112 | :caption: *Deploy a Contract with async/await --- ethers v4* 113 | 114 | async function() { 115 | let factory = new ethers.ContractFactory(abi, bytecode, signer); 116 | 117 | let contract = await factory.deploy(arg1, arg2); 118 | 119 | try { 120 | await contract.deployed(); 121 | 122 | } catch (error) { 123 | console.log('Failed to deploy in TX:', error.transactionHash); 124 | throw error; 125 | } 126 | 127 | contract.someFunction(); 128 | } 129 | 130 | 131 | .. code-block:: javascript 132 | :caption: *Get Deployment Transaction --- ethers v4* 133 | 134 | // If you still need the deployment transaction, and don't wish to 135 | // actually deploy, you can much more easily just use the Interface 136 | // object without the need for a provider or signer. 137 | 138 | let factory = new ethers.ContractFactory(abi, bytecode); 139 | 140 | let tx = factory.getDeployTransaction(arg1, arg2); 141 | 142 | ----- 143 | 144 | 处理加密JSON 钱包文件变更 145 | ---------------------------------- 146 | 147 | .. code-block:: javascript 148 | :caption: *Checking JSON Wallets --- ethers v3* 149 | 150 | let isJsonWallet = ethers.Wallet.isEncryptedWallet(json); 151 | 152 | .. code-block:: javascript 153 | :caption: *Checking JSON Wallets --- ethers v4* 154 | 155 | let address = ethers.utils.getJsonWalletAddress(json); 156 | let isJsonWallet = (address !== null) 157 | 158 | .. code-block:: javascript 159 | :caption: *Decrypting JSON Wallets --- ethers v3* 160 | 161 | let wallet = await ethers.Wallet.fromEncryptedWallet(json, password); 162 | 163 | .. code-block:: javascript 164 | :caption: *Decrypting JSON Wallets --- ethers v4* 165 | 166 | let wallet = await ethers.Wallet.fromEncryptedJson(json, password); 167 | 168 | 169 | ----- 170 | 171 | 监听事件方法变更 172 | ----------------- 173 | 174 | Events now behave like a modern JavaScript Event Emitter, rather than a 1995 175 | web browser. 176 | 177 | The events now play nicer with the arrow operator (i.e. ``() => { ... }``), 178 | since rather than modifying the `this` inside the callbacks, an additional 179 | rich object is passed along. 180 | 181 | .. code-block:: javascript 182 | :caption: *Events --- ethers v3* 183 | 184 | // Solidity: event SomeEvent(address foo, uint256 bar) 185 | contract.onsomeevent = function(foo, bar) { 186 | console.log(foo, bar); 187 | // The Log was available at this: 188 | // - this.event 189 | // - this.removeListener() 190 | }; 191 | 192 | .. code-block:: javascript 193 | :caption: *Listening to an Event --- ethers v4* 194 | 195 | // Solidity: event SomeEvent(address foo, uint256 bar) 196 | contract.on('SomeEvent', (foo, bar, eventInfo) => { 197 | console.log(foo, bar); 198 | // eventInfo 199 | // - Log (blockNumber, blockHash, txHash, removed, address, data, etc.) 200 | // - args: [ foo, bar ] 201 | // - decode: (data, topics) => [ foo, bar ] 202 | // - event: "SomeEvent" 203 | // - eventSignature: "SomeEvent(address,uint256)" 204 | // - removeListener: () => removes this listener 205 | // - getBlock: () => returns a Promise of the block 206 | // - getTransaction: () => returns a Promise of transaction 207 | // - getTransactionReceipt: () => returns a Promise of the receipt 208 | }); 209 | 210 | .. code-block:: javascript 211 | :caption: *Indexed Events --- ethers v3* 212 | 213 | // Detecting a parameters is an indexed hash, and not a value 214 | contract.someEvent = function(foo) { 215 | if (foo.indexed) { 216 | // The value is just a hash to filter by 217 | } 218 | } 219 | 220 | .. code-block:: javascript 221 | :caption: *Indexed Events --- ethers v4* 222 | 223 | let Indexed = ethers.types.Indexed; 224 | 225 | // Detecting a parameters is an indexed hash, and not a value 226 | contract.someEvent = function(foo) { 227 | if (Indexed.isIndexed(foo)) { 228 | // The value is just a hash to filter by 229 | } 230 | } 231 | 232 | .. code-block:: javascript 233 | :caption: *Filtering Events --- ethers v4* 234 | 235 | // Solidity: event SomeEvent(address indexed foo, uint256 bar) 236 | let address = '0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7'; 237 | let filter = contract.filters.SomeEvent(address, null); 238 | 239 | console.log(filter); 240 | // { 241 | // address: contract.address, 242 | // topics: [ 243 | // 0xdde371250dcd21c331edbb965b9163f4898566e8c60e28868533281edf66ab03, 244 | // 0x0000000000000000000000008b40a2e27c5e87aa66dfa7f80bf675176f49dca7 245 | // ] 246 | // } 247 | 248 | contract.on(filter, (foo, bar, eventInfo) => { 249 | console.log(foo === address); 250 | // true 251 | }); 252 | 253 | 254 | If there are multiple events with the same name: 255 | 256 | .. code-block:: javascript 257 | :caption: *Event Name Collision --- ethers v4* 258 | 259 | // Solidity 260 | // - event SomeEvent(address foo, uint256 bar) 261 | // - event SomeEvent(address foo, address bar) 262 | 263 | contract.on('SomeEvent(address, uint256)', (foo, bar, eventInfo) => { 264 | // ... 265 | }); 266 | 267 | contract.on('SomeEvent(address, address)', (foo, bar, eventInfo) => { 268 | // ... 269 | }); 270 | 271 | 272 | ----- 273 | 274 | 获取JSON方法变更 275 | ------------------ 276 | 277 | The JSON fetching routine, since it was mostly used for Providers was 278 | on the Provider object in v3. In v4, it has moved to utils, since there 279 | are other common cases where it may be useful. 280 | 281 | .. code-block:: javascript 282 | :caption: *Fetching JSON --- ethers v3* 283 | 284 | ethers.providers.Provider.fetchJson(url).then((object) => { 285 | // ... 286 | }); 287 | 288 | .. code-block:: javascript 289 | :caption: *Fetching JSON --- ethers v4* 290 | 291 | ethers.utils.fetchJson(url).then((object) => { 292 | // ... 293 | }); 294 | 295 | ----- 296 | 297 | 抽象接口Interface变更 298 | ----------------------- 299 | 300 | This has always been a fairly low-level API, and mostly available for 301 | framework developers and other tools that require quite specific access 302 | to working with an ABI. Most of the changes are to simplify the interaction, 303 | so while there will probably be changes required, if you use this class, the 304 | complexity and size of your code should be reduced. 305 | 306 | .. code-block:: javascript 307 | :caption: *Interface --- ethers v3* 308 | 309 | let iface = ethers.Interface(address, abi, providerOrSigner); 310 | 311 | .. code-block:: javascript 312 | :caption: *Interface --- ethers v4* 313 | 314 | let iface = ethers.utils.Interface(address, abi, providerOrSigner); 315 | 316 | .. code-block:: javascript 317 | :caption: *Function Description --- ethers v3* 318 | 319 | let address = "0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7"; 320 | let value = 1000; 321 | 322 | // Solidity: function someFunc(address foo, uint256 bar) constant returns (address result) 323 | let functionCallable = iface.functionst.someFunc 324 | // functionInfo 325 | // - inputs: { names: [ "foo", "bar" ], types: [ "address", "uint256" ] } 326 | // - outputs: { names: [ "result" ], types: [ "address" ] } 327 | // - payable: false 328 | // - parseResult: (data) => any 329 | // - signature: "someFunc(address,uint256)" 330 | // - sighash: "0xd90a6a67" 331 | 332 | let data = functionCallable(address, value); 333 | let result = functionCallable.parseResult(callResultData); 334 | 335 | .. code-block:: javascript 336 | :caption: *Function Description --- ethers v4* 337 | 338 | let address = "0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7"; 339 | let value = 1000; 340 | 341 | // Solidity: function someFunc(address foo, uint256 bar) constant returns (address result) 342 | let functionInfo = iface.functions.someFunc; 343 | // functionInfo 344 | // - type: "call" (or "transaction" for non-constant functions) 345 | // - name: "someFunc" 346 | // - signature: "someFunc(address,uint256)" 347 | // - sighash: "0xd90a6a67" 348 | // - inputs: [ { name: foo", type: "bar" }, { name: "bar", type: "uint256" } ] 349 | // - outputs: [ { name: "result", type: "address" } ] 350 | // - payable: false 351 | // - encode: (params) => string 352 | // - decode: (data) => any 353 | 354 | // Note: This takes in an array; it no longer uses ...args 355 | let data = functionInfo.encode([ address, value ]); 356 | let result = functionInfo.decode(callResultData); 357 | 358 | .. code-block:: javascript 359 | :caption: *Event Description --- ethers v3* 360 | 361 | // Solidity: event SomeEvent(address foo, uint256 bar) 362 | let eventInfo = iface.events.SomeEvent; 363 | // eventInfo 364 | // - topics: [ ethers.utils.id("SomeEvent(address,uint256)") ] 365 | // - anonymous: false 366 | // - name: "SomeEvent" 367 | // - signature: "SomeEvent(address,uint256)" 368 | // - type: "event" 369 | // - inputs: { names: [ 'foo', 'bar' ], types: [ 'address', 'uint256' ] } 370 | // - parse: (topics, data) => Result 371 | 372 | .. code-block:: javascript 373 | :caption: *Event Description --- ethers v4* 374 | 375 | // Solidity: event SomeEvent(address foo, uint256 bar) 376 | let eventInfo = iface.events.SomeEvent; 377 | // eventInfo 378 | // - name: "SomeEvent" 379 | // - signature: "SomeEvent(address,bar)" 380 | // - inputs: [ { name: "foo", type: "address" }, { name: "bar", type: "uint256" } ] 381 | // - anonymous: false 382 | // - topic: ethers.utils.id("SomeEvent(address,uint256)") 383 | // - encodeTopics: (Array) => Array 384 | // - decode: (data, topics) => Result 385 | 386 | // Create event filter topics 387 | let address = '0x8B40a2E27C5E87aa66DfA7F80BF675176F49DCA7'; 388 | eventInfo.encodeTopics(address, null) 389 | // topics: [ 390 | // "0xdde371250dcd21c331edbb965b9163f4898566e8c60e28868533281edf66ab03", 391 | // "0x0000000000000000000000008b40a2e27c5e87aa66dfa7f80bf675176f49dca7" 392 | // ] 393 | 394 | 395 | ----- 396 | 397 | 获取网络Network变更方法 398 | ------------------------ 399 | 400 | .. code-block:: javascript 401 | :caption: *Getting Network Info - ethers v3* 402 | 403 | let network = ethers.providers.getNetwork('ropsten') 404 | 405 | .. code-block:: javascript 406 | :caption: *Getting Network Info - ethers v4* 407 | 408 | let network = ethers.utils.getNetwork('ropsten'); 409 | 410 | // Networks may now also be found by their network ID 411 | let network = ethers.utils.getNetwork(3); 412 | 413 | // And networks can be validated as an object 414 | let network = ethers.utils.getNetwork({ name: "custom", chainId: 1337 }); 415 | 416 | // Validation fails; this will throw an error, since Rinkeby is not 417 | // chain ID 1 (homestead is) 418 | let network = ethers.utils.getNetwork({ name: "rinkeby", chainId: 1 }); 419 | 420 | ----- 421 | 422 | 解析交易方法变更 423 | -------------------- 424 | 425 | The transaction parsing was moved out of the Wallet and into its own class 426 | in the utilities, along with a general serialization API. 427 | 428 | .. code-block:: javascript 429 | :caption: *ethers v3* 430 | 431 | let tx = ethers.Wallet.parseTransaction(rawTransaction); 432 | 433 | .. code-block:: javascript 434 | :caption: *ethers v4* 435 | 436 | let tx = ethers.utils.parseTransaction(rawTransaction); 437 | 438 | ----- 439 | 440 | 定制 |signer| 方法变更 441 | -------------------------- 442 | 443 | .. code-block:: javascript 444 | :caption: *Custome Signer --- ethers v3* 445 | 446 | let signer = { 447 | // Required 448 | getAddress: function() { ... }, 449 | provider: provider, 450 | 451 | // Optional 452 | estimateGas: function(tx) { ... }, 453 | sendTransaction: function(tx) { ... }, 454 | sign: function(tx) { ... }, 455 | }; 456 | 457 | .. code-block:: javascript 458 | :caption: *Custom Signer --- JavaScript --- ethers v4* 459 | 460 | function CustomSigner { 461 | ethers.Signer.call(this); 462 | 463 | // Optional 464 | this.provider = provider; 465 | } 466 | inherits(CustomSigner, ethers.Signer); 467 | 468 | // Required 469 | CustomSigner.prototype.getAddress = () => { ... }; 470 | CustomSigner.prototype.sendTransaction = (tx) => { ... }; 471 | CustomSigner.prototype.signMessage = (message) => { ... }; 472 | 473 | // Optional 474 | CustomSigner.prototype.connect = (provider) => { ... }; 475 | 476 | .. code-block:: javascript 477 | :caption: *Custom Signer --- TypeScript --- ethers v4* 478 | 479 | import { 480 | Signer, 481 | utils 482 | } from 'ethers'; 483 | 484 | import { 485 | Provider, 486 | TransactionRequest, 487 | TransactionReqponse 488 | } from 'ethers/providers'; 489 | 490 | class CustomSigner extends Signer { 491 | this.provider = provider; 492 | readony provider: Provider; 493 | constructor(provider) { 494 | super(); 495 | 496 | // Optional 497 | this.provider = // ... 498 | } 499 | 500 | getAddress() { 501 | // Return a promise to the address 502 | }; 503 | 504 | sendTransaction = (transaction: TransactionRequest): Promise { 505 | // This will popualte missing properties, like nonce, gasLimit, etc 506 | return utils.populateTransaction(transaction).then((tx) => { 507 | // Send the transaction and resolve the transaction 508 | }); 509 | }; 510 | 511 | signMessage(message: string | ethers.utils.Arrayish): Promise { 512 | let dataToSign: Uint8Array = utils.hashMessage(message);; 513 | // Sign ths dataToSign and resolve teh flat-format signature 514 | }; 515 | 516 | // Optional; highly recommended 517 | connect(provider: Provider): CustomSigner { 518 | return new CustomSigner(provider); 519 | } 520 | } 521 | 522 | 523 | ----- 524 | 525 | 获取默认 |provider| 方法变更 526 | ------------------------------ 527 | 528 | .. code-block:: javascript 529 | :caption: *Default Provider --- ethers v3* 530 | 531 | let provider = ethers.providers.getDefaultProvider(); 532 | 533 | .. code-block:: javascript 534 | :caption: *Default Provider --- ethers v4* 535 | 536 | let provider = ethers.getDefaultProvider(); 537 | 538 | ----- 539 | 540 | Big Number变更 541 | ---------------- 542 | 543 | .. code-block:: javascript 544 | :caption: *isBigNumber --- ethers v3* 545 | 546 | let checkBigNumber = ethers.utils.isBigNumber(value); 547 | 548 | .. code-block:: javascript 549 | :caption: *isBigNumber --- ethers v4* 550 | 551 | let checkBigNumber = BigNumber.isBigNumber(value); 552 | 553 | ----- 554 | 555 | JsonRpcProvider变更 556 | ------------------------- 557 | 558 | .. code-block:: javascript 559 | :caption: *Connecting --- ethers v3* 560 | 561 | let url = "http://localhost:8545"; 562 | let network = "rinkeby"; 563 | let provider = new ethers.providers.JsonRpcProvider(url, network); 564 | 565 | // Even if the network was wrong, this would mostly seem to work and 566 | // fail once the chain ID was attempted 567 | 568 | // The network was a synchronous property on Provider 569 | let network = provider.network; 570 | 571 | .. code-block:: javascript 572 | :caption: *Connecting --- ethers v4* 573 | 574 | // In v4, the network is automatically determined; you may override 575 | // the network, but it must match, or it will fail early 576 | 577 | let url = "http://localhost:8545"; 578 | let provider = new ethers.providers.JsonRpcProvider(url); 579 | 580 | // The network is now an asynchronous property: 581 | provider.getNetwork().then((network) => { 582 | // ... 583 | }); 584 | 585 | // One useful and common exception it that, if any async call from 586 | // the provider has ever succeeded, the synchronous network property 587 | // is then valid. The network property is populated before any 588 | // async call is made, so once an async call has finished, the network 589 | // property is available synchronously. 590 | 591 | async function() { 592 | await provider.getBlockNumber(); 593 | 594 | let network = provider.network; 595 | } 596 | 597 | .. code-block:: javascript 598 | :caption: *Sending Transactions --- ethers v3* 599 | 600 | provider.sendTransaction(rawTransaction).then((hash) => { 601 | // Just a transaction hash 602 | }); 603 | 604 | .. code-block:: javascript 605 | :caption: *Sending Transactions --- ethers v4* 606 | 607 | provider.sendTransaction(rawTransaction).then((transaction) => { 608 | // A full Transaction Response is returned 609 | // - from 610 | // - to 611 | // - gasLimit, gasPrice 612 | // - nonce 613 | // - r, s, v 614 | // - wait() => Promise that resolves the Transaction Receipt once mined 615 | // and rejects with an error is the stats is 0; the error 616 | // will have a transactionHash property as well as a 617 | // transaction property. 618 | 619 | let hash = transaction.hash; 620 | }); 621 | 622 | ----- 623 | 624 | 验证 Messages 方法变更 625 | ----------------------------- 626 | 627 | The message verification was moved from a static class on the Wallet to the 628 | utilities, along with a few other functions of the elliptic curve cryptographic 629 | exposed. 630 | 631 | .. code-block:: javascript 632 | :caption: *ethers v3* 633 | 634 | let signingAddress = ethers.Wallet.verifyMessage(message, signature); 635 | 636 | .. code-block:: javascript 637 | :caption: *ethers v4* 638 | 639 | let signingAddress = ethers.utils.verifyMessage(message, signature); 640 | 641 | ----- 642 | 643 | 等待交易方法变更 644 | ------------------------------- 645 | 646 | In v3, the ``transaction.wait()`` returned a Promise which would resolve to the 647 | **TransactionResponse** once it is mined. 648 | 649 | In v4, the ``transaction.wait()`` returned a Promise which would resolve to the 650 | **TransactionReceipt** once it is mined. 651 | 652 | ----- 653 | 654 | .. eof 655 | -------------------------------------------------------------------------------- /source/notes.rst: -------------------------------------------------------------------------------- 1 | 说明 2 | ********** 3 | 4 | A few quick notes about some of the less obvious aspects of interacting with 5 | Ethereum in JavaScript. 6 | 7 | ----- 8 | 9 | .. _ieee754: 10 | 11 | Why can't I just use numbers? 12 | ============================= 13 | 14 | The first problem many encounter when dealing with Ethereum is the concept of numbers. Most 15 | common currencies are broken down with very little granularity. For example, there are only 16 | 100 cents in a single dollar. However, there are 10\ :sup:`18` **wei** in a single 17 | **ether**. 18 | 19 | JavaScript uses `IEEE 754 double-precision binary floating point`_ numbers to represent 20 | numeric values. As a result, there are *holes* in the integer set after 21 | 9,007,199,254,740,991; which is problematic for *Ethereum* because that is only 22 | around 0.009 ether (in wei). 23 | 24 | To demonstrate how this may be an issue in your code, consider:: 25 | 26 | > (Number.MAX_SAFE_INTEGER + 4 - 5) == (Number.MAX_SAFE_INTEGER - 1) 27 | false 28 | 29 | 30 | To remedy this, all numbers (which can be large) are stored and manipulated 31 | as :ref:`Big Numbers `. 32 | 33 | The functions :ref:`parseEther( etherString ) ` and :ref:`formatEther( wei ) ` can be used to convert between 34 | string representations, which are displayed to or entered by the user and Big Number representations 35 | which can have mathematical operations handled safely. 36 | 37 | ----- 38 | 39 | .. _promise: 40 | 41 | Promises 42 | ======== 43 | 44 | A `Promise in JavaScript`_ is an object which simplifies many aspects of dealing with 45 | asynchronous functions. 46 | 47 | It allows a pending result to be treated in many ways as if it has already been resolved. 48 | 49 | The most useful operations you will need are: 50 | 51 | :sup:`Promise` . all ( promises ) 52 | Returns a new promise that resolves once all the *promises* have resolved. 53 | 54 | :sup:`prototype` . then ( onResolve, onReject ) 55 | Returns another Promise, which once the Promise was resolved, the *onResolve* 56 | function will be executed and if an error occurs, *onReject* will be called. 57 | 58 | If *onResolve* returns a Promise, it will be inserted into the chain of the returned 59 | promise. If *onResolve* throws an Error, the returned Promise will reject. 60 | 61 | .. code-block:: javascript 62 | :caption: *Cleaning out an account* 63 | 64 | var ethers = require('ethers'); 65 | var targetAddress = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0"; 66 | 67 | var privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123"; 68 | var wallet = new ethers.Wallet(privateKey); 69 | 70 | // Promises we are interested in 71 | var provider = ethers.getDefaultProvider('ropsten'); 72 | var balancePromise = provider.getBalance(wallet.address); 73 | var gasPricePromise = provider.getGasPrice(); 74 | var transactionCountPromise = provider.getTransactionCount(wallet.address); 75 | 76 | var allPromises = Promise.all([ 77 | gasPricePromise, 78 | balancePromise, 79 | transactionCountPromise 80 | ]); 81 | 82 | var sendPromise = allPromises.then(function(results) { 83 | // This function is ONLY called once ALL promises are fulfilled 84 | 85 | var gasPrice = results[0]; 86 | var balance = results[1]; 87 | var transactionCount = results[2]; 88 | 89 | // Sending a transaction to an externally owned account (EOA) is 21000 gas) 90 | var txFeeInWei = gasPrice.mul(21000); 91 | 92 | // This will send the maximum amount (our balance minus the fee) 93 | var value = balance.sub(txFeeInWei); 94 | 95 | var transaction = { 96 | to: targetAddress, 97 | gasPrice: gasPrice, 98 | gasLimit: 21000, 99 | nonce: transactionCount, 100 | 101 | // The amount to send 102 | value: value, 103 | 104 | // Prevent replay attacks across networks 105 | chainId: provider.chainId, 106 | }; 107 | 108 | var signedTransaction = wallet.sign(transaction); 109 | 110 | // By returning a Promise, the sendPromise will resolve once the 111 | // transaction is sent 112 | return provider.sendTransaction(signedTransaction); 113 | }); 114 | 115 | var minedPromise = sendPromise.then(function(transaction) { 116 | // This will be called once the transaction is sent 117 | 118 | // This promise will be resolve once the transaction has been mined. 119 | return provider.waitForTransaction(transaction); 120 | }); 121 | 122 | minedPromise.then(function(transaction) { 123 | console.log("The transaction was mined: Block " + transaction.blockNumber); 124 | }); 125 | 126 | 127 | // Promises can be re-used for their value; it will not make the external 128 | // call again, and will provide the exact same result every time. 129 | balancePromise.then(function(balance) { 130 | // This *may* return before the above allPromises, since it only 131 | // required one external call. Keep in mind asynchronous calls can 132 | // be called out of order. 133 | console.log(balance); 134 | }); 135 | 136 | ----- 137 | 138 | .. _checksum-address: 139 | 140 | Checksum Address 141 | ================ 142 | 143 | A `checksum address`_ uses mixed case hexadecimal strings to encode the checksum 144 | information in the capitalization of the alphabetic characters, while remaining 145 | backwards compatible with non-checksum addresses. 146 | 147 | Example:: 148 | 149 | // Valid; checksum (mixed case) 150 | 0xCd2a3d9f938e13Cd947eC05ABC7fe734df8DD826 151 | 152 | // Valid; NO checksum (no mixed case) 153 | 0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826 154 | 0xCD2A3D9F938E13CD947EC05ABC7FE734DF8DD826 155 | 156 | // INVALID; (mixed case, but case differs from first example) 157 | 0xDc2a3d9f938e13cd947ec05abc7fe734df8dd826 158 | ^^ 159 | 160 | To convert to a checksum addresses, see :ref:`getAddress() `. 161 | 162 | .. _checksum address: https://eips.ethereum.org/EIPS/eip-55 163 | 164 | ----- 165 | 166 | .. _icap-address: 167 | 168 | ICAP Address 169 | ============ 170 | 171 | The original method of adding a checksum to an Ethereum address was by using the 172 | a format compatible with `IBAN`_ addresses, using the country code **XE**. However, 173 | only addresses which have 0 as the first byte (i.e. the address begins with 0x00) 174 | are truly compatible with IBAN, so ICAP extends the definition to allow for 31 175 | alphanumeric characters (instead of the standard 30). 176 | 177 | An ICAP address has the following format:: 178 | 179 | XE [2 digit checksum] [up to 31 alphanumeric characters] 180 | 181 | To convert to an ICAP addresses, see :ref:`getIcapAddress() `. 182 | 183 | ----- 184 | 185 | Supported Platforms 186 | =================== 187 | 188 | The ethers.js library aims to be as inclusive as possible. People often ask, "why 189 | don't you use feature X or syntax Y", to which the response is usually that it 190 | begins to heavily restricts the potential user-base. 191 | 192 | The current target for ethers.js is to support an environment which is close to ES3, 193 | with the addition of Object.defineProperty, which is a bit more advanced than an old 194 | ES3 environment, but which adds considerable safety and security to the library. 195 | 196 | The phantomjs test harness (``npm run test-phantomjs``) has a handful of shims included 197 | in the tests/test.html, but serves as a good benchmark for what minimum features as 198 | supported. 199 | 200 | Currently the Test Suite runs against: 201 | 202 | - node 6 203 | - node 8 204 | - node 10 205 | - phantomjs 206 | 207 | Another supported aspect is the use of paths in ``require``. A small part of the 208 | library may be included, for example, ``keccak256``, by using:: 209 | 210 | var keccak256 = require('ethers/utils/keccak256').keccak256; 211 | 212 | Which means renaming files is a breaking change, and may only be done between 213 | major version releases. This is useful for people using older, pre-ES6 214 | tree-shaking, to keep their package sizes small. 215 | 216 | Now that the library also supports TypeScript, another question that often comes 217 | up is (for example) "why are you doing runtime checks that a value is a number, 218 | the TypeScript compiler checks that for you". It is important to keep in mind that 219 | TypeScript, while a useful tool, is not the tool that everyone uses, and so for 220 | anyone using JavaScript sans TypeScript, the library should guarantee safety and 221 | correctness for them too and fail early and fail loud if anything is out of the 222 | ordinary. 223 | 224 | ----- 225 | 226 | Contributing 227 | ============ 228 | 229 | I fully welcome anyone to contribute to the project, and appreciate all the 230 | help I can get. That said, if you have ideas for a PR, please discuss them 231 | as an issue on GitHub first. 232 | 233 | A few notes on contributing. 234 | 235 | - Please read the above section on Supported Platforms. 236 | - An important feature of ethers.js is that it is small, which means uncommon features or large features need a great deal of discussion. 237 | - Since ethers.js is designed to be extensible, there are often ways to add optional packages; for example, look at the BIP39 mnemonic wordlists, which are not bundled into the browser version, but are designed to be seamlessly loaded into the browser if their functionality is required. 238 | - Dependencies; part A) in line with the above, "keep things small", adding a dependency is a big deal, as they often bring many other packages with them. A great deal of effort has been used to tune the build process and dependency list to keep things tight 239 | - Dependencies; part B) adding additional third party libraries, adds a huge attack vector fun malicious code or unexpected consequences, so adding a dependency is certainly something that needs to be very convincingly argued. 240 | - Dependencies; part C) part B applies to dev dependencies too. A devDependency can inject or otherwise do strange things and increases the attack vector for bugs and malicious code 241 | - Changing filenames or breaking backwards compatibility is a no-go for minor version changes 242 | - Major version changes do not happen often. We place @TODO in the source code for things that will be updated at the next version change. 243 | - Please use the GitHub issue system to make requests, or discuss changes you would like to make. 244 | - Testing is a must. It should generally take you longer to write test cases than it does the actual code. 245 | - All test cases must pass on all platforms supported on Travis CI. 246 | 247 | ----- 248 | 249 | Security 250 | ======== 251 | 252 | A lot of people store a lot of value in Ethereum and the code that runs it. As 253 | such, security is important. 254 | 255 | 256 | The GitHub and NPM Package 257 | -------------------------- 258 | 259 | The keys used to sign code on GitHub are well protected, but anyones computer 260 | can be compromised. 261 | 262 | All services involved have two-factor authentication set up, but please keep in 263 | mind that bleeding-edge technology should probably not be used in production 264 | environments. 265 | 266 | Keep in mind, however, that at the end of the day, if NPM were hacked, anything 267 | in the system could be replaced. 268 | 269 | By using a version that is perhaps a few weeks old, providing there are no 270 | advisories otherwise, there has been adequate time for any compromise to have 271 | been broadcast. 272 | 273 | Also, one of the test cases verifies the deterministic build on `Travis CI`_. **Never** 274 | install a version which has failed the Continuous Integration tests on Travis CI. 275 | 276 | Long story short, be careful. 277 | 278 | In the event of any significant issue, it will be posted on the README.md file, 279 | have an issue posted, with ALL CAPS in the title and will be broadcast on the 280 | @ethersproject twitter. 281 | 282 | 283 | Memory Hard Brute-Force Encrpyting 284 | ---------------------------------- 285 | 286 | A topic that often comes up is the poor performance of decrypting Wallet. 287 | 288 | While it may not be immediately obvious, this is intentional for security 289 | purposes. 290 | 291 | If it takes the legitimate user, who knows the password 5 seconds or so to 292 | unlock their account, that means that an attacker must spend 5 seconds per 293 | password attempt, so to guess a million passwords, requires 5 million 294 | seconds. Client software can streamline the process by using Secure Enclaves 295 | or other secure local places to store the decrypted wallet to improve the 296 | customer experience past the first decryption. 297 | 298 | 299 | Responsible Disclosure 300 | ---------------------- 301 | 302 | If you find a critical bug or security issue with ethers.js, please contact 303 | support@ethers.io so that we can address it before you make it public. 304 | You will receive credit for the discovery after it is fixed and announced. :) 305 | 306 | ----- 307 | 308 | .. _IBAN: https://en.wikipedia.org/wiki/International_Bank_Account_Number 309 | .. _IEEE 754 double-precision binary floating point: https://en.wikipedia.org/wiki/Double-precision_floating-point_format 310 | .. _BN.js: https://github.com/indutny/bn.js/ 311 | .. _Promise in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 312 | .. _Travis CI: https://travis-ci.org/ethers-io/ethers.js 313 | 314 | .. EOF 315 | -------------------------------------------------------------------------------- /source/testing.rst: -------------------------------------------------------------------------------- 1 | 测试 2 | ******* 3 | 4 | Ethers uses a large suite of test cases to help ensure the library is as 5 | complete, backwards compatible and correct as possible and pass 6 | regression as new features are added. 7 | 8 | Many of the test cases are created procedurally. 9 | 10 | **@TODO:** 11 | Explain more here on how to run and add testcases. 12 | 13 | **@TODO:** 14 | Post links to the testcases on IPFS (the generated test cases can takes hours to 15 | generate and are too large to check into GitHub) 16 | 17 | ----- 18 | 19 | .. EOF 20 | -------------------------------------------------------------------------------- /status.md: -------------------------------------------------------------------------------- 1 | ## 翻译状态记录 2 | 3 | 地址:https://github.com/ethers-io/documentation 4 | commit: cfdd293f0a6071a5653cf6a43a7a3804669fe607 --------------------------------------------------------------------------------