├── .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 | 签名器
5 |
6 | .. |wallet| raw:: html
7 |
8 | 钱包
9 |
10 | .. |provider| raw:: html
11 |
12 | 提供者
13 |
14 | .. |ABI| raw:: html
15 |
16 | 应用二进制接口
17 |
18 | .. |Ether| raw:: html
19 |
20 | 以太
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
--------------------------------------------------------------------------------