Compare commits
256 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc1e006575 | ||
|
|
d9f45b3b9d | ||
|
|
8a7b5efad0 | ||
|
|
24bd3281f7 | ||
|
|
3f631e9681 | ||
|
|
8770cc46fd | ||
|
|
04c0515f0b | ||
|
|
4467d9fa00 | ||
|
|
1a5af9b8e2 | ||
|
|
bd152f7ea0 | ||
|
|
24c3caae14 | ||
|
|
bebd6698c6 | ||
|
|
a72e404259 | ||
|
|
7b299dd9c9 | ||
|
|
9bf17fa07c | ||
|
|
66d6aaf4b4 | ||
|
|
f599d6f23d | ||
|
|
7a15201786 | ||
|
|
7bc9c6b953 | ||
|
|
0855d6e9f5 | ||
|
|
948f77050d | ||
|
|
9e57e71dc0 | ||
|
|
dab6ede226 | ||
|
|
1f6c0ab281 | ||
|
|
056d7c8bfc | ||
|
|
47c41143cb | ||
|
|
ef1b28e958 | ||
|
|
e192903050 | ||
|
|
9d9b14b952 | ||
|
|
bc400c7b87 | ||
|
|
120dcd024a | ||
|
|
04f7a9f3b7 | ||
|
|
e70f3fe26f | ||
|
|
ef529dc5e6 | ||
|
|
9f0967f21f | ||
|
|
774c310389 | ||
|
|
21fae9f0ba | ||
|
|
ce85a7e976 | ||
|
|
7c4a9083c2 | ||
|
|
7becc93ed0 | ||
|
|
540a670f94 | ||
|
|
ab628c285e | ||
|
|
9bff2cb3d9 | ||
|
|
96de58122a | ||
|
|
b1c7f5c21a | ||
|
|
905e98aa39 | ||
|
|
dca0d14d38 | ||
|
|
5998fea53d | ||
|
|
dfaa8ee7e6 | ||
|
|
fa4a29028d | ||
|
|
f46aa75ef1 | ||
|
|
d160bac273 | ||
|
|
be518c32ec | ||
|
|
26cdbab59b | ||
|
|
b8cda5dffd | ||
|
|
f67a9a8569 | ||
|
|
bae215eb7f | ||
|
|
54e6e57fce | ||
|
|
38e825cee6 | ||
|
|
16007d4d1e | ||
|
|
cf47ec5fd5 | ||
|
|
ae23bb76a9 | ||
|
|
33a029e457 | ||
|
|
c2a6a012bf | ||
|
|
6807a76b8d | ||
|
|
5f26fd55c9 | ||
|
|
c562150d26 | ||
|
|
4e8f004e9e | ||
|
|
9aac785395 | ||
|
|
1651389571 | ||
|
|
2d98b4fca1 | ||
|
|
f26074b92b | ||
|
|
eb91d708ac | ||
|
|
83891f9258 | ||
|
|
7b134bd5c9 | ||
|
|
e175448380 | ||
|
|
1d419b5829 | ||
|
|
95b2c72b12 | ||
|
|
7b0d02d30e | ||
|
|
0c72e0f1fd | ||
|
|
315ecfd19e | ||
|
|
c61f3bc2a0 | ||
|
|
1be096130c | ||
|
|
9eed04a6d5 | ||
|
|
82d6dcbdde | ||
|
|
4935f93015 | ||
|
|
3df0e06c64 | ||
|
|
18d8d1f34d | ||
|
|
7b80ba20fe | ||
|
|
f635af2684 | ||
|
|
813fcef4ad | ||
|
|
32c9a09762 | ||
|
|
03545aa78b | ||
|
|
03152ea014 | ||
|
|
0578a88efa | ||
|
|
3f5bc6ddc1 | ||
|
|
ab13887cda | ||
|
|
28f383300c | ||
|
|
4ba63acc10 | ||
|
|
3d6a7ec020 | ||
|
|
2f57c6a4ab | ||
|
|
d3d2953e8d | ||
|
|
0403314023 | ||
|
|
eb432aa1f4 | ||
|
|
617714d196 | ||
|
|
42784b8d38 | ||
|
|
50d712d6af | ||
|
|
c7e9715758 | ||
|
|
0844de4eb4 | ||
|
|
caa1983665 | ||
|
|
b8391b0e61 | ||
|
|
1e1c93effa | ||
|
|
b145898976 | ||
|
|
1bd91615ee | ||
|
|
d3079745c5 | ||
|
|
ecce86125d | ||
|
|
5899c8aec0 | ||
|
|
3de1b81501 | ||
|
|
ab319f2f4c | ||
|
|
5b94ce2966 | ||
|
|
91c577b611 | ||
|
|
2f363da5ff | ||
|
|
73a46efea3 | ||
|
|
8f3d71dc5f | ||
|
|
a5c6a468f4 | ||
|
|
8947fd405e | ||
|
|
cb43a99405 | ||
|
|
b7e61bd67e | ||
|
|
0a8be37b08 | ||
|
|
6582ede1ce | ||
|
|
f3c6d819f3 | ||
|
|
bee76a49b2 | ||
|
|
68095a48ae | ||
|
|
0e5419ec79 | ||
|
|
a48552a4fb | ||
|
|
ab806cad15 | ||
|
|
d5b41ce210 | ||
|
|
fb6d141723 | ||
|
|
7a404fb8ed | ||
|
|
f8adf82e16 | ||
|
|
8395cc146f | ||
|
|
8fc5914c5a | ||
|
|
cc250b2060 | ||
|
|
375627f6b1 | ||
|
|
d67f8fb778 | ||
|
|
45f367512d | ||
|
|
ad87b718a9 | ||
|
|
48c9e0bf39 | ||
|
|
d1d636b503 | ||
|
|
4166b2753d | ||
|
|
32a6b2a362 | ||
|
|
f2a32d0d5b | ||
|
|
5762a1f83d | ||
|
|
8320d534d7 | ||
|
|
c41b89a0c1 | ||
|
|
b6a061e7bf | ||
|
|
a662490e82 | ||
|
|
bdb54ac52b | ||
|
|
32a90b66f0 | ||
|
|
95b87f61a6 | ||
|
|
017b1feba2 | ||
|
|
accb85268c | ||
|
|
f0b3bc32d5 | ||
|
|
78e4273a32 | ||
|
|
dd09bf0735 | ||
|
|
4b163e9e73 | ||
|
|
aacb95cd6b | ||
|
|
e6315a6b3c | ||
|
|
3ac91a414c | ||
|
|
2dd5c1a6d2 | ||
|
|
2653449f3c | ||
|
|
cddb03880a | ||
|
|
e80f8dd4e6 | ||
|
|
1b4bc7a6a6 | ||
|
|
4e9394554b | ||
|
|
1d27d95670 | ||
|
|
2e431a5002 | ||
|
|
da4e107268 | ||
|
|
7175e2e99c | ||
|
|
68229ac0af | ||
|
|
7274cd06cf | ||
|
|
be3854e648 | ||
|
|
63f8b28223 | ||
|
|
593b4886ff | ||
|
|
6d1904c379 | ||
|
|
0aafca71db | ||
|
|
0d40156fcb | ||
|
|
576e9b54ab | ||
|
|
bc5cc2e7e3 | ||
|
|
660e69db71 | ||
|
|
551cfa0062 | ||
|
|
0f0d0c00d3 | ||
|
|
a1f8d188a7 | ||
|
|
bde861436e | ||
|
|
6e8a39ec35 | ||
|
|
ecae793edf | ||
|
|
bac684c5a0 | ||
|
|
53671d0b17 | ||
|
|
25c8b8b3e6 | ||
|
|
a0fa92c075 | ||
|
|
72feee8f58 | ||
|
|
71b7547f10 | ||
|
|
4970385e7b | ||
|
|
0364dd9368 | ||
|
|
e95708eedc | ||
|
|
ba6854bdd5 | ||
|
|
1e31b34a5a | ||
|
|
7deb4c174a | ||
|
|
f053a7ad58 | ||
|
|
b1affdbc10 | ||
|
|
c2c0ce7503 | ||
|
|
7efc36df29 | ||
|
|
720bde7719 | ||
|
|
319987ec3e | ||
|
|
2a7ce0e72a | ||
|
|
8ba64af29f | ||
|
|
17af9f812f | ||
|
|
d001901c8c | ||
|
|
91951dc825 | ||
|
|
8277f5a62a | ||
|
|
e615e51fbf | ||
|
|
99422c1c7c | ||
|
|
e8a0144b7a | ||
|
|
f9d09645e7 | ||
|
|
91fff1449d | ||
|
|
c5bca7767e | ||
|
|
79c5bf6bcb | ||
|
|
412bbe2939 | ||
|
|
ee82e86ccc | ||
|
|
376cf3cdbf | ||
|
|
89bae3bd63 | ||
|
|
a6e128f5cc | ||
|
|
5456c35924 | ||
|
|
be20e28de1 | ||
|
|
30c0c97270 | ||
|
|
4e6d121fb8 | ||
|
|
bfcd05fcbb | ||
|
|
819b1ace5c | ||
|
|
4b331148d9 | ||
|
|
7adcf3b154 | ||
|
|
630656e949 | ||
|
|
8681cd5969 | ||
|
|
470551e4ee | ||
|
|
7a12216cfb | ||
|
|
d395d16fa3 | ||
|
|
8077ce0aae | ||
|
|
2fe78ad7e3 | ||
|
|
5f1f2c5e2c | ||
|
|
3c79ee8cef | ||
|
|
772067a3c9 | ||
|
|
621897f249 | ||
|
|
d3b7130ed6 | ||
|
|
4898e7baac | ||
|
|
c71bbbe7db | ||
|
|
c8fecbbc29 | ||
|
|
b4df28dddd |
67
.github/ISSUE_TEMPLATE/beta-issue.yml
vendored
Normal file
67
.github/ISSUE_TEMPLATE/beta-issue.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: Beta (v6) Bug
|
||||
description: Open an issue for a bug in the v6 beta
|
||||
title: "Title Here"
|
||||
labels: ["v6-beta"]
|
||||
assignees:
|
||||
- ricmoo
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This form is **only** for issues in the **v6 beta**, which you can access using either the `v6-beta` tag in the repository or install using `ethers@beta` with `npm`.
|
||||
|
||||
The v6 branch will be very lively, undergoing a lot of changes, including backwards compatible changes between beta versions.
|
||||
|
||||
Before opening an issue, please make sure you have **fully updated to the latest version** by removing the `node_modules/` and `package-lock.json` and then running a fresh `npm install`. Otherwise you may end up with incompatible versions which may conflict with each other.
|
||||
|
||||
Thanks for trying out the v6 beta! Cheers!
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Ethers Beta Version
|
||||
description: What version of ethers are you using? Before opening an issue, please make sure you are using the latest beta.
|
||||
placeholder: x.y.z-beta.N
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: about-the-bug
|
||||
attributes:
|
||||
label: Describe the Problem
|
||||
description: Please describe what you expected to happen vs what did happen?
|
||||
placeholder: What happened?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: code-snippet
|
||||
attributes:
|
||||
label: Code Snippet
|
||||
description: If possible, please include a **short and concise** code snippets that can reproduce this issue. Ideally code that can be pasted into the [Ethers Playground](https://playground.ethers.org).
|
||||
placeholder: e.g. provider.getBlockNumber()
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: errors
|
||||
attributes:
|
||||
label: Errors
|
||||
description: If there is an error, please include the **entire error** (redacting any sensitive information).
|
||||
placeholder: "e.g. Error: invalid name (code='INVALID_ARGUMENT, ...)"
|
||||
render: shell
|
||||
- type: dropdown
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: What environment, platforms or frameworks are you using? Select all that apply.
|
||||
multiple: true
|
||||
options:
|
||||
- node.js
|
||||
- Browser (Chrome, Safari, etc)
|
||||
- React Native/Expo/JavaScriptCore
|
||||
- Hardhat
|
||||
- Geth
|
||||
- Parity
|
||||
- Ganache
|
||||
- Other (please specify)
|
||||
- type: input
|
||||
id: other-envrionment
|
||||
attributes:
|
||||
label: Environment (Other)
|
||||
placeholder: anything else?
|
||||
81
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
81
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
name: Bug Report
|
||||
description: Open an issue for a bug in Ethers
|
||||
title: "Bug Report Title"
|
||||
labels: ["investigate"]
|
||||
assignees:
|
||||
- ricmoo
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**READ THIS FIRST** and follow all instructions, please. `:)`
|
||||
|
||||
Thank you for taking the time to report an issue. This form is for reporting **bugs within ethers**.
|
||||
|
||||
If you are **new to ethers** or *uncertain* whether this is a bug in ethers, a bug in another framework or a bug in your own code, please [start a discussion](https://github.com/ethers-io/ethers.js/discussions) first.
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Ethers Version
|
||||
description: What version of ethers are you using? Before opening an issue, please make sure you are up to date.
|
||||
placeholder: x.y.z
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: search-terms
|
||||
attributes:
|
||||
label: Search Terms
|
||||
description: Have you searched for answers [in the documentation](https://docs.ethers.io), through [the issues](https://github.com/ethers-io/ethers.js/issues) and [on the discusions](https://github.com/ethers-io/ethers.js/discussions)? Please include the search terms you have tried. This helps us add more keywords where needed.
|
||||
placeholder: e.g. abi, network, utf8
|
||||
- type: textarea
|
||||
id: about-the-bug
|
||||
attributes:
|
||||
label: Describe the Problem
|
||||
description: Please describe what you expected to happen vs what did happen?
|
||||
placeholder: What happened?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: code-snippet
|
||||
attributes:
|
||||
label: Code Snippet
|
||||
description: If possible, please include a **short and concise** code snippets that can reproduce this issue. Ideally code that can be pasted into the [Ethers Playground](https://playground.ethers.org).
|
||||
placeholder: e.g. provider.getBlockNumber()
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: contract-abi
|
||||
attributes:
|
||||
label: Contract ABI
|
||||
description: If this involves a contract, please include any **concise and relevant** ABI fragments.
|
||||
placeholder: e.g. [ 'function balanceOf(address owner) view returns (uint)' ]
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: errors
|
||||
attributes:
|
||||
label: Errors
|
||||
description: If there is an error, please include the **entire error** (redacting any sensitive information).
|
||||
placeholder: "e.g. Error: invalid name (code='INVALID_ARGUMENT, ...)"
|
||||
render: shell
|
||||
- type: dropdown
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: What environment, platforms or frameworks are you using? Select all that apply.
|
||||
multiple: true
|
||||
options:
|
||||
- Ethereum (mainnet/ropsten/rinkeby/goerli)
|
||||
- Altcoin - Please specify (e.g. Polygon)
|
||||
- node.js (v12 or newer)
|
||||
- node.js (older than v12)
|
||||
- Browser (Chrome, Safari, etc)
|
||||
- React Native/Expo/JavaScriptCore
|
||||
- Hardhat
|
||||
- Geth
|
||||
- Parity
|
||||
- Ganache
|
||||
- Other (please specify)
|
||||
- type: input
|
||||
id: other-envrionment
|
||||
attributes:
|
||||
label: Environment (Other)
|
||||
placeholder: anything else?
|
||||
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,22 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: investigate
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Note: Not all sections may be relevant, but please be as thorough while remaining concise as possible. Remove this Notice and any sections that don't feel pertinent.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Reproduction steps**
|
||||
Please include code snippets, with console.log output, any contract ABI, contract address, network and the full error.
|
||||
|
||||
**Environment:**
|
||||
Please include anything that may be useful in diagnosing the issue. Node vs Browser? Geth vs Parity vs Ganache? Third Party tools, like Hardhat? Mobile vs. Desktop?
|
||||
|
||||
**Search Terms**
|
||||
Often similar issues have come up before. Include any search terms you have tried in this repository's Issues (including closed issues) and Discussions, so if there are matching issues, we can be sure to add those keywords to make it easier for people to find in the future.
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
23
.github/ISSUE_TEMPLATE/documentation.yml
vendored
Normal file
23
.github/ISSUE_TEMPLATE/documentation.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Documentation
|
||||
description: Documentation update, change or suggestion
|
||||
title: "Documentation Title"
|
||||
labels: ["documentation"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please include anything about the [documentation](https://docs.ethers.io) you would like to see improved.
|
||||
|
||||
- Missing information or details?
|
||||
- Spelling or Grammar mistakes?
|
||||
- Wrong Information?
|
||||
- Dead or wrong links?
|
||||
- Something needs code examples?
|
||||
- General feedback or anything else?
|
||||
- type: textarea
|
||||
id: suggestion
|
||||
attributes:
|
||||
label: Suggestion
|
||||
placeholder: e.g. please add an example for ropsten
|
||||
validations:
|
||||
required: true
|
||||
22
.github/ISSUE_TEMPLATE/feature-request.md
vendored
22
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@@ -1,22 +0,0 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest a new feature for ethers
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Note: The best place to start a Feature Request is usually in the Discussions, to mull through the desired feature, current options and think through the impact on the library overall.
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
26
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature or addition to Ethers
|
||||
title: "Feature Request Title"
|
||||
labels: [ "enhancement" ]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
The best place to start a new feature request is by starting an [Idea discussion](https://github.com/ethers-io/ethers.js/discussions), to mull over the feature, discuss current options and think through the impact on the overall library.
|
||||
|
||||
Keep in mind that features increase the library size, and may require additional dependencies. Ethers strives to remain lean and the number of dependencies low, so many features may make more sense as ancillary packages.
|
||||
- type: textarea
|
||||
id: about-the-feature
|
||||
attributes:
|
||||
label: Describe the Feature
|
||||
description: Please describe the feature, the problem it is solving, your solution and alternatives you've considered.
|
||||
placeholder: e.g. I want Ethers to be more/less magical.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: code-example
|
||||
attributes:
|
||||
label: Code Example
|
||||
description: Optionally, provide an example of how the feature would be used in code.
|
||||
placeholder: e.g. provider.doMagic()
|
||||
render: shell
|
||||
2
.github/workflows/nodejs.yml
vendored
2
.github/workflows/nodejs.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [ 8.x, 10.x, 12.x, 13.x ]
|
||||
node-version: [ 12.x, 14.x, 16.x ]
|
||||
|
||||
steps:
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
|
||||
190
CHANGELOG.md
190
CHANGELOG.md
@@ -3,6 +3,196 @@ Changelog
|
||||
|
||||
This change log is managed by `admin/cmds/update-versions` but may be manually updated.
|
||||
|
||||
|
||||
ethers/v5.6.5 (2022-05-01 02:10)
|
||||
--------------------------------
|
||||
|
||||
- Added testnets for AnkrProvider. ([#2949](https://github.com/ethers-io/ethers.js/issues/2949), [#2950](https://github.com/ethers-io/ethers.js/issues/2950); [d9f45b3](https://github.com/ethers-io/ethers.js/commit/d9f45b3b9db92c72f9c606bab8315d0eb02fec70))
|
||||
- Better error coalescing for OpenEthereum nodes. ([#2846](https://github.com/ethers-io/ethers.js/issues/2846); [bebd669](https://github.com/ethers-io/ethers.js/commit/bebd6698c6c3193f0bdb96b54c5daa5ee5d0692c))
|
||||
- Enforce 32-byte private key length (2926). ([7b299dd](https://github.com/ethers-io/ethers.js/commit/7b299dd9c97571b12916e3ae529540f3f2e5a367))
|
||||
- Fixed decimal strings as value-type properties for JsonRpcSigner. ([#2948](https://github.com/ethers-io/ethers.js/issues/2948); [9bf17fa](https://github.com/ethers-io/ethers.js/commit/9bf17fa07c6149a02ef217f2b89f1bfd990b1a6c))
|
||||
|
||||
ethers/v5.6.4 (2022-04-13 16:56)
|
||||
--------------------------------
|
||||
|
||||
- Support new OpenEthereum NONCE_EXPIRED string. ([#2845](https://github.com/ethers-io/ethers.js/issues/2845), [#2846](https://github.com/ethers-io/ethers.js/issues/2846); [0855d6e](https://github.com/ethers-io/ethers.js/commit/0855d6e9f593515b639c10a3f65bad712c68221c))
|
||||
|
||||
ethers/v5.6.3 (2022-04-13 00:23)
|
||||
--------------------------------
|
||||
|
||||
- Mimic Hardhard error strings in CALL_EXCEPTION for popular matchers. ([#2849](https://github.com/ethers-io/ethers.js/issues/2849), [#2862](https://github.com/ethers-io/ethers.js/issues/2862); [dab6ede](https://github.com/ethers-io/ethers.js/commit/dab6ede226e572706655e2865d4c953e37741a5c))
|
||||
- Fix pocket API key not being passed in for default provider. ([#2890](https://github.com/ethers-io/ethers.js/issues/2890); [056d7c8](https://github.com/ethers-io/ethers.js/commit/056d7c8bfc5896759c383d7cfae8ed0ec5c5eefb))
|
||||
|
||||
ethers/v5.6.2 (2022-03-25 17:56)
|
||||
--------------------------------
|
||||
|
||||
- Fixed left-padding in arrayify. ([#2833](https://github.com/ethers-io/ethers.js/issues/2833); [e192903](https://github.com/ethers-io/ethers.js/commit/e19290305080ebdfa2cb2ab2719cb53fee5a6cc7))
|
||||
- More robust JSON-RPC error handling for reverted executions. ([#2603](https://github.com/ethers-io/ethers.js/issues/2603); [9d9b14b](https://github.com/ethers-io/ethers.js/commit/9d9b14b95299b793c1a0f4cb8f42e4e0252fed1c))
|
||||
- Added IPNS support for ENS contenthash. ([e70f3fe](https://github.com/ethers-io/ethers.js/commit/e70f3fe26f3b0dfd44fdbc163e2cc6c8eb9433f8))
|
||||
- Added initial AnkrProvider ([96de581](https://github.com/ethers-io/ethers.js/commit/96de58122af57be761e431e9268958eeaa352480))
|
||||
|
||||
ethers/v5.6.1 (2022-03-16 01:25)
|
||||
--------------------------------
|
||||
|
||||
- Fix issue with CCIP Read using wrong sender. ([#2478](https://github.com/ethers-io/ethers.js/issues/2478); [5998fea](https://github.com/ethers-io/ethers.js/commit/5998fea53d5ea26358c2f10939dfdf0bc679936d), [905e98a](https://github.com/ethers-io/ethers.js/commit/905e98aa392e2a52d6b0339b21bfce5237fd8662))
|
||||
|
||||
ethers/v5.6.0 (2022-03-09 14:57)
|
||||
--------------------------------
|
||||
|
||||
- Tweaked test case to re-order transaction after event listeners added. ([fa4a290](https://github.com/ethers-io/ethers.js/commit/fa4a29028d97d598b43b2f5ff98077e8cadf56a4))
|
||||
- Ignore errors when resolving ENS resolver properties. ([d160bac](https://github.com/ethers-io/ethers.js/commit/d160bac273775f928a9441b0275dbdb6032368fa))
|
||||
- Enable CCIP Read for ENS resolvers. ([#2478](https://github.com/ethers-io/ethers.js/issues/2478); [be518c3](https://github.com/ethers-io/ethers.js/commit/be518c32ec7db9dd4769b57cdf130eb333aebb72))
|
||||
- Fix missing events on certain network conditions. ([#1798](https://github.com/ethers-io/ethers.js/issues/1798), [#1814](https://github.com/ethers-io/ethers.js/issues/1814), [#1830](https://github.com/ethers-io/ethers.js/issues/1830), [#2274](https://github.com/ethers-io/ethers.js/issues/2274), [#2652](https://github.com/ethers-io/ethers.js/issues/2652); [f67a9a8](https://github.com/ethers-io/ethers.js/commit/f67a9a8569cdfd0ef9ce5fbf09866aab6e4814d4), [f46aa75](https://github.com/ethers-io/ethers.js/commit/f46aa75ef1f3428e640cd046db3f080d264b32f3))
|
||||
- Added defaultProvider option to omit specific Providers. ([bae215e](https://github.com/ethers-io/ethers.js/commit/bae215eb7fb3efea8473a544579abac1bebb7ef0))
|
||||
- Add support for pending blocks. ([#2225](https://github.com/ethers-io/ethers.js/issues/2225); [54e6e57](https://github.com/ethers-io/ethers.js/commit/54e6e57fcece4c1718a577ecbeb1af97998e8bdc))
|
||||
- Help URLs for errors. ([#2489](https://github.com/ethers-io/ethers.js/issues/2489); [38e825c](https://github.com/ethers-io/ethers.js/commit/38e825cee624ff935ec6b70023cf288126a6bb85), [c562150](https://github.com/ethers-io/ethers.js/commit/c562150d2678710f50e5ee3ffa88d0e62d6f696f))
|
||||
- Added CCIP support to provider.call. ([#2478](https://github.com/ethers-io/ethers.js/issues/2478); [ae23bb7](https://github.com/ethers-io/ethers.js/commit/ae23bb76a937924bf57baf679e6efd8cdf59bc47))
|
||||
- Adjust default maxPriorityFeePerGas to 1.5 gwei. ([33a029e](https://github.com/ethers-io/ethers.js/commit/33a029e457320a226c68a01f4cfa2d110125a8b8))
|
||||
- Fix contracts when name resolution fails without any checks. ([#2737](https://github.com/ethers-io/ethers.js/issues/2737); [c2a6a01](https://github.com/ethers-io/ethers.js/commit/c2a6a012bf1d8fcd5805e45754cebdfe211c6933))
|
||||
- Preserve explicit chainId in JsonRpcProvider during transaction serialization. ([#2691](https://github.com/ethers-io/ethers.js/issues/2691); [6807a76](https://github.com/ethers-io/ethers.js/commit/6807a76b8ddfdd121f98b21e269de3b195a7673e))
|
||||
- Fixed eth_chainId response for Eip1193Bridge. ([#2711](https://github.com/ethers-io/ethers.js/issues/2711); [5f26fd5](https://github.com/ethers-io/ethers.js/commit/5f26fd55c9d010c00f830a4c83a480a54773858d))
|
||||
- Remove spurious console.log from Interface. ([#2714](https://github.com/ethers-io/ethers.js/issues/2714); [4e8f004](https://github.com/ethers-io/ethers.js/commit/4e8f004e9e42892840663311cafe042c0b24c61e))
|
||||
- Allow raw WebSocket to be passed into WebSocketProvider. ([#2562](https://github.com/ethers-io/ethers.js/issues/2562), [#2644](https://github.com/ethers-io/ethers.js/issues/2644); [9aac785](https://github.com/ethers-io/ethers.js/commit/9aac785395e9b47655477a3ba7baf05df3274de9))
|
||||
- Added Cloudflare Worker support. ([#1886](https://github.com/ethers-io/ethers.js/issues/1886); [2d98b4f](https://github.com/ethers-io/ethers.js/commit/2d98b4fca1eb2544fec728f7c1c7b0d450e0dbee), [1651389](https://github.com/ethers-io/ethers.js/commit/1651389571b5dd16c1c056dcd94729b48a4bdd85))
|
||||
- Add support for EIP-2098 compact signatures. ([#2246](https://github.com/ethers-io/ethers.js/issues/2246); [f26074b](https://github.com/ethers-io/ethers.js/commit/f26074b92b0fc8efd3d85c68e84cc6ff8897e4a8))
|
||||
- Add EIP-2544 Wildcard support. ([#2477](https://github.com/ethers-io/ethers.js/issues/2477), [#2582](https://github.com/ethers-io/ethers.js/issues/2582), [#2583](https://github.com/ethers-io/ethers.js/issues/2583); [83891f9](https://github.com/ethers-io/ethers.js/commit/83891f9258492f9801aa579ac50764b6491b6180))
|
||||
|
||||
ethers/v5.5.4 (2022-01-24 16:45)
|
||||
--------------------------------
|
||||
|
||||
- Support invalid but popular IPFS URI format. ([#2271](https://github.com/ethers-io/ethers.js/issues/2271), [#2527](https://github.com/ethers-io/ethers.js/issues/2527), [#2590](https://github.com/ethers-io/ethers.js/issues/2590); [03545aa](https://github.com/ethers-io/ethers.js/commit/03545aa78b0e7bd177e22432e4842b0580a11d7d))
|
||||
|
||||
ethers/v5.5.3 (2022-01-06 03:52)
|
||||
--------------------------------
|
||||
|
||||
- Fixed case-folding in schemes for ENS avatars. ([#2500](https://github.com/ethers-io/ethers.js/issues/2500); [3f5bc6d](https://github.com/ethers-io/ethers.js/commit/3f5bc6ddc1013f0a5974f2ee6f542d6c91480c13))
|
||||
- Added Kintsugi network. ([#2434](https://github.com/ethers-io/ethers.js/issues/2434); [ab13887](https://github.com/ethers-io/ethers.js/commit/ab13887cda3939703dc1f7e27d139ef6001b7dd2))
|
||||
- Fix browser random in WebWorkers. ([#2405](https://github.com/ethers-io/ethers.js/issues/2405); [4ba63ac](https://github.com/ethers-io/ethers.js/commit/4ba63acc107fdd0a6d6ef3e27349e65edb007447))
|
||||
- Add support for IPFS metadata imageUrl in getAvatar. ([#2426](https://github.com/ethers-io/ethers.js/issues/2426); [3d6a7ec](https://github.com/ethers-io/ethers.js/commit/3d6a7ec020eacd993b4b0fd3274574de3ddcc257))
|
||||
- Do not swallow ENS not supported errors. ([#2387](https://github.com/ethers-io/ethers.js/issues/2387); [2f57c6a](https://github.com/ethers-io/ethers.js/commit/2f57c6a4ab44083b2c03f5e57b2702ab7078d286))
|
||||
|
||||
ethers/v5.5.2 (2021-11-30 19:16)
|
||||
--------------------------------
|
||||
|
||||
- Fixed test case for getAvatar; url has moved ([617714d](https://github.com/ethers-io/ethers.js/commit/617714d19632c7b4789f042ef8357f858421fbae))
|
||||
- Added basic redirect support. ([42784b8](https://github.com/ethers-io/ethers.js/commit/42784b8d38a96170d19ea8adcbc42ebf7415804c))
|
||||
- Added arbitrum and optimism to networks and providers. ([#2335](https://github.com/ethers-io/ethers.js/issues/2335); [0844de4](https://github.com/ethers-io/ethers.js/commit/0844de4eb45eb4170fafb6f2a239b53b6be22f1c))
|
||||
- Added support for data URLs for avatar metadata. ([b8391b0](https://github.com/ethers-io/ethers.js/commit/b8391b0e61bf3627702668920c4fd6506f9bdc60))
|
||||
- Fixed getAvatar for unconfigured ENS names. ([1e1c93e](https://github.com/ethers-io/ethers.js/commit/1e1c93effa083765be52f3dee10400a9b3eeb003))
|
||||
|
||||
ethers/v5.5.1 (2021-10-20 03:59)
|
||||
--------------------------------
|
||||
|
||||
- Fixed abstract Provider signature issue. ([#2190](https://github.com/ethers-io/ethers.js/issues/2190); [1bd9161](https://github.com/ethers-io/ethers.js/commit/1bd91615eedcb34a24fca04aa93a9aac394968ed))
|
||||
|
||||
ethers/v5.5.0 (2021-10-19 00:01)
|
||||
--------------------------------
|
||||
|
||||
- Added ENS avatar support to provider. ([#2185](https://github.com/ethers-io/ethers.js/issues/2185); [ecce861](https://github.com/ethers-io/ethers.js/commit/ecce86125d87ef5258406bde2fff5bc8c9ff3141))
|
||||
- Fixed splitSignature logic for verifying EIP-2930 and EIP-1559 v. ([#2084](https://github.com/ethers-io/ethers.js/issues/2084); [3de1b81](https://github.com/ethers-io/ethers.js/commit/3de1b815014b10d223a42e524fe9c25f9087293b))
|
||||
- Include events on ContractFactory deployment transactions. ([#1334](https://github.com/ethers-io/ethers.js/issues/1334); [ab319f2](https://github.com/ethers-io/ethers.js/commit/ab319f2f4c365d4cd1b1e17e577ecd18a7a89276))
|
||||
- admin: fixed alias script. ([#1494](https://github.com/ethers-io/ethers.js/issues/1494); [8f3d71d](https://github.com/ethers-io/ethers.js/commit/8f3d71dc5fd0e91407737a4b82c58c31269ed2be))
|
||||
- Better errors when non-string address or ENS name is passed into Contracts or provider methods. ([#1051](https://github.com/ethers-io/ethers.js/issues/1051); [a5c6a46](https://github.com/ethers-io/ethers.js/commit/a5c6a468f4a7ad29fb5277e08c6b8b208383a575))
|
||||
- Use personal_sign instead of eth_sign for message signing with JsonRpcSigner; added _legacySignMessage for legacy support. ([#1542](https://github.com/ethers-io/ethers.js/issues/1542), [#1840](https://github.com/ethers-io/ethers.js/issues/1840); [8947fd4](https://github.com/ethers-io/ethers.js/commit/8947fd405e3aea07f6db958d89a3ad39abe3a25a))
|
||||
- Removed extra wordlists from the dist files. ([#2058](https://github.com/ethers-io/ethers.js/issues/2058), [#2077](https://github.com/ethers-io/ethers.js/issues/2077); [cb43a99](https://github.com/ethers-io/ethers.js/commit/cb43a99405cdc5bdcc875efc1821e00e55447791))
|
||||
- Fix issue when Solidity method collises with JavaScript prototype. ([#1432](https://github.com/ethers-io/ethers.js/issues/1432), [#2054](https://github.com/ethers-io/ethers.js/issues/2054), [#2120](https://github.com/ethers-io/ethers.js/issues/2120); [0a8be37](https://github.com/ethers-io/ethers.js/commit/0a8be37b087470d9354f387d7c439cb0166eaf4d))
|
||||
- Add support for Cloudflare Workers. ([#1886](https://github.com/ethers-io/ethers.js/issues/1886); [6582ede](https://github.com/ethers-io/ethers.js/commit/6582ede1ce46be0b3abafb120e052b95a2d172b3))
|
||||
- Added more information to some invalid argument errors. ([#1130](https://github.com/ethers-io/ethers.js/issues/1130); [f3c6d81](https://github.com/ethers-io/ethers.js/commit/f3c6d819f34b6d93f53d98b9f337ade5aa37a594))
|
||||
- Fix compile-time error in new TypeScript version. ([bee76a4](https://github.com/ethers-io/ethers.js/commit/bee76a49b2e5f95ea2eab49aabf5e44cb4ca794b))
|
||||
- Adding customData support to transactions to assist L2 chains. ([#1761](https://github.com/ethers-io/ethers.js/issues/1761); [68095a4](https://github.com/ethers-io/ethers.js/commit/68095a48ae19ed06cbcf2f415f1fcbda90d4b2ae))
|
||||
- Added some explicit null results to previously implicit null results for ENS. ([#1850](https://github.com/ethers-io/ethers.js/issues/1850); [0e5419e](https://github.com/ethers-io/ethers.js/commit/0e5419ec79cb18d82bab8c47bfa3ab4a21cfd293))
|
||||
- Added BigNumber _difficulty to Block results. ([#2001](https://github.com/ethers-io/ethers.js/issues/2001), [#2036](https://github.com/ethers-io/ethers.js/issues/2036); [a48552a](https://github.com/ethers-io/ethers.js/commit/a48552a4fb85a08178d07437a3934db98b7d0736))
|
||||
- Removed redundant call to normalizing blockTag (1838). ([d5b41ce](https://github.com/ethers-io/ethers.js/commit/d5b41ce210c0f22dd795749810f6ce798f71a00f))
|
||||
- Fixed isBytes check for invalid length or elements. ([#1964](https://github.com/ethers-io/ethers.js/issues/1964); [7a404fb](https://github.com/ethers-io/ethers.js/commit/7a404fb8ed95a99baab8f3b384f438b697fa5d76))
|
||||
- Fixed randomBytes not rejecting NaN as a length. ([#1977](https://github.com/ethers-io/ethers.js/issues/1977); [f8adf82](https://github.com/ethers-io/ethers.js/commit/f8adf82e16aaad1a7c1750e7f2e3a9f8073b73e1))
|
||||
- Allow any Networkish for getDefaultProvider. ([#2031](https://github.com/ethers-io/ethers.js/issues/2031); [cc250b2](https://github.com/ethers-io/ethers.js/commit/cc250b2060451e0ee6b1cf3edb6b005f9eee9c61))
|
||||
- Stop allowing commas in fixed numbers; left over from legacy comma support. ([#2083](https://github.com/ethers-io/ethers.js/issues/2083); [45f3675](https://github.com/ethers-io/ethers.js/commit/45f367512d1d5dccfd06fad9cc8688e4d0cccdb8))
|
||||
- Export FallbackProviderConfig. ([#2121](https://github.com/ethers-io/ethers.js/issues/2121); [48c9e0b](https://github.com/ethers-io/ethers.js/commit/48c9e0bf39eec9b5b30ab7cd5685effdccaa1b1a))
|
||||
|
||||
ethers/v5.4.7 (2021-09-16 13:17)
|
||||
--------------------------------
|
||||
|
||||
- Fix parseUints with excess zeros and fix ReDoS issue. ([#2016](https://github.com/ethers-io/ethers.js/issues/2016), [#1975](https://github.com/ethers-io/ethers.js/issues/1975), [#1976](https://github.com/ethers-io/ethers.js/issues/1976); [32a6b2a](https://github.com/ethers-io/ethers.js/commit/32a6b2a362815eb85ce3f3abad5adf92f2b80e10))
|
||||
|
||||
ethers/v5.4.6 (2021-08-27 15:34)
|
||||
--------------------------------
|
||||
|
||||
- Temporarily remove the block miner for clique-based networks from CI testing. ([#1967](https://github.com/ethers-io/ethers.js/issues/1967); [8320d53](https://github.com/ethers-io/ethers.js/commit/8320d534d78173dfa8ecb4def634a00483a6aa9c))
|
||||
- More readable errors involving Uint8Arrays. ([b6a061e](https://github.com/ethers-io/ethers.js/commit/b6a061e7bfd14c1f2df1418df37f704275908e8b))
|
||||
- Added Deferred Error support to Description objects to extent Interface parse methods. ([#1894](https://github.com/ethers-io/ethers.js/issues/1894); [a662490](https://github.com/ethers-io/ethers.js/commit/a662490e82a9b71b5f6dee0a8242e6fa78409d79))
|
||||
- Fix address coder to prepare non-hexdatastring addresses as hexdatastring. ([#1906](https://github.com/ethers-io/ethers.js/issues/1906); [017b1fe](https://github.com/ethers-io/ethers.js/commit/017b1feba2c9dea88f078b299d211cbd58d43b49))
|
||||
- Removed temporary code for better errors needed until Alchemy added EIP-1559 support. ([#1893](https://github.com/ethers-io/ethers.js/issues/1893); [accb852](https://github.com/ethers-io/ethers.js/commit/accb85268c92fa894e769ec1dca322e117d33e5f))
|
||||
|
||||
ethers/v5.4.5 (2021-08-18 03:05)
|
||||
--------------------------------
|
||||
|
||||
- Fxied getBlockWithTransactions results (#1858). ([78e4273](https://github.com/ethers-io/ethers.js/commit/78e4273a327d12da9a1ec008d3f2146d97385921))
|
||||
|
||||
ethers/v5.4.4 (2021-08-04 01:37)
|
||||
--------------------------------
|
||||
|
||||
- Fixed Etherscan API key in default provider. ([#1807](https://github.com/ethers-io/ethers.js/issues/1807); [1d27d95](https://github.com/ethers-io/ethers.js/commit/1d27d95670ee3a51879393fed44297128c4a42a3))
|
||||
- Adjust default masPriorityFeePerGas to account for MEV-heavy blocks. ([#1817](https://github.com/ethers-io/ethers.js/issues/1817); [7175e2e](https://github.com/ethers-io/ethers.js/commit/7175e2e99c2747e8d2314feb407bf0a0f9371ece))
|
||||
|
||||
ethers/v5.4.3 (2021-07-29 23:26)
|
||||
--------------------------------
|
||||
|
||||
- Fixed JsonRpcProvider for pre-EIP-2930 chains. ([#1766](https://github.com/ethers-io/ethers.js/issues/1766); [7274cd0](https://github.com/ethers-io/ethers.js/commit/7274cd06cf3f6f31c6df3fd6636706d8536b7ee2))
|
||||
- Forward some missing EIP-1559 fields to call and estimateGas. ([#1766](https://github.com/ethers-io/ethers.js/issues/1766); [be3854e](https://github.com/ethers-io/ethers.js/commit/be3854e648fdef0478db8a64c26be6d9e90cf453))
|
||||
- Fixed possible UnhandledPromiseException for bad ENS names. ([63f8b28](https://github.com/ethers-io/ethers.js/commit/63f8b2822318d1e0fcc41f4662feb6e5ae338f3d))
|
||||
- Prevent overriding value for non-payble constructors. ([#1785](https://github.com/ethers-io/ethers.js/issues/1785); [593b488](https://github.com/ethers-io/ethers.js/commit/593b4886ff607d00d656b8131b843933eb48838e))
|
||||
|
||||
ethers/v5.4.2 (2021-07-23 17:22)
|
||||
--------------------------------
|
||||
|
||||
- Fix test case for new transactions responses. ([0aafca7](https://github.com/ethers-io/ethers.js/commit/0aafca71dbc019beb398e1b5a0f24936a4fd215a))
|
||||
- Added matic support to INFURA and Alchemy. ([#1546](https://github.com/ethers-io/ethers.js/issues/1546); [576e9b5](https://github.com/ethers-io/ethers.js/commit/576e9b54abc3ff048113f93f765aa3177bf3b819))
|
||||
- Added string change to coalesce errors on some clients. ([bc5cc2e](https://github.com/ethers-io/ethers.js/commit/bc5cc2e7e34f6cc69c43c1665be9c18854fb26b8))
|
||||
- Added wait to transactions returned by getBlockWithTransactions. ([#971](https://github.com/ethers-io/ethers.js/issues/971); [660e69d](https://github.com/ethers-io/ethers.js/commit/660e69db71d42084b1fe791d864d13f0111f84fb))
|
||||
- Fixed floor, ceiling and round for FixedNumber for non-default Formats. ([#1749](https://github.com/ethers-io/ethers.js/issues/1749); [551cfa0](https://github.com/ethers-io/ethers.js/commit/551cfa0062ec1645c9310335e0e6cbd250bb3788))
|
||||
- Fixed null confirmations in Wallet transaction. ([#1706](https://github.com/ethers-io/ethers.js/issues/1706); [0f0d0c0](https://github.com/ethers-io/ethers.js/commit/0f0d0c00d3fc14e5454169d42a9286b1d8b0abef))
|
||||
- Fixed Etherscan string change and enabled all tests. ([a1f8d18](https://github.com/ethers-io/ethers.js/commit/a1f8d188a7bc0b0d11426b7ef0d018cc1b7b399d))
|
||||
|
||||
ethers/v5.4.1 (2021-07-02 01:47)
|
||||
--------------------------------
|
||||
|
||||
- Added Pocket back into Homestead defaultProvider and skip certain EtherscanProvider tests affected by outage. ([6e8a39e](https://github.com/ethers-io/ethers.js/commit/6e8a39ec35123e681e47807f54ef9b9122635ea0))
|
||||
- Fixed EtherscanProvider NONCE_EXPIRED matching string update. ([ecae793](https://github.com/ethers-io/ethers.js/commit/ecae793edff172a885e5ee014a8ad0b28b68c1e5))
|
||||
- Fixed explicit EIP-1559 keys for JsonRpcSigner. ([72feee8](https://github.com/ethers-io/ethers.js/commit/72feee8f5841febdab0d15f09baa69539d95e199))
|
||||
|
||||
ethers/v5.4.0 (2021-06-26 01:50)
|
||||
--------------------------------
|
||||
|
||||
- Added EIP-1559 support. ([#1610](https://github.com/ethers-io/ethers.js/issues/1610); [319987e](https://github.com/ethers-io/ethers.js/commit/319987ec3e1d0e8787f98f525e5fc07875bf5570), [91fff14](https://github.com/ethers-io/ethers.js/commit/91fff1449df5e337fd3b4681b5a04b151d92f5a1), [c5bca77](https://github.com/ethers-io/ethers.js/commit/c5bca7767e3f3d43e3d0bd3c9e9420321ee9907a), [5456c35](https://github.com/ethers-io/ethers.js/commit/5456c359245d9eef5d2abdc05ccedb5269576c94), [7a12216](https://github.com/ethers-io/ethers.js/commit/7a12216cfbd3f86b917451924957471b8be21a8b), [e95708e](https://github.com/ethers-io/ethers.js/commit/e95708eedc130aeb92820a2234398970a987c507))
|
||||
- Added effectiveGasPrice to receipt. ([ba6854b](https://github.com/ethers-io/ethers.js/commit/ba6854bdd5a912fe873d5da494cb5c62c190adde))
|
||||
- Fixed ENS names for JsonRpcSigner. ([1e31b34](https://github.com/ethers-io/ethers.js/commit/1e31b34a5a3a269867a45b519662db85f0c86654))
|
||||
- Added EIP-2930 and EIP-1559 transaction tests. ([7deb4c1](https://github.com/ethers-io/ethers.js/commit/7deb4c174a30b75f8419b8661829add4e5cb69d6))
|
||||
- Added ConstructorFragment to exports. ([7efc36d](https://github.com/ethers-io/ethers.js/commit/7efc36df294ddd333e37793cad712cbd587bc686))
|
||||
- Added error utilities to Interface. ([720bde7](https://github.com/ethers-io/ethers.js/commit/720bde7719d9a2fbc7e859f8952b7918e7164b87), [f053a7a](https://github.com/ethers-io/ethers.js/commit/f053a7ad58866c8192a64e1e335a2613358385be))
|
||||
- merged master including transaction type 0 legacy constant. ([#1610](https://github.com/ethers-io/ethers.js/issues/1610); [2a7ce0e](https://github.com/ethers-io/ethers.js/commit/2a7ce0e72a1e0c9469e10392b0329e75e341cf18))
|
||||
- Added type to TransactionResponse and TrnsactionReceipt. ([#1687](https://github.com/ethers-io/ethers.js/issues/1687); [d001901](https://github.com/ethers-io/ethers.js/commit/d001901c8c0541c823eb9638b9b309a316b00757))
|
||||
- Trap CALL_EXCEPTION errors when resolving ENS entries. ([#1690](https://github.com/ethers-io/ethers.js/issues/1690); [91951dc](https://github.com/ethers-io/ethers.js/commit/91951dc825af42d4440d2d3b43cfa7a601b20342))
|
||||
- Fixed transaction serialization with explicit null type. ([#1628](https://github.com/ethers-io/ethers.js/issues/1628); [8277f5a](https://github.com/ethers-io/ethers.js/commit/8277f5a62a6739a05ae6682da6956fb490b81e4a))
|
||||
- Fix issue with loading JSON ABI with internalType property. ([#728](https://github.com/ethers-io/ethers.js/issues/728); [e8a0144](https://github.com/ethers-io/ethers.js/commit/e8a0144b7aa95add967578d9629d70bf01fc55cf))
|
||||
|
||||
ethers/v5.3.1 (2021-06-10 18:28)
|
||||
--------------------------------
|
||||
|
||||
- Fixed replacement transaction detection for JsonRpcSigner. ([#1658](https://github.com/ethers-io/ethers.js/issues/1658); [ee82e86](https://github.com/ethers-io/ethers.js/commit/ee82e86ccc439825259d20825a00050217890ad3))
|
||||
- Added Matic testnet info to networks. ([#1546](https://github.com/ethers-io/ethers.js/issues/1546); [376cf3c](https://github.com/ethers-io/ethers.js/commit/376cf3cdbf6d2281331d36c5742414a425927318))
|
||||
- Match Solidity identifier regex. ([#1657](https://github.com/ethers-io/ethers.js/issues/1657); [a6e128f](https://github.com/ethers-io/ethers.js/commit/a6e128f5cc566d291b722cca1734ba41aae6c548))
|
||||
|
||||
ethers/v5.3.0 (2021-05-31 18:41)
|
||||
--------------------------------
|
||||
|
||||
- Added MinInt256 and MaxInt256 constants. ([#1576](https://github.com/ethers-io/ethers.js/issues/1576); [bfcd05f](https://github.com/ethers-io/ethers.js/commit/bfcd05fcbb132d456d6f22f70c8ac9cf5b1826f7))
|
||||
- Version bumps for bn.js and hash.js to match elliptic and fix some build tools. ([#1478](https://github.com/ethers-io/ethers.js/issues/1478); [819b1ac](https://github.com/ethers-io/ethers.js/commit/819b1ace5c9b16e29dc354ad80e0e5b71ac63c52))
|
||||
- Removed Hangul checks in shims which crashes Android. ([#1519](https://github.com/ethers-io/ethers.js/issues/1519); [4b33114](https://github.com/ethers-io/ethers.js/commit/4b331148d980e3056ceaabdcd6e50a2aa1beb40d))
|
||||
- Fixed ENS namehash with leading and trailing dots. ([#1605](https://github.com/ethers-io/ethers.js/issues/1605); [7adcf3b](https://github.com/ethers-io/ethers.js/commit/7adcf3b154669d9d1a0a66d5e15dabfbf6618180))
|
||||
- Fixed broken variable in template string. ([#1624](https://github.com/ethers-io/ethers.js/issues/1624), [#1626](https://github.com/ethers-io/ethers.js/issues/1626); [630656e](https://github.com/ethers-io/ethers.js/commit/630656e949a8ffd940e4b66ec93ec07cd6ec2634))
|
||||
- Fixed FixedNumber rounding for non-default formats. ([#1629](https://github.com/ethers-io/ethers.js/issues/1629); [8681cd5](https://github.com/ethers-io/ethers.js/commit/8681cd59698d02d040871aa889fc6ccc8550df98))
|
||||
- Update ws dependency version to fix security. ([#1633](https://github.com/ethers-io/ethers.js/issues/1633), [#1634](https://github.com/ethers-io/ethers.js/issues/1634); [470551e](https://github.com/ethers-io/ethers.js/commit/470551e4ee3f1e343a26fc0775f9d9f7489129f8))
|
||||
|
||||
ethers/v5.2.0 (2021-05-17 16:18)
|
||||
--------------------------------
|
||||
|
||||
|
||||
41
README.md
41
README.md
@@ -26,10 +26,12 @@ A complete Ethereum wallet implementation and utilities in JavaScript (and TypeS
|
||||
Keep Updated
|
||||
------------
|
||||
|
||||
For the latest news and advisories, please follow the [@ethersproject](https://twitter.com/ethersproject)
|
||||
on Twitter (low-traffic, non-marketing, important information only) as well as watch this GitHub project.
|
||||
For the latest news and advisories, please follow the
|
||||
[@ethersproject](https://twitter.com/ethersproject) on Twitter (low-traffic,
|
||||
non-marketing, important information only) as well as watch this GitHub project.
|
||||
|
||||
For the latest changes, see the [CHANGELOG](https://github.com/ethers-io/ethers.js/blob/master/CHANGELOG.md).
|
||||
For the latest changes, see the
|
||||
[CHANGELOG](https://github.com/ethers-io/ethers.js/blob/master/CHANGELOG.md).
|
||||
|
||||
|
||||
Installing
|
||||
@@ -44,7 +46,7 @@ Installing
|
||||
**browser (UMD)**
|
||||
|
||||
```
|
||||
<script src="https://cdn.ethers.io/lib/ethers-5.1.umd.min.js" type="text/javascript">
|
||||
<script src="https://cdn.ethers.io/lib/ethers-5.6.umd.min.js" type="text/javascript">
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -52,7 +54,7 @@ Installing
|
||||
|
||||
```
|
||||
<script type="module">
|
||||
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.1.esm.min.js";
|
||||
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.6.esm.min.js";
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -66,7 +68,34 @@ Browse the [documentation](https://docs.ethers.io/v5/) online:
|
||||
- [Full API Documentation](https://docs.ethers.io/v5/api/)
|
||||
- [Various Ethereum Articles](https://blog.ricmoo.com/)
|
||||
|
||||
Or browse the entire documentation as a [single page](https://docs.ethers.io/v5/single-page/) to make searching easier.
|
||||
|
||||
Providers
|
||||
---------
|
||||
|
||||
Ethers works closely with an ever-growing list of third-party providers
|
||||
to ensure getting started is quick and easy, by providing default keys
|
||||
to each service.
|
||||
|
||||
These built-in keys mean you can use `ethers.getDefaultProvider()` and
|
||||
start developing right away.
|
||||
|
||||
However, the API keys provided to ethers are also shared and are
|
||||
intentionally throttled to encourage developers to eventually get
|
||||
their own keys, which unlock many other features, such as faster
|
||||
responses, more capacity, analytics and other features like archival
|
||||
data.
|
||||
|
||||
When you are ready to sign up and start using for your own keys, please
|
||||
check out the [Provider API Keys](https://docs.ethers.io/v5/api-keys/) in
|
||||
the documentation.
|
||||
|
||||
A special thanks to these services for providing community resources:
|
||||
|
||||
- [Ankr](https://www.ankr.com/)
|
||||
- [Etherscan](https://etherscan.io/)
|
||||
- [INFURA](https://infura.io/)
|
||||
- [Alchemy](https://dashboard.alchemyapi.io/signup?referral=55a35117-028e-4b7c-9e47-e275ad0acc6d)
|
||||
- [Pocket](https://pokt.network/pocket-gateway-ethereum-mainnet/)
|
||||
|
||||
|
||||
Ancillary Packages
|
||||
|
||||
@@ -25,7 +25,7 @@ free tier, which (depending on the service) includes many advantages:
|
||||
- useful **metric tracking** for performance tuning and to analyze your customer behaviour
|
||||
- more **advanced APIs**, such as archive data or advanced log queries
|
||||
|
||||
_subsection: Etherscan @<api-keys--etherscan>
|
||||
_subsection: Etherscan @NOTE<(see the [[EtherscanProvider]])> @<api-keys--etherscan>
|
||||
|
||||
Etherscan is an Ethereum block explorer, which is possibly the most useful
|
||||
developer tool for building and debugging Ethereum applications.
|
||||
@@ -40,13 +40,17 @@ operations required to interact with the Ethereum Blockchain.
|
||||
- higher rate limit (since you are not using the [shared rate limit](link-etherscan-ratelimit))
|
||||
- customer usage metrics
|
||||
|
||||
_subsection: INFURA @<api-keys--infura>
|
||||
_definition: **Networks:**
|
||||
``homestead``, ``ropsten``, ``rinkeby``, ``goerli`` and ``kovan``.
|
||||
|
||||
|
||||
_subsection: INFURA @NOTE<(see the [[InfuraProvider]])> @<api-keys--infura>
|
||||
|
||||
The INFURA service has been around for quite some time and is very robust
|
||||
and reliable and highly recommended.
|
||||
|
||||
They offer a standard JSON-RPC interface and a WebSocket interface, which makes
|
||||
interaction with standard tools versatile, simple and straight forward.
|
||||
interaction with standard tools versatile, simple and straightforward.
|
||||
|
||||
[Sign up for a free Project ID on INFURA](link-infura-signup)
|
||||
|
||||
@@ -56,7 +60,13 @@ interaction with standard tools versatile, simple and straight forward.
|
||||
- customer usage metrics
|
||||
- access to archive data (requires paid upgrade)
|
||||
|
||||
_subsection: Alchemy @<api-keys--alchemy>
|
||||
_definition: **Networks:**
|
||||
``homestead``, ``ropsten``, ``rinkeby``, ``goerli``, ``kovan``, ``matic``,
|
||||
``maticmum``, ``optimism``, ``optimism-kovan``, ``arbitrum`` and
|
||||
``arbitrum-rinkeby``.
|
||||
|
||||
|
||||
_subsection: Alchemy @NOTE<(see the [[AlchemyProvider]])> @<api-keys--alchemy>
|
||||
|
||||
The Alchemy service has been around a few years and is also very robust
|
||||
and reliable.
|
||||
@@ -74,9 +84,17 @@ with debugging.
|
||||
- access to advanced token balance and metadata APIs
|
||||
- access to advanced debugging trace and revert reason APIs
|
||||
|
||||
_subsection: Pocket Gateway@<api-keys--pocket-gateway>
|
||||
_definition: **Networks:**
|
||||
``homestead``, ``ropsten``, ``rinkeby``, ``goerli``, ``kovan``, ``matic``,
|
||||
``maticmum``, ``optimism``, ``optimism-kovan``, ``arbitrum`` and
|
||||
``arbitrum-rinkeby``.
|
||||
|
||||
|
||||
_subsection: Pocket Gateway @NOTE<(see the [[PocketProvider]])> @<api-keys--pocket-gateway>
|
||||
|
||||
They offer a standard JSON-RPC interface using either a load-balanced
|
||||
network or non-load-balanced fleet.
|
||||
|
||||
[Sign up for a free API key on Pocket](link-pocket-signup)
|
||||
|
||||
**Benefits:**
|
||||
@@ -86,6 +104,26 @@ _subsection: Pocket Gateway@<api-keys--pocket-gateway>
|
||||
- Stake as opposed to paying a monthly fee
|
||||
- Highly redundant global set of nodes incentivized by cryptoeconomic incentives
|
||||
|
||||
_definition: **Networks:**
|
||||
``homestead``
|
||||
|
||||
|
||||
_subsection: Ankr @NOTE<(see the [[AnkrProvider]])> @<api-keys--ankr>
|
||||
|
||||
They offer a standard JSON-RPC interface and have fairly high capacity without
|
||||
the need for an API key early on in the development cycle.
|
||||
|
||||
[See their free tier features on Ankr](link-ankr-public)
|
||||
|
||||
**Benefits:**
|
||||
|
||||
- higher rate limit
|
||||
- customer usage metrics
|
||||
- access to archive data (requires paid upgrade)
|
||||
|
||||
_definition: **Networks:**
|
||||
``homestead``, ``matic`` and ``arbitrum``
|
||||
|
||||
|
||||
_subsection: Creating a Default Provider @<api-keys--getDefaultProvider>
|
||||
|
||||
@@ -100,6 +138,8 @@ using the default API key for that service.
|
||||
It is **highly recommended** that you provide an API for each service, to
|
||||
maximize your applications performance.
|
||||
|
||||
If the API key ``"-"`` is used, the corresponding Provider will be omitted.
|
||||
|
||||
_code: Passing API Keys into getDefaultProvider @lang<script>
|
||||
|
||||
// Use the mainnet
|
||||
@@ -122,5 +162,6 @@ const provider = ethers.getDefaultProvider(network, {
|
||||
// pocket: {
|
||||
// applicationId: ,
|
||||
// applicationSecretKey:
|
||||
// }
|
||||
// },
|
||||
ankr: YOUR_ANKR_API_KEY
|
||||
});
|
||||
|
||||
34
docs.wrm/api/contract/MyToken.sol
Normal file
34
docs.wrm/api/contract/MyToken.sol
Normal file
@@ -0,0 +1,34 @@
|
||||
// Do not use this; it is only for an example in the docs
|
||||
|
||||
contract MyToken {
|
||||
event Transfer(address indexed from, address indexed to, uint amount);
|
||||
|
||||
mapping (address => uint256) _balances;
|
||||
|
||||
constructor(uint256 totalSupply) {
|
||||
emit Transfer(address(0), msg.sender, totalSupply);
|
||||
_balances[msg.sender] = totalSupply;
|
||||
}
|
||||
|
||||
// Read-Only Functions
|
||||
function balanceOf(address owner) public view returns (uint256) {
|
||||
return _balances[owner];
|
||||
}
|
||||
|
||||
function decimals() public pure returns (uint8) {
|
||||
return 18;
|
||||
}
|
||||
|
||||
function symbol() public pure returns (string memory) {
|
||||
return "MyToken";
|
||||
}
|
||||
|
||||
// Authenticated Functions
|
||||
function transfer(address to, uint amount) public returns (bool) {
|
||||
require(_balances[msg.sender] >= amount, "insufficient token balance");
|
||||
_balances[msg.sender] -= amount;
|
||||
_balances[to] += amount;
|
||||
emit Transfer(msg.sender, to, amount);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ Consumes the output of the Solidity compiler, extracting the ABI
|
||||
and bytecode from it, allowing for the various formats the solc
|
||||
compiler has emitted over its life.
|
||||
|
||||
_property: contractFactory.connect(signer) => [[Contract]] @<ContractFactory-connect>
|
||||
_property: contractFactory.connect(signer) => [[ContractFactory]] @<ContractFactory-connect>
|
||||
|
||||
Returns a **new instance** of the ContractFactory with the same //interface//
|
||||
and //bytecode//, but with a different //signer//.
|
||||
@@ -78,12 +78,9 @@ override the endowment ``value``, transaction ``nonce``, ``gasLimit`` or
|
||||
|
||||
_code: Deploying a Contract @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const signer = localSigner;
|
||||
const ContractFactory = ethers.ContractFactory;
|
||||
const bytecode = "608060405234801561001057600080fd5b5060405161012e38038061012e8339818101604052604081101561003357600080fd5b81019080805190602001909291908051906020019092919050505081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060008190555050506088806100a66000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633fa4f24514602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000805490509056fea2646970667358221220926465385af0e8706644e1ff3db7161af699dc063beaadd55405f2ccd6478d7564736f6c63430007040033";
|
||||
// </hide>
|
||||
|
||||
//_hide: const signer = localSigner;
|
||||
//_hide: const ContractFactory = ethers.ContractFactory;
|
||||
//_hide: const bytecode = "608060405234801561001057600080fd5b5060405161012e38038061012e8339818101604052604081101561003357600080fd5b81019080805190602001909291908051906020019092919050505081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060008190555050506088806100a66000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633fa4f24514602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000805490509056fea2646970667358221220926465385af0e8706644e1ff3db7161af699dc063beaadd55405f2ccd6478d7564736f6c63430007040033";
|
||||
|
||||
// If your contract constructor requires parameters, the ABI
|
||||
// must include the constructor
|
||||
@@ -97,25 +94,26 @@ factory = new ContractFactory(abi, bytecode, signer)
|
||||
|
||||
// Deploy an instance of the contract
|
||||
contract = await factory.deploy("ricmoo.eth", 42);
|
||||
//<hide>
|
||||
//! async contract
|
||||
//</hide>
|
||||
|
||||
// The address is available immediately, but the contract
|
||||
// is NOT deployed yet
|
||||
//_result:
|
||||
contract.address
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// The transaction that the signer sent to deploy
|
||||
//_result:
|
||||
contract.deployTransaction
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Wait until the transaction is mined (i.e. contract is deployed)
|
||||
// - returns the receipt
|
||||
// - throws on failure (the reciept is on the error)
|
||||
contract.deployTransaction.wait()
|
||||
//!
|
||||
//_result:
|
||||
await contract.deployTransaction.wait()
|
||||
//_log:
|
||||
|
||||
// Now the contract is safe to interact with
|
||||
contract.value()
|
||||
//!
|
||||
//_result:
|
||||
await contract.value()
|
||||
//_log:
|
||||
|
||||
@@ -98,11 +98,12 @@ at run-time during the **Contract** constructor.
|
||||
|
||||
_heading: Read-Only Methods (constant) @<Contract--readonly>
|
||||
|
||||
A constant method is read-only and evaluates a small amount of EVM
|
||||
code against the current blockchain state and can be computed by
|
||||
asking a single node, which can return a result. It is therefore
|
||||
free and does not require any ether, but **cannot make changes** to
|
||||
the blockchain state..
|
||||
A constant method (denoted by ``pure`` or ``view`` in Solidity)
|
||||
is read-only and evaluates a small amount of EVM code against the
|
||||
current blockchain state and can be computed by asking a single
|
||||
node, which can return a result. It is therefore free and does
|
||||
not require any ether, but **cannot make changes** to the
|
||||
blockchain state..
|
||||
|
||||
_property: contract.METHOD_NAME(...args [, overrides ]) => Promise<any> @<Contract-functionsCall>
|
||||
The type of the result depends on the ABI. If the method returns a single
|
||||
@@ -111,7 +112,7 @@ be returned with each parameter available positionally and if the parameter
|
||||
is named, it will also be available by its name.
|
||||
|
||||
For values that have a simple meaning in JavaScript, the types are fairly
|
||||
straight forward; strings and booleans are returned as JavaScript strings
|
||||
straightforward; strings and booleans are returned as JavaScript strings
|
||||
and booleans.
|
||||
|
||||
For numbers, if the **type** is in the JavaScript safe range (i.e. less
|
||||
@@ -132,7 +133,7 @@ The //overrides// object for a read-only method may include any of:
|
||||
- ``overrides.from`` - the ``msg.sender`` (or ``CALLER``) to use during the
|
||||
execution of the code
|
||||
- ``overrides.value`` - the ``msg.value`` (or ``CALLVALUE``) to use during the
|
||||
exectuiont of the code
|
||||
execution of the code
|
||||
- ``overrides.gasPrice`` - the price to pay per gas (theoretically); since there
|
||||
is no transaction, there is not going to be any fee charged, but the EVM still
|
||||
requires a value to report to ``tx.gasprice`` (or ``GASPRICE``);
|
||||
|
||||
@@ -1,10 +1,75 @@
|
||||
_section: Example: ERC-20 Contract
|
||||
|
||||
The concept of Meta-Classes is somewhat confusing, so we will go
|
||||
over a short example.
|
||||
|
||||
A meta-class is a class which is defined at run-time. A Contract
|
||||
is specified by an //Application Binary Interface// (ABI), which describes
|
||||
the methods and events it has. This description is passed the the
|
||||
[[Contract]] object at run-time, and it creates a new Class, adding
|
||||
all the methods defined in the ABI at run-time.
|
||||
|
||||
_subsection: Deploying a Contract
|
||||
|
||||
Most often, any contract you will need to interact with will already
|
||||
be deployed to the blockchain, but for this example will will first
|
||||
deploy the contract.
|
||||
|
||||
_property: new ethers.ContractFactory(abi, bytecode, signer)
|
||||
Create a new [[ContractFactory]] which can deploy a contract to the
|
||||
blockchain.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const signer = localSigner;
|
||||
//_hide: const parseUnits = utils.parseUnits;
|
||||
|
||||
const bytecode = "0x608060405234801561001057600080fd5b506040516103bc3803806103bc83398101604081905261002f9161007c565b60405181815233906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a333600090815260208190526040902055610094565b60006020828403121561008d578081fd5b5051919050565b610319806100a36000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063313ce5671461005157806370a082311461006557806395d89b411461009c578063a9059cbb146100c5575b600080fd5b604051601281526020015b60405180910390f35b61008e610073366004610201565b6001600160a01b031660009081526020819052604090205490565b60405190815260200161005c565b604080518082018252600781526626bcaa37b5b2b760c91b6020820152905161005c919061024b565b6100d86100d3366004610222565b6100e8565b604051901515815260200161005c565b3360009081526020819052604081205482111561014b5760405162461bcd60e51b815260206004820152601a60248201527f696e73756666696369656e7420746f6b656e2062616c616e6365000000000000604482015260640160405180910390fd5b336000908152602081905260408120805484929061016a9084906102b6565b90915550506001600160a01b0383166000908152602081905260408120805484929061019790849061029e565b90915550506040518281526001600160a01b0384169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350600192915050565b80356001600160a01b03811681146101fc57600080fd5b919050565b600060208284031215610212578081fd5b61021b826101e5565b9392505050565b60008060408385031215610234578081fd5b61023d836101e5565b946020939093013593505050565b6000602080835283518082850152825b818110156102775785810183015185820160400152820161025b565b818111156102885783604083870101525b50601f01601f1916929092016040019392505050565b600082198211156102b1576102b16102cd565b500190565b6000828210156102c8576102c86102cd565b500390565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220d80384ce584e101c5b92e4ee9b7871262285070dbcd2d71f99601f0f4fcecd2364736f6c63430008040033";
|
||||
|
||||
// A Human-Readable ABI; we only need to specify relevant fragments,
|
||||
// in the case of deployment this means the constructor
|
||||
const abi = [
|
||||
"constructor(uint totalSupply)"
|
||||
];
|
||||
|
||||
const factory = new ethers.ContractFactory(abi, bytecode, signer)
|
||||
|
||||
// Deploy, setting total supply to 100 tokens (assigned to the deployer)
|
||||
const contract = await factory.deploy(parseUnits("100"));
|
||||
|
||||
// The contract is not currentl live on the network yet, however
|
||||
// its address is ready for us
|
||||
//_result:
|
||||
contract.address
|
||||
//_log:
|
||||
//_hide: _page.address = contract.address;
|
||||
|
||||
// Wait until the contract has been deployed before interacting
|
||||
// with it; returns the receipt for the deployemnt transaction
|
||||
//_result:
|
||||
await contract.deployTransaction.wait();
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Connecting to a Contract
|
||||
|
||||
_code: A simple ERC-20 contract @lang<javascript>
|
||||
_heading: ERC20Contract @INHERIT<[[Contract]]>
|
||||
|
||||
// A Human-Readable ABI; any supported ABI format could be used
|
||||
_property: new ethers.Contract(address, abi, providerOrSigner)
|
||||
Creating a new instance of a Contract connects to an existing
|
||||
contract by specifying its //address// on the blockchain,
|
||||
its //abi// (used to populate the class' methods) a //providerOrSigner//.
|
||||
|
||||
If a [[Provider]] is given, the contract has only read-only access, while
|
||||
a [[Signer]] offers access to state manipulating methods.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const provider = localProvider;
|
||||
//_hide: const signer = localSigner;
|
||||
|
||||
// A Human-Readable ABI; for interacting with the contract, we
|
||||
// must include any fragment we wish to use
|
||||
const abi = [
|
||||
// Read-Only Functions
|
||||
"function balanceOf(address owner) view returns (uint256)",
|
||||
@@ -12,20 +77,15 @@ const abi = [
|
||||
"function symbol() view returns (string)",
|
||||
|
||||
// Authenticated Functions
|
||||
"function transfer(address to, uint amount) returns (boolean)",
|
||||
"function transfer(address to, uint amount) returns (bool)",
|
||||
|
||||
// Events
|
||||
"event Transfer(address indexed from, address indexed to, uint amount)"
|
||||
];
|
||||
|
||||
// This can be an address or an ENS name
|
||||
const address = "dai.tokens.ethers.eth";
|
||||
|
||||
// An example Provider
|
||||
const provider = ethers.getDefaultProvider();
|
||||
|
||||
// An example Signer
|
||||
const signer = ethers.Wallet.createRandom().connect(provider);
|
||||
//_hide: const address = _page.address;
|
||||
//_verbatim: `const address = ${ JSON.stringify(address) };`
|
||||
|
||||
// Read-Only; By connecting to a Provider, allows:
|
||||
// - Any constant function
|
||||
@@ -34,20 +94,13 @@ const signer = ethers.Wallet.createRandom().connect(provider);
|
||||
// - Estimating Gas for non-constant (as an anonymous sender)
|
||||
// - Static Calling non-constant methods (as anonymous sender)
|
||||
const erc20 = new ethers.Contract(address, abi, provider);
|
||||
//_hide: _page.erc20 = erc20;
|
||||
|
||||
// Read-Write; By connecting to a Signer, allows:
|
||||
// - Everything from Read-Only (except as Signer, not anonymous)
|
||||
// - Sending transactions for non-constant functions
|
||||
const erc20_rw = new ethers.Contract(address, abi, signer)
|
||||
|
||||
|
||||
_heading: ERC20Contract @INHERIT<[[Contract]]>
|
||||
|
||||
_property: new ethers.Contract(address, abi, providerOrSigner)
|
||||
See the above code example for creating an Instance which will
|
||||
(in addition to the Contact methods and properties) automatically
|
||||
add the additional properties defined in //abi// to a **Contract**
|
||||
connected to //address// using the //providerOrSigner//.
|
||||
const erc20_rw = new ethers.Contract(address, abi, signer);
|
||||
//_hide: _page.erc20_rw = erc20_rw;
|
||||
|
||||
|
||||
_subsection: Properties @NOTE<(inheritted from [[Contract]])>
|
||||
@@ -101,6 +154,8 @@ _property: Contract.isIndexed(value) => boolean
|
||||
|
||||
_subsection: Events @NOTE<(inheritted from [[Contract]])> @<erc20-events>
|
||||
|
||||
See [Meta-Class Filters](erc20-meta-events) for examples using events.
|
||||
|
||||
_property: erc20.queryFilter(event [ , fromBlockOrBlockHash [ , toBlock ]) => Promise<Array<Event>> @<erc20-queryfilter>
|
||||
Return Events that match the //event//.
|
||||
|
||||
@@ -126,7 +181,7 @@ Unsubscribe all listeners for //event//. If no event is provided,
|
||||
all events are unsubscribed.
|
||||
|
||||
|
||||
_subsection: Meta-Class Methods @NOTE<(added at Runtime)>
|
||||
_subsection: Meta-Class Methods @NOTE<(added at Runtime)> @<erc20-meta-methods>
|
||||
|
||||
Since the Contract is a Meta-Class, the methods available here depend
|
||||
on the ABI which was passed into the **Contract**.
|
||||
@@ -136,12 +191,35 @@ Returns the number of decimal places used by this ERC-20 token. This can be
|
||||
used with [parseUnits](utils-parseUnits) when taking input from the user or
|
||||
[formatUnits](utils-formatunits] when displaying the token amounts in the UI.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const erc20 = _page.erc20;
|
||||
//_result:
|
||||
await erc20.decimals();
|
||||
//_log:
|
||||
|
||||
_property: erc20.balanceOf(owner [, overrides ]) => Promise<[[BigNumber]]>
|
||||
Returns the balance of //owner// for this ERC-20 token.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const signer = localSigner;
|
||||
//_hide: const erc20 = _page.erc20;
|
||||
|
||||
//_result:
|
||||
await erc20.balanceOf(signer.getAddress())
|
||||
//_log:
|
||||
|
||||
_property: erc20.symbol([ overrides ]) => Promise<string>
|
||||
Returns the symbol of the token.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const erc20 = _page.erc20;
|
||||
//_result:
|
||||
await erc20.symbol();
|
||||
//_log:
|
||||
|
||||
_property: erc20_rw.transfer(target, amount [, overrides ]) => Promise<[[providers-TransactionResponse]]>
|
||||
Transfers //amount// tokens to //target// from the current signer.
|
||||
The return value (a boolean) is inaccessible during a write operation
|
||||
@@ -149,20 +227,86 @@ using a transaction. Other techniques (such as events) are required
|
||||
if this value is required. On-chain contracts calling the ``transfer``
|
||||
function have access to this result, which is why it is possible.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const signer = localSigner;
|
||||
//_hide: const erc20_rw = _page.erc20_rw;
|
||||
//_hide: const parseUnits = utils.parseUnits;
|
||||
//_hide: const formatUnits = utils.formatUnits;
|
||||
|
||||
// Before...
|
||||
//_result:
|
||||
formatUnits(await erc20_rw.balanceOf(signer.getAddress()));
|
||||
//_log:
|
||||
|
||||
// Transfer 1.23 tokens to the ENS name "ricmoo.eth"
|
||||
//_result:
|
||||
tx = await erc20_rw.transfer("ricmoo.eth", parseUnits("1.23"));
|
||||
//_log:
|
||||
|
||||
// Wait for the transaction to be mined...
|
||||
//_result:
|
||||
await tx.wait();
|
||||
//_log:
|
||||
|
||||
// After!
|
||||
//_result:
|
||||
formatUnits(await erc20_rw.balanceOf(signer.getAddress()));
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
formatUnits(await erc20_rw.balanceOf("ricmoo.eth"));
|
||||
//_log:
|
||||
|
||||
_property: erc20.callStatic.transfer(target, amount [, overrides ]) => Promise<boolean>
|
||||
Performs a dry-run of transferring //amount// tokens to //target// from
|
||||
the current signer, without actually signing or sending a transaction.
|
||||
|
||||
This can be used to preflight check that a transaction will be successful.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const erc20_rw = _page.erc20_rw;
|
||||
//_hide: const randomWallet = ethers.Wallet.createRandom().connect(erc20_rw.provider);
|
||||
//_hide: const parseUnits = utils.parseUnits;
|
||||
|
||||
// The signer has enough tokens to send, so true is returned
|
||||
//_result:
|
||||
await erc20_rw.callStatic.transfer("ricmoo.eth", parseUnits("1.23"));
|
||||
//_log:
|
||||
|
||||
// A random address does not have enough tokens to
|
||||
// send, in which case the contract throws an error
|
||||
erc20_random = erc20_rw.connect(randomWallet);
|
||||
//_throws:
|
||||
await erc20_random.callStatic.transfer("ricmoo.eth", parseUnits("1.23"));
|
||||
//_log:
|
||||
|
||||
_property: erc20.estimateGas.transfer(target, amount [, overrides ]) => Promise<[[BigNumber]]>
|
||||
Returns an estimate for how many units of gas would be required
|
||||
to transfer //amount// tokens to //target//.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const erc20_rw = _page.erc20_rw;
|
||||
//_hide: const parseUnits = utils.parseUnits;
|
||||
|
||||
//_result:
|
||||
await erc20_rw.estimateGas.transfer("ricmoo.eth", parseUnits("1.23"));
|
||||
//_log:
|
||||
|
||||
_property: erc20.populateTransaction.transfer(target, amount [, overrides ]) => Promise<[UnsignedTx](UnsignedTransaction)>
|
||||
Returns an [[UnsignedTransaction]] which could be signed and submitted
|
||||
to the network to transaction //amount// tokens to //target//.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const erc20_rw = _page.erc20_rw;
|
||||
//_hide: const parseUnits = utils.parseUnits;
|
||||
|
||||
//_result:
|
||||
await erc20_rw.populateTransaction.transfer("ricmoo.eth", parseUnits("1.23"));
|
||||
//_log:
|
||||
|
||||
_note: Note on Estimating and Static Calling
|
||||
|
||||
@@ -173,7 +317,7 @@ blockchain also means there are certain consistency modes that cannot be
|
||||
known until an actual transaction is attempted.
|
||||
|
||||
|
||||
_subsection: Meta-Class Filters @NOTE<(added at Runtime)>
|
||||
_subsection: Meta-Class Filters @NOTE<(added at Runtime)> @<erc20-meta-events>
|
||||
|
||||
Since the Contract is a Meta-Class, the methods available here depend
|
||||
on the ABI which was passed into the **Contract**.
|
||||
@@ -184,3 +328,75 @@ to [subscribe/unsubscribe to events](erc20-events).
|
||||
|
||||
If //fromAddress// is null or not provided, then any from address matches.
|
||||
If //toAddress// is null or not provided, then any to address matches.
|
||||
|
||||
_code: query filter *from* events @lang<javascript>
|
||||
|
||||
//_hide: const signer = localSigner;
|
||||
//_hide: const erc20 = _page.erc20;
|
||||
|
||||
//_result:
|
||||
filterFrom = erc20.filters.Transfer(signer.address);
|
||||
//_log:
|
||||
|
||||
// Search for transfers *from* me in the last 10 blocks
|
||||
//_result:
|
||||
logsFrom = await erc20.queryFilter(filterFrom, -10, "latest");
|
||||
//_log:
|
||||
|
||||
// Note that the args providees the details of the event, each
|
||||
// parameters is available positionally, and since our ABI
|
||||
// included parameter names also by name
|
||||
//_result:
|
||||
logsFrom[0].args
|
||||
//_log:
|
||||
|
||||
//_hide: _page.filterFrom = filterFrom;
|
||||
|
||||
|
||||
_code: query filter with *to* events @lang<javascript>
|
||||
|
||||
//_hide: const signer = localSigner;
|
||||
//_hide: const erc20 = _page.erc20;
|
||||
|
||||
//_result:
|
||||
filterTo = erc20.filters.Transfer(null, signer.address);
|
||||
//_log:
|
||||
|
||||
// Search for transfers *to* me in the last 10 blocks
|
||||
// Note: the contract transferred totalSupply tokens to us
|
||||
// when it was deployed in its constructor
|
||||
//_result:
|
||||
logsTo = await erc20.queryFilter(filterTo, -10, "latest");
|
||||
//_log:
|
||||
|
||||
// Note that the args providees the details of the event, each
|
||||
// parameters is available positionally, and since our ABI
|
||||
// included parameter names also by name
|
||||
//_result:
|
||||
logsTo[0].args
|
||||
//_log:
|
||||
|
||||
//_hide: _page.filterTo = filterTo;
|
||||
|
||||
_code: listen for events @lang<javascript>
|
||||
|
||||
//_hide: const erc20 = _page.erc20;
|
||||
//_hide: const filterFrom = _page.filterFrom;
|
||||
//_hide: const filterTo = _page.filterTo;
|
||||
|
||||
// Listen to incoming events from signer:
|
||||
erc20.on(filterFrom, (from, to, amount, event) => {
|
||||
// The `from` will always be the signer address
|
||||
});
|
||||
|
||||
// Listen to incoming events to signer:
|
||||
erc20.on(filterTo, (from, to, amount, event) => {
|
||||
// The `to` will always be the signer address
|
||||
});
|
||||
|
||||
// Listen to all Transfer events:
|
||||
erc20.on("Transfer", (from, to, amount, event) => {
|
||||
// ...
|
||||
});
|
||||
|
||||
//_hide: erc20.removeAllListeners();
|
||||
|
||||
@@ -5,6 +5,10 @@ to be included in the base library. The API should not be considered
|
||||
stable and does not follow [[link-semver]] versioning, so applications
|
||||
requiring it should specify the //exact version// needed.
|
||||
|
||||
These features are not available in the core ethers package, so to use them
|
||||
you must install the ``@ethersproject/experimental`` package and import them
|
||||
from that.
|
||||
|
||||
_subsection: BrainWallet @<experimental-brainwallet> @INHERIT<[[Wallet]]>
|
||||
|
||||
Ethers removed support for BrainWallets in v4, since they are unsafe and
|
||||
@@ -19,6 +23,14 @@ the generated wallet has a mnemonic.
|
||||
_property: BrainWallet.generateLegacy(username, password [ , progressCallback ]) => [[experimental-brainwallet]]
|
||||
Generate a brain wallet which is compatible with the ethers v3 and earlier.
|
||||
|
||||
_code: Importing @lang<script>
|
||||
|
||||
// Node
|
||||
const { BrainWallet } = require("@ethersproject/experimental");
|
||||
|
||||
// ESM/TypeScript
|
||||
import { BrainWallet } from "@ethersproject/experimental";
|
||||
|
||||
|
||||
_subsection: EIP1193Bridge @<experimental-eip1193bridge> @INHERIT<[[link-npm-events]]>
|
||||
|
||||
@@ -26,6 +38,14 @@ The **EIP1193Bridge** allows a normal Ethers [[Signer]] and [[Provider]] to be
|
||||
exposed in as a standard [EIP-1193 Provider](link-eip-1193), which may be useful
|
||||
when interacting with other libraries.
|
||||
|
||||
_code: Importing @lang<script>
|
||||
|
||||
// Node
|
||||
const { Eip1193Bridge } = require("@ethersproject/experimental");
|
||||
|
||||
// ESM/TypeScript
|
||||
import { Eip1193Bridge } from "@ethersproject/experimental";
|
||||
|
||||
|
||||
_subsection: NonceManager @<experimental-noncemanager> @INHERIT<[[Signer]]>
|
||||
|
||||
@@ -63,3 +83,11 @@ Bump the current transaction count (nonce) by //count//.
|
||||
|
||||
This may be useful in interacting with the signer outside of using
|
||||
this class.
|
||||
|
||||
_code: Importing @lang<script>
|
||||
|
||||
// Node
|
||||
const { NonceManager } = require("@ethersproject/experimental");
|
||||
|
||||
// ESM/TypeScript
|
||||
import { NonceManager } from "@ethersproject/experimental";
|
||||
|
||||
@@ -11,7 +11,7 @@ To mitigate these issues, it is recommended you use a
|
||||
[Default Provider](providers-getDefaultProvider).
|
||||
|
||||
|
||||
_subsection: EtherscanProvider @<EtherscanProvider> @inherit<[[Provider]]> @src<providers:class.EtherscanProvider>
|
||||
_subsection: EtherscanProvider @<EtherscanProvider> @inherit<[[BaseProvider]]> @src<providers:class.EtherscanProvider>
|
||||
|
||||
The **EtherscanProvider** is backed by a combination of the various
|
||||
[Etherscan APIs](link-etherscan-api).
|
||||
@@ -39,18 +39,16 @@ It is highly recommended for production, you register with
|
||||
|
||||
_definition: **Supported Networks**
|
||||
|
||||
- Homestead (Mainnet)
|
||||
- Ropsten (proof-of-work testnet)
|
||||
- Rinkeby (proof-of-authority testnet)
|
||||
- Görli (clique testnet)
|
||||
- Kovan (proof-of-authority testnet)
|
||||
- ``homestead`` - Homestead (Mainnet)
|
||||
- ``ropsten`` - Ropsten (proof-of-work testnet)
|
||||
- ``rinkeby`` - Rinkeby (proof-of-authority testnet)
|
||||
- ``goerli`` - Görli (clique testnet)
|
||||
- ``kovan`` - Kovan (proof-of-authority testnet)
|
||||
|
||||
_code: Etherscan Examples @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const EtherscanProvider = ethers.providers.EtherscanProvider;
|
||||
const apiKey = "...";
|
||||
// </hide>
|
||||
//_hide: const EtherscanProvider = ethers.providers.EtherscanProvider;
|
||||
//_hide: const apiKey = "...";
|
||||
|
||||
// Connect to mainnet (homestead)
|
||||
provider = new EtherscanProvider();
|
||||
@@ -59,12 +57,9 @@ provider = new EtherscanProvider();
|
||||
provider = new EtherscanProvider("rinkeby");
|
||||
provider = new EtherscanProvider(4);
|
||||
|
||||
const network = ethers.providers.getNetwork("rinkeby");
|
||||
// <hide>
|
||||
delete network._defaultProvider;
|
||||
network
|
||||
// </hide>
|
||||
//!
|
||||
network = ethers.providers.getNetwork("rinkeby");
|
||||
//_hide: delete network._defaultProvider;
|
||||
//_log: network
|
||||
|
||||
provider = new EtherscanProvider(network);
|
||||
|
||||
@@ -111,19 +106,23 @@ It is highly recommended for production, you register with
|
||||
|
||||
_definition: **Supported Networks**
|
||||
|
||||
- Homestead (Mainnet)
|
||||
- Ropsten (proof-of-work testnet)
|
||||
- Rinkeby (proof-of-authority testnet)
|
||||
- Görli (clique testnet)
|
||||
- Kovan (proof-of-authority testnet)
|
||||
- ``homestead`` - Homestead (Mainnet)
|
||||
- ``ropsten`` - Ropsten (proof-of-work testnet)
|
||||
- ``rinkeby`` - Rinkeby (proof-of-authority testnet)
|
||||
- ``goerli`` - Görli (clique testnet)
|
||||
- ``kovan`` - Kovan (proof-of-authority testnet)
|
||||
- ``matic`` - Polygon
|
||||
- ``maticmum`` - Polygon Mumbai Testnet
|
||||
- ``optimism`` - Optimism (L2; optimistic roll-up)
|
||||
- ``optimism-kovan`` - Optimism Testnet (L2; optimistic roll-up testnet)
|
||||
- ``arbitrum`` - Arbitrum (L2; optimistic roll-up)
|
||||
- ``arbitrum-rinkeby`` - Arbitrum Testnet (L2; optimistic roll-up testnet)
|
||||
|
||||
_code: INFURA Examples @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const InfuraProvider = ethers.providers.InfuraProvider;
|
||||
const projectId = "...";
|
||||
const projectSecret = "...";
|
||||
// </hide>
|
||||
//_hide: const InfuraProvider = ethers.providers.InfuraProvider;
|
||||
//_hide: const projectId = "...";
|
||||
//_hide: const projectSecret = "...";
|
||||
|
||||
// Connect to mainnet (homestead)
|
||||
provider = new InfuraProvider();
|
||||
@@ -144,9 +143,7 @@ provider = new InfuraProvider("homestead", {
|
||||
|
||||
// Connect to the INFURA WebSocket endpoints with a WebSocketProvider
|
||||
provider = InfuraProvider.getWebSocketProvider()
|
||||
// <hide>
|
||||
provider.destroy();
|
||||
// </hide>
|
||||
//_hide: await provider.destroy();
|
||||
|
||||
|
||||
_subsection: AlchemyProvider @<AlchemyProvider> @inherit<[[UrlJsonRpcProvider]]> @src<providers:class.AlchemyProvider>
|
||||
@@ -170,18 +167,22 @@ It is highly recommended for production, you register with
|
||||
|
||||
_definition: **Supported Networks**
|
||||
|
||||
- Homestead (Mainnet)
|
||||
- Ropsten (proof-of-work testnet)
|
||||
- Rinkeby (proof-of-authority testnet)
|
||||
- Görli (clique testnet)
|
||||
- Kovan (proof-of-authority testnet)
|
||||
- ``homestead`` - Homestead (Mainnet)
|
||||
- ``ropsten`` - Ropsten (proof-of-work testnet)
|
||||
- ``rinkeby`` - Rinkeby (proof-of-authority testnet)
|
||||
- ``goerli`` - Görli (clique testnet)
|
||||
- ``kovan`` - Kovan (proof-of-authority testnet)
|
||||
- ``matic`` - Polygon
|
||||
- ``maticmum`` - Polygon Mumbai Testnet
|
||||
- ``optimism`` - Optimism (L2; optimistic roll-up)
|
||||
- ``optimism-kovan`` - Optimism Testnet (L2; optimistic roll-up testnet)
|
||||
- ``arbitrum`` - Arbitrum (L2; optimistic roll-up)
|
||||
- ``arbitrum-rinkeby`` - Arbitrum Testnet (L2; optimistic roll-up testnet)
|
||||
|
||||
_code: Alchemy Examples @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const AlchemyProvider = ethers.providers.AlchemyProvider;
|
||||
const apiKey = "...";
|
||||
// </hide>
|
||||
//_hide: const AlchemyProvider = ethers.providers.AlchemyProvider;
|
||||
//_hide: const apiKey = "...";
|
||||
|
||||
// Connect to mainnet (homestead)
|
||||
provider = new AlchemyProvider();
|
||||
@@ -196,9 +197,7 @@ provider = new AlchemyProvider("homestead", apiKey);
|
||||
|
||||
// Connect to the Alchemy WebSocket endpoints with a WebSocketProvider
|
||||
provider = AlchemyProvider.getWebSocketProvider()
|
||||
// <hide>
|
||||
provider.destroy();
|
||||
// </hide>
|
||||
//_hide: provider.destroy();
|
||||
|
||||
|
||||
_subsection: CloudflareProvider @<CloudflareProvider> @inherit<[[UrlJsonRpcProvider]]> @src<providers:class.CloudflareProvider>
|
||||
@@ -210,13 +209,106 @@ Create a new **CloudflareProvider** connected to mainnet (i.e. "homestead").
|
||||
|
||||
_definition: **Supported Networks**
|
||||
|
||||
- Homestead (Mainnet)
|
||||
- ``homestead`` - Homestead (Mainnet)
|
||||
|
||||
_code: Cloudflare Examples @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const CloudflareProvider = ethers.providers.CloudflareProvider;
|
||||
// </hide>
|
||||
//_hide: const CloudflareProvider = ethers.providers.CloudflareProvider;
|
||||
|
||||
// Connect to mainnet (homestead)
|
||||
provider = new CloudflareProvider();
|
||||
|
||||
|
||||
_subsection: PocketProvider @<PocketProvider> @inherit<[[UrlJsonRpcProvider]]> @src<providers:class.PocketProvider>
|
||||
|
||||
The **PocketProvider** is backed by [Pocket](link-pocket).
|
||||
|
||||
_property: new ethers.providers.PocketProvider([ network = "homestead", [ apiKey ] ])
|
||||
Create a new **PocketProvider** connected to //network// with
|
||||
the optional //apiKey//.
|
||||
|
||||
The //network// may be specified as a **string** for a common
|
||||
network name, a **number** for a common chain ID or a
|
||||
[Network Object](providers-Network).
|
||||
|
||||
_note: Note: Default API keys
|
||||
If no //apiKey// is provided, a shared API key will be used,
|
||||
which may result in reduced performance and throttled requests.
|
||||
|
||||
It is highly recommended for production, you register with
|
||||
[Pocket](link-pocket) for your own API key.
|
||||
|
||||
_definition: **Supported Networks**
|
||||
|
||||
- ``homestead`` - Homestead (Mainnet)
|
||||
- ``ropsten`` - Ropsten (proof-of-work testnet)
|
||||
- ``rinkeby`` - Rinkeby (proof-of-authority testnet)
|
||||
- ``goerli`` - Görli (clique testnet)
|
||||
|
||||
_code: Pocket Examples @lang<javascript>
|
||||
|
||||
//_hide: const PocketProvider = ethers.providers.PocketProvider;
|
||||
//_hide: const applicationId = "...";
|
||||
//_hide: const applicationSecretKey = "...";
|
||||
//_hide: const loadBalancer = true;
|
||||
|
||||
// Connect to mainnet (homestead)
|
||||
provider = new PocketProvider();
|
||||
|
||||
// Connect to the ropsten testnet
|
||||
// (see EtherscanProvider above for other network examples)
|
||||
provider = new PocketProvider("ropsten");
|
||||
|
||||
// Connect to mainnet with an Application ID (these are equivalent)
|
||||
provider = new PocketProvider(null, applicationId);
|
||||
provider = new PocketProvider("homestead", applicationId);
|
||||
|
||||
// Connect to mainnet with an application ID, application secret
|
||||
// and specify whether to use the load balances
|
||||
provider = new PocketProvider("homestead", {
|
||||
applicationId: applicationId,
|
||||
applicationSecretKey: applicationSecretKey,
|
||||
loadBalancer: loadBalancer // true or false
|
||||
});
|
||||
|
||||
|
||||
_subsection: AnkrProvider @<AnkrProvider> @inherit<[[UrlJsonRpcProvider]]> @src<providers:class.AnkrProvider>
|
||||
|
||||
The **AnkrProvider** is backed by [Ankr](link-ankr).
|
||||
|
||||
_property: new ethers.providers.AnkrProvider([ network = "homestead", [ apiKey ] ])
|
||||
Create a new **AnkrProvider** connected to //network// with
|
||||
the optional //apiKey//.
|
||||
|
||||
The //network// may be specified as a **string** for a common
|
||||
network name, a **number** for a common chain ID or a
|
||||
[Network Object](providers-Network).
|
||||
|
||||
_note: Note: Default API keys
|
||||
If no //apiKey// is provided, a shared API key will be used,
|
||||
which may result in reduced performance and throttled requests.
|
||||
|
||||
It is highly recommended for production, you register with
|
||||
[Ankr](link-ankr) for your own API key.
|
||||
|
||||
_definition: **Supported Networks**
|
||||
|
||||
- ``homestead`` - Homestead (Mainnet)
|
||||
- ``matic`` - Polygon
|
||||
- ``arbitrum`` - Arbitrum (L2; optimistic roll-up)
|
||||
|
||||
_code: Ankr Examples @lang<javascript>
|
||||
|
||||
//_hide: const AnkrProvider = ethers.providers.AnkrProvider;
|
||||
//_hide: const apiKey = "...";
|
||||
|
||||
// Connect to mainnet (homestead)
|
||||
provider = new AnkrProvider();
|
||||
|
||||
// Connect to polygont
|
||||
// (see EtherscanProvider above for other network examples)
|
||||
provider = new AnkrProvider("matic");
|
||||
|
||||
// Connect to mainnet with an API Key (these are equivalent)
|
||||
provider = new AnkrProvider(null, apiKey);
|
||||
provider = new AnkrProvider("homestead", apiKey);
|
||||
|
||||
@@ -77,9 +77,33 @@ _subsection: Networks
|
||||
There are several official common Ethereum networks as well as custom
|
||||
networks and other compatible projects.
|
||||
|
||||
Any API that accept a [[providers-Networkish]] can be passed a common name (such as
|
||||
``"mainnet"`` or ``"ropsten"``) to use that network definition or may specify
|
||||
custom parameters.
|
||||
Any API that accept a [[providers-Networkish]] can be passed a common
|
||||
name (such as ``"mainnet"`` or ``"ropsten"``) or chain ID to use that
|
||||
network definition or may specify custom parameters.
|
||||
|
||||
_property: ethers.providers.getNetwork(aNetworkish) => [[providers-Network]]
|
||||
|
||||
Returns the full [[providers-Network]] for the given standard
|
||||
//aNetworkish// [[providers-Networkish]].
|
||||
|
||||
This is useful for functions and classes which wish to accept [[providers-Networkish]]
|
||||
as an input parameter.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const getNetwork = ethers.providers.getNetwork;
|
||||
|
||||
// By Chain Name
|
||||
//_result:
|
||||
getNetwork("homestead");
|
||||
//_hide: delete _._defaultProvider;
|
||||
//_log:
|
||||
|
||||
// By Chain ID
|
||||
//_result:
|
||||
getNetwork(1);
|
||||
//_hide: delete _._defaultProvider;
|
||||
//_log:
|
||||
|
||||
_heading: Custom ENS Contract
|
||||
|
||||
@@ -92,10 +116,11 @@ _code: Example: Override the ENS registry @lang<script>
|
||||
|
||||
const network = {
|
||||
name: "dev",
|
||||
chianId: 1337,
|
||||
chainId: 1337,
|
||||
ensAddress: customEnsAddress
|
||||
};
|
||||
|
||||
|
||||
_subsection: Provider Documentation
|
||||
|
||||
_toc:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
_section: JsonRpcProvider @<JsonRpcProvider> @INHERIT<[[Provider]]> @SRC<providers:class.JsonRpcProvider>
|
||||
_section: JsonRpcProvider @<JsonRpcProvider> @INHERIT<[[BaseProvider]]> @SRC<providers:class.JsonRpcProvider>
|
||||
|
||||
The [JSON-RPC API](link-jsonrpc) is a popular method for interacting
|
||||
with Ethereum and is available in all major Ethereum node implementations
|
||||
@@ -11,7 +11,7 @@ connected to the //networkish// network.
|
||||
|
||||
If //urlOrConnectionInfo// is not specified, the default (i.e. ``http:/\/localhost:8545``)
|
||||
is used and if no network is specified, it will be determined automatically by querying the
|
||||
node using ``eth_chaindId`` and falling back on ``eth_networkId``.
|
||||
node using ``eth_chainId`` and falling back on ``eth_networkId``.
|
||||
|
||||
_note: Note: Connecting to a Local Node
|
||||
Each node implementation is slightly different and may require specific
|
||||
@@ -19,6 +19,9 @@ command-line flags, configuration or settings in their UI to enable
|
||||
JSON-RPC, unlock accounts or expose specific APIs. Please consult
|
||||
their documentation.
|
||||
|
||||
_property: jsonRpcProvider.connection => [[ConnectionInfo]]
|
||||
The fully formed [[ConnectionInfo]] the Provider is connected to.
|
||||
|
||||
_property: jsonRpcProvider.getSigner([ addressOrIndex ]) => [[JsonRpcSigner]] @<JsonRpcProvider-getSigner> @SRC<providers/json-rpc-provider>
|
||||
Returns a [[JsonRpcSigner]] which is managed by this Ethereum node, at
|
||||
//addressOrIndex//. If no //addressOrIndex// is provided, the first
|
||||
@@ -26,7 +29,7 @@ account (account #0) is used.
|
||||
|
||||
_property: jsonRpcProvider.getUncheckedSigner([ addressOrIndex ]) => [[UncheckedJsonRpcSigner]] @<JsonRpcProvider-getUncheckedSigner> @SRC<providers/json-rpc-provider>
|
||||
|
||||
_property: jsonRpcProvider.listAccounts() => Array<string> @<JsonRpcProvider-listAccounts> @SRC<providers/json-rpc-provider>
|
||||
_property: jsonRpcProvider.listAccounts() => Promise<Array<string>> @<JsonRpcProvider-listAccounts> @SRC<providers/json-rpc-provider>
|
||||
Returns a list of all account addresses managed by this provider.
|
||||
|
||||
_property: jsonRpcProvider.send(method, params) => Promise<any> @<JsonRpcProvider-send> @SRC<providers/json-rpc-provider>
|
||||
@@ -75,6 +78,25 @@ object, with most of the properties set to null, but allows access to the
|
||||
transaction hash quickly, if that is all that is required.
|
||||
|
||||
|
||||
_subsection: StaticJsonRpcProvider @<StaticJsonRpcProvider> @INHERIT<[[JsonRpcProvider]]> @SRC<providers:class.StaticJsonRpcProvider>
|
||||
|
||||
An ethers Provider will execute frequent ``getNetwork`` calls to ensure
|
||||
the network calls and network being communicated with are consistent.
|
||||
|
||||
In the case of a client like MetaMask, this is desired as the network
|
||||
may be changed by the user at any time, in such cases the cost of
|
||||
checking the chainId is local and therefore cheap.
|
||||
|
||||
However, there are also many times where it is known the network cannot
|
||||
change, such as when connecting to an INFURA endpoint, in which case,
|
||||
the **StaticJsonRpcProvider** can be used which will indefinitely cache
|
||||
the chain ID, which can reduce network traffic and reduce round-trip
|
||||
queries for the chain ID.
|
||||
|
||||
This [[Provider]] should **only** be used when it is known the network
|
||||
cannot change.
|
||||
|
||||
|
||||
_subsection: Node-Specific Methods @<JsonRpcProvider--other>
|
||||
|
||||
Many methods are less common or specific to certain Ethereum Node implementations
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
_section: Other Providers
|
||||
|
||||
_subsection: FallbackProvider @<FallbackProvider> @INHERIT<[[Provider]]> @SRC<providers/fallback-provider:class.FallbackProvider>
|
||||
_subsection: FallbackProvider @<FallbackProvider> @INHERIT<[[BaseProvider]]> @SRC<providers/fallback-provider:class.FallbackProvider>
|
||||
|
||||
The **FallbackProvider** is the most advanced [[Provider]] available in
|
||||
ethers.
|
||||
@@ -68,6 +68,18 @@ _property: ipcProvider.path => string
|
||||
The path this [[Provider]] is connected to.
|
||||
|
||||
|
||||
_subsection: JsonRpcBatchProvider @<JsonRpcBatchProvider> @INHERIT<[[JsonRpcProvider]]> @SRC<providers:class.JsonRpcBatchProvider>
|
||||
|
||||
The **JsonRpcBatchProvider** operated identically to any other Provider,
|
||||
except the calls are implicly batched during an event-loop and sent using
|
||||
the JSON-RPC batch protocol to the backend.
|
||||
|
||||
This results in fewer connections and fewer requests, which may result
|
||||
in lower costs or faster responses, depending on your use case.
|
||||
|
||||
Keep in mind some backends may not support batched requests.
|
||||
|
||||
|
||||
_subsection: UrlJsonRpcProvider @<UrlJsonRpcProvider> @INHERIT<[[JsonRpcProvider]]> @SRC<providers:class.UrlJsonRpcProvider>
|
||||
|
||||
This class is intended to be sub-classed and not used directly. It
|
||||
@@ -99,7 +111,7 @@ application to ethers by wrapping an existing Web3-compatible (such as a
|
||||
[Web3WsProvider](link-web3-ws)) and exposing it as an ethers.js [[Provider]]
|
||||
which can then be used with the rest of the library.
|
||||
|
||||
This may also be used to wrap a standard [EIP-1193 Provider](link-eip-1193].
|
||||
This may also be used to wrap a standard [EIP-1193 Provider](link-eip-1193).
|
||||
|
||||
_property: new ethers.providers.Web3Provider(externalProvider [, network ])
|
||||
Create a new **Web3Provider**, which wraps an [EIP-1193 Provider](link-eip-1193) or
|
||||
|
||||
@@ -21,35 +21,41 @@ _subsection: Accounts Methods @<Provider--account-methods>
|
||||
_property: provider.getBalance(address [ , blockTag = latest ]) => Promise<[[BigNumber]]> @<Provider-getBalance> @SRC<providers/base-provider>
|
||||
Returns the balance of //address// as of the //blockTag// block height.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getBalance("ricmoo.eth");
|
||||
//_log:
|
||||
|
||||
_property: provider.getCode(address [ , blockTag = latest ]) => Promise<string<[[DataHexString]]>> @<Provider-getCode> @SRC<providers/base-provider>
|
||||
Returns the contract code of //address// as of the //blockTag// block height. If there is
|
||||
no contract currently deployed, the result is ``0x``.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getCode("registrar.firefly.eth");
|
||||
//_log:
|
||||
|
||||
_property: provider.getStorageAt(addr, pos [ , blockTag = latest ]) => Promise<string<[[DataHexString]]>> @<Provider-getStorageAt> @SRC<providers/base-provider>
|
||||
Returns the ``Bytes32`` value of the position //pos// at address //addr//, as of the //blockTag//.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getStorageAt("registrar.firefly.eth", 0)
|
||||
//_log:
|
||||
|
||||
_property: provider.getTransactionCount(address [ , blockTag = latest ]) => Promise<number> @<Provider-getTransactionCount> @SRC<providers/base-provider>
|
||||
Returns the number of transactions //address// has ever **sent**, as of //blockTag//.
|
||||
This value is required to be the nonce for the next transaction from //address//
|
||||
sent to the network.
|
||||
|
||||
_code: Account Examples @lang<javascript>
|
||||
_code: @lang<javascript>
|
||||
|
||||
// Get the balance for an account...
|
||||
provider.getBalance("ricmoo.firefly.eth");
|
||||
//!
|
||||
|
||||
// Get the code for a contract...
|
||||
provider.getCode("registrar.firefly.eth");
|
||||
//!
|
||||
|
||||
// Get the storage value at position 0...
|
||||
provider.getStorageAt("registrar.firefly.eth", 0)
|
||||
//!
|
||||
|
||||
// Get transaction count of an account...
|
||||
provider.getTransactionCount("ricmoo.firefly.eth");
|
||||
//!
|
||||
//_result:
|
||||
await provider.getTransactionCount("ricmoo.eth");
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Blocks Methods @<Provider--block-methods>
|
||||
@@ -58,17 +64,21 @@ _property: provider.getBlock(block) => Promise<[[providers-Block]]> @<Provider-
|
||||
Get the //block// from the network, where the ``result.transactions`` is a list
|
||||
of transaction hashes.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getBlock(100004)
|
||||
//_log:
|
||||
|
||||
_property: provider.getBlockWithTransactions(block) => Promise<[[providers-BlockWithTransactions]]> @<Provider-getBlockWithTransactions> @SRC<providers/base-provider>
|
||||
Get the //block// from the network, where the ``result.transactions`` is
|
||||
an Array of [[providers-TransactionResponse]] objects.
|
||||
|
||||
_code: Block Examples @lang<javascript>
|
||||
_code: @lang<javascript>
|
||||
|
||||
provider.getBlock(100004)
|
||||
//!
|
||||
|
||||
provider.getBlockWithTransactions(100004)
|
||||
//!
|
||||
//_result:
|
||||
await provider.getBlockWithTransactions(100004)
|
||||
//_log:
|
||||
|
||||
_subsection: Ethereum Naming Service (ENS) Methods @<Provider--ens-methods>
|
||||
|
||||
@@ -86,29 +96,47 @@ reading and debugging much simpler.
|
||||
The provider offers some basic operations to help resolve and
|
||||
work with ENS names.
|
||||
|
||||
_property: provider.getAvatar(name) => Promise<string>
|
||||
Returns the URL for the avatar associated to the ENS name, or null
|
||||
if no avatar was configured.
|
||||
|
||||
_property: provider.getResolver(name) => Promise<[[EnsResolver]]>
|
||||
Returns an EnsResolver instance which can be used to further inquire
|
||||
about specific entries for an ENS name.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: provider = ethers.getDefaultProvider();
|
||||
|
||||
// See below (Resolver) for examples of using this object
|
||||
const resolver = await provider.getResolver("ricmoo.eth");
|
||||
|
||||
//_hide: _page.resolver = resolver;
|
||||
|
||||
_property: provider.lookupAddress(address) => Promise<string> @<Provider-lookupAddress> @SRC<providers/base-provider>
|
||||
Performs a reverse lookup of the //address// in ENS using the
|
||||
//Reverse Registrar//. If the name does not exist, or the
|
||||
forward lookup does not match, ``null`` is returned.
|
||||
|
||||
An ENS name requries additional configuration to setup a reverse
|
||||
record, they are not automatically set up.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.lookupAddress("0x5555763613a12D8F3e73be831DFf8598089d3dCa");
|
||||
//_log:
|
||||
|
||||
_property: provider.resolveName(name) => Promise<string<[Address](address)>> @<Provider-ResolveName> @SRC<providers/base-provider>
|
||||
Looks up the address of //name//. If the name is not owned, or
|
||||
does not have a //Resolver// configured, or the //Resolver// does
|
||||
not have an address configured, ``null`` is returned.
|
||||
|
||||
_code: ENS Examples @lang<javascript>
|
||||
_code: @lang<javascript>
|
||||
|
||||
// Reverse lookup of an ENS by address...
|
||||
provider.lookupAddress("0x6fC21092DA55B392b045eD78F4732bff3C580e2c");
|
||||
//!
|
||||
|
||||
// Lookup an address of an ENS name...
|
||||
provider.resolveName("ricmoo.firefly.eth");
|
||||
//!
|
||||
//_result:
|
||||
await provider.resolveName("ricmoo.eth");
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: EnsResolver @<EnsResolver>
|
||||
@@ -124,12 +152,63 @@ Returns a Promise which resolves to the [[link-eip-2304]] multicoin address
|
||||
stored for the //coinType//. By default an Ethereum [[address]]
|
||||
(``coinType = 60``) will be returned.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const resolver = _page.resolver;
|
||||
|
||||
// By default, looks up the Ethereum address
|
||||
// (this will match provider.resolveName)
|
||||
//_result:
|
||||
await resolver.getAddress();
|
||||
//_log:
|
||||
|
||||
// Specify the coinType for other coin addresses (0 = Bitcoin)
|
||||
//_result:
|
||||
await resolver.getAddress(0);
|
||||
//_log:
|
||||
|
||||
_property: resolver.getAvatar() => Promise<AvatarInfo>
|
||||
Returns an object the provides the URL of the avatar and the
|
||||
linkage representing each stage in the avatar resolution.
|
||||
|
||||
If there is no avatar found (or the owner of any NFT does not
|
||||
match the name owner), null is returned.
|
||||
|
||||
The AvatarInfo has the properties:
|
||||
|
||||
- ``info.linkage`` - An array of info on each step resolving the avatar
|
||||
- ``info.url`` - The URL of the avatar
|
||||
|
||||
_property: resolver.getContentHash() => Promise<string>
|
||||
Returns a Promise which resolves to any stored [[link-eip-1577]] content hash.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const resolver = _page.resolver;
|
||||
|
||||
//_result:
|
||||
await resolver.getContentHash();
|
||||
//_log:
|
||||
|
||||
_property: resolver.getText(key) => Promise<string>
|
||||
Returns a Promise which resolves to any stored [[link-eip-634]] text entry for //key//.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const resolver = _page.resolver;
|
||||
|
||||
//_result:
|
||||
await resolver.getText("email");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
await resolver.getText("url");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
await resolver.getText("com.twitter");
|
||||
//_log:
|
||||
|
||||
_subsection: Logs Methods @<Provider--log-methods>
|
||||
|
||||
_property: provider.getLogs(filter) => Promise<Array<[[providers-Log]]>> @<Provider-getLogs> @SRC<providers/base-provider>
|
||||
@@ -145,12 +224,59 @@ _subsection: Network Status Methods @<Provider--network-methods>
|
||||
_property: provider.getNetwork() => Promise<[[providers-Network]]> @<Provider-getNetwork> @SRC<providers/base-provider:method.BaseProvider.getNetwork>
|
||||
Returns the [[providers-Network]] this Provider is connected to.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getNetwork()
|
||||
//_hide: _ = utils.shallowCopy(_);
|
||||
//_hide: delete _._defaultProvider;
|
||||
//_log:
|
||||
|
||||
_property: provider.getBlockNumber() => Promise<number> @<Provider-getBlockNumber> @SRC<providers/base-provider>
|
||||
Returns the block number (or height) of the most recently mined block.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getBlockNumber()
|
||||
//_log:
|
||||
|
||||
_property: provider.getGasPrice() => Promise<[[BigNumber]]> @<Provider-getGasPrice> @SRC<providers/base-provider>
|
||||
Returns a //best guess// of the [[gas-price]] to use in a transaction.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
// The gas price (in wei)...
|
||||
gasPrice = await provider.getGasPrice()
|
||||
//_log: gasPrice
|
||||
|
||||
// ...often this gas price is easier to understand or
|
||||
// display to the user in gwei
|
||||
//_result:
|
||||
utils.formatUnits(gasPrice, "gwei")
|
||||
//_log:
|
||||
|
||||
_property: provider.getFeeData() => Promise<[[providers-FeeData]]> @<Provider-getFeeData> @SRC<abstract-provider>
|
||||
Returns the current recommended [[providers-FeeData]] to use in a transaction.
|
||||
|
||||
For an EIP-1559 transaction, the ``maxFeePerGas`` and ``maxPriorityFeePerGas``
|
||||
should be used.
|
||||
|
||||
For legacy transactions and networks which do not support EIP-1559, the ``gasPrice``
|
||||
should be used.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
// The gas price (in wei)...
|
||||
feeData = await provider.getFeeData()
|
||||
//_log: feeData
|
||||
|
||||
// ...often these values are easier to understand or
|
||||
// display to the user in gwei
|
||||
//_result:
|
||||
utils.formatUnits(feeData.maxFeePerGas, "gwei")
|
||||
//_log:
|
||||
|
||||
_property: provider.ready => Promise<[[providers-Network]]> @<Provider-ready> @src<providers/base-provider>
|
||||
Returns a Promise which will stall until the network has heen established,
|
||||
ignoring errors due to the target node not being active yet.
|
||||
@@ -158,31 +284,6 @@ ignoring errors due to the target node not being active yet.
|
||||
This can be used for testing or attaching scripts to wait until the node is
|
||||
up and running smoothly.
|
||||
|
||||
_code: Network Status Examples @lang<javascript>
|
||||
|
||||
// The network information
|
||||
provider.getNetwork()
|
||||
// <hide>
|
||||
//!
|
||||
network = utils.shallowCopy(_)
|
||||
delete network._defaultProvider
|
||||
network
|
||||
// </hide>
|
||||
//!
|
||||
|
||||
// The current block number
|
||||
provider.getBlockNumber()
|
||||
//!
|
||||
|
||||
// Get the current suggested gas price (in wei)...
|
||||
gasPrice = await provider.getGasPrice()
|
||||
//! async gasPrice
|
||||
|
||||
// ...often this gas price is easier to understand or
|
||||
// display to the user in gwei (giga-wei, or 1e9 wei)
|
||||
utils.formatUnits(gasPrice, "gwei")
|
||||
//!
|
||||
|
||||
|
||||
_subsection: Transactions Methods @<Provider--transaction-methods>
|
||||
|
||||
@@ -191,6 +292,18 @@ Returns the result of executing the //transaction//, using //call//. A call
|
||||
does not require any ether, but cannot change any state. This is useful
|
||||
for calling getters on Contracts.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.call({
|
||||
// ENS public resolver address
|
||||
to: "0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41",
|
||||
|
||||
// `function addr(namehash("ricmoo.eth")) view returns (address)`
|
||||
data: "0x3b3b57debf074faa138b72c65adbdcfb329847e4f2c04bde7f7dd7fcad5a52d2f395a558"
|
||||
});
|
||||
//_log:
|
||||
|
||||
_property: provider.estimateGas(transaction) => Promise<[[BigNumber]]> @<Provider-estimateGas> @SRC<providers/base-provider>
|
||||
Returns an estimate of the amount of gas that would be required to submit //transaction//
|
||||
to the network.
|
||||
@@ -199,6 +312,23 @@ An estimate may not be accurate since there could be another transaction
|
||||
on the network that was not accounted for, but after being mined affected
|
||||
relevant state.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
//_result:
|
||||
await provider.estimateGas({
|
||||
// Wrapped ETH address
|
||||
to: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
||||
|
||||
// `function deposit() payable`
|
||||
data: "0xd0e30db0",
|
||||
|
||||
// 1 ether
|
||||
value: parseEther("1.0")
|
||||
});
|
||||
//_log:
|
||||
|
||||
_property: provider.getTransaction(hash) => Promise<[[providers-TransactionResponse]]> @<Provider-getTransaction> @src<providers/base-provider>
|
||||
Returns the transaction with //hash// or null if the transaction is unknown.
|
||||
|
||||
@@ -207,6 +337,12 @@ pool. Various backends may have more restrictive transaction pool access (e.g.
|
||||
if the gas price is too low or the transaction was only recently sent and not
|
||||
yet indexed) in which case this method may also return null.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getTransaction("0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0");
|
||||
//_log:
|
||||
|
||||
_property: provider.getTransactionReceipt(hash) => Promise<[[providers-TransactionReceipt]]> @<Provider-getTransactionReceipt> @src<providers/base-provider>
|
||||
Returns the transaction receipt for //hash// or null if the transaction
|
||||
has not been mined.
|
||||
@@ -214,11 +350,34 @@ has not been mined.
|
||||
To stall until the transaction has been mined, consider the ``waitForTransaction``
|
||||
method below.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
await provider.getTransactionReceipt("0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0");
|
||||
//_log:
|
||||
|
||||
_property: provider.sendTransaction(transaction) => Promise<[[providers-TransactionResponse]]> @<Provider-sendTransaction> @SRC<providers/base-provider>
|
||||
Submits //transaction// to the network to be mined. The //transaction// **must** be signed,
|
||||
and be valid (i.e. the nonce is correct and the account has sufficient balance to pay
|
||||
for the transaction).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const provider = localProvider;
|
||||
//_hide: const wallet = new ethers.Wallet(ethers.utils.id("HelloWorld"), provider);
|
||||
//_hide: const fundTx = await localSigner.sendTransaction({
|
||||
//_hide: to: wallet.address,
|
||||
//_hide: value: ethers.utils.parseEther("2.0")
|
||||
//_hide: });
|
||||
//_hide: await fundTx.wait();
|
||||
//_hide: const tx = await localSigner.populateTransaction({ to: "ricmoo.eth", value: ethers.utils.parseEther("3.14159") });
|
||||
//_hide: const signedTx = await localSigner.signTransaction(tx);
|
||||
|
||||
//_verbatim: `const signedTx = ${ JSON.stringify(signedTx) };`
|
||||
//_result:
|
||||
await provider.sendTransaction(signedTx);
|
||||
//_log:
|
||||
|
||||
_property: provider.waitForTransaction(hash [ , confirms = 1 [ , timeout ] ]) => Promise<[TxReceipt](providers-TransactionReceipt)> @<Provider-waitForTransaction> @SRC<providers/base-provider>
|
||||
Returns a Promise which will not resolve until //transactionHash// is mined.
|
||||
|
||||
@@ -331,11 +490,10 @@ $Debug: each Provider may use this to emit useful debugging information
|
||||
|
||||
_code: Events Example @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const txHash = utils.id("dummy-data");
|
||||
const myAddress = ethers.constants.HashZero;
|
||||
const myOtherAddress = ethers.constants.HashZero;
|
||||
// </hide>
|
||||
//_hide: const txHash = utils.id("dummy-data");
|
||||
//_hide: const myAddress = ethers.constants.HashZero;
|
||||
//_hide: const myOtherAddress = ethers.constants.HashZero;
|
||||
//_hide: const hexZeroPad = ethers.utils.hexZeroPad;
|
||||
|
||||
provider.on("block", (blockNumber) => {
|
||||
// Emitted on every block change
|
||||
@@ -367,8 +525,8 @@ topicSets = [
|
||||
utils.id("Transfer(address,address,uint256)"),
|
||||
null,
|
||||
[
|
||||
myAddress,
|
||||
myOtherAddress
|
||||
hexZeroPad(myAddress, 32),
|
||||
hexZeroPad(myOtherAddress, 32)
|
||||
]
|
||||
]
|
||||
provider.on(topicSets, (log, event) => {
|
||||
@@ -385,13 +543,24 @@ provider.on("error", (tx) => {
|
||||
// Emitted when any error occurs
|
||||
});
|
||||
|
||||
// <hide>
|
||||
// Make sure our documentation builds without waiting forever
|
||||
provider.removeAllListeners()
|
||||
// </hide>
|
||||
//_hide: provider.removeAllListeners() /* Make sure the docs build without waiting forever */
|
||||
|
||||
_subsection: Inspection Methods @<Provider--inspection-methods>
|
||||
|
||||
_property: Provider.isProvider(object) => boolean @<Provider-isProvider> @SRC<abstract-provider>
|
||||
Returns true if and only if //object// is a Provider.
|
||||
|
||||
|
||||
_subsection: BaseProvider @<BaseProvider> @INHERIT<[[Provider]]> @SRC<providers:class.BaseProvider>
|
||||
|
||||
Most Providers available in ethers are sub-classes of BaseProvider, which
|
||||
simplifies sub-classes, as it handles much of the event operations, such as
|
||||
polling and formatting.
|
||||
|
||||
_property: provider.polling => boolean
|
||||
Indicates if the Provider is currently polling. If there are no events to
|
||||
poll for or polling has been explicitly disabled, this will be false.
|
||||
|
||||
_property: provider.pollingInterval => number
|
||||
The frequency at which the provider polls.
|
||||
|
||||
|
||||
@@ -34,6 +34,23 @@ _property: network.ensAddress => string<[[address]]>
|
||||
The address at which the ENS registry is deployed on this network.
|
||||
|
||||
|
||||
_subsection: FeeData @<providers-FeeData>
|
||||
|
||||
A **FeeData** object encapsulates the necessary fee data required
|
||||
to send a transaction, based on the best available recommendations.
|
||||
|
||||
_property: feeData.gasPrice => [[BigNumber]]
|
||||
The gasPrice to use for legacy transactions or networks which do not
|
||||
support EIP-1559.
|
||||
|
||||
_property: feeData.maxFeePerGas => [[BigNumber]]
|
||||
The ``maxFeePerGas`` to use for a transaction. This is based on the
|
||||
most recent block's ``baseFee``.
|
||||
|
||||
_property: feeData.maxPriorityFeePerGas => [[BigNumber]]
|
||||
The ``maxPriorityFeePerGas`` to use for a transaction. This accounts
|
||||
for the uncle risk and for the majority of current MEV risk.
|
||||
|
||||
_subsection: Block @<providers-Block>
|
||||
|
||||
_property: block.hash => string<[[DataHexString]]<32>>
|
||||
@@ -56,6 +73,21 @@ This property is generally of little interest to developers.
|
||||
_property: block.difficulty => number
|
||||
The difficulty target required to be met by the miner of the block.
|
||||
|
||||
Recently the difficulty frequently exceeds the size that a JavaScript
|
||||
number can safely store (53-bits), so in that case this property may
|
||||
be null. It is recommended to use the `_difficulty` property below,
|
||||
which will always return a value, but as a [[BigNumber]].
|
||||
|
||||
This property is generally of little interest to developers.
|
||||
|
||||
_property: block._difficulty => [[BigNumber]]
|
||||
The difficulty target required to be met by the miner of the block,
|
||||
as a [[BigNumber]].
|
||||
|
||||
Recently the difficulty frequently exceeds the size that a JavaScript
|
||||
number can safely store (53-bits), so this property was added to
|
||||
safely encode the value for applications that require it.
|
||||
|
||||
This property is generally of little interest to developers.
|
||||
|
||||
_property: block.gasLimit => [[BigNumber]]
|
||||
@@ -183,18 +215,47 @@ _property: transactionRequest.nonce => number | Promise<number>
|
||||
The nonce for this transaction. This should be set to the number of
|
||||
transactions ever sent **from** this address.
|
||||
|
||||
_property: transactionRequest.gasLimit => [[BigNumber]] | Promise<[[BigNumber]]>
|
||||
The maximum amount of gas this transaction is permitted to use.
|
||||
|
||||
_property: transactionRequest.gasPrice => [[BigNumber]] | Promise<[[BigNumber]]>
|
||||
The price (in wei) per unit of gas this transaction will pay.
|
||||
|
||||
_property: transactionRequest.data => [[DataHexString]] | Promise<[[DataHexString]]>
|
||||
The transaction data.
|
||||
|
||||
_property: transactionRequest.value => [[BigNumber]] | Promise<[[BigNumber]]>
|
||||
The amount (in wei) this transaction is sending.
|
||||
|
||||
_property: transactionRequest.gasLimit => [[BigNumber]] | Promise<[[BigNumber]]>
|
||||
The maximum amount of gas this transaction is permitted to use.
|
||||
|
||||
If left unspecified, ethers will use ``estimateGas`` to determine the value
|
||||
to use. For transactions with unpredicatable gas estimates, this may be required
|
||||
to specify explicitly.
|
||||
|
||||
_property: transactionRequest.gasPrice => [[BigNumber]] | Promise<[[BigNumber]]>
|
||||
The price (in wei) per unit of gas this transaction will pay.
|
||||
|
||||
This may not be specified for transactions with ``type`` set to ``1`` or ``2``, or
|
||||
if ``maxFeePerGas`` or ``maxPriorityFeePerGas`` is given.
|
||||
|
||||
_property: transactionRequest.maxFeePerGas => [[BigNumber]] | Promise<[[BigNumber]]>
|
||||
The maximum price (in wei) per unit of gas this transaction will pay for the
|
||||
combined [[link-eip-1559]] block's base fee and this transaction's priority fee.
|
||||
|
||||
Most developers should leave this unspecified and use the default value that
|
||||
ethers determines from the network.
|
||||
|
||||
This may not be specified for transactions with ``type`` set to ``0`` or if ``gasPrice``
|
||||
is specified..
|
||||
|
||||
_property: transactionRequest.maxPriorityFeePerGas => [[BigNumber]] | Promise<[[BigNumber]]>
|
||||
The price (in wei) per unit of gas this transaction will allow in addition to
|
||||
the [[link-eip-1559]] block's base fee to bribe miners into giving this transaction
|
||||
priority. This is **included in** the ``maxFeePerGas``, so this will **not affect**
|
||||
the total maximum cost set with ``maxFeePerGas``.
|
||||
|
||||
Most developers should leave this unspecified and use the default value that
|
||||
ethers determines from the network.
|
||||
|
||||
This may not be specified for transactions with ``type`` set to ``0`` or if ``gasPrice``
|
||||
is specified.
|
||||
|
||||
_property: transactionRequest.chainId => number | Promise<number>
|
||||
The chain ID this transaction is authorized on, as specified by
|
||||
[EIP-155](link-eip-155).
|
||||
@@ -208,12 +269,13 @@ on recent versions of Geth and require configuration to enable.
|
||||
_property: transactionRequest.type => null | number
|
||||
|
||||
The [[link-eip-2718]] type of this transaction envelope, or ``null``
|
||||
for legacy transactions that do not have an envelope.
|
||||
for to use the network default. To force using a lagacy transaction
|
||||
without an envelope, use type ``0``.
|
||||
|
||||
_property: transactionRequest.accessList => [[providers-AccessListish]]
|
||||
|
||||
The [[providers-AccessList]] to include in an [[link-eip-2930]] transaction, which will
|
||||
include a ``type`` of ``1``.
|
||||
The [[providers-AccessList]] to include; only available for [[link-eip-2930]]
|
||||
and [[link-eip-1559]] transactions.
|
||||
|
||||
_heading: TransactionResponse @<providers-TransactionResponse> @INHERIT<[[Transaction]]>
|
||||
|
||||
@@ -237,7 +299,9 @@ The number of blocks that have been mined (including the initial block) since th
|
||||
transaction was mined.
|
||||
|
||||
_property: transaction.raw => string<[[DataHexString]]>
|
||||
The serialized transaction.
|
||||
The serialized transaction. This may be null as some backends do not
|
||||
populate it. If this is required, it can be computed from a **TransactionResponse**
|
||||
object using [this cookbook recipe](cookbook--compute-raw-transaction).
|
||||
|
||||
_property: transaction.wait([ confirms = 1 ]) => Promise<[[providers-TransactionReceipt]]>
|
||||
Resolves to the [[providers-TransactionReceipt]] once the transaction
|
||||
@@ -245,22 +309,35 @@ has been included in the chain for //confirms// blocks. If //confirms//
|
||||
is 0, and the transaction has not been mined, ``null`` is returned.
|
||||
|
||||
If the transaction execution failed (i.e. the receipt status is ``0``),
|
||||
a [CALL_EXCEPTION](errors--call-exception) Error will be rejected with
|
||||
a [CALL_EXCEPTION](errors--call-exception) error will be rejected with
|
||||
the following properties:
|
||||
|
||||
- ``error.transaction`` - the original transaction
|
||||
- ``error.transactionHash`` - the hash of the transaction
|
||||
- ``error.receipt`` - the actual receipt, with the status of ``0``
|
||||
|
||||
_property: transactionRequest.type => null | number
|
||||
If the transaction is replaced by another transaction, a
|
||||
[TRANSACTION_REPLACED](errors--transaction-replaced) error will be rejected
|
||||
with the following properties:
|
||||
|
||||
The [[link-eip-2718]] type of this transaction envelope, or ``null``
|
||||
for legacy transactions that do not have an envelope.
|
||||
- ``error.hash`` - the hash of the original transaction which was replaced
|
||||
- ``error.reason`` - a string reason; one of ``"repriced"``, ``"cancelled"`` or ``"replaced"``
|
||||
- ``error.cancelled`` - a boolean; a ``"repriced"`` transaction is not considered cancelled, but ``"cancelled"`` and ``"replaced"`` are
|
||||
- ``error.replacement`` - the replacement transaction (a [[providers-TransactionResponse]])
|
||||
- ``error.receipt`` - the receipt of the replacement transaction (a [[providers-TransactionReceipt]])
|
||||
|
||||
Transactions are replaced when the user uses an option in their client to
|
||||
send a new transaction from the same account with the original ``nonce``.
|
||||
This is usually to speed up a transaction or to cancel one, by bribing
|
||||
miners with additional fees to prefer the new transaction over the original one.
|
||||
|
||||
_property: transactionRequest.type => number
|
||||
The [[link-eip-2718]] type of this transaction. If the transaction
|
||||
is a legacy transaction without an envelope, it will have the type ``0``.
|
||||
|
||||
_property: transactionRequest.accessList => [[providers-AccessList]]
|
||||
|
||||
The [[providers-AccessList]] included in an [[link-eip-2930]] transaction, which will
|
||||
also have its ``type`` equal to ``1``.
|
||||
The [[providers-AccessList]] included, or null for transaction types which
|
||||
do not support access lists.
|
||||
|
||||
_heading: TransactionReceipt @<providers-TransactionReceipt>
|
||||
|
||||
@@ -284,6 +361,10 @@ _property: receipt.transactionIndex => number
|
||||
The index of this transaction in the list of transactions included in
|
||||
the block this transaction was mined in.
|
||||
|
||||
_property: receipt.type => number
|
||||
The [[link-eip-2718]] type of this transaction. If the transaction
|
||||
is a legacy transaction without an envelope, it will have the type ``0``.
|
||||
|
||||
_property: receipt.root => string
|
||||
The intermediate state root of a receipt.
|
||||
|
||||
@@ -298,6 +379,16 @@ must be considered.
|
||||
_property: receipt.gasUsed => [[BigNumber]]
|
||||
The amount of gas actually used by this transaction.
|
||||
|
||||
_property: receipt.effectiveGasPrice => [[BigNumber]]
|
||||
The effective gas price the transaction was charged at.
|
||||
|
||||
Prior to EIP-1559 or on chains that do not support it, this value will
|
||||
simply be equal to the transaction ``gasPrice``.
|
||||
|
||||
On EIP-1559 chains, this is equal to the block ``baseFee`` for the block
|
||||
that the transaction was included in, plus the transaction
|
||||
``maxPriorityFeePerGas`` clamped to the transaction ``maxFeePerGas``.
|
||||
|
||||
_property: receipt.logsBloom => string<[[DataHexString]]>
|
||||
A [bloom-filter](link-wiki-bloomfilter), which
|
||||
includes all the addresses and topics included in any log in this
|
||||
@@ -331,7 +422,7 @@ _property: receipt.byzantium => boolean
|
||||
This is true if the block is in a [post-Byzantium Hard Fork](link-eip-609)
|
||||
block.
|
||||
|
||||
_property: receipt.status => boolean
|
||||
_property: receipt.status => number
|
||||
The status of a transaction is 1 is successful or 0 if it was
|
||||
reverted. Only transactions included in blocks [post-Byzantium Hard Fork](link-eip-609)
|
||||
have this property.
|
||||
@@ -371,7 +462,8 @@ _code: equivalent to the AccessList example below @lang<javascript>
|
||||
|
||||
// Option 2:
|
||||
// Array< [ Address, Array<Bytes32> ] >
|
||||
[
|
||||
//_hide: ;
|
||||
accessList = [
|
||||
[
|
||||
"0x0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
|
||||
[
|
||||
@@ -385,17 +477,11 @@ _code: equivalent to the AccessList example below @lang<javascript>
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000001"
|
||||
]
|
||||
]
|
||||
]
|
||||
// <hide>
|
||||
;
|
||||
// </hide>
|
||||
];
|
||||
|
||||
// Option 3:
|
||||
// Record<Address, Array<Bytes32>>
|
||||
// <hide>
|
||||
(
|
||||
// </hide>
|
||||
{
|
||||
accessList = {
|
||||
"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e": [
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000004",
|
||||
"0x0bcad17ecf260d6506c6b97768bdc2acfb6694445d27ffd3f9c1cfbee4a9bd6d"
|
||||
@@ -403,10 +489,7 @@ _code: equivalent to the AccessList example below @lang<javascript>
|
||||
"0x5FfC014343cd971B7eb70732021E26C35B744cc4": [
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000001"
|
||||
]
|
||||
}
|
||||
// <hide>
|
||||
)
|
||||
// </hide>
|
||||
};
|
||||
|
||||
|
||||
_heading: AccessList @<providers-AccessList>
|
||||
@@ -427,7 +510,7 @@ _code: example access list
|
||||
// storageKey: Array< DataHexString< 32 > >
|
||||
// }
|
||||
|
||||
[
|
||||
accessList = [
|
||||
{
|
||||
address: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
|
||||
storageKeys: [
|
||||
@@ -441,4 +524,4 @@ _code: example access list
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000001"
|
||||
]
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
@@ -39,7 +39,7 @@ asynchronous source, such as hardware wallets.
|
||||
Sub-classes **must** implement this.
|
||||
|
||||
_property: Signer.isSigner(object) => boolean @<Signer-isSigner> @SRC<abstract-signer>
|
||||
Returns true if an only if //object// is a **Signer**.
|
||||
Returns true if and only if //object// is a **Signer**.
|
||||
|
||||
_heading: Blockchain Methods @<Signer--blockchain-methods>
|
||||
|
||||
@@ -74,6 +74,12 @@ _property: signer.signMessage(message) => Promise<string<[RawSignature](signatur
|
||||
This returns a Promise which resolves to the [[signature-raw]]
|
||||
of //message//.
|
||||
|
||||
A signed message is prefixd with ``"\\x19Ethereum Signed Message:\\n"`` and
|
||||
the length of the message, using the [hashMessage](utils-hashMessage)
|
||||
method, so that it is [EIP-191](link-eip-191) compliant. If recovering
|
||||
the address in Solidity, this prefix will be required to create a matching
|
||||
hash.
|
||||
|
||||
Sub-classes **must** implement this, however they may throw if signing a
|
||||
message is not supported, such as in a Contract-based Wallet or
|
||||
Meta-Transaction-based Wallet.
|
||||
@@ -126,9 +132,7 @@ it has been used in the field a bit.
|
||||
|
||||
_code: Typed Data Example @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
signer = new Wallet("0x1234567890123456789012345678901234567890123456789012345678901234");
|
||||
// </hide>
|
||||
//_hide: signer = new Wallet("0x1234567890123456789012345678901234567890123456789012345678901234");
|
||||
|
||||
// All properties on a domain are optional
|
||||
const domain = {
|
||||
@@ -164,9 +168,9 @@ const value = {
|
||||
contents: 'Hello, Bob!'
|
||||
};
|
||||
|
||||
|
||||
const signature = await signer._signTypedData(domain, types, value);
|
||||
//! async signature
|
||||
//_result:
|
||||
signature = await signer._signTypedData(domain, types, value);
|
||||
//_log:
|
||||
|
||||
|
||||
_heading: Sub-Classes @<Signer--subclassing>
|
||||
@@ -224,7 +228,7 @@ does not have a secure entropy source, an error is thrown.
|
||||
Wallets created using this method will have a mnemonic.
|
||||
|
||||
_property: ethers.Wallet.fromEncryptedJson(json, password [ , progress ]) => Promise<[[Wallet]]> @<Wallet-fromEncryptedJson> @SRC<wallet>
|
||||
Create an instance from an encrypted JSON wallet.
|
||||
Create an instance by decrypting an encrypted JSON wallet.
|
||||
|
||||
If //progress// is provided it will be called during decryption
|
||||
with a value between 0 and 1 indicating the progress towards
|
||||
@@ -281,35 +285,43 @@ walletMnemonic = Wallet.fromMnemonic(mnemonic)
|
||||
// ...or from a private key
|
||||
walletPrivateKey = new Wallet(walletMnemonic.privateKey)
|
||||
|
||||
//_result:
|
||||
walletMnemonic.address === walletPrivateKey.address
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// The address as a Promise per the Signer API
|
||||
walletMnemonic.getAddress()
|
||||
//!
|
||||
//_result:
|
||||
await walletMnemonic.getAddress()
|
||||
//_log:
|
||||
|
||||
// A Wallet address is also available synchronously
|
||||
//_result:
|
||||
walletMnemonic.address
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// The internal cryptographic components
|
||||
//_result:
|
||||
walletMnemonic.privateKey
|
||||
//!
|
||||
//_log:
|
||||
//_result:
|
||||
walletMnemonic.publicKey
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// The wallet mnemonic
|
||||
//_result:
|
||||
walletMnemonic.mnemonic
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Note: A wallet created with a private key does not
|
||||
// have a mnemonic (the derivation prevents it)
|
||||
//_result:
|
||||
walletPrivateKey.mnemonic
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Signing a message
|
||||
walletMnemonic.signMessage("Hello World")
|
||||
//!
|
||||
//_result:
|
||||
await walletMnemonic.signMessage("Hello World")
|
||||
//_log:
|
||||
|
||||
tx = {
|
||||
to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
|
||||
@@ -317,24 +329,29 @@ tx = {
|
||||
}
|
||||
|
||||
// Signing a transaction
|
||||
walletMnemonic.signTransaction(tx)
|
||||
//!
|
||||
//_result:
|
||||
await walletMnemonic.signTransaction(tx)
|
||||
//_log:
|
||||
|
||||
// The connect method returns a new instance of the
|
||||
// Wallet connected to a provider
|
||||
//_result:
|
||||
wallet = walletMnemonic.connect(provider)
|
||||
//_null:
|
||||
|
||||
// Querying the network
|
||||
wallet.getBalance();
|
||||
//!
|
||||
wallet.getTransactionCount();
|
||||
//!
|
||||
//_result:
|
||||
await wallet.getBalance();
|
||||
//_log:
|
||||
//_result:
|
||||
await wallet.getTransactionCount();
|
||||
//_log:
|
||||
|
||||
// Sending ether
|
||||
wallet.sendTransaction(tx)
|
||||
// <hide>
|
||||
//! error
|
||||
// </hide>
|
||||
//_hide: wallet = localSigner; /* prevent insufficient funds error from blowing up the docs */
|
||||
//_result:
|
||||
await wallet.sendTransaction(tx)
|
||||
//_log:
|
||||
|
||||
|
||||
|
||||
@@ -367,12 +384,10 @@ abi = [
|
||||
]
|
||||
contract = new ethers.Contract("dai.tokens.ethers.eth", abi, signer)
|
||||
|
||||
// <hide>
|
||||
//!
|
||||
// </hide>
|
||||
// Get the number of tokens for this account
|
||||
//_result:
|
||||
tokens = await contract.balanceOf(signer.getAddress())
|
||||
//! async tokens
|
||||
//_log:
|
||||
|
||||
//
|
||||
// Pre-flight (check for revert) on DAI from the signer
|
||||
@@ -384,12 +399,14 @@ tokens = await contract.balanceOf(signer.getAddress())
|
||||
//
|
||||
|
||||
// This will pass since the token balance is available
|
||||
contract.callStatic.transfer("donations.ethers.eth", tokens)
|
||||
//!
|
||||
//_result:
|
||||
await contract.callStatic.transfer("donations.ethers.eth", tokens)
|
||||
//_log:
|
||||
|
||||
// This will fail since it is greater than the token balance
|
||||
contract.callStatic.transfer("donations.ethers.eth", tokens.add(1))
|
||||
//! error
|
||||
//_throws:
|
||||
await contract.callStatic.transfer("donations.ethers.eth", tokens.add(1))
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: ExternallyOwnedAccount @<ExternallyOwnedAccount>
|
||||
|
||||
@@ -42,7 +42,78 @@ _property: abiCoder.encode(types, values) => string<[[DataHexString]]> @<AbiCode
|
||||
Encode the array //values// according to the array of //types//, each of which may be a
|
||||
string or a [[ParamType]].
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const abiCoder = utils.defaultAbiCoder;
|
||||
|
||||
// Encoding simple types
|
||||
//_result:
|
||||
abiCoder.encode([ "uint", "string" ], [ 1234, "Hello World" ]);
|
||||
//_log:
|
||||
//_hide: _page.example1 = _;
|
||||
|
||||
// Encoding with arrays types
|
||||
//_result:
|
||||
abiCoder.encode([ "uint[]", "string" ], [ [ 1234, 5678 ] , "Hello World" ]);
|
||||
//_log:
|
||||
//_hide: _page.example2 = _;
|
||||
|
||||
// Encoding complex structs (using positional properties)
|
||||
//_result:
|
||||
abiCoder.encode(
|
||||
[ "uint", "tuple(uint256, string)" ],
|
||||
[
|
||||
1234,
|
||||
[ 5678, "Hello World" ]
|
||||
]
|
||||
);
|
||||
//_log:
|
||||
//_hide: _page.example3 = _;
|
||||
|
||||
// Encoding complex structs (using keyword properties)
|
||||
//_result:
|
||||
abiCoder.encode(
|
||||
[ "uint a", "tuple(uint256 b, string c) d" ],
|
||||
[
|
||||
1234,
|
||||
{ b: 5678, c: "Hello World" }
|
||||
]
|
||||
);
|
||||
//_log:
|
||||
|
||||
_property: abiCoder.decode(types, data) => [[Result]] @<AbiCoder-decode> @SRC<abi/abi-coder>
|
||||
|
||||
Decode the //data// according to the array of //types//, each of which may be a
|
||||
string or [[ParamType]].
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const abiCoder = utils.defaultAbiCoder;
|
||||
|
||||
// Decoding simple types
|
||||
//_hide: data = _page.example1;
|
||||
//_verbatim: `data = ${ JSON.stringify(data) };`
|
||||
//_result:
|
||||
abiCoder.decode([ "uint", "string" ], data);
|
||||
//_log:
|
||||
|
||||
// Decoding with arrays types
|
||||
//_hide: data = _page.example2;
|
||||
//_verbatim: `data = ${ JSON.stringify(data) };`
|
||||
//_result:
|
||||
abiCoder.decode([ "uint[]", "string" ], data);
|
||||
//_log:
|
||||
|
||||
// Decoding complex structs; unnamed parameters allows ONLY
|
||||
// positional access to values
|
||||
//_hide: data = _page.example3;
|
||||
//_verbatim: `data = ${ JSON.stringify(data) };`
|
||||
//_result:
|
||||
abiCoder.decode([ "uint", "tuple(uint256, string)" ], data);
|
||||
//_log:
|
||||
|
||||
// Decoding complex structs; named parameters allows positional
|
||||
// or keyword access to values
|
||||
//_result:
|
||||
abiCoder.decode([ "uint a", "tuple(uint256 b, string c) d" ], data);
|
||||
//_log:
|
||||
|
||||
@@ -1,11 +1,289 @@
|
||||
_section: ABI Formats @<abi-formats>
|
||||
|
||||
@TODO: Expand this section
|
||||
There are several formats available to specify an ABI for
|
||||
a Smart Contract, which specifies to the under-lying library
|
||||
what methods, events and errors exist so that encoding and
|
||||
decoding the data from and to the network can be handled by
|
||||
the library.
|
||||
|
||||
The supports ABI types are:
|
||||
|
||||
- [Human-Readable ABI](abi-formats--human-readable-abi)
|
||||
- [Solidity JSON ABI](abi-formats--solidity)
|
||||
- [Solidity Object ABI](abi-formats--object)
|
||||
|
||||
_subsection: Human-Readable ABI @<abi-formats--human-readable-abi>
|
||||
|
||||
See [Human-Readable Abi](link-ricmoo-humanreadableabi).
|
||||
The **Human-Readable ABI** was [introduced early by ethers](link-ricmoo-humanreadableabi),
|
||||
which allows for a Solidity signatures to be used to describe each
|
||||
method, event and error.
|
||||
|
||||
It is important to note that a Solidity signature **fully describes**
|
||||
all the properties the ABI requires:
|
||||
|
||||
- name
|
||||
- type (constructor, event, function)
|
||||
- inputs (types, nested structures and optionally names)
|
||||
- outputs (types nested structures and optionally names)
|
||||
- state mutability (for constructors and methods)
|
||||
- payability (for constructors and methods)
|
||||
- whether inputs are indexed (for events)
|
||||
|
||||
This allows for a simple format which is both machine-readable (since
|
||||
the parser is a machine) and human-readable (at least **developer-readable**),
|
||||
as well as simple for humans to type and inline into code, which improves
|
||||
code readability. The Human-Readable ABI is also considerably smaller, which
|
||||
helps reduce code size.
|
||||
|
||||
A Human-Readable ABI is simple an array of strings, where each string is
|
||||
the Solidity signature.
|
||||
|
||||
Signatures may be minimally specified (i.e. names of inputs and outputs
|
||||
may be omitted) or fully specified (i.e. with all property names) and
|
||||
whitespace is ignored.
|
||||
|
||||
Several modifiers available in Solidity are dropped internally, as they
|
||||
are not required for the ABI and used old by Solidity's semantic checking
|
||||
system, such as input parameter data location like ``"calldata"``
|
||||
and ``"memory"``. As such, they can be safely dropped in the ABI as well.
|
||||
|
||||
_code: Human-Readable ABI Example @lang<javascript>
|
||||
|
||||
const humanReadableAbi = [
|
||||
|
||||
// Simple types
|
||||
"constructor(string symbol, string name)",
|
||||
"function transferFrom(address from, address to, uint value)",
|
||||
"function balanceOf(address owner) view returns (uint balance)",
|
||||
"event Transfer(address indexed from, address indexed to, address value)",
|
||||
"error InsufficientBalance(account owner, uint balance)",
|
||||
|
||||
// Some examples with the struct type, we use the tuple keyword:
|
||||
// (note: the tuple keyword is optional, simply using additional
|
||||
// parentheses accomplishes the same thing)
|
||||
// struct Person {
|
||||
// string name;
|
||||
// uint16 age;
|
||||
// }
|
||||
"function addPerson(tuple(string name, uint16 age) person)",
|
||||
"function addPeople(tuple(string name, uint16 age)[] person)",
|
||||
"function getPerson(uint id) view returns (tuple(string name, uint16 age))",
|
||||
|
||||
"event PersonAdded(uint indexed id, tuple(string name, uint16 age) person)"
|
||||
];
|
||||
|
||||
//_hide: _page.humanReadableAbi = humanReadableAbi;
|
||||
|
||||
|
||||
_subsection: Solidity JSON ABI @<abi-formats--solidity>
|
||||
|
||||
See [Solidity compiler](link-solc-output).
|
||||
The **Solidity JSON ABI** is a standard format that many tools export,
|
||||
including the Solidity compiler. For the full specification, see
|
||||
the [Solidity compiler documentation](link-solc-output).
|
||||
|
||||
Various versions include slightly different keys and values. For example,
|
||||
early compilers included only a boolean ``"constant"`` to indicate mutability,
|
||||
while newer versions include a string ``"mutabilityState"``, which encompasses
|
||||
several older properties.
|
||||
|
||||
When creating an instance of a [Fragment](Fragment) using a JSON ABI, it will
|
||||
automatically infer all legacy properties for new-age ABIs and for legacy
|
||||
ABIs will infer the new-age properties. All properties will be populated, so
|
||||
it will match the equivalent created using a Human-Readable ABI fragment.
|
||||
|
||||
_code: The same ABI as JSON ABI @lang<javascript>
|
||||
|
||||
const jsonAbi = `[
|
||||
{
|
||||
"type": "constructor",
|
||||
"payable": false,
|
||||
"inputs": [
|
||||
{ "type": "string", "name": "symbol" },
|
||||
{ "type": "string", "name": "name" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "transferFrom",
|
||||
"constant": false,
|
||||
"payable": false,
|
||||
"inputs": [
|
||||
{ "type": "address", "name": "from" },
|
||||
{ "type": "address", "name": "to" },
|
||||
{ "type": "uint256", "name": "value" }
|
||||
],
|
||||
"outputs": [ ]
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "balanceOf",
|
||||
"constant":true,
|
||||
"stateMutability": "view",
|
||||
"payable":false, "inputs": [
|
||||
{ "type": "address", "name": "owner"}
|
||||
],
|
||||
"outputs": [
|
||||
{ "type": "uint256"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "event",
|
||||
"anonymous": false,
|
||||
"name": "Transfer",
|
||||
"inputs": [
|
||||
{ "type": "address", "name": "from", "indexed":true},
|
||||
{ "type": "address", "name": "to", "indexed":true},
|
||||
{ "type": "address", "name": "value"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "error",
|
||||
"name": "InsufficientBalance",
|
||||
"inputs": [
|
||||
{ "type": "account", "name": "owner"},
|
||||
{ "type": "uint256", "name": "balance"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "addPerson",
|
||||
"constant": false,
|
||||
"payable": false,
|
||||
"inputs": [
|
||||
{
|
||||
"type": "tuple",
|
||||
"name": "person",
|
||||
"components": [
|
||||
{ "type": "string", "name": "name" },
|
||||
{ "type": "uint16", "name": "age" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "addPeople",
|
||||
"constant": false,
|
||||
"payable": false,
|
||||
"inputs": [
|
||||
{
|
||||
"type": "tuple[]",
|
||||
"name": "person",
|
||||
"components": [
|
||||
{ "type": "string", "name": "name" },
|
||||
{ "type": "uint16", "name": "age" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"name": "getPerson",
|
||||
"constant": true,
|
||||
"stateMutability": "view",
|
||||
"payable": false,
|
||||
"inputs": [
|
||||
{ "type": "uint256", "name": "id" }
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"type": "tuple",
|
||||
"components": [
|
||||
{ "type": "string", "name": "name" },
|
||||
{ "type": "uint16", "name": "age" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "event",
|
||||
"anonymous": false,
|
||||
"name": "PersonAdded",
|
||||
"inputs": [
|
||||
{ "type": "uint256", "name": "id", "indexed": true },
|
||||
{
|
||||
"type": "tuple",
|
||||
"name": "person",
|
||||
"components": [
|
||||
{ "type": "string", "name": "name", "indexed": false },
|
||||
{ "type": "uint16", "name": "age", "indexed": false }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]`;
|
||||
|
||||
//_hide: _page.jsonAbi = jsonAbi;
|
||||
|
||||
_subsection: Solidity Object ABI @<abi-formats--object>
|
||||
|
||||
The output from parsing (using JSON.parse) a Solidity JSON ABI
|
||||
is also fully compatible with the [[Interface]] class and each
|
||||
method, event and error from that object are compatible with
|
||||
the [[Fragment]] class.
|
||||
|
||||
Some developers may prefer this as it allows access to the ABI
|
||||
properties as normal JavaScript objects, and closely matches the
|
||||
JSON ABI that those familiar with the Solidity ABI will recognize.
|
||||
|
||||
_subsection: Converting Between Formats
|
||||
|
||||
The [[Fragment]] object makes it simple to reformat a single
|
||||
method, event or error, however most developers will be interested
|
||||
in converting an entire ABI.
|
||||
|
||||
For production code it is recommended to inline the Human-Readable
|
||||
ABI as it makes it easy to see at a glance which methods, events
|
||||
and errors are available. It is also highly recommend to strip out
|
||||
unused parts of the ABI (such as admin methods) to further reduce
|
||||
code size.
|
||||
|
||||
_code: Converting to Full Human-Readable ABI @lang<javascript>
|
||||
|
||||
//_hide: const Interface = ethers.utils.Interface;
|
||||
//_hide: const FormatTypes = ethers.utils.FormatTypes;
|
||||
//_hide: jsonAbi = _page.jsonAbi;
|
||||
|
||||
// Using the "full" format will ensure the Result objects
|
||||
// have named properties, which improves code readability
|
||||
const iface = new Interface(jsonAbi);
|
||||
//_result:
|
||||
iface.format(FormatTypes.full);
|
||||
//_log:
|
||||
|
||||
_code: Converting to Minimal Human-Readable ABI @lang<javascript>
|
||||
|
||||
//_hide: const Interface = ethers.utils.Interface;
|
||||
//_hide: const FormatTypes = ethers.utils.FormatTypes;
|
||||
//_hide: jsonAbi = _page.jsonAbi;
|
||||
|
||||
// Using the "minimal" format will save a small amount of
|
||||
// space, but is generally not worth it as named properties
|
||||
// on Results will not be available
|
||||
const iface = new Interface(jsonAbi);
|
||||
//_result:
|
||||
iface.format(FormatTypes.minimal);
|
||||
//_log:
|
||||
|
||||
_code: Converting to JSON ABI @lang<javascript>
|
||||
|
||||
//_hide: const Interface = ethers.utils.Interface;
|
||||
//_hide: const FormatTypes = ethers.utils.FormatTypes;
|
||||
//_hide: humanReadableAbi = _page.humanReadableAbi;
|
||||
|
||||
// Sometimes you may need to export a Human-Readable ABI to
|
||||
// JSON for tools that do not have Human-Readable support
|
||||
|
||||
// For compactness, the JSON is kept with minimal white-space
|
||||
const iface = new Interface(humanReadableAbi);
|
||||
//_result:
|
||||
jsonAbi = iface.format(FormatTypes.json);
|
||||
//_log:
|
||||
|
||||
// However it is easy to use JSON.parse and JSON.stringify
|
||||
// with formatting parameters to assist with readability
|
||||
//_result:
|
||||
JSON.stringify(JSON.parse(jsonAbi), null, 2);
|
||||
//_log:
|
||||
|
||||
@@ -5,7 +5,6 @@ Explain an ABI.
|
||||
_subsection: Formats
|
||||
|
||||
_heading: JSON String ABI (Solidity Output JSON)
|
||||
|
||||
The **JSON ABI Format** is the format that is
|
||||
[output from the Solidity compiler](link-solc-output).
|
||||
|
||||
@@ -15,50 +14,74 @@ of Objects, where each Object has various properties describing the [[Fragment]]
|
||||
The deserialized JSON string (which is a normal JavaScript Object) may
|
||||
also be passed into any function which accepts a JSON String ABI.
|
||||
|
||||
_heading: Humanb-Readable ABI
|
||||
_heading: Humanb-Readable ABI @<human-readable-abi>
|
||||
The Human-Readable ABI was introduced by ethers in [this article](link-ricmoo-humanreadableabi)
|
||||
and has since gained wider adoption.
|
||||
|
||||
The Human-Readable ABI was @TODO
|
||||
The ABI is described by using an array of strings, where each string is the
|
||||
Solidity signature of the **constructor**, **function**, **event** or **error**.
|
||||
|
||||
[article](link-ricmoo-humanreadableabi)
|
||||
When parsing a fragment, all inferred properties will be injected (e.g. a //payable//
|
||||
method will have its ``constant`` proeprty set to false).
|
||||
|
||||
Tuples can be specified by using the ``tuple(...)`` syntax or with bare (additional)
|
||||
parenthesis, ``(...)``.
|
||||
|
||||
_code: Example Human-Readable ABI
|
||||
|
||||
const ABI = [
|
||||
// Constructor
|
||||
"constructor(address ens)",
|
||||
|
||||
// Constant functions (pure or view)
|
||||
"function balanceOf(address owner) view returns (uint)",
|
||||
|
||||
// State-mutating functions (payable or non-payable)
|
||||
"function mint(uint amount) payable",
|
||||
"function transfer(address to, uint amount) returns (bool)",
|
||||
|
||||
// Events
|
||||
"event Transfer(address indexed from, address indexed to, uint amount)",
|
||||
|
||||
// Errors
|
||||
"error InsufficientFunds(address from, uint balance)",
|
||||
]
|
||||
|
||||
|
||||
_heading: Output Formats @<fragments--output-formats> @SRC<abi/fragments:FormatTypes>
|
||||
|
||||
Each [[Fragment]] and [[ParamType]] may be output using its ``format``
|
||||
method.
|
||||
|
||||
_property: ethers.utils.FragmentTypes.full => string
|
||||
|
||||
_property: ethers.utils.FormatTypes.full => string
|
||||
This is a full human-readable string, including all parameter names, any
|
||||
optional modifiers (e.g. ``indexed``, ``public``, etc) and white-space
|
||||
to aid in human readability.
|
||||
|
||||
_property: ethers.utils.FragmentTypes.minimal => string
|
||||
|
||||
_property: ethers.utils.FormatTypes.minimal => string
|
||||
This is similar to ``full``, except with no unnecessary whitespace or parameter
|
||||
names. This is useful for storing a minimal string which can still fully
|
||||
reconstruct the original Fragment using [Fragment . from](Fragment-from).
|
||||
|
||||
_property: ethers.utils.FragmentTypes.json => string
|
||||
|
||||
_property: ethers.utils.FormatTypes.json => string
|
||||
This returns a JavaScript Object which is safe to call ``JSON.stringify``
|
||||
on to create a JSON string.
|
||||
|
||||
_property: ethers.utils.FragmentTypes.sighash => string
|
||||
|
||||
_property: ethers.utils.FormatTypes.sighash => string
|
||||
This is a minimal output format, which is used by Solidity when computing a
|
||||
signature hash or an event topic hash.
|
||||
|
||||
_warning: Note
|
||||
|
||||
The ``sighash`` format is **insufficient** to re-create the original [[Fragment]],
|
||||
since it discards modifiers such as indexed, anonymous, stateMutability, etc.
|
||||
|
||||
It is only useful for computing the selector for a Fragment, and cannot
|
||||
be used to format an Interface.
|
||||
|
||||
|
||||
_subsection: Fragment @<Fragment> @SRC<abi/fragments:class.Fragment>
|
||||
|
||||
An ABI is a collection of **Fragments**, where each fragment specifies:
|
||||
|
||||
- An [Error](ErrorFragment)
|
||||
- An [Event](EventFragment)
|
||||
- A [Function](FunctionFragment)
|
||||
- A [Constructor](ConstructorFragment)
|
||||
@@ -66,12 +89,10 @@ An ABI is a collection of **Fragments**, where each fragment specifies:
|
||||
_heading: Properties
|
||||
|
||||
_property: fragment.name => string
|
||||
|
||||
This is the name of the Event or Function. This will be null for
|
||||
a [[ConstructorFragment]].
|
||||
|
||||
_property: fragment.type => string
|
||||
|
||||
This is a string which indicates the type of the [[Fragment]]. This
|
||||
will be one of:
|
||||
|
||||
@@ -80,19 +101,20 @@ will be one of:
|
||||
- ``function``
|
||||
|
||||
_property: fragment.inputs => Array<[[ParamType]]>
|
||||
|
||||
This is an array of each [[ParamType]] for the input parameters to
|
||||
the Constructor, Event of Function.
|
||||
|
||||
_heading: Methods
|
||||
|
||||
_property: ethers.utils.Fragment.from(objectOrString) => [[Fragment]] @<Fragment-from> @SRC<abi/fragments:Fragment.from>
|
||||
_property: fragment.format([ format = sighash]) => string @<Fragment-format> @SRC<abi/fragments:Fragment.format>
|
||||
Creates a string representation of the Fragment using the available
|
||||
[output formats](fragments--output-formats).
|
||||
|
||||
Returns a
|
||||
_property: ethers.utils.Fragment.from(objectOrString) => [[Fragment]] @<Fragment-from> @SRC<abi/fragments:Fragment.from>
|
||||
Creates a new **Fragment** sub-class from any compatible //objectOrString//.
|
||||
|
||||
_property: ethers.utils.Fragment.isFragment(object) => boolean @<Fragment-isFragment> @SRC<abi/fragments:Fragment.isFragment>
|
||||
|
||||
Tra lal al
|
||||
Returns true if //object// is a **Fragment**.
|
||||
|
||||
|
||||
_subsection: ConstructorFragment @<ConstructorFragment> @INHERIT<[[Fragment]]> @SRC<abi/fragments:class.ConstructorFragment>
|
||||
@@ -100,17 +122,14 @@ _subsection: ConstructorFragment @<ConstructorFragment> @INHERIT<[[Fragment]]> @
|
||||
_heading: Properties
|
||||
|
||||
_property: fragment.gas => [[BigNumber]]
|
||||
|
||||
This is the gas limit that should be used during deployment. It may be
|
||||
null.
|
||||
|
||||
_property: fragment.payable => boolean
|
||||
|
||||
This is whether the constructor may receive ether during deployment as
|
||||
an endowment (i.e. msg.value != 0).
|
||||
|
||||
_property: fragment.stateMutability => string
|
||||
|
||||
This is the state mutability of the constructor. It can be any of:
|
||||
|
||||
- ``nonpayable``
|
||||
@@ -119,12 +138,21 @@ This is the state mutability of the constructor. It can be any of:
|
||||
_heading: Methods
|
||||
|
||||
_property: ethers.utils.ConstructorFragment.from(objectOrString) => [[ConstructorFragment]] @<ConstructorFragment-from> @SRC<abi/fragments:ConstructorFragment.from>
|
||||
|
||||
Tra la la...
|
||||
Creates a new **ConstructorFragment** from any compatible //objectOrString//.
|
||||
|
||||
_property: ethers.utils.ConstructorFragment.isConstructorFragment(object) => boolean @<ConstructorFragment-isConstructorFragment> @SRC<abi/fragments:ConstructorFragment.isConstructorFragment>
|
||||
Returns true if //object// is a **ConstructorFragment**.
|
||||
|
||||
Tra lal al
|
||||
|
||||
_subsection: ErrorFragment @<ErrorFragment> @INHERIT<[[Fragment]]> @SRC<abi/fragments:class.ErrorFragment>
|
||||
|
||||
_heading: Methods
|
||||
|
||||
_property: ethers.utils.ErrorFragment.from(objectOrString) => [[ErrorFragment]] @<ErrorFragment-from> @SRC<abi/fragments:ErrorFragment.from>
|
||||
Creates a new **ErrorFragment** from any compatible //objectOrString//.
|
||||
|
||||
_property: ethers.utils.ErrorFragment.isErrorFragment(object) => boolean @<ErrorFragment-isErrorFragment> @SRC<abi/fragments:ErrorFragment.isErrorFragment>
|
||||
Returns true if //object// is an **ErrorFragment**.
|
||||
|
||||
|
||||
_subsection: EventFragment @<EventFragment> @INHERIT<[[Fragment]]> @SRC<abi/fragments:class.EventFragment>
|
||||
@@ -132,19 +160,16 @@ _subsection: EventFragment @<EventFragment> @INHERIT<[[Fragment]]> @SRC<abi/frag
|
||||
_heading: Properties
|
||||
|
||||
_property: fragment.anonymous => boolean
|
||||
|
||||
This is whether the event is anonymous. An anonymous Event does not inject its
|
||||
topic hash as topic0 when creating a log.
|
||||
|
||||
_heading: Methods
|
||||
|
||||
_property: ethers.utils.EventFragment.from(objectOrString) => [[EventFragment]] @<EventFragment-from> @SRC<abi/fragments:EventFragment.from>
|
||||
|
||||
Tra la la...
|
||||
Creates a new **EventFragment** from any compatible //objectOrString//.
|
||||
|
||||
_property: ethers.utils.EventFragment.isEventFragment(object) => boolean @<EventFragment-isEventFragment> @SRC<abi/fragments:EventFragment.isEventFragment>
|
||||
|
||||
Tra lal al
|
||||
Returns true if //object// is an **EventFragment**.
|
||||
|
||||
|
||||
_subsection: FunctionFragment @<FunctionFragment> @INHERIT<[[ConstructorFragment]]> @SRC<abi/fragments:class.FunctionFragment>
|
||||
@@ -152,12 +177,10 @@ _subsection: FunctionFragment @<FunctionFragment> @INHERIT<[[ConstructorFragment
|
||||
_heading: Properties
|
||||
|
||||
_property: fragment.constant => boolean
|
||||
|
||||
This is whether the function is constant (i.e. does not change state). This
|
||||
is true if the state mutability is ``pure`` or ``view``.
|
||||
|
||||
_property: fragment.stateMutability => string
|
||||
|
||||
This is the state mutability of the constructor. It can be any of:
|
||||
|
||||
- ``nonpayable``
|
||||
@@ -166,22 +189,18 @@ This is the state mutability of the constructor. It can be any of:
|
||||
- ``view``
|
||||
|
||||
_property: fragment.outputs => Array<[[ParamType]]>
|
||||
|
||||
A list of the Function output parameters.
|
||||
|
||||
_heading: Method
|
||||
_heading: Methods
|
||||
|
||||
_property: ethers.utils.FunctionFragment.from(objectOrString) => [[FunctionFragment]] @<FunctionFragment-from> @SRC<abi/fragments:ConstructorFragment.from>
|
||||
|
||||
Tra la la...
|
||||
Creates a new **FunctionFragment** from any compatible //objectOrString//.
|
||||
|
||||
_property: ethers.utils.FunctionFragment.isFunctionFragment(object) => boolean @<FunctionFragment-isFunctionFragment> @SRC<abi/fragments:FunctionFragment.isFunctionFragment>
|
||||
|
||||
Tra lal al
|
||||
Returns true if //object// is a **FunctionFragment**.
|
||||
|
||||
|
||||
_subsection: ParamType @<ParamType> @SRC<abi/fragments:class.ParamType>
|
||||
|
||||
The following examples will represent the Solidity parameter:
|
||||
|
||||
``string foobar``
|
||||
@@ -189,53 +208,42 @@ The following examples will represent the Solidity parameter:
|
||||
_heading: Properties
|
||||
|
||||
_property: paramType.name => string @<ParamType-name>
|
||||
|
||||
The local parameter name. This may be null for unnamed parameters. For example,
|
||||
the parameter definition ``string foobar`` would be ``foobar``.
|
||||
|
||||
_property: paramType.type => string @<ParamType-type>
|
||||
|
||||
The full type of the parameter, including tuple and array symbols. This may be null
|
||||
for unnamed parameters. For the above example, this would be ``foobar``.
|
||||
|
||||
_property: paramType.baseType => string @<ParamType-baseType>
|
||||
|
||||
The base type of the parameter. For primitive types (e.g. ``address``, ``uint256``, etc)
|
||||
this is equal to [type](ParamType-type). For arrays, it will be the string ``array`` and for
|
||||
a tuple, it will be the string ``tuple``.
|
||||
|
||||
_property: paramType.indexed => boolean @<ParamType-indexed>
|
||||
|
||||
Whether the parameter has been marked as indexed. This **only** applies
|
||||
to parameters which are part of an [[EventFragment]].
|
||||
|
||||
_property: paramType.arrayChildren => [[ParamType]] @<ParamType-arrayChildren>
|
||||
|
||||
The type of children of the array. This is null for any parameter
|
||||
which is not an array.
|
||||
|
||||
_property: paramType.arrayLength => number @<ParamType-arrayLength>
|
||||
|
||||
The length of the array, or ``-1`` for dynamic-length arrays. This is
|
||||
null for parameters which are not arrays.
|
||||
|
||||
_property: paramType.components => Array<[[ParamType]]> @<ParamType-components>
|
||||
|
||||
The components of a tuple. This is null for non-tuple parameters.
|
||||
|
||||
|
||||
_heading: Methods
|
||||
|
||||
Tra la la...
|
||||
|
||||
_property: paramType.format([ outputType = sighash ])
|
||||
|
||||
Tra la la...
|
||||
Creates a string representation of the Fragment using the available
|
||||
[output formats](fragments--output-formats).
|
||||
|
||||
_property: ethers.utils.ParamType.from(objectOrString) => [[ParamType]] @<ParamType-from> @SRC<abi/fragments:ParamType.from>
|
||||
|
||||
Tra la la...
|
||||
Creates a new **ParamType** from any compatible //objectOrString//.
|
||||
|
||||
_property: ethers.utils.ParamType.isParamType(object) => boolean @<ParamType-isParamType> @SRC<abi/fragments:ParamType.isParamType>
|
||||
|
||||
Tra la la...
|
||||
Returns true if //object// is a **ParamType**.
|
||||
|
||||
@@ -26,11 +26,47 @@ which is a format the Ethers created to simplify manually typing the ABI
|
||||
into the source and so that a Contract ABI can also be referenced easily
|
||||
within the same source file.
|
||||
|
||||
_code: Creating an Interface instance @lang<javascript>
|
||||
|
||||
//_hide: const Interface = ethers.utils.Interface;
|
||||
|
||||
// This interface is used for the below examples
|
||||
|
||||
const iface = new Interface([
|
||||
// Constructor
|
||||
"constructor(string symbol, string name)",
|
||||
|
||||
// State mutating method
|
||||
"function transferFrom(address from, address to, uint amount)",
|
||||
|
||||
// State mutating method, which is payable
|
||||
"function mint(uint amount) payable",
|
||||
|
||||
// Constant method (i.e. "view" or "pure")
|
||||
"function balanceOf(address owner) view returns (uint)",
|
||||
|
||||
// An Event
|
||||
"event Transfer(address indexed from, address indexed to, uint256 amount)",
|
||||
|
||||
// A Custom Solidity Error
|
||||
"error AccountLocked(address owner, uint256 balance)",
|
||||
|
||||
// Examples with structured types
|
||||
"function addUser(tuple(string name, address addr) user) returns (uint id)",
|
||||
"function addUsers(tuple(string name, address addr)[] user) returns (uint[] id)",
|
||||
"function getUser(uint id) view returns (tuple(string name, address addr) user)"
|
||||
]);
|
||||
|
||||
//_hide: _page.iface = iface;
|
||||
|
||||
_subsection: Properties @<Interface--properties>
|
||||
|
||||
_property: interface.fragments => Array<[[Fragment]]>
|
||||
All the [Fragments](Fragment) in the interface.
|
||||
|
||||
_property: interface.errors => Array<[[ErrorFragment]]>
|
||||
All the [Error Fragments](ErrorFragment) in the interface.
|
||||
|
||||
_property: interface.events => Array<[[EventFragment]]>
|
||||
All the [Event Fragments](EventFragment) in the interface.
|
||||
|
||||
@@ -48,24 +84,133 @@ Return the formatted **Interface**. If the format type is ``json`` a
|
||||
single string is returned, otherwise an Array of the human-readable
|
||||
strings is returned.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
const FormatTypes = ethers.utils.FormatTypes;
|
||||
|
||||
//_result:
|
||||
iface.format(FormatTypes.json)
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
iface.format(FormatTypes.full)
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
iface.format(FormatTypes.minimal)
|
||||
//_log:
|
||||
|
||||
_subsection: Fragment Access @<Interface--fragments>
|
||||
|
||||
_property: interface.getFunction(fragment) => [[FunctionFragment]] @SRC<abi/interface>
|
||||
Returns the [[FunctionFragment]] for //fragment// (see [[Interface--specifying-fragments]]).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
// By method signature, which is normalized so whitespace
|
||||
// and superfluous attributes are ignored
|
||||
iface.getFunction("transferFrom(address, address, uint256)");
|
||||
|
||||
// By name; this ONLY works if the method is non-ambiguous
|
||||
iface.getFunction("transferFrom");
|
||||
|
||||
// By method selector
|
||||
iface.getFunction("0x23b872dd");
|
||||
|
||||
// Throws if the method does not exist
|
||||
//_throws:
|
||||
iface.getFunction("doesNotExist()");
|
||||
//_log:
|
||||
|
||||
_property: interface.getError(fragment) => [[ErrorFragment]] @SRC<abi/interface>
|
||||
Returns the [[ErrorFragment]] for //fragment// (see [[Interface--specifying-fragments]]).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
// By error signature, which is normalized so whitespace
|
||||
// and superfluous attributes are ignored
|
||||
iface.getError("AccountLocked(address, uint256)");
|
||||
|
||||
// By name; this ONLY works if the error is non-ambiguous
|
||||
iface.getError("AccountLocked");
|
||||
|
||||
// By error selector
|
||||
iface.getError("0xf7c3865a");
|
||||
|
||||
// Throws if the error does not exist
|
||||
//_throws:
|
||||
iface.getError("DoesNotExist()");
|
||||
//_log:
|
||||
|
||||
_property: interface.getEvent(fragment) => [[EventFragment]] @SRC<abi/interface>
|
||||
Returns the [[EventFragment]] for //fragment// (see [[Interface--specifying-fragments]]).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
// By event signature, which is normalized so whitespace
|
||||
// and superfluous attributes are ignored
|
||||
iface.getEvent("Transfer(address, address, uint256)");
|
||||
|
||||
// By name; this ONLY works if the event is non-ambiguous
|
||||
iface.getEvent("Transfer");
|
||||
|
||||
// By event topic hash
|
||||
iface.getEvent("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");
|
||||
|
||||
// Throws if the event does not exist
|
||||
//_throws:
|
||||
iface.getEvent("DoesNotExist()");
|
||||
//_log:
|
||||
|
||||
_subsection: Signature and Topic Hashes @<Interface--selectors>
|
||||
|
||||
_property: interface.getSighash(fragment) => string<[[DataHexString]]<4>> @SRC<abi/interface:method.Interface.getSighash>
|
||||
Return the sighash (or Function Selector) for //fragment// (see [[Interface--specifying-fragments]]).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
//_result:
|
||||
iface.getSighash("balanceOf");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
iface.getSighash("balanceOf(address)");
|
||||
//_log:
|
||||
|
||||
const fragment = iface.getFunction("balanceOf")
|
||||
//_result:
|
||||
iface.getSighash(fragment);
|
||||
//_log:
|
||||
|
||||
_property: interface.getEventTopic(fragment) => string<[[DataHexString]]<32>> @SRC<abi/interface:method.Interface.getEventTopic>
|
||||
Return the topic hash for //fragment// (see [[Interface--specifying-fragments]]).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
//_result:
|
||||
iface.getEventTopic("Transfer");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
iface.getEventTopic("Transfer(address, address, uint)");
|
||||
//_log:
|
||||
|
||||
const fragment = iface.getEvent("Transfer")
|
||||
//_result:
|
||||
iface.getEventTopic(fragment);
|
||||
//_log:
|
||||
|
||||
_subsection: Encoding Data @<Interface--encoding>
|
||||
|
||||
@@ -74,25 +219,145 @@ Return the encoded deployment data, which can be concatenated to the
|
||||
deployment bytecode of a contract to pass //values// into the contract
|
||||
constructor.
|
||||
|
||||
_property: interface.encodeFilterTopics(fragment [ , values ]) => Array<topic | Array<topic>> @SRC<abi/interface>
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
// The data that should be appended to the bytecode to pass
|
||||
// parameters to the constructor during deployment
|
||||
//_result:
|
||||
iface.encodeDeploy([ "SYM", "Some Name" ])
|
||||
//_log:
|
||||
|
||||
_property: interface.encodeErrorResult(fragment [ , values ]) => string<[[DataHexString]]> @SRC<abi/interface>
|
||||
Returns the encoded error result, which would normally be the response from
|
||||
a reverted call for //fragment// (see [[Interface--specifying-fragments]]) for
|
||||
the given //values//.
|
||||
|
||||
Most developers will not need this method, but may be useful for authors of
|
||||
a mock blockchain.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
// Encoding result data (like is returned by eth_call during a revert)
|
||||
//_result:
|
||||
iface.encodeErrorResult("AccountLocked", [
|
||||
"0x8ba1f109551bD432803012645Ac136ddd64DBA72",
|
||||
parseEther("1.0")
|
||||
]);
|
||||
//_log:
|
||||
|
||||
_property: interface.encodeFilterTopics(fragment, values) => Array<topic | Array<topic>> @SRC<abi/interface>
|
||||
Returns the encoded topic filter, which can be passed to getLogs for //fragment//
|
||||
(see [[Interface--specifying-fragments]]) for the given //values//.
|
||||
|
||||
Each //topic// is a 32 byte (64 nibble) [[DataHexString]].
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
// Filter that matches all Transfer events
|
||||
//_result:
|
||||
iface.encodeFilterTopics("Transfer", [])
|
||||
//_log:
|
||||
|
||||
// Filter that matches the sender
|
||||
//_result:
|
||||
iface.encodeFilterTopics("Transfer", [
|
||||
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
||||
])
|
||||
//_log:
|
||||
|
||||
// Filter that matches the receiver
|
||||
//_result:
|
||||
iface.encodeFilterTopics("Transfer", [
|
||||
null,
|
||||
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
||||
])
|
||||
//_log:
|
||||
|
||||
_property: interface.encodeFunctionData(fragment [ , values ]) => string<[[DataHexString]]> @SRC<abi/interface>
|
||||
Returns the encoded data, which can be used as the data for a transaction for
|
||||
//fragment// (see [[Interface--specifying-fragments]]) for the given //values//.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
// Encoding data for the tx.data of a call or transaction
|
||||
//_result:
|
||||
iface.encodeFunctionData("transferFrom", [
|
||||
"0x8ba1f109551bD432803012645Ac136ddd64DBA72",
|
||||
"0xaB7C8803962c0f2F5BBBe3FA8bf41cd82AA1923C",
|
||||
parseEther("1.0")
|
||||
])
|
||||
//_log:
|
||||
|
||||
// Encoding structured data (using positional Array)
|
||||
user = [
|
||||
"Richard Moore",
|
||||
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
||||
];
|
||||
//_result:
|
||||
iface.encodeFunctionData("addUser", [ user ]);
|
||||
//_log:
|
||||
|
||||
// Encoding structured data, using objects. Only available
|
||||
// if paramters are named.
|
||||
user = {
|
||||
name: "Richard Moore",
|
||||
addr: "0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
||||
};
|
||||
//_result:
|
||||
iface.encodeFunctionData("addUser", [ user ]);
|
||||
//_log:
|
||||
|
||||
_property: interface.encodeFunctionResult(fragment [ , values ]) => string<[[DataHexString]]> @SRC<abi/interface>
|
||||
Returns the encoded result, which would normally be the response from a call for
|
||||
//fragment// (see [[Interface--specifying-fragments]]) for the given //values//.
|
||||
|
||||
Most developers will not need this method, but may be useful for authors of a mock blockchain.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
// Encoding result data (like is returned by eth_call)
|
||||
//_result:
|
||||
iface.encodeFunctionResult("balanceOf", [
|
||||
"0x8ba1f109551bD432803012645Ac136ddd64DBA72"
|
||||
])
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Decoding Data @<Interface--decoding>
|
||||
|
||||
_property: interface.decodeErrorResult(fragment, data) => [[Result]] @SRC<abi/interface>
|
||||
Returns the decoded values from the result of a call during a revert for
|
||||
//fragment// (see [[Interface--specifying-fragments]]) for the given //data//.
|
||||
|
||||
Most developers won't need this, as the ``decodeFunctionResult`` will automatically
|
||||
decode errors if the //data// represents a revert.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
// Decoding result data (e.g. from an eth_call)
|
||||
errorData = "0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
|
||||
//_result:
|
||||
iface.decodeErrorResult("AccountLocked", errorData)
|
||||
//_log:
|
||||
|
||||
_property: interface.decodeEventLog(fragment, data [ , topics ]) => [[Result]] @SRC<abi/interface>
|
||||
Returns the decoded event values from an event log for
|
||||
//fragment// (see [[Interface--specifying-fragments]]) for the given //data//
|
||||
@@ -100,6 +365,26 @@ with the optional //topics//.
|
||||
|
||||
If //topics// is not specified, placeholders will be inserted into the result.
|
||||
|
||||
Most develoeprs will find the [parsing methods](Interface--parsing) more
|
||||
convenient for decoding event data, as they will automatically detect the
|
||||
matching event.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
// Decoding log data and topics (the entries in a receipt)
|
||||
const data = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
const topics = [
|
||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
||||
"0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72",
|
||||
"0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c"
|
||||
];
|
||||
|
||||
//_result:
|
||||
iface.decodeEventLog("Transfer", data, topics);
|
||||
//_log:
|
||||
|
||||
_property: interface.decodeFunctionData(fragment, data) => [[Result]] @SRC<abi/interface>
|
||||
Returns the decoded values from transaction data for
|
||||
//fragment// (see [[Interface--specifying-fragments]]) for the given //data//.
|
||||
@@ -107,25 +392,119 @@ Returns the decoded values from transaction data for
|
||||
Most developers will not need this method, but may be useful for debugging
|
||||
or inspecting transactions.
|
||||
|
||||
Most develoeprs will also find the [parsing methods](Interface--parsing) more
|
||||
convenient for decoding transation data, as they will automatically detect the
|
||||
matching function.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
// Decoding function data (the value of tx.data)
|
||||
const txData = "0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
//_result:
|
||||
iface.decodeFunctionData("transferFrom", txData);
|
||||
//_log:
|
||||
|
||||
_property: interface.decodeFunctionResult(fragment, data) => [[Result]] @SRC<abi/interface>
|
||||
Returns the decoded values from the result of a call for
|
||||
//fragment// (see [[Interface--specifying-fragments]]) for the given //data//.
|
||||
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
// Decoding result data (e.g. from an eth_call)
|
||||
resultData = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
//_result:
|
||||
iface.decodeFunctionResult("balanceOf", resultData)
|
||||
//_log:
|
||||
|
||||
// Decoding result data which was caused by a revert
|
||||
// Throws a CALL_EXCEPTION, with extra details
|
||||
errorData = "0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
//_throws:
|
||||
iface.decodeFunctionResult("balanceOf", errorData)
|
||||
//_log:
|
||||
|
||||
// Decoding structured data returns a Result object, which
|
||||
// will include all values positionally and if the ABI
|
||||
// included names, values will additionally be available
|
||||
// by their name.
|
||||
resultData = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000000000000000000000000000000000000000000d52696368617264204d6f6f726500000000000000000000000000000000000000";
|
||||
//_result:
|
||||
result = iface.decodeFunctionResult("getUser", resultData);
|
||||
//_log:
|
||||
|
||||
// Access positionally:
|
||||
// The 0th output parameter, the 0th proerty of the structure
|
||||
//_result:
|
||||
result[0][0];
|
||||
//_log:
|
||||
|
||||
// Access by name: (only avilable because parameters were named)
|
||||
//_result:
|
||||
result.user.name
|
||||
//_log:
|
||||
|
||||
_subsection: Parsing @<Interface--parsing>
|
||||
|
||||
The functions are generally the most useful for most developers. They will
|
||||
automatically search the ABI for a matching Event or Function and decode
|
||||
the components as a fully specified description.
|
||||
|
||||
_property: interface.parseError(data) => [[ErrorDescription]] @SRC<abi/interface>
|
||||
Search for the error that matches the error selector in //data// and parse out
|
||||
the details.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
const data = "0xf7c3865a0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba720000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
|
||||
//_result:
|
||||
iface.parseError(data);
|
||||
//_hide: _.errorFragment = createClass("ErrorFragment");
|
||||
//_log:
|
||||
|
||||
_property: interface.parseLog(log) => [[LogDescription]] @SRC<abi/interface>
|
||||
Search the event that matches the //log// topic hash and parse the values
|
||||
the log represents.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
|
||||
const data = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
const topics = [
|
||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
||||
"0x0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72",
|
||||
"0x000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c"
|
||||
];
|
||||
|
||||
//_result:
|
||||
iface.parseLog({ data, topics });
|
||||
//_hide: _.eventFragment = createClass("EventFragment");
|
||||
//_log:
|
||||
|
||||
_property: interface.parseTransaction(transaction) => [[TransactionDescription]] @SRC<abi/interface>
|
||||
Search for the function that matches the //transaction// data sighash
|
||||
and parse the transaction properties.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const iface = _page.iface;
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
const data = "0x23b872dd0000000000000000000000008ba1f109551bd432803012645ac136ddd64dba72000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c0000000000000000000000000000000000000000000000000de0b6b3a7640000";
|
||||
const value = parseEther("1.0");
|
||||
|
||||
//_result:
|
||||
iface.parseTransaction({ data, value });
|
||||
//_hide: _.functionFragment = createClass("FunctionFragment");
|
||||
//_log:
|
||||
|
||||
_subsection: Types @<Interface--types>
|
||||
|
||||
@@ -142,6 +521,24 @@ any named value for this key is renamed to ``_length``. If there is a
|
||||
name collision, only the first is available by its key.
|
||||
|
||||
|
||||
_heading: ErrorDescription @<ErrorDescription>
|
||||
|
||||
_property: errorDescription.args => [[Result]]
|
||||
The values of the input parameters of the error.
|
||||
|
||||
_property: errorDescription.errorFragment => [[ErrorFragment]]
|
||||
The [[ErrorFragment]] which matches the selector in the data.
|
||||
|
||||
_property: errorDescription.name => string
|
||||
The error name. (e.g. ``AccountLocked``)
|
||||
|
||||
_property: errorDescription.signature => string
|
||||
The error signature. (e.g. ``AccountLocked(address,uint256)``)
|
||||
|
||||
_property: errorDescription.sighash => string
|
||||
The selector of the error.
|
||||
|
||||
|
||||
_heading: LogDescription @<LogDescription>
|
||||
|
||||
_property: logDescription.args => [[Result]]
|
||||
|
||||
@@ -18,7 +18,6 @@ of errors introduced from typing an address or cut and paste issues.
|
||||
|
||||
All functions that return an Address will return a Checksum Address.
|
||||
|
||||
|
||||
_heading: ICAP Address @<address-icap>
|
||||
|
||||
The **ICAP Address Format** was an early attempt to introduce a checksum
|
||||
@@ -49,13 +48,72 @@ the checksum is invalid, an [INVALID_ARGUMENT](errors--invalid-argument) Error i
|
||||
|
||||
The value of //address// may be any supported address format.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const getAddress = ethers.utils.getAddress;
|
||||
|
||||
// Injects the checksum (via upper-casing specific letters)
|
||||
//_result:
|
||||
getAddress("0x8ba1f109551bd432803012645ac136ddd64dba72");
|
||||
//_log:
|
||||
|
||||
// Converts and injects the checksum
|
||||
//_result:
|
||||
getAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
|
||||
//_log:
|
||||
|
||||
// Throws if a checksummed address is provided, but a
|
||||
// letter is the wrong case
|
||||
// ------------v (should be lower-case)
|
||||
//_throws:
|
||||
getAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBA72")
|
||||
//_log:
|
||||
|
||||
// Throws if the ICAP/IBAN checksum fails
|
||||
//_throws:
|
||||
getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK37");
|
||||
//_log:
|
||||
|
||||
// Throws if the address is invalid, in general
|
||||
//_throws:
|
||||
getIcapAddress("I like turtles!");
|
||||
//_log:
|
||||
|
||||
|
||||
_property: ethers.utils.getIcapAddress(address) => string<[IcapAddress](address-icap)> @<utils-getIcapAddress> @SRC<address>
|
||||
Returns //address// as an [ICAP address](link-icap).
|
||||
Supports the same restrictions as [getAddress](utils-getAddress).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const getIcapAddress = ethers.utils.getIcapAddress;
|
||||
|
||||
//_result:
|
||||
getIcapAddress("0x8ba1f109551bd432803012645ac136ddd64dba72");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.isAddress(address) => boolean @<utils-isAddress> @SRC<address>
|
||||
Returns true if //address// is valid (in any supported format).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const isAddress = ethers.utils.isAddress;
|
||||
|
||||
//_result:
|
||||
isAddress("0x8ba1f109551bd432803012645ac136ddd64dba72");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
isAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
isAddress("I like turtles.");
|
||||
//_log:
|
||||
|
||||
_subsection: Derivation @<utils--address-derivation>
|
||||
|
||||
@@ -64,10 +122,49 @@ Returns the address for //publicOrPrivateKey//. A public key may be
|
||||
compressed or uncompressed, and a private key will be converted
|
||||
automatically to a public key for the derivation.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const computeAddress = ethers.utils.computeAddress;
|
||||
|
||||
// Private Key
|
||||
//_result:
|
||||
computeAddress("0xb976778317b23a1385ec2d483eda6904d9319135b89f1d8eee9f6d2593e2665d");
|
||||
//_log:
|
||||
|
||||
// Public Key (compressed)
|
||||
//_result:
|
||||
computeAddress("0x0376698beebe8ee5c74d8cc50ab84ac301ee8f10af6f28d0ffd6adf4d6d3b9b762");
|
||||
//_log:
|
||||
|
||||
// Public Key (uncompressed)
|
||||
//_result:
|
||||
computeAddress("0x0476698beebe8ee5c74d8cc50ab84ac301ee8f10af6f28d0ffd6adf4d6d3b9b762d46ca56d3dad2ce13213a6f42278dabbb53259f2d92681ea6a0b98197a719be3");
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.recoverAddress(digest, signature) => string<[[address]]> @<utils-recoverAddress> @SRC<transactions>
|
||||
Use [[link-wiki-ecrecover]] to determine the address that signed //digest// to
|
||||
which generated //signature//.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const recoverAddress = ethers.utils.recoverAddress;
|
||||
|
||||
const digest = "0x7c5ea36004851c764c44143b1dcb59679b11c9a68e5f41497f6cf3d480715331";
|
||||
|
||||
// Using an expanded Signature
|
||||
//_result:
|
||||
recoverAddress(digest, {
|
||||
r: "0x528459e4aec8934dc2ee94c4f3265cf6ce00d47cf42bb106afda3642c72e25eb",
|
||||
s: "0x42544137118256121502784e5a6425e6183ca964421ecd577db6c66ba9bccdcf",
|
||||
v: 27
|
||||
});
|
||||
//_log:
|
||||
|
||||
// Using a flat Signature
|
||||
const signature = "0x528459e4aec8934dc2ee94c4f3265cf6ce00d47cf42bb106afda3642c72e25eb42544137118256121502784e5a6425e6183ca964421ecd577db6c66ba9bccdcf1b";
|
||||
//_result:
|
||||
recoverAddress(digest, signature);
|
||||
//_log:
|
||||
|
||||
_subsection: Contracts Addresses @<utils--contract-addresses>
|
||||
|
||||
@@ -75,9 +172,33 @@ _property: ethers.utils.getContractAddress(transaction) => string<[[address]]>
|
||||
Returns the contract address that would result if //transaction// was
|
||||
used to deploy a contract.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const getContractAddress = ethers.utils.getContractAddress;
|
||||
|
||||
const from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
|
||||
const nonce = 5;
|
||||
|
||||
//_result:
|
||||
getContractAddress({ from, nonce });
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.getCreate2Address(from, salt, initCodeHash) => string<[[address]]> @<utils-getCreate2Address> @SRC<address>
|
||||
Returns the contract address that would result from the given
|
||||
[CREATE2](link-eip-1014) call.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const getCreate2Address = ethers.utils.getCreate2Address;
|
||||
//_hide: const keccak256 = ethers.utils.keccak256;
|
||||
|
||||
const from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
|
||||
const salt = "0x7c5ea36004851c764c44143b1dcb59679b11c9a68e5f41497f6cf3d480715331";
|
||||
const initCode = "0x6394198df16000526103ff60206004601c335afa6040516060f3";
|
||||
const initCodeHash = keccak256(initCode);
|
||||
|
||||
//_result:
|
||||
getCreate2Address(from, salt, initCodeHash);
|
||||
//_log:
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
_section: BigNumber @<BigNumber>
|
||||
|
||||
Many operations in Ethereum operation on numbers which are
|
||||
Many operations in Ethereum operate on numbers which are
|
||||
[outside the range of safe values](BigNumber--notes-safenumbers) to use
|
||||
in JavaScript.
|
||||
|
||||
@@ -49,43 +49,52 @@ _heading: Examples: @<>
|
||||
_code: @lang<javascript>
|
||||
|
||||
// From a decimal string...
|
||||
//_result:
|
||||
BigNumber.from("42")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// From a HexString...
|
||||
//_result:
|
||||
BigNumber.from("0x2a")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// From a negative HexString...
|
||||
//_result:
|
||||
BigNumber.from("-0x2a")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// From an Array (or Uint8Array)...
|
||||
//_result:
|
||||
BigNumber.from([ 42 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// From an existing BigNumber...
|
||||
let one1 = constants.One;
|
||||
let one2 = BigNumber.from(one1)
|
||||
|
||||
//_result:
|
||||
one2
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// ...which returns the same instance
|
||||
//_result:
|
||||
one1 === one2
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// From a (safe) number...
|
||||
//_result:
|
||||
BigNumber.from(42)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// From a ES2015 BigInt... (only on platforms with BigInt support)
|
||||
//_result:
|
||||
BigNumber.from(42n)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Numbers outside the safe range fail:
|
||||
//_throws:
|
||||
BigNumber.from(Number.MAX_SAFE_INTEGER);
|
||||
//! error
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Methods @<BigNumber--methods>
|
||||
@@ -159,6 +168,10 @@ Returns true if and only if the value of //BigNumber// is zero.
|
||||
|
||||
_heading: Conversion
|
||||
|
||||
_property: BigNumber.toBigInt() => bigint @SRC<bignumber>
|
||||
Returns the value of //BigNumber// as a [JavaScript BigInt](link-js-bigint) value,
|
||||
on platforms which support them.
|
||||
|
||||
_property: BigNumber.toNumber() => number @SRC<bignumber>
|
||||
Returns the value of //BigNumber// as a JavaScript value.
|
||||
|
||||
@@ -186,8 +199,9 @@ _code: @lang<javascript>
|
||||
let a = BigNumber.from(42);
|
||||
let b = BigNumber.from("91");
|
||||
|
||||
//_result:
|
||||
a.mul(b);
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Notes @<BigNumber--notes>
|
||||
@@ -214,8 +228,9 @@ To demonstrate how this may be an issue in your code, consider:
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_result:
|
||||
(Number.MAX_SAFE_INTEGER + 2 - 2) == (Number.MAX_SAFE_INTEGER)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
_null:
|
||||
|
||||
|
||||
@@ -38,8 +38,10 @@ _heading: Signature @<Signature>
|
||||
|
||||
- **r** and **s** --- The x co-ordinate of **r** and the **s** value of the signature
|
||||
- **v** --- The parity of the y co-ordinate of **r**
|
||||
- **_vs** --- The [compact representation](link-eip-2098) of the **s** and **v**
|
||||
- **yParityAndS** --- The [compact representation](link-eip-2098) of the **s** and **v**
|
||||
- **_vs** --- Deprecated property; renamed to yParityAndS
|
||||
- **recoveryParam** --- The normalized (i.e. 0 or 1) value of **v**
|
||||
- **compact** - The full siggnature using [compact representation](link-eip-2098)
|
||||
|
||||
_heading: Raw Signature @<signature-raw> @inherit<string\<[[DataHexString]]\<65\>\>>
|
||||
|
||||
@@ -86,28 +88,34 @@ zeros.
|
||||
_code: Examples @lang<javascript>
|
||||
|
||||
// Convert a hexstring to a Uint8Array
|
||||
//_result:
|
||||
arrayify("0x1234")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Convert an Array to a hexstring
|
||||
//_result:
|
||||
hexlify([1, 2, 3, 4])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Convert an Object to a hexstring
|
||||
//_result:
|
||||
hexlify({ length: 2, "0": 1, "1": 2 })
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Convert an Array to a hexstring
|
||||
//_result:
|
||||
hexlify([ 1 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Convert a number to a stripped hex value
|
||||
//_result:
|
||||
hexValue(1)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Convert an Array to a stripped hex value
|
||||
//_result:
|
||||
hexValue([ 1, 2 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Array Manipulation
|
||||
@@ -170,15 +178,18 @@ Return a copy of //array// shuffled using [[link-wiki-shuffle]].
|
||||
|
||||
_code: Examples @lang<javascript>
|
||||
|
||||
//_result:
|
||||
utils.randomBytes(8)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
const data = [ 1, 2, 3, 4, 5, 6, 7 ];
|
||||
|
||||
// Returns a new Array
|
||||
//_result:
|
||||
utils.shuffled(data);
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// The Original is unscathed...
|
||||
//_result:
|
||||
data
|
||||
//!
|
||||
//_log:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
_section: Constants @<constants>
|
||||
|
||||
The **ethers.contants** Object contains commonly used values.
|
||||
The **ethers.constants** Object contains commonly used values.
|
||||
|
||||
|
||||
_subsection: Bytes
|
||||
|
||||
@@ -53,6 +53,13 @@ _heading: Formatting @<display-logic--formatting>
|
||||
_property: ethers.utils.commify(value) => string @<utils-commify> @SRC<units>
|
||||
Returns a string with value grouped by 3 digits, separated by ``,``.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const commify = ethers.utils.commify;
|
||||
|
||||
//_result:
|
||||
commify("-1000.3000");
|
||||
//_log:
|
||||
|
||||
_heading: Conversion @<unit-conversion>
|
||||
|
||||
@@ -60,13 +67,88 @@ _property: ethers.utils.formatUnits(value [ , unit = "ether" ] ) => string @<ut
|
||||
Returns a string representation of //value// formatted with //unit//
|
||||
digits (if it is a number) or to the unit specified (if a string).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const formatUnits = ethers.utils.formatUnits;
|
||||
//_hide: const BigNumber = ethers.BigNumber;
|
||||
|
||||
const oneGwei = BigNumber.from("1000000000");
|
||||
const oneEther = BigNumber.from("1000000000000000000");
|
||||
|
||||
//_result:
|
||||
formatUnits(oneGwei, 0);
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
formatUnits(oneGwei, "gwei");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
formatUnits(oneGwei, 9);
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
formatUnits(oneEther);
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
formatUnits(oneEther, 18);
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.formatEther(value) => string @<utils-formatEther> @SRC<units>
|
||||
The equivalent to calling ``formatUnits(value, "ether")``.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const formatEther = ethers.utils.formatEther;
|
||||
//_hide: const BigNumber = ethers.BigNumber;
|
||||
|
||||
const value = BigNumber.from("1000000000000000000");
|
||||
|
||||
//_result:
|
||||
formatEther(value);
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.parseUnits(value [ , unit = "ether" ] ) => [BigNumber](BigNumber) @<utils-parseUnits> @SRC<units>
|
||||
Returns a [BigNumber](BigNumber) representation of //value//, parsed with
|
||||
//unit// digits (if it is a number) or from the unit specified (if
|
||||
a string).
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const parseUnits = ethers.utils.parseUnits;
|
||||
|
||||
//_result:
|
||||
parseUnits("1.0");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
parseUnits("1.0", "ether");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
parseUnits("1.0", 18);
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
parseUnits("121.0", "gwei");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
parseUnits("121.0", 9);
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.parseEther(value) => [BigNumber](BigNumber) @<utils-parseEther> @SRC<units>
|
||||
The equivalent to calling ``parseUnits(value, "ether")``.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const parseEther = ethers.utils.parseEther;
|
||||
|
||||
//_result:
|
||||
parseEther("1.0");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
parseEther("-0.5");
|
||||
//_log:
|
||||
|
||||
@@ -2,23 +2,63 @@ _section: Encoding Utilities @<encoding>
|
||||
|
||||
_subsection: Base58 @<Bse58> @SRC<basex:Base58>
|
||||
|
||||
_property: ethers.utils.base58.decode(textData) => Uin8Array
|
||||
_property: ethers.utils.base58.decode(textData) => Uint8Array
|
||||
Return a typed Uint8Array representation of //textData// decoded using
|
||||
base-58 encoding.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const base58 = ethers.utils.base58;
|
||||
|
||||
//_result:
|
||||
base58.decode("TzMhH");
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.base58.encode(aBytesLike) => string
|
||||
Return //aBytesLike// encoded as a string using the base-58 encoding.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const base58 = ethers.utils.base58;
|
||||
|
||||
//_result:
|
||||
base58.encode("0x12345678");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
base58.encode([ 0x12, 0x34, 0x56, 0x78 ]);
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Base64 @<Base64>
|
||||
|
||||
_property: ethers.utils.base64.decode(textData) => Uin8Array @SRC<base64>
|
||||
_property: ethers.utils.base64.decode(textData) => Uint8Array @SRC<base64>
|
||||
Return a typed Uint8Array representation of //textData// decoded using
|
||||
base-64 encoding.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const base64 = ethers.utils.base64;
|
||||
|
||||
//_result:
|
||||
base64.decode("EjQ=");
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.base64.encode(aBytesLike) => string @SRC<base64>
|
||||
Return //aBytesLike// encoded as a string using the base-64 encoding.
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const base64 = ethers.utils.base64;
|
||||
|
||||
//_result:
|
||||
base64.encode("0x1234");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
base64.encode([ 0x12, 0x34 ]);
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Recursive-Length Prefix @<rlp--methods>
|
||||
|
||||
@@ -26,15 +66,53 @@ The [[link-rlp]] encoding is used throughout Ethereum to serialize nested
|
||||
structures of Arrays and data.
|
||||
|
||||
_property: ethers.utils.RLP.encode(dataObject) => string<[[DataHexString]]> @<utils-rlpEncode> @SRC<rlp>
|
||||
Encode a structured Data Object into its RLP-encoded representation.
|
||||
Encode a structured [Data Object](rlp--dataobject) into its RLP-encoded representation.
|
||||
|
||||
Each Data component may be a valid [[BytesLike]].
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const RLP = ethers.utils.RLP;
|
||||
|
||||
//_result:
|
||||
RLP.encode("0x12345678");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
RLP.encode([ "0x12345678" ]);
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
RLP.encode([ new Uint8Array([ 0x12, 0x34, 0x56, 0x78 ]) ]);
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
RLP.encode([ [ "0x42", [ "0x43" ] ], "0x12345678", [ ] ]);
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
RLP.encode([ ]);
|
||||
//_log:
|
||||
|
||||
_property: ethers.utils.RLP.decode(aBytesLike) => [DataObject](rlp--dataobject) @<utils.rlpDecode> @SRC<rlp>
|
||||
Decode an RLP-encoded //aBytesLike// into its structured Data Object.
|
||||
Decode an RLP-encoded //aBytesLike// into its structured [Data Object](rlp--dataobject).
|
||||
|
||||
All Data components will be returned as a [[DataHexString]].
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
//_hide: const RLP = ethers.utils.RLP;
|
||||
|
||||
//_result:
|
||||
RLP.decode("0x8412345678");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
RLP.decode("0xcac342c1438412345678c0");
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
RLP.decode("0xc0");
|
||||
//_log:
|
||||
|
||||
_heading: Data Object @<rlp--dataobject>
|
||||
|
||||
A **Data Object** is a recursive structure which is used to serialize many
|
||||
|
||||
@@ -27,14 +27,17 @@ Returns the [SHA2-512](link-wiki-sha2) digest of //aBytesLike//.
|
||||
|
||||
_code: KECCAK256 @lang<javascript>
|
||||
|
||||
//_result:
|
||||
utils.keccak256([ 0x12, 0x34 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.keccak256("0x")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.keccak256("0x1234")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// The value MUST be data, such as:
|
||||
// - an Array of numbers
|
||||
@@ -42,16 +45,19 @@ utils.keccak256("0x1234")
|
||||
// - a Uint8Array
|
||||
|
||||
// Do NOT use UTF-8 strings that are not a DataHexstring
|
||||
//_throws:
|
||||
utils.keccak256("hello world")
|
||||
//! error
|
||||
//_log:
|
||||
|
||||
// If needed, convert strings to bytes first:
|
||||
//_result:
|
||||
utils.keccak256(utils.toUtf8Bytes("hello world"))
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Or equivalently use the identity function:
|
||||
//_result:
|
||||
utils.id("hello world")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Keep in mind that the string "0x1234" represents TWO
|
||||
// bytes (i.e. [ 0x12, 0x34 ]. If you wish to compute the
|
||||
@@ -61,48 +67,56 @@ utils.id("hello world")
|
||||
// Consider the following examples:
|
||||
|
||||
// Hash of TWO (2) bytes:
|
||||
//_result:
|
||||
utils.keccak256("0x1234")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Hash of TWO (2) bytes: (same result)
|
||||
//_result:
|
||||
utils.keccak256([ 0x12, 0x34 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
const bytes = utils.toUtf8Bytes("0x1234")
|
||||
// <hide>
|
||||
bytes
|
||||
// </hide>
|
||||
//!
|
||||
//_result:
|
||||
bytes = utils.toUtf8Bytes("0x1234")
|
||||
//_log:
|
||||
|
||||
// Hash of SIX (6) characters (different than above)
|
||||
//_result:
|
||||
utils.keccak256(bytes)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Hash of SIX (6) characters (same result)
|
||||
//_result:
|
||||
utils.id("0x1234")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
_code: RIPEMD160 @lang<javascript>
|
||||
|
||||
//_result:
|
||||
utils.ripemd160("0x")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.ripemd160("0x1234")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
_code: SHA-2 @lang<javascript>
|
||||
|
||||
//_result:
|
||||
utils.sha256("0x")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.sha256("0x1234")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.sha512("0x")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.sha512("0x1234")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: HMAC @<utils--hmac>
|
||||
@@ -123,8 +137,9 @@ _code: HMAC @lang<javascript>
|
||||
|
||||
const key = "0x0102"
|
||||
const data = "0x1234"
|
||||
//_result:
|
||||
utils.computeHmac("sha256", key, data)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Hashing Helpers @<utils--hashing-helpers>
|
||||
@@ -137,12 +152,14 @@ and the length of //message//.
|
||||
_code: Hashing Messages @lang<javascript>
|
||||
|
||||
// Hashing a string message
|
||||
//_result:
|
||||
utils.hashMessage("Hello World")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Hashing binary data (also "Hello World", but as bytes)
|
||||
//_result:
|
||||
utils.hashMessage( [ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// NOTE: It is important to understand how strings and binary
|
||||
// data is handled differently. A string is ALWAYS processed
|
||||
@@ -151,18 +168,21 @@ utils.hashMessage( [ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100 ])
|
||||
|
||||
// Hashing a hex string is the same as hashing a STRING
|
||||
// Note: this is the hash of the 4 characters [ '0', 'x', '4', '2' ]
|
||||
//_result:
|
||||
utils.hashMessage("0x42")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Hashing the binary data
|
||||
// Note: this is the hash of the 1 byte [ 0x42 ]
|
||||
//_result:
|
||||
utils.hashMessage([ 0x42 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// Hashing the binary data
|
||||
// Note: similarly, this is the hash of the 1 byte [ 0x42 ]
|
||||
//_result:
|
||||
utils.hashMessage(utils.arrayify("0x42"))
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_property: ethers.utils.namehash(name) => string<[[DataHexString]]<32>> @<utils-namehash> @SRC<hash>
|
||||
@@ -170,17 +190,21 @@ Returns the [ENS Namehash](link-namehash) of //name//.
|
||||
|
||||
_code: Namehash @lang<javascript>
|
||||
|
||||
//_result:
|
||||
utils.namehash("")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.namehash("eth")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.namehash("ricmoo.firefly.eth")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.namehash("ricmoo.xyz")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
_heading: Typed Data Encoder @<TypedDataEncoder> @SRC<hash:class.TypedDataEncoder>
|
||||
|
||||
@@ -244,19 +268,17 @@ been recursively replacedwith the value of calling //resolveName// with that val
|
||||
|
||||
_code: Typed Data Example @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
TypedDataEncoder = ethers.utils._TypedDataEncoder
|
||||
// </hide>
|
||||
//_hide: TypedDataEncoder = ethers.utils._TypedDataEncoder
|
||||
|
||||
const domain = {
|
||||
domain = {
|
||||
name: 'Ether Mail',
|
||||
version: '1',
|
||||
chainId: 1,
|
||||
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC'
|
||||
}
|
||||
};
|
||||
|
||||
// The named list of all type definitions
|
||||
const types = {
|
||||
types = {
|
||||
Person: [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'wallet', type: 'address' }
|
||||
@@ -266,10 +288,10 @@ const types = {
|
||||
{ name: 'to', type: 'Person' },
|
||||
{ name: 'contents', type: 'string' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// The data to sign
|
||||
const value = {
|
||||
value = {
|
||||
from: {
|
||||
name: 'Cow',
|
||||
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826'
|
||||
@@ -279,28 +301,32 @@ const value = {
|
||||
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB'
|
||||
},
|
||||
contents: 'Hello, Bob!'
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//_result:
|
||||
TypedDataEncoder.encode(domain, types, value)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
TypedDataEncoder.getPayload(domain, types, value)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
TypedDataEncoder.getPrimaryType(types)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
TypedDataEncoder.hash(domain, types, value)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
TypedDataEncoder.hashDomain(domain)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Solidity Hashing Algorithms @<utils--solidity-hashing>
|
||||
|
||||
When using the Solidity ``abi.packEncoded(...)`` function, a non-standard
|
||||
When using the Solidity ``abi.encodePacked(...)`` function, a non-standard
|
||||
//tightly packed// version of encoding is used. These functions implement
|
||||
the tightly packing algorithm.
|
||||
|
||||
@@ -318,17 +344,21 @@ according to their respective type in //types//.
|
||||
|
||||
_code: Solidity Hashing @lang<javascript>
|
||||
|
||||
//_result:
|
||||
utils.solidityPack([ "int16", "uint48" ], [ -1, 12 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.solidityPack([ "string", "uint8" ], [ "Hello", 3 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.solidityKeccak256([ "int16", "uint48" ], [ -1, 12 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.soliditySha256([ "int16", "uint48" ], [ -1, 12 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// As a short example of the non-distinguished nature of
|
||||
// Solidity tight-packing (which is why it is inappropriate
|
||||
@@ -336,14 +366,18 @@ utils.soliditySha256([ "int16", "uint48" ], [ -1, 12 ])
|
||||
// the following examples are all equal, despite representing
|
||||
// very different values and layouts.
|
||||
|
||||
//_result:
|
||||
utils.solidityPack([ "string", "string" ], [ "hello", "world01" ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.solidityPack([ "string", "string" ], [ "helloworld", "01" ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.solidityPack([ "string", "string", "uint16" ], [ "hell", "oworld", 0x3031 ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_result:
|
||||
utils.solidityPack([ "uint96" ], [ "32309054545061485574011236401" ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
_section: HD Wallet @<hdnodes>
|
||||
|
||||
The Hierarchal Desterministic (HD) Wallet was a standard
|
||||
The Hierarchal Deterministic (HD) Wallet was a standard
|
||||
created for Bitcoin, but lends itself well to a wide variety of
|
||||
Blockchains which rely on secp256k1 private keys.
|
||||
|
||||
|
||||
@@ -216,6 +216,22 @@ it deals with unmined transactions, and can be configured by each node, however
|
||||
to ensure a transaction is propagated to a miner it is best practice to follow
|
||||
the defaults most nodes have enabled.
|
||||
|
||||
_property: Logger.errors.TRANSACTION_REPLACED @<errors--transaction-replaced>
|
||||
When a transaction has been replaced by the user, by broadcasting a new transaction
|
||||
with the same nonce as an existing in-flight (unmined) transaction in the mempool,
|
||||
this error will occur while waiting if the transaction being waited for has become
|
||||
invalidated by that other transaction.
|
||||
|
||||
This can happen for several reasons, but most commonly because the user has increased
|
||||
the gas price (which changes the transaction hash) to "speed up" a transaction or if
|
||||
a user has "cancelled" the transaction in their client. In either case this is
|
||||
usually accomplished by bribing the miners with a higher gas priced transaction.
|
||||
|
||||
This error will have the additional properties, ``cancelled``, ``hash``, ``reason``,
|
||||
``receipt`` and ``replacement``.
|
||||
|
||||
See the [[providers-TransactionResponse]] for the ``wait`` method for more details.
|
||||
|
||||
_property: Logger.errors.UNPREDICTABLE_GAS_LIMIT @<errors--unpredicatable-gas-limit>
|
||||
When estimating the required amount of gas for a transaction, a node is queried for
|
||||
its best guess.
|
||||
|
||||
@@ -18,6 +18,12 @@ The gas limit for this transaction.
|
||||
_property: unsignedTransaction.gasPrice => [[BigNumberish]]
|
||||
The gas price for this transaction.
|
||||
|
||||
_property: unsignedTransaction.maxFeePerGas => [[BigNumberish]]
|
||||
The maximum fee per unit of gas for this transaction.
|
||||
|
||||
_property: unsignedTransaction.maxPriorityFeePerGas => [[BigNumberish]]
|
||||
The maximum priority fee per unit of gas for this transaction.
|
||||
|
||||
_property: unsignedTransaction.data => [[BytesLike]]
|
||||
The data for this transaction.
|
||||
|
||||
@@ -38,7 +44,7 @@ The transaction hash, which can be used as an identifier for
|
||||
//transaction//. This is the keccak256 of the serialized RLP encoded
|
||||
representation of //transaction//.
|
||||
|
||||
_property: unsignedTransaction.to => string<[Address](address)>
|
||||
_property: transaction.to => string<[Address](address)>
|
||||
The address //transaction// is to.
|
||||
|
||||
_property: transaction.from => string<[Address](address)>
|
||||
@@ -57,9 +63,21 @@ refunded at the end of the transaction, and if there is insufficient gas
|
||||
to complete execution, the effects of the transaction are reverted, but
|
||||
the gas is **fully consumed** and an out-of-gas error occurs.
|
||||
|
||||
_property: transaction.gasPrice => [[BigNumber]]
|
||||
_property: transaction.gasPrice => null | [[BigNumber]]
|
||||
The price (in wei) per unit of gas for //transaction//.
|
||||
|
||||
For [[link-eip-1559]] transactions, this will be null.
|
||||
|
||||
_property: transaction.maxFeePerGas => [[BigNumber]]
|
||||
The maximum price (in wei) per unit of gas for //transaction//.
|
||||
|
||||
For transactions that are not [[link-eip-1559]] transactions, this will be null.
|
||||
|
||||
_property: transaction.maxPriorityFeePerGas => [[BigNumber]]
|
||||
The priority fee price (in wei) per unit of gas for //transaction//.
|
||||
|
||||
For transactions that are not [[link-eip-1559]] transactions, this will be null.
|
||||
|
||||
_property: transaction.data => [[BytesLike]]
|
||||
The data for //transaction//. In a contract this is the call data.
|
||||
|
||||
|
||||
@@ -33,6 +33,12 @@ How long to wait before rejecting with a //timeout// error.
|
||||
_property: connection.headers => { [ key: string]: string }
|
||||
Additional headers to include in the connection.
|
||||
|
||||
_property: connection.skipFetchSetup => boolean
|
||||
Normally a connection will specify the default values for a connection
|
||||
such as CORS-behavior and caching policy, to ensure compatibility across
|
||||
platforms. On some services, such as Cloudflare Workers, specifying any
|
||||
value (inclluding the default values) will cause failure. Setting this
|
||||
to true will prevent any values being passed to the underlying API.
|
||||
|
||||
_heading: PollOptions @<PollOptions>
|
||||
|
||||
|
||||
@@ -57,13 +57,11 @@ $TopicABaCD: **[** (topic[0] = A) **OR** (topic[0] = B) **]** **AND**
|
||||
|
||||
_code: ERC-20 Transfer Filter Examples @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const tokenAddress = ethers.constants.AddressZero;
|
||||
const myAddress = ethers.constants.AddressZero;
|
||||
const myOtherAddress = ethers.constants.AddressZero;
|
||||
const id = ethers.utils.id;
|
||||
const hexZeroPad = ethers.utils.hexZeroPad;
|
||||
// </hide>
|
||||
//_hide: const tokenAddress = ethers.constants.AddressZero;
|
||||
//_hide: const myAddress = ethers.constants.AddressZero;
|
||||
//_hide: const myOtherAddress = ethers.constants.AddressZero;
|
||||
//_hide: const id = ethers.utils.id;
|
||||
//_hide: const hexZeroPad = ethers.utils.hexZeroPad;
|
||||
|
||||
// Short example of manually creating filters for an ERC-20
|
||||
// Transfer event.
|
||||
@@ -93,33 +91,33 @@ const hexZeroPad = ethers.utils.hexZeroPad;
|
||||
filter = {
|
||||
address: tokenAddress,
|
||||
topics: [
|
||||
id("Transfer(address,address,uint256)"),
|
||||
utils.id("Transfer(address,address,uint256)"),
|
||||
hexZeroPad(myAddress, 32)
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// List all token transfers *to* myAddress:
|
||||
filter = {
|
||||
address: tokenAddress,
|
||||
topics: [
|
||||
id("Transfer(address,address,uint256)"),
|
||||
utils.id("Transfer(address,address,uint256)"),
|
||||
null,
|
||||
hexZeroPad(myAddress, 32)
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// List all token transfers *to* myAddress or myOtherAddress:
|
||||
filter = {
|
||||
address: tokenAddress,
|
||||
topics: [
|
||||
id("Transfer(address,address,uint256)"),
|
||||
utils.id("Transfer(address,address,uint256)"),
|
||||
null,
|
||||
[
|
||||
hexZeroPad(myAddress, 32),
|
||||
hexZeroPad(myOtherAddress, 32),
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
_null:
|
||||
|
||||
@@ -128,35 +126,37 @@ To simplify life, ..., explain here, the contract API
|
||||
|
||||
_code: ERC-20 Contract Filter Examples @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const tokenAddress = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; // DAI
|
||||
const myAddress = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
|
||||
const otherAddress = "0xEA517D5a070e6705Cc5467858681Ed953d285Eb9";
|
||||
const provider = ethers.getDefaultProvider();
|
||||
const Contract = ethers.Contract;
|
||||
// </hide>
|
||||
//_hide: const tokenAddress = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; /* DAI */
|
||||
//_hide: const myAddress = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
|
||||
//_hide: const otherAddress = "0xEA517D5a070e6705Cc5467858681Ed953d285Eb9";
|
||||
//_hide: const provider = ethers.getDefaultProvider();
|
||||
//_hide: const Contract = ethers.Contract;
|
||||
|
||||
const abi = [
|
||||
abi = [
|
||||
"event Transfer(address indexed src, address indexed dst, uint val)"
|
||||
];
|
||||
|
||||
const contract = new Contract(tokenAddress, abi, provider);
|
||||
contract = new Contract(tokenAddress, abi, provider);
|
||||
|
||||
// List all token transfers *from* myAddress
|
||||
//_result:
|
||||
contract.filters.Transfer(myAddress)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// List all token transfers *to* myAddress:
|
||||
//_result:
|
||||
contract.filters.Transfer(null, myAddress)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// List all token transfers *from* myAddress *to* otherAddress:
|
||||
//_result:
|
||||
contract.filters.Transfer(myAddress, otherAddress)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// List all token transfers *to* myAddress OR otherAddress:
|
||||
//_result:
|
||||
contract.filters.Transfer(null, [ myAddress, otherAddress ])
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: Solidity Topics @<events-solidity>
|
||||
|
||||
@@ -1,5 +1,82 @@
|
||||
_section: Security @<security>
|
||||
|
||||
While security should be a concern for all developers, in the
|
||||
blockchain space developers must be additionally conscious of
|
||||
many areas which can be exploited.
|
||||
|
||||
Once a problem has an economic incentives to exploit it, there
|
||||
is a much larger risk and with blockchain apps it can become
|
||||
quite valuable to attack.
|
||||
|
||||
In addition to many of the other security issues app developers
|
||||
may have to worry about, there are a few additional vectors
|
||||
that JavaScript developers should be aware of.
|
||||
|
||||
_subsection: Side-Channel Attacks
|
||||
|
||||
A [Side-Channel Attack](link-wiki-side-channel-attack) occurs
|
||||
when something orthogonal to the implementation of the algorithm
|
||||
used can be exploited to learn more about secure or private
|
||||
information.
|
||||
|
||||
_heading: Released Data (Strings, Uint8Arrays, Buffers)
|
||||
|
||||
In JavaScript, memory may not be securely allocated, or more
|
||||
importantly securely released.
|
||||
|
||||
[Historically](https://github.com/nodejs/node/issues/4660),
|
||||
``new Buffer(16)`` would re-use old memory that had been
|
||||
released. This would mean that code running later, may have
|
||||
access to data that was discarded.
|
||||
|
||||
As an example of the dangers, imagine if you had used a Buffer
|
||||
to store a private key, signed data and then returned from the
|
||||
function, allowing the Buffer to be de-allocated. A future
|
||||
function may be able to request a new Buffer, which would still
|
||||
have that left-over private key, which it could then use to
|
||||
steal the funds from that account.
|
||||
|
||||
There are also many debugging tools and systems designed to
|
||||
assist developers inspect the memory contents of JavaScript
|
||||
programs. In these cases, any //private key// or //mnemonic//
|
||||
sitting in memory may be visible to other users on the system,
|
||||
or malicious scripts.
|
||||
|
||||
_heading: Timing Attack
|
||||
|
||||
Timing attacks allow a malicious user or script to determine
|
||||
private data through analysing how long an operation requires
|
||||
to execute.
|
||||
|
||||
In JavaScript, //Garbage Collection// occurs periodically when the
|
||||
system determines it is required. Each JavaScript implementation
|
||||
is different, with a variety of strategies and and abilities.
|
||||
|
||||
Most Garbage Collection requires "stopping the world", or pausing
|
||||
all code being executed while it runs. This adds a large delay
|
||||
to any code that was currently running.
|
||||
|
||||
This can be exploited by attackers to "condition cause a delay".
|
||||
They will set up a scenario where the system is on the edge of
|
||||
needing to garbage collect, and call your code with two paths,
|
||||
a simple path and complex path. The simple path won't stir things
|
||||
up enough to cause a garbage collection, while the complex one
|
||||
will. By timing how long the code took to execute, they now know
|
||||
whether garbage collection occured and therefore whether the simple
|
||||
or complex path was taken.
|
||||
|
||||
Advanced timing attacks are very difficult to mitigate in any
|
||||
garbage-collection-based language. Most libraries where this
|
||||
matters will hopefully mitigate this for you as much as possible,
|
||||
but it is still good to be aware of.
|
||||
|
||||
_heading: General Concerns
|
||||
|
||||
- [Cross-Site Scripting](link-wiki-xss)
|
||||
- [Cross-Site Request Forgery](link-wiki-csrf)
|
||||
- [Phishing](link-wiki-phishing)
|
||||
|
||||
|
||||
_subsection: Key Derivation Functions @<security--pbkdf>
|
||||
|
||||
This is not specific to Ethereum, but is a useful technique
|
||||
@@ -51,7 +128,7 @@ progress callback which will be periodically called with a number between
|
||||
In general a progress bar makes the experience feel faster, as well as
|
||||
more comfortable since there is a clear indication how much (relative) time
|
||||
is remaining. Additionally, using language like //"decrypting..."// in
|
||||
a progress bar makes a user feel like there time is not being //needlessly//
|
||||
a progress bar makes a user feel like their time is not being //needlessly//
|
||||
wasted.
|
||||
|
||||
_heading: Work-Arounds (not recommended)
|
||||
|
||||
@@ -117,10 +117,14 @@ const getSourceUrl = (function(path, include, exclude) {
|
||||
}
|
||||
})("../packages/", new RegExp("packages/.*/src.ts/.*\.ts$"), new RegExp("/node_modules/|src.ts/.*browser.*"));
|
||||
|
||||
let localSigner = null;
|
||||
|
||||
function codeContextify(context) {
|
||||
const { inspect } = require("util");
|
||||
const ethers = context.require("./packages/ethers");
|
||||
|
||||
if (localSigner == null) { localSigner = ethers.Wallet.createRandom(); }
|
||||
|
||||
context.ethers = ethers;
|
||||
context.BigNumber = ethers.BigNumber;
|
||||
context.constants = ethers.constants;
|
||||
@@ -133,21 +137,44 @@ function codeContextify(context) {
|
||||
|
||||
// We use a local dev node for some signing examples, but want to
|
||||
// resolve ENS names against mainnet; super hacky but makes the
|
||||
// docs nicer
|
||||
// docs nicer (funded in _startup)
|
||||
context.localProvider = new ethers.providers.JsonRpcProvider();
|
||||
context.localSigner = context.localProvider.getSigner();
|
||||
context.localSigner = localSigner.connect(context.localProvider);
|
||||
context.localProvider.resolveName = context.provider.resolveName.bind(context.provider);
|
||||
|
||||
context.BigNumber.prototype[inspect.custom] = function(depth, options) {
|
||||
return `{ BigNumber: ${JSON.stringify(this.toString()) } }`;
|
||||
}
|
||||
|
||||
context.createClass = function(name) {
|
||||
let C = class{ }
|
||||
Object.defineProperty(C, "name", { value: name })
|
||||
return C;
|
||||
}
|
||||
|
||||
|
||||
context._inspect = function(value, depth) {
|
||||
if (toString.call(value) === '[object Error]') {
|
||||
// Not an error from ethers...
|
||||
if (ethers.utils.Logger.errors[value.code] == null) {
|
||||
return `Error: ${ value.message }`;
|
||||
}
|
||||
|
||||
// Trim the ethers errors down on their verbosity for the docs...
|
||||
if (value.message) {
|
||||
value.message = value.message.split(" (")[0];
|
||||
}
|
||||
value.stack = undefined;
|
||||
}
|
||||
|
||||
if (value && value.constructor && value.constructor.name === "Uint8Array") {
|
||||
return `Uint8Array [ ${ Array.prototype.join.call(value, ", ") } ]`;
|
||||
}
|
||||
|
||||
if (typeof(value) === "string" && value.indexOf("\n") >= 0) {
|
||||
return "`" + value + "`";
|
||||
}
|
||||
|
||||
//return JSON.stringify(value);
|
||||
return inspect(value, {
|
||||
compact: false,
|
||||
@@ -156,12 +183,26 @@ function codeContextify(context) {
|
||||
sorted: true,
|
||||
});
|
||||
}
|
||||
|
||||
context._startup = async function() {
|
||||
console.log("Startup");
|
||||
const signer = context.localProvider.getSigner();
|
||||
const tx = await signer.sendTransaction({
|
||||
to: localSigner.address,
|
||||
value: ethers.utils.parseEther("10.0")
|
||||
});
|
||||
await tx.wait();
|
||||
}
|
||||
|
||||
context._shutdown = function() {
|
||||
console.log("Shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
title: "ethers",
|
||||
subtitle: "v5.2",
|
||||
subtitle: "v5.4",
|
||||
description: "Documentation for ethers, a complete, tiny and simple Ethereum library.",
|
||||
logo: "logo.svg",
|
||||
|
||||
@@ -185,6 +226,7 @@ module.exports = {
|
||||
externalLinks: {
|
||||
"link-mail": "mailto:me@ricmoo.com",
|
||||
"link-alchemy": { name: "Alchemy", url: "https:/\/alchemyapi.io" },
|
||||
"link-ankr": { name: "Ankr", url: "https:/\/www.ankr.com" },
|
||||
"link-cloudflare": { name: "Cloudflare", url: "https:/\/developers.cloudflare.com/distributed-web/ethereum-gateway/" },
|
||||
"link-ens": { name: "ENS", url: "https:/\/ens.domains/" },
|
||||
"link-ethereum": { name: "Ethereum", url: "https:/\/ethereumorg" },
|
||||
@@ -196,7 +238,7 @@ module.exports = {
|
||||
"link-infura": { name: "INFURA", url: "https:/\/infura.io" },
|
||||
"link-javascriptcore": { name: "JavaScriptCore", url: "https:/\/developer.apple.com/documentation/javascriptcore?language=objc" },
|
||||
"link-ledger": "https:/\/www.ledger.com",
|
||||
"link-metamask": { name: "Metamask", url: "https:/\/metamask.io/" },
|
||||
"link-metamask": { name: "MetaMask", url: "https:/\/metamask.io/" },
|
||||
"link-otto": "https:/\/github.com/robertkrimen/otto",
|
||||
"link-parity": { name: "Parity", url: "https:/\/www.parity.io" },
|
||||
"link-pocket": { name: "Pocket Network", url: "https:/\/pokt.network" },
|
||||
@@ -209,6 +251,8 @@ module.exports = {
|
||||
"link-sphinx": { name: "Sphinx", url: "https:/\/www.sphinx-doc.org/" },
|
||||
|
||||
"link-alchemy-signup": "https:/\/dashboard.alchemyapi.io/signup?referral=55a35117-028e-4b7c-9e47-e275ad0acc6d",
|
||||
"link-ankr-public": "https:/\/www.ankr.com/protocol/public/",
|
||||
"link-ankr-premium": "https:/\/www.ankr.com/protocol/plan/",
|
||||
"link-etherscan-signup": "https:/\/etherscan.io/apis",
|
||||
"link-etherscan-ratelimit": "https:/\/info.etherscan.com/api-return-errors/",
|
||||
"link-infura-signup": "https:/\/infura.io/register",
|
||||
@@ -258,6 +302,7 @@ module.exports = {
|
||||
"link-eip-712": { name: "EIP-712", url: "https:/\/eips.ethereum.org/EIPS/eip-712" },
|
||||
"link-eip-1014": { name: "EIP-1014", url: "https:/\/eips.ethereum.org/EIPS/eip-1014" },
|
||||
"link-eip-1193": { name: "EIP-1193", url: "https:/\/eips.ethereum.org/EIPS/eip-1193" },
|
||||
"link-eip-1559": { name: "EIP-1559", url: "https:/\/eips.ethereum.org/EIPS/eip-1559" },
|
||||
"link-eip-1577": { name: "EIP-1577", url: "https:/\/eips.ethereum.org/EIPS/eip-1577" },
|
||||
"link-eip-2098": { name: "EIP-2098", url: "https:/\/eips.ethereum.org/EIPS/eip-2098" },
|
||||
"link-eip-2304": { name: "EIP-2304", url: "https:/\/eips.ethereum.org/EIPS/eip-2304" },
|
||||
@@ -292,12 +337,14 @@ module.exports = {
|
||||
"link-wiki-bloomfilter": { name: "Bloom Filter", url: "https:/\/en.wikipedia.org/wiki/Bloom_filter" },
|
||||
"link-wiki-bruteforce": "https:/\/en.wikipedia.org/wiki/Brute-force_attack",
|
||||
"link-wiki-cryptographichash": "https:/\/en.wikipedia.org/wiki/Cryptographic_hash_function",
|
||||
"link-wiki-csrf": "https:/\/en.wikipedia.org/wiki/Cross-site_request_forgery",
|
||||
"link-wiki-ecrecover": { name: "ECDSA Public Key Recovery", url: "https:/\/en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery" },
|
||||
"link-wiki-homoglyph": "https:/\/en.wikipedia.org/wiki/IDN_homograph_attack",
|
||||
"link-wiki-hmac": "https:/\/en.wikipedia.org/wiki/HMAC",
|
||||
"link-wiki-iban": "https:/\/en.wikipedia.org/wiki/International_Bank_Account_Number",
|
||||
"link-wiki-ieee754": "https:/\/en.wikipedia.org/wiki/Double-precision_floating-point_format",
|
||||
"link-wiki-observer-pattern": { name: "Obeserver Pattern", url: "https:/\/en.wikipedia.org/wiki/Observer_pattern" },
|
||||
"link-wiki-observer-pattern": { name: "Observer Pattern", url: "https:/\/en.wikipedia.org/wiki/Observer_pattern" },
|
||||
"link-wiki-phishing": "https:/\/en.wikipedia.org/wiki/Phishing",
|
||||
"link-wiki-ripemd": "https:/\/en.m.wikipedia.org/wiki/RIPEMD",
|
||||
"link-wiki-sha2": "https:/\/en.wikipedia.org/wiki/SHA-2",
|
||||
"link-wiki-twoscomplement": "https:/\/en.wikipedia.org/wiki/Two%27s_complement",
|
||||
@@ -305,9 +352,11 @@ module.exports = {
|
||||
"link-wiki-utf8-overlong": "https:/\/en.wikipedia.org/wiki/UTF-8#Overlong_encodings",
|
||||
"link-wiki-utf8-replacement": "https:/\/en.wikipedia.org/wiki/Specials_%28Unicode_block%29#Replacement_character",
|
||||
"link-wiki-scrypt": "https:/\/en.wikipedia.org/wiki/Scrypt",
|
||||
"link-wiki-side-channel-attack": "https:/\/en.wikipedia.org/wiki/Side-channel_attack",
|
||||
"link-wiki-sha3": "https:/\/en.wikipedia.org/wiki/SHA-3",
|
||||
"link-wiki-shuffle": { name: "Fisher-Yates Shuffle", url: "https:/\/en.wikipedia.org/wiki/Fisher-Yates_shuffle" },
|
||||
"link-wiki-overflow": { name: "overflow", url: "https:/\/en.wikipedia.org/wiki/Integer_overflow" },
|
||||
"link-wiki-underflow": { name: "arithmetic underflow", url: "https:/\/en.wikipedia.org/wiki/Arithmetic_underflow" },
|
||||
"link-wiki-xss": "https:/\/en.wikipedia.org/wiki/Cross-site_scripting",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ have a public discussion and figure out the best way to address the problem/feat
|
||||
_subsection: Building @<contributing--building>
|
||||
|
||||
The build process for ethers is unfortunatly not super trivial, but
|
||||
I have attempted to make it as straight-forward as possible.
|
||||
I have attempted to make it as straightforward as possible.
|
||||
|
||||
It is a mono-repo which attempts to be compatibile with a large
|
||||
number of environments, build tools and platforms, which is why
|
||||
|
||||
@@ -6,4 +6,5 @@ snippets of code that are in general useful.
|
||||
_toc:
|
||||
|
||||
react-native
|
||||
transactions
|
||||
|
||||
|
||||
24
docs.wrm/cookbook/transactions.wrm
Normal file
24
docs.wrm/cookbook/transactions.wrm
Normal file
@@ -0,0 +1,24 @@
|
||||
_section: Transactions @<cookbook--transactions>
|
||||
|
||||
_subsection: Compute the raw transaction @<cookbook--compute-raw-transaction>
|
||||
|
||||
_code: @lang<javascript>
|
||||
|
||||
function getRawTransaction(tx) {
|
||||
function addKey(accum, key) {
|
||||
if (tx[key]) { accum[key] = tx[key]; }
|
||||
return accum;
|
||||
}
|
||||
|
||||
// Extract the relevant parts of the transaction and signature
|
||||
const txFields = "accessList chainId data gasPrice gasLimit maxFeePerGas maxPriorityFeePerGas nonce to type value".split(" ");
|
||||
const sigFields = "v r s".split(" ");
|
||||
|
||||
// Seriailze the signed transaction
|
||||
const raw = utils.serializeTransaction(txFields.reduce(addKey, { }), sigFields.reduce(addKey, { }));
|
||||
|
||||
// Double check things went well
|
||||
if (utils.keccak256(raw) !== tx.hash) { throw new Error("serializing failed!"); }
|
||||
|
||||
return raw;
|
||||
}
|
||||
@@ -219,58 +219,64 @@ for displaying code samples.
|
||||
|
||||
_heading: JavaScript Evaluation @<flatworm--code-eval>
|
||||
|
||||
For JavaScript files, the file is executed with some simple substitution.
|
||||
For JavaScript files, the file is transpiled and executed in a VM,
|
||||
allowiung output (or exceptions) of blocks to be included in the
|
||||
fragment output.
|
||||
|
||||
A bare ``\/\/!`` on a line is replaced with the result of the last
|
||||
statement. Building will fail if an error is thrown.
|
||||
The entire **code fragment** source is included in an async IIFE,
|
||||
whick means ``await`` is allowed, and several special comment
|
||||
directives are allowed.
|
||||
|
||||
A bare ``\/\/!error`` is replaced with the throw error. Building will
|
||||
fail if an error is not thrown.
|
||||
A ``/\/_hide:`` will include any following code directly into the
|
||||
output, but will not include it in the generated output for the fragment.
|
||||
|
||||
Also any code included between the lines **``\/\/ <hide>``** and
|
||||
**``\/\/ </hide>``** will be omitted from the output, which can be used
|
||||
to setup variables.
|
||||
A ``/\/_log:`` will include the value of any following expression in the
|
||||
output, prefixed with a ``/\/ ``. Renderers will mark output in different
|
||||
style if possible.
|
||||
|
||||
A ``/\/_result:`` will begin a block, assigning the contents to ``_``. The
|
||||
block can be ended with a ``/\/_log:`` or ``/\/_null:``, if no value is given
|
||||
to log, then ``_`` is assumed. If an error occurs, generation fails.
|
||||
|
||||
A ``/\/_throws:`` will begin a block, which is expected to throw assigning
|
||||
the error to ``_``. The block can be ended with a ``/\/_log:`` or ``/\/_null:``,
|
||||
if no value is given to log, then ``_`` is assumed. If an error do not occur,
|
||||
generation fails.
|
||||
|
||||
_code: Code Evaluation Example @lang<text>
|
||||
|
||||
\_code: Result of Code Example @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const url = require("url");
|
||||
// </hide>
|
||||
//_hide: const url = require("url");
|
||||
|
||||
//_result:
|
||||
url.parse("https://www.ricmoo.com/").protocol
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_throws:
|
||||
url.parse(45)
|
||||
//! error
|
||||
//_log:
|
||||
|
||||
// You want to assign (doesn't emit eval) AND display the value
|
||||
const foo = 4 + 5;
|
||||
// <hide>
|
||||
foo
|
||||
// </hide>
|
||||
//!
|
||||
//_log: foo
|
||||
|
||||
|
||||
_code: Result of Code Example @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const url = require("url");
|
||||
// </hide>
|
||||
//_hide: const url = require("url");
|
||||
|
||||
//_result:
|
||||
url.parse("https://www.ricmoo.com/").protocol
|
||||
//!
|
||||
//_log:
|
||||
|
||||
//_throws:
|
||||
url.parse(45)
|
||||
//! error
|
||||
//_log:
|
||||
|
||||
// You want to assign (doesn't emit eval) AND display the value
|
||||
const foo = 4 + 5;
|
||||
// <hide>
|
||||
foo
|
||||
// </hide>
|
||||
//!
|
||||
//_log: foo
|
||||
|
||||
|
||||
_heading: Languages
|
||||
|
||||
@@ -39,14 +39,14 @@ Web Applications from our CDN.
|
||||
_code: ES6 in the Browser @lang<html>
|
||||
|
||||
<script type="module">
|
||||
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.0.esm.min.js";
|
||||
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.2.esm.min.js";
|
||||
// Your code here...
|
||||
</script>
|
||||
|
||||
|
||||
_code: ES3 (UMD) in the Browser @lang<html>
|
||||
|
||||
<script src="https://cdn.ethers.io/lib/ethers-5.0.umd.min.js"
|
||||
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"
|
||||
type="application/javascript"></script>
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ $Contract: A Contract is an abstraction which represents a connection to a
|
||||
| **Contract** | $Contract |
|
||||
|
||||
|
||||
_subsection: Connecting to Ethereum: Metamask @<getting-started--connecting>
|
||||
_subsection: Connecting to Ethereum: MetaMask @<getting-started--connecting>
|
||||
|
||||
The quickest and easiest way to experiment and begin developing on
|
||||
Ethereum is to use [[link-metamask]], which is a browser extension
|
||||
@@ -82,13 +82,16 @@ that provides:
|
||||
- A connection to the Ethereum network (a [[Provider]])
|
||||
- Holds your private key and can sign things (a [[Signer]])
|
||||
|
||||
_code: Connecting to Metamask @lang<script>
|
||||
_code: Connecting to MetaMask @lang<script>
|
||||
|
||||
// A Web3Provider wraps a standard Web3 provider, which is
|
||||
// what Metamask injects as window.ethereum into each page
|
||||
// what MetaMask injects as window.ethereum into each page
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum)
|
||||
|
||||
// The Metamask plugin also allows signing transactions to
|
||||
// MetaMask requires requesting permission to connect users accounts
|
||||
await provider.send("eth_requestAccounts", []);
|
||||
|
||||
// The MetaMask plugin also allows signing transactions to
|
||||
// send ether and pay to change state within the blockchain.
|
||||
// For this, you need the account signer...
|
||||
const signer = provider.getSigner()
|
||||
@@ -123,22 +126,26 @@ logs, look up deployed code and so on.
|
||||
_code: Basic Queries @lang<javascript>
|
||||
|
||||
// Look up the current block number
|
||||
provider.getBlockNumber()
|
||||
//!
|
||||
//_result:
|
||||
await provider.getBlockNumber()
|
||||
//_log:
|
||||
|
||||
// Get the balance of an account (by address or ENS name, if supported by network)
|
||||
//_result:
|
||||
balance = await provider.getBalance("ethers.eth")
|
||||
//! async balance
|
||||
//_log:
|
||||
|
||||
// Often you need to format the output to something more user-friendly,
|
||||
// such as in ether (instead of wei)
|
||||
//_result:
|
||||
ethers.utils.formatEther(balance)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
// If a user enters a string in an input field, you may need
|
||||
// to convert it from ether (as a string) to wei (as a BigNumber)
|
||||
//_result:
|
||||
ethers.utils.parseEther("1.0")
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_heading: Writing to the Blockchain @<getting-started--sending>
|
||||
@@ -204,38 +211,33 @@ const daiAbi = [
|
||||
// The Contract object
|
||||
const daiContract = new ethers.Contract(daiAddress, daiAbi, provider);
|
||||
|
||||
//_hide: _page.daiAbi = daiAbi;
|
||||
//_hide: _page.daiContract = daiContract;
|
||||
|
||||
_heading: Read-Only Methods @<getting-started--reading>
|
||||
|
||||
_code: Querying the DAI Contract @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const daiAbi = [
|
||||
// Some simple details about the token
|
||||
"function name() view returns (string)",
|
||||
"function symbol() view returns (string)",
|
||||
|
||||
// Get the account balance
|
||||
"function balanceOf(address) view returns (uint)",
|
||||
];
|
||||
const daiContract = new ethers.Contract("dai.tokens.ethers.eth", daiAbi, provider);
|
||||
// </hide>
|
||||
//_hide: const daiContract = _page.daiContract;
|
||||
|
||||
// Get the ERC-20 token name
|
||||
daiContract.name()
|
||||
//!
|
||||
//_result:
|
||||
await daiContract.name()
|
||||
//_log:
|
||||
|
||||
// Get the ERC-20 token symbol (for tickers and UIs)
|
||||
daiContract.symbol()
|
||||
//!
|
||||
//_result:
|
||||
await daiContract.symbol()
|
||||
//_log:
|
||||
|
||||
// Get the balance of an address
|
||||
balance = await daiContract.balanceOf("ricmoo.firefly.eth")
|
||||
//! async balance
|
||||
//_log: balance
|
||||
|
||||
// Format the DAI for displaying to the user
|
||||
//_result:
|
||||
ethers.utils.formatUnits(balance, 18)
|
||||
//!
|
||||
//_log:
|
||||
|
||||
|
||||
_heading: State Changing Methods @<getting-started--writing>
|
||||
@@ -258,13 +260,8 @@ _heading: Listening to Events @<getting-started--events>
|
||||
|
||||
_code: Listening to Events @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const daiAbi = [
|
||||
"event Transfer(address indexed, address indexed, uint256)"
|
||||
];
|
||||
const daiContract = new ethers.Contract("dai.tokens.ethers.eth", daiAbi, provider);
|
||||
const formatEther = ethers.utils.formatEther;
|
||||
// </hide>
|
||||
//_hide: const daiContract = _page.daiContract;
|
||||
//_hide: const formatEther = ethers.utils.formatEther;
|
||||
|
||||
// Receive an event when ANY transfer occurs
|
||||
daiContract.on("Transfer", (from, to, amount, event) => {
|
||||
@@ -277,10 +274,7 @@ daiContract.on("Transfer", (from, to, amount, event) => {
|
||||
// A filter for when a specific address receives tokens
|
||||
myAddress = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
|
||||
filter = daiContract.filters.Transfer(null, myAddress)
|
||||
// <hide>
|
||||
filter
|
||||
// </hide>
|
||||
//!
|
||||
//_log: filter
|
||||
|
||||
// Receive an event when that filter occurs
|
||||
daiContract.on(filter, (from, to, amount, event) => {
|
||||
@@ -288,46 +282,32 @@ daiContract.on(filter, (from, to, amount, event) => {
|
||||
console.log(`I got ${ formatEther(amount) } from ${ from }.`);
|
||||
});
|
||||
|
||||
// <hide>
|
||||
// Don't want to block the docs from compiling...
|
||||
daiContract.removeAllListeners();
|
||||
// </hide>
|
||||
//_hide: daiContract.removeAllListeners(); /* Don't want to block the docs from compiling... */
|
||||
|
||||
|
||||
_heading: Query Historic Events @<getting-started--history>
|
||||
|
||||
_code: Filtering Historic Events @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const signer = new ethers.VoidSigner("0x8ba1f109551bD432803012645Ac136ddd64DBA72");
|
||||
const daiAbi = [
|
||||
"event Transfer(address indexed, address indexed, uint256)"
|
||||
];
|
||||
const daiContract = new ethers.Contract("dai.tokens.ethers.eth", daiAbi, provider);
|
||||
//!
|
||||
// </hide>
|
||||
//_hide: const signer = new ethers.VoidSigner("0x8ba1f109551bD432803012645Ac136ddd64DBA72");
|
||||
//_hide: const daiContract = _page.daiContract;
|
||||
|
||||
// Get the address of the Signer
|
||||
myAddress = await signer.getAddress()
|
||||
//! async myAddress
|
||||
//_log: myAddress
|
||||
|
||||
// Filter for all token transfers from me
|
||||
filterFrom = daiContract.filters.Transfer(myAddress, null);
|
||||
// <hide>
|
||||
filterFrom
|
||||
// </hide>
|
||||
//!
|
||||
//_log: filterFrom
|
||||
|
||||
// Filter for all token transfers to me
|
||||
filterTo = daiContract.filters.Transfer(null, myAddress);
|
||||
// <hide>
|
||||
filterTo
|
||||
// </hide>
|
||||
//!
|
||||
//_log: filterTo
|
||||
|
||||
// List all transfers sent from me a specific block range
|
||||
daiContract.queryFilter(filterFrom, 9843470, 9843480)
|
||||
//!
|
||||
// List all transfers sent from me in a specific block range
|
||||
//_result:
|
||||
await daiContract.queryFilter(filterFrom, 9843470, 9843480)
|
||||
//_log:
|
||||
|
||||
//
|
||||
// The following have had the results omitted due to the
|
||||
@@ -335,26 +315,22 @@ daiContract.queryFilter(filterFrom, 9843470, 9843480)
|
||||
//
|
||||
|
||||
// List all transfers sent in the last 10,000 blocks
|
||||
daiContract.queryFilter(filterFrom, -10000)
|
||||
await daiContract.queryFilter(filterFrom, -10000)
|
||||
|
||||
// List all transfers ever sent to me
|
||||
daiContract.queryFilter(filterTo)
|
||||
|
||||
await daiContract.queryFilter(filterTo)
|
||||
|
||||
_subsection: Signing Messages @<getting-started--signing>
|
||||
|
||||
_code: Signing Messages @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const signer = ethers.Wallet.createRandom();
|
||||
//!
|
||||
// </hide>
|
||||
//_hide: const signer = ethers.Wallet.createRandom();
|
||||
|
||||
// To sign a simple string, which are used for
|
||||
// logging into a service, such as CryptoKitties,
|
||||
// pass the string in.
|
||||
signature = await signer.signMessage("Hello World");
|
||||
//! async signature
|
||||
//_log: signature
|
||||
|
||||
//
|
||||
// A common case is also signing a hash, which is 32
|
||||
@@ -367,8 +343,8 @@ message = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
|
||||
|
||||
// This array representation is 32 bytes long
|
||||
messageBytes = ethers.utils.arrayify(message);
|
||||
//!
|
||||
//_log: messageBytes
|
||||
|
||||
// To sign a hash, you most often want to sign the bytes
|
||||
signature = await signer.signMessage(messageBytes)
|
||||
//! async signature
|
||||
//_log: signature
|
||||
|
||||
@@ -69,7 +69,7 @@ signature = await signer.signMessage('Some data')
|
||||
|
||||
_subsection: Contracts
|
||||
|
||||
A contract object is an abstraction of a smart contract on the Ethereum Network. It allows for easy interaction with the smart contact.
|
||||
A contract object is an abstraction of a smart contract on the Ethereum Network. It allows for easy interaction with the smart contract.
|
||||
|
||||
_heading: Deploying a Contract
|
||||
|
||||
|
||||
@@ -14,4 +14,4 @@ _subsection: Tutorials
|
||||
I do not manage or maintain these tutorials, but have happened across them.
|
||||
If a link is dead or outdated, please [let me know](link-mail) and I'll update it.
|
||||
|
||||
- No links yet; send me some
|
||||
- [Alchemy - How to Mint an NFT](https://docs.alchemy.com/alchemy/tutorials/how-to-create-an-nft/how-to-mint-an-nft-with-ethers)
|
||||
|
||||
@@ -151,7 +151,7 @@ This section is still a work in progress, but will outline some of the more nuan
|
||||
aspects of the test cases and their values.
|
||||
|
||||
There will likely be an overhaul of the test cases in the next major version, to
|
||||
make code coverage testing more straight forward and to collapse some of the redundancy.
|
||||
make code coverage testing more straightforward and to collapse some of the redundancy.
|
||||
|
||||
For example, there is no longer a need to separate the ABI and ABIv2 test case and the
|
||||
accounts and transactions suites can be merged into one large collection.
|
||||
|
||||
15
docs.wrm/troubleshooting/building.wrm
Normal file
15
docs.wrm/troubleshooting/building.wrm
Normal file
@@ -0,0 +1,15 @@
|
||||
_section: Building @<troubleshooting-building>
|
||||
|
||||
@TODO
|
||||
|
||||
_subsection: Packages
|
||||
|
||||
Sometimes packages get out of sync.
|
||||
|
||||
_code:
|
||||
|
||||
/home/ethers> rm package-lock.json node_modules/
|
||||
|
||||
/home/ethers> rm yarn.lock
|
||||
|
||||
/home/ethers> npm install
|
||||
249
docs.wrm/troubleshooting/errors.wrm
Normal file
249
docs.wrm/troubleshooting/errors.wrm
Normal file
@@ -0,0 +1,249 @@
|
||||
_section: Error Codes @<error-codes>
|
||||
|
||||
All errors in ethers are created by the [[Logger]] class, which includes
|
||||
a number of additional properties and extra data, which can assist in
|
||||
debugging and when submitting issues.
|
||||
|
||||
When submitting an issue, please include as much of any error as possible,
|
||||
but also make sure you understand the error and have tried suggested solutions
|
||||
both in this trouble-shooting document and any other issues you find when
|
||||
searching the GitHub issues.
|
||||
|
||||
|
||||
_subsection: CALL_EXCEPTION @<help-CALL_EXCEPTION>
|
||||
|
||||
This error occurs when a call or transaction is used to interact with
|
||||
the blockchain reverts (via ``revert``, ``require``, et cetera).
|
||||
|
||||
Due to the overall flexibility of Ethereum and Turing Completeness,
|
||||
there is a large variety of reasons this can occur and troubleshooting
|
||||
requires attention.
|
||||
|
||||
|
||||
_heading: Common Causes
|
||||
|
||||
- The code does not exist on-chain. This may happen if you failed to wait
|
||||
until the contract was deployed, the address is incorrect or if you
|
||||
are connected to a different network than the contract has been deployed.
|
||||
Check the code exists using ``provider.getCode(address)``.
|
||||
- The wrong code is being accessed, for example if an artifact file was
|
||||
not correctly updated so an older instance of the contract is being called
|
||||
- The contract is failing during a ``require`` statement. For example, if
|
||||
a contract method requires an //admin account// to be used, but the
|
||||
contract is connected to another [[Signer]].
|
||||
- The wrong ABI is being used to interact with a contract.
|
||||
|
||||
_heading: Debugging
|
||||
|
||||
- Always double check the address and network you are connected to and use
|
||||
``provider.getCode(address)`` to verify the deployed code matches your
|
||||
most recent version.
|
||||
- Try accessing other, simpler contract methods to verify the account is correct.
|
||||
|
||||
|
||||
_subsection: INSUFFICIENT_FUNDS @<help-INSUFFICIENT_FUNDS>
|
||||
|
||||
This usually occurs when a transaction is attempted, but the sending account
|
||||
does not have enough ether to cover the cost of the transaction.
|
||||
|
||||
A transaction has an intrinsic cost which must be met, which accounts for
|
||||
the value being sent, the base fee of the transaction, additional fees per byte
|
||||
of calldata and whether the transaction will create a new account (i.e. the ``to``
|
||||
is empty).
|
||||
|
||||
This error can also happen if ``provider.estimateGas`` is used with a non-zero
|
||||
fee (i.e. ``gasPrice``, ``maxFeePerGas`` or ``maxPriorityFeePerGas``). If any
|
||||
fee properties are specified, the ``from`` account must have sufficient ether
|
||||
to execute the transaction.
|
||||
|
||||
|
||||
_subsection: MISSING_NEW @<help-MISSING_NEW>
|
||||
|
||||
Classes in ethers must be instantiated with the ``new`` operator. This
|
||||
error indicates that a Class is attempting to be used as a function.
|
||||
|
||||
_code: Examples @lang<javascript>
|
||||
|
||||
//_hide: privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123";
|
||||
//_hide: Wallet = ethers.Wallet;
|
||||
|
||||
// Bad:
|
||||
//_throws:
|
||||
ethers.Wallet(privateKey)
|
||||
//_log:
|
||||
|
||||
// Good:
|
||||
//_result:
|
||||
new ethers.Wallet(privateKey)
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: NONCE_EXPIRED @<help-NONCE_EXPIRED>
|
||||
|
||||
This error occurs when a transaction is being sent with a ``nonce`` that
|
||||
is lower than next required ``nonce``.
|
||||
|
||||
Each Ethereum transaction requires a ``nonce`` property equal to the index
|
||||
of that transaction for that account for all time. So, if an account has
|
||||
send four transactions over its lifetime, that means the nonces 0 though 3
|
||||
(inclusive) have been used. The next transaction must use a nonce of 4.
|
||||
Attempting to re-use a nonce less than 4 will result in this error.
|
||||
|
||||
|
||||
_subsection: NUMERIC_FAULT @<help-NUMERIC_FAULT>
|
||||
|
||||
A [numeric fault](errors--numeric-fault) is a consequence of
|
||||
performing an illegal operation with numeric values, such as
|
||||
dividing by zero.
|
||||
|
||||
The error will indicate the ``operation``, which further indicates
|
||||
the reason for the error.
|
||||
|
||||
|
||||
_heading: Overflow @<help-NUMERIC_FAULT-overflow>
|
||||
|
||||
JavaScript uses [IEEE 754 double-precision binary floating point](link-wiki-ieee754)
|
||||
numbers to represent numeric values. As a result, there are //holes//
|
||||
in the integer set after 9,007,199,254,740,991; which is
|
||||
problematic for //Ethereum// because that is only around 0.009
|
||||
ether (in wei), which means any value over that will begin to
|
||||
experience rounding errors.
|
||||
|
||||
As a result, any attempt to use a number which is outside the safe
|
||||
range, which would result in incorrect values, an error is thrown.
|
||||
|
||||
In general, numbers should be kept as strings, [[BigNumber]] instances or
|
||||
using ES2020 bigints, which all can safely be used without loss of precission.
|
||||
|
||||
_code: Examples @lang<javascript>
|
||||
|
||||
// One ether is outside the safe range
|
||||
//_throws:
|
||||
BigNumber.from(1000000000000000000)
|
||||
//_log:
|
||||
|
||||
// Providing the value as a string is safe
|
||||
//_result:
|
||||
BigNumber.from("1000000000000000000")
|
||||
//_log:
|
||||
|
||||
// As is using a bigint (notice the `n` suffix)
|
||||
//_result:
|
||||
BigNumber.from(1000000000000000000n)
|
||||
//_log:
|
||||
|
||||
// But most often, the `parseEther` function solves this
|
||||
//_result:
|
||||
utils.parseEther("1.0")
|
||||
//_log:
|
||||
|
||||
|
||||
_heading: Numeric Underflow @<help-NUMERIC_FAULT-underflow>
|
||||
|
||||
Numeric underflow sbould not be confused with overflow.
|
||||
|
||||
Numeric underflow occurs when the precission of a value cannot be
|
||||
safely represented in the current data type.
|
||||
|
||||
**Common Causes**
|
||||
|
||||
- Using values with fractional componets (e.g. ``BigNumber.from(1.2)``).
|
||||
If you require fractions, you must use the [[FixedNumber]] class.
|
||||
- Parsing string values that have more decimals than the unit supports
|
||||
(e.g. ``parseUints("1.33", 1)``).
|
||||
|
||||
_code: Examples @lang<javascript>
|
||||
|
||||
// BigNumbers cannot be created with a fractional component
|
||||
//_throws:
|
||||
BigNumber.from(1.2)
|
||||
//_log:
|
||||
|
||||
// Parsing a value with more decimals than the type
|
||||
//_throws:
|
||||
utils.parseUnits("1.34", 1);
|
||||
//_log:
|
||||
|
||||
|
||||
_heading: Division by zero @<help-NUMERIC_FAULT-division-by-zero>
|
||||
|
||||
This error occurs when dividing by zero or attempting to take the modulo zero.
|
||||
|
||||
|
||||
_heading: Unbound Result @<help-NUMERIC_FAULT-unbound-result>
|
||||
|
||||
The ethers [[BigNumber]] does not support bitwise operators
|
||||
on negative numbers which can result in the need for an infinite
|
||||
number of set bits.
|
||||
|
||||
Other implementations may use negative values to indicate this,
|
||||
but this is considered out of scope for ethers.
|
||||
|
||||
|
||||
_heading: Unsupported Operation @<help-NUMERIC_FAULT-unsupported>
|
||||
|
||||
The ethers [[BigNumber]] does not support negative powers or bitwise
|
||||
shift operation using negative values.
|
||||
|
||||
_code: Examples @lang<javascript>
|
||||
|
||||
two = BigNumber.from(2);
|
||||
|
||||
//_throws:
|
||||
two.pow(-2)
|
||||
//_log:
|
||||
|
||||
// Cannot use negative values to alter shift direction
|
||||
//_throws:
|
||||
two.shr(-1)
|
||||
//_log:
|
||||
|
||||
|
||||
_subsection: REPLACEMENT_UNDERPRICED @<help-REPLACEMENT_UNDERPRICED>
|
||||
|
||||
To prevent nodes from being overloaded with junk transactions, a transaction
|
||||
is only accepted into the memory pool if it has a reasonable chance of being
|
||||
actually mined, which means that the account has sufficient balance, the nonce
|
||||
is correct and the fee seems reasonable.
|
||||
|
||||
Once a transaction is in the memory pool though, to prevent an account from
|
||||
flooding the network with many different transactions with the same nonce (each
|
||||
of which satisfies the above criteria), to replace an existing transaction
|
||||
an additional committment of a fee must be made by increasing the promised fee.
|
||||
|
||||
When replacing a legacy non-EIP1559 transaction, the ``gasPrice`` must be
|
||||
increased. When replacing a modern, EIP-1559 transaction, the ``maxPriorityFeePerGas``
|
||||
should be increased.
|
||||
|
||||
|
||||
_subsection: TRANSACTION_REPLACED @<help-TRANSACTION_REPLACED>
|
||||
|
||||
This error is thrown when waiting for a transaction which has been
|
||||
replaced by another, by the sender submitting a second transaction
|
||||
with the same nonce, while the transaction was pending in the
|
||||
transaction pool.
|
||||
|
||||
You can learn more about this feature in the ``.wait`` method of
|
||||
[TransactionResponse](providers-TransactionResponse).
|
||||
|
||||
|
||||
_subsection: UNPREDICTABLE_GAS_LIMIT @<help-UNPREDICTABLE_GAS_LIMIT>
|
||||
|
||||
During gas estimation it is possible that a transaction would actually
|
||||
fail (and hence has no reasonable estimate of gas requirements) or that
|
||||
the transaction is complex in a way that does not permit a node to
|
||||
estiamte the gas requirements, in which case this error is thrown.
|
||||
|
||||
In almost all cases, this will unfortunately require you specify an
|
||||
explicit ``gasLimit`` for your transaction, which will disable ether's
|
||||
automatic population of the ``gasLimit`` field, which will cause this
|
||||
error to go away.
|
||||
|
||||
To dial in an appropriate gas limit, try a value that is much higher
|
||||
than you expect, and then make a few transactions to discover reasonable
|
||||
values and then you can reduce this value down to that ballpark.
|
||||
|
||||
Keep in mind this error can also occur if the transaction would
|
||||
legitimately fail, in which case the root cause must be addressed, such
|
||||
as ensuring the correct [[Signer]] is being used, the appropriate allowance
|
||||
for an ERC-20 token has been approved, etc.
|
||||
62
docs.wrm/troubleshooting/help.wrm
Normal file
62
docs.wrm/troubleshooting/help.wrm
Normal file
@@ -0,0 +1,62 @@
|
||||
_section: Getting Help @<troubleshooting-issues>
|
||||
|
||||
@TODO
|
||||
|
||||
_subsection: Starting a discussion
|
||||
|
||||
Before opening an issue
|
||||
|
||||
|
||||
_subsection: Opening an Issue
|
||||
|
||||
Keep in mind that opening an issue should be a last resort, as it
|
||||
requires time and energy by the library developers to look at that
|
||||
could otherwise be spent on improving the library, documentation
|
||||
and tools.
|
||||
|
||||
Before opening an issue, please make sure you have searched any
|
||||
public information, such as:
|
||||
|
||||
- Documentation
|
||||
- GitHub Discussions
|
||||
- GitHub Issues (including closed issues)
|
||||
|
||||
There are several types of issues tracked by ethers. Using the correct
|
||||
one helps you receive feedback quicker and helps us keep the right
|
||||
person
|
||||
|
||||
_heading: Feature Requests
|
||||
|
||||
|
||||
|
||||
_heading: Bugs
|
||||
|
||||
This type of issue is for anything you you believe to be a bug in ethers.
|
||||
|
||||
Keep in mind that ethers is used extensively by thousands of people every
|
||||
day, so while chances are possible you found a bug, please make sure to
|
||||
do your due diligence to rule out user error.
|
||||
|
||||
If you are new to ethers, or are doing a fairly common operation, it is
|
||||
quite likely what you are experiencing is a misunderstanding of how to
|
||||
use a function, method or class. You should consider opening a discussion first.
|
||||
|
||||
|
||||
Please make sure you include as much information as is useful:
|
||||
|
||||
- Are you using a third-party library, like Hardhat or Truffle?
|
||||
- What platform are you on, a web browser, React Native, node, etc.?
|
||||
- What network are you on, such as Ethereum mainnet, Optimism, etc.?
|
||||
- What backend are you using, such as Geth, INFURA, Provider Engine, etc.?
|
||||
|
||||
|
||||
_heading: Docuementation
|
||||
|
||||
If you have found a typo in the documentation, a feature which isn't
|
||||
documented (or documented well) or just find something described in
|
||||
the documentation confusing, please feel free to create an issue and
|
||||
we will try to improve it.
|
||||
|
||||
_heading: Other
|
||||
|
||||
This should never be used.
|
||||
11
docs.wrm/troubleshooting/index.wrm
Normal file
11
docs.wrm/troubleshooting/index.wrm
Normal file
@@ -0,0 +1,11 @@
|
||||
_section: TroubleShooting
|
||||
|
||||
|
||||
|
||||
_toc:
|
||||
building
|
||||
errors
|
||||
network
|
||||
help
|
||||
|
||||
_subsection: About Trbouble-Shooting
|
||||
9
docs.wrm/troubleshooting/network.wrm
Normal file
9
docs.wrm/troubleshooting/network.wrm
Normal file
@@ -0,0 +1,9 @@
|
||||
_section: Troubleshooting Network @<troubleshooting-network>
|
||||
|
||||
@TODO
|
||||
|
||||
_subsection: Links
|
||||
|
||||
_subsection: Cross-Origin Resource Sharing (CORS)
|
||||
|
||||
_subsection: Mobile Development (Device Firewalls)
|
||||
@@ -35,7 +35,12 @@ module.exports = function(config) {
|
||||
// Cloudflare will block (on the testnet endpoints) any traffic
|
||||
// from a headless chome (based on the user agent), so we lie
|
||||
// This was take from Safari, because that is what I had on-hand
|
||||
'--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15']
|
||||
'--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15',
|
||||
|
||||
// https://stackoverflow.com/questions/58484124/karma-disconnectedreconnect-failed-before-timeout-of-with-chromeheadless
|
||||
'--disable-gpu',
|
||||
'--no-sandbox'
|
||||
],
|
||||
}
|
||||
},
|
||||
/*
|
||||
|
||||
@@ -36,7 +36,12 @@ module.exports = function(config) {
|
||||
// Cloudflare will block (on the testnet endpoints) any traffic
|
||||
// from a headless chome (based on the user agent), so we lie
|
||||
// This was take from Safari, because that is what I had on-hand
|
||||
'--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15']
|
||||
'--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15',
|
||||
|
||||
// https://stackoverflow.com/questions/58484124/karma-disconnectedreconnect-failed-before-timeout-of-with-chromeheadless
|
||||
'--disable-gpu',
|
||||
'--no-sandbox'
|
||||
]
|
||||
}
|
||||
},
|
||||
/*
|
||||
|
||||
@@ -5,23 +5,23 @@ const path_1 = require("./path");
|
||||
const utils_1 = require("./utils");
|
||||
function setupConfig(outDir, moduleType, targetType) {
|
||||
// Configure the tsconfit.package.json...
|
||||
const path = path_1.resolve("tsconfig.package.json");
|
||||
const content = utils_1.loadJson(path);
|
||||
const path = (0, path_1.resolve)("tsconfig.package.json");
|
||||
const content = (0, utils_1.loadJson)(path);
|
||||
content.compilerOptions.module = moduleType;
|
||||
content.compilerOptions.target = targetType;
|
||||
utils_1.saveJson(path, content, true);
|
||||
(0, utils_1.saveJson)(path, content, true);
|
||||
// Configure the browser field for every pacakge, copying the
|
||||
// browser.umd filed for UMD and browser.esm for ESM
|
||||
path_1.dirnames.forEach((dirname) => {
|
||||
const filename = path_1.getPackageJsonPath(dirname);
|
||||
const info = utils_1.loadJson(filename);
|
||||
const filename = (0, path_1.getPackageJsonPath)(dirname);
|
||||
const info = (0, utils_1.loadJson)(filename);
|
||||
if (info._ethers_nobuild) {
|
||||
return;
|
||||
}
|
||||
let path = path_1.resolve("packages", dirname, "tsconfig.json");
|
||||
let content = utils_1.loadJson(path);
|
||||
let path = (0, path_1.resolve)("packages", dirname, "tsconfig.json");
|
||||
let content = (0, utils_1.loadJson)(path);
|
||||
content.compilerOptions.outDir = outDir;
|
||||
utils_1.saveJson(path, content, true);
|
||||
(0, utils_1.saveJson)(path, content, true);
|
||||
});
|
||||
}
|
||||
function setupBuild(buildModule) {
|
||||
|
||||
@@ -39,7 +39,7 @@ const npm = __importStar(require("./npm"));
|
||||
const path_1 = require("./path");
|
||||
const run_1 = require("./run");
|
||||
const utils_1 = require("./utils");
|
||||
const changelogPath = path_1.resolve("CHANGELOG.md");
|
||||
const changelogPath = (0, path_1.resolve)("CHANGELOG.md");
|
||||
function generate() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const lines = fs_1.default.readFileSync(changelogPath).toString().trim().split("\n");
|
||||
@@ -59,11 +59,11 @@ function generate() {
|
||||
const published = yield npm.getPackage("ethers");
|
||||
if (versions.indexOf(version) >= 0) {
|
||||
const line = `Version ${version} already in CHANGELOG. Please edit before committing.`;
|
||||
console.log(log_1.colorify.red(utils_1.repeat("=", line.length)));
|
||||
console.log(log_1.colorify.red((0, utils_1.repeat)("=", line.length)));
|
||||
console.log(log_1.colorify.red(line));
|
||||
console.log(log_1.colorify.red(utils_1.repeat("=", line.length)));
|
||||
console.log(log_1.colorify.red((0, utils_1.repeat)("=", line.length)));
|
||||
}
|
||||
const gitResult = yield run_1.run("git", ["log", (published.gitHead + "..")]);
|
||||
const gitResult = yield (0, run_1.run)("git", ["log", (published.gitHead + "..")]);
|
||||
if (!gitResult.ok) {
|
||||
console.log(gitResult);
|
||||
throw new Error("Error running git log");
|
||||
@@ -78,7 +78,7 @@ function generate() {
|
||||
});
|
||||
}
|
||||
else if (line.toLowerCase().substring(0, 5) === "date:") {
|
||||
changes[changes.length - 1].date = utils_1.getDateTime(new Date(line.substring(5).trim()));
|
||||
changes[changes.length - 1].date = (0, utils_1.getDateTime)(new Date(line.substring(5).trim()));
|
||||
}
|
||||
else if (line.substring(0, 1) === " ") {
|
||||
line = line.trim();
|
||||
@@ -92,9 +92,9 @@ function generate() {
|
||||
for (let i = 0; i < firstLine; i++) {
|
||||
output.push(lines[i]);
|
||||
}
|
||||
const newTitle = `ethers/v${version} (${utils_1.getDateTime(new Date())})`;
|
||||
const newTitle = `ethers/v${version} (${(0, utils_1.getDateTime)(new Date())})`;
|
||||
output.push(newTitle);
|
||||
output.push(utils_1.repeat("-", newTitle.length));
|
||||
output.push((0, utils_1.repeat)("-", newTitle.length));
|
||||
output.push("");
|
||||
changes.forEach((change) => {
|
||||
let body = change.body.trim();
|
||||
|
||||
@@ -65,7 +65,7 @@ const path_1 = require("../path");
|
||||
accum[name] = version;
|
||||
return accum;
|
||||
}, {});
|
||||
const packageJsonPath = path_1.getPackageJsonPath(dirname);
|
||||
const packageJsonPath = (0, path_1.getPackageJsonPath)(dirname);
|
||||
local.updateJson(packageJsonPath, {
|
||||
dependencies: deps,
|
||||
version: newVersion
|
||||
|
||||
@@ -40,8 +40,8 @@ const npm = __importStar(require("../npm"));
|
||||
const utils_1 = require("../utils");
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const common = utils_1.loadJson(path_1.resolve("package.json")).common;
|
||||
const progress = log_1.getProgressBar(log_1.colorify.bold("Bumping package.json versions"));
|
||||
const common = (0, utils_1.loadJson)((0, path_1.resolve)("package.json")).common;
|
||||
const progress = (0, log_1.getProgressBar)(log_1.colorify.bold("Bumping package.json versions"));
|
||||
const latestVersions = {};
|
||||
let updated = false;
|
||||
const output = [];
|
||||
@@ -49,7 +49,7 @@ const utils_1 = require("../utils");
|
||||
for (let i = 0; i < path_1.dirnames.length; i++) {
|
||||
progress(i / path_1.dirnames.length);
|
||||
const dirname = path_1.dirnames[i];
|
||||
const packageJsonPath = path_1.getPackageJsonPath(dirname);
|
||||
const packageJsonPath = (0, path_1.getPackageJsonPath)(dirname);
|
||||
// Set the common elements to the package.json
|
||||
local.updateJson(packageJsonPath, common, true);
|
||||
const pLocal = local.getPackage(dirname);
|
||||
@@ -68,7 +68,7 @@ const utils_1 = require("../utils");
|
||||
output.push([
|
||||
" ",
|
||||
log_1.colorify.blue(pLocal.name),
|
||||
utils_1.repeat(" ", 47 - pLocal.name.length - pNpm.version.length),
|
||||
(0, utils_1.repeat)(" ", 47 - pLocal.name.length - pNpm.version.length),
|
||||
pNpm.version,
|
||||
log_1.colorify.bold(" => "),
|
||||
log_1.colorify.green(version)
|
||||
@@ -80,13 +80,13 @@ const utils_1 = require("../utils");
|
||||
// Write out the _version.ts
|
||||
if (!pLocal._ethers_nobuild) {
|
||||
const code = "export const version = " + JSON.stringify(dirname + "/" + version) + ";\n";
|
||||
fs_1.default.writeFileSync(path_1.resolve(path_1.getPackagePath(dirname), "src.ts/_version.ts"), code);
|
||||
fs_1.default.writeFileSync((0, path_1.resolve)((0, path_1.getPackagePath)(dirname), "src.ts/_version.ts"), code);
|
||||
}
|
||||
}
|
||||
progress(1);
|
||||
if (updated) {
|
||||
const filename = path_1.resolve("packages/ethers/package.json");
|
||||
const info = utils_1.loadJson(filename);
|
||||
const filename = (0, path_1.resolve)("packages/ethers/package.json");
|
||||
const info = (0, utils_1.loadJson)(filename);
|
||||
Object.keys(info.dependencies).forEach((name) => {
|
||||
const version = latestVersions[name];
|
||||
if (name == null) {
|
||||
@@ -94,7 +94,7 @@ const utils_1 = require("../utils");
|
||||
}
|
||||
info.dependencies[name] = version;
|
||||
});
|
||||
utils_1.saveJson(filename, info);
|
||||
(0, utils_1.saveJson)(filename, info);
|
||||
}
|
||||
output.forEach((line) => { console.log(line); });
|
||||
});
|
||||
|
||||
@@ -38,10 +38,10 @@ const config = {
|
||||
console.log(log_1.colorify.bold(`Bundling Testcase Data...`));
|
||||
const data = { "_": JSON.stringify({ name: "browser-fs", config: config }) };
|
||||
config.dirs.forEach((dirname) => {
|
||||
let fulldirname = path_2.resolve("packages/testcases", dirname);
|
||||
let fulldirname = (0, path_2.resolve)("packages/testcases", dirname);
|
||||
fs_1.default.readdirSync(fulldirname).forEach((filename) => {
|
||||
const key = path_1.join(dirname, filename);
|
||||
const content = fs_1.default.readFileSync(path_1.join(fulldirname, filename));
|
||||
const key = (0, path_1.join)(dirname, filename);
|
||||
const content = fs_1.default.readFileSync((0, path_1.join)(fulldirname, filename));
|
||||
if (filename.split(".").pop() === "gz") {
|
||||
const contentData = zlib_1.default.gunzipSync(content);
|
||||
data[key] = String(contentData.length) + "," + zlib_1.default.deflateRawSync(contentData).toString("base64");
|
||||
@@ -52,15 +52,15 @@ const config = {
|
||||
//console.log(` - Added ${ key } (${ data[key].length } bytes)`);
|
||||
});
|
||||
});
|
||||
utils_1.mkdir(path_2.resolve("packages/testcases/lib"));
|
||||
utils_1.mkdir(path_2.resolve("packages/testcases/lib._esm"));
|
||||
utils_1.mkdir(path_2.resolve("packages/testcases/lib.esm"));
|
||||
(0, utils_1.mkdir)((0, path_2.resolve)("packages/testcases/lib"));
|
||||
(0, utils_1.mkdir)((0, path_2.resolve)("packages/testcases/lib._esm"));
|
||||
(0, utils_1.mkdir)((0, path_2.resolve)("packages/testcases/lib.esm"));
|
||||
// We write it out to all needed places
|
||||
fs_1.default.writeFileSync(path_2.resolve("packages/testcases/lib/browser-data.json"), JSON.stringify(data));
|
||||
fs_1.default.writeFileSync(path_2.resolve("packages/testcases/lib._esm/browser-data.json"), JSON.stringify(data));
|
||||
fs_1.default.writeFileSync(path_2.resolve("packages/testcases/lib.esm/browser-data.json"), JSON.stringify(data));
|
||||
fs_1.default.writeFileSync((0, path_2.resolve)("packages/testcases/lib/browser-data.json"), JSON.stringify(data));
|
||||
fs_1.default.writeFileSync((0, path_2.resolve)("packages/testcases/lib._esm/browser-data.json"), JSON.stringify(data));
|
||||
fs_1.default.writeFileSync((0, path_2.resolve)("packages/testcases/lib.esm/browser-data.json"), JSON.stringify(data));
|
||||
// Write it to the TypeScript source last, in case it is running it will
|
||||
// be regenerated overwriting the above files, but with identical content
|
||||
fs_1.default.writeFileSync(path_2.resolve("packages/testcases/src.ts/browser-data.json"), JSON.stringify(data));
|
||||
fs_1.default.writeFileSync((0, path_2.resolve)("packages/testcases/src.ts/browser-data.json"), JSON.stringify(data));
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -15,6 +15,6 @@ const github_1 = require("../github");
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const user = yield config_1.config.get("github-user");
|
||||
const password = yield config_1.config.get("github-readonly");
|
||||
yield github_1.syncIssues(user, password);
|
||||
yield (0, github_1.syncIssues)(user, password);
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -24,8 +24,8 @@ const log_1 = require("../log");
|
||||
function alias(name) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log(` Aliasing: ${name}`);
|
||||
const baseDir = path_2.resolve("packages", name);
|
||||
const info = utils_1.loadJson(path_2.resolve(baseDir, "package.json"));
|
||||
const baseDir = (0, path_2.resolve)("packages", name);
|
||||
const info = (0, utils_1.loadJson)((0, path_2.resolve)(baseDir, "package.json"));
|
||||
const replacements = info["_ethers.alias"] || {};
|
||||
const skip = Object.keys(replacements).reduce((accum, key) => {
|
||||
const replace = replacements[key];
|
||||
@@ -37,10 +37,10 @@ function alias(name) {
|
||||
}, ({}));
|
||||
const transforms = [];
|
||||
const recurse = function (input, output) {
|
||||
fs_1.default.readdirSync(path_1.join(baseDir, input)).forEach((filename) => {
|
||||
const stat = fs_1.default.statSync(path_1.join(baseDir, input, filename));
|
||||
fs_1.default.readdirSync((0, path_1.join)(baseDir, input)).forEach((filename) => {
|
||||
const stat = fs_1.default.statSync((0, path_1.join)(baseDir, input, filename));
|
||||
if (stat.isDirectory()) {
|
||||
recurse(path_1.join(input, filename), path_1.join(output, filename));
|
||||
recurse((0, path_1.join)(input, filename), (0, path_1.join)(output, filename));
|
||||
return;
|
||||
}
|
||||
if (skip[filename]) {
|
||||
@@ -61,7 +61,7 @@ function alias(name) {
|
||||
if (replace) {
|
||||
inputFilename = replace;
|
||||
transform = function (content) {
|
||||
content = content.replace(/(\/\/# sourceMappingURL=)(.*)$/g, (all, prefix, mapFilename) => {
|
||||
content = content.replace(/^(\/\/# sourceMappingURL=)(.*)$/mg, (all, prefix, mapFilename) => {
|
||||
return prefix + filename + ".map";
|
||||
});
|
||||
return content;
|
||||
@@ -118,19 +118,19 @@ function alias(name) {
|
||||
};
|
||||
}
|
||||
}
|
||||
transforms.push({ input: path_1.join(input, inputFilename), output: path_1.join(output, filename), transform });
|
||||
transforms.push({ input: (0, path_1.join)(input, inputFilename), output: (0, path_1.join)(output, filename), transform });
|
||||
});
|
||||
};
|
||||
recurse("lib._esm", "lib.esm");
|
||||
transforms.forEach(({ input, output, transform }) => {
|
||||
const sourceFile = path_1.join(baseDir, input);
|
||||
const sourceFile = (0, path_1.join)(baseDir, input);
|
||||
let content = fs_1.default.readFileSync(sourceFile).toString();
|
||||
if (transform) {
|
||||
content = transform(content);
|
||||
}
|
||||
const targetFile = path_1.join(baseDir, output);
|
||||
const targetDir = path_1.dirname(targetFile);
|
||||
utils_1.mkdir(targetDir);
|
||||
const targetFile = (0, path_1.join)(baseDir, output);
|
||||
const targetDir = (0, path_1.dirname)(targetFile);
|
||||
(0, utils_1.mkdir)(targetDir);
|
||||
fs_1.default.writeFileSync(targetFile, content);
|
||||
});
|
||||
});
|
||||
@@ -138,9 +138,9 @@ function alias(name) {
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log(log_1.colorify.bold(`Aliasing Node ESM to Browser ESM...`));
|
||||
const dirnames = depgraph_1.getOrdered(true);
|
||||
const dirnames = (0, depgraph_1.getOrdered)(true);
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
//if (dirnames[i] !== "base64") { continue; }
|
||||
//if (dirnames[i] !== "signing-key") { continue; }
|
||||
yield alias(dirnames[i]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,11 +14,11 @@ const local_1 = require("../local");
|
||||
const log_1 = require("../log");
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const dependencies = local_1.getDependencies(null, (name) => {
|
||||
return !path_1.isEthers(name);
|
||||
const dependencies = (0, local_1.getDependencies)(null, (name) => {
|
||||
return !(0, path_1.isEthers)(name);
|
||||
});
|
||||
console.log(log_1.colorify.bold(`Hoisting ${Object.keys(dependencies).length} dependencies into root package...`));
|
||||
local_1.updateJson(path_1.dirs.rootPackageJsonPath, { dependencies });
|
||||
(0, local_1.updateJson)(path_1.dirs.rootPackageJsonPath, { dependencies });
|
||||
});
|
||||
})().catch((error) => {
|
||||
console.log(`Error running ${process.argv[0]}: ${error.message}`);
|
||||
|
||||
@@ -33,28 +33,28 @@ function link(existing, path) {
|
||||
}
|
||||
}
|
||||
// Link
|
||||
const dir = path_1.dirname(path);
|
||||
utils_1.mkdir(dir);
|
||||
const dir = (0, path_1.dirname)(path);
|
||||
(0, utils_1.mkdir)(dir);
|
||||
fs_1.default.symlinkSync(existing, path, "junction");
|
||||
}
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log(log_1.colorify.bold(`Linking ${path_2.packages.length} package node_modules rat nests...`));
|
||||
const nodeModulesBase = path_1.resolve(path_2.dirs.root, ".package_node_modules");
|
||||
const nodeModulesBase = (0, path_1.resolve)(path_2.dirs.root, ".package_node_modules");
|
||||
// Make a symlink in the ROOT/node_mpdules to each package in this repo
|
||||
path_2.packages.forEach((name) => {
|
||||
// e.g. /node_modules/@ethersproject/abi => /packages/abi
|
||||
link(path_2.getPackagePath(name), path_1.resolve(path_2.dirs.root, "node_modules", name));
|
||||
link((0, path_2.getPackagePath)(name), (0, path_1.resolve)(path_2.dirs.root, "node_modules", name));
|
||||
// e.g. /packages/abi/node_modules => /.package_node_modules/abi/
|
||||
const nodeModules = path_1.resolve(nodeModulesBase, path_2.getDirname(name));
|
||||
utils_1.mkdir(nodeModules);
|
||||
link(nodeModules, path_1.resolve(path_2.getPackagePath(name), "node_modules"));
|
||||
const nodeModules = (0, path_1.resolve)(nodeModulesBase, (0, path_2.getDirname)(name));
|
||||
(0, utils_1.mkdir)(nodeModules);
|
||||
link(nodeModules, (0, path_1.resolve)((0, path_2.getPackagePath)(name), "node_modules"));
|
||||
});
|
||||
path_2.packages.forEach((name) => {
|
||||
const nodeModules = path_1.resolve(nodeModulesBase, path_2.getDirname(name));
|
||||
const deps = local_1.getDependencies(name);
|
||||
const nodeModules = (0, path_1.resolve)(nodeModulesBase, (0, path_2.getDirname)(name));
|
||||
const deps = (0, local_1.getDependencies)(name);
|
||||
Object.keys(deps).forEach((name) => {
|
||||
link(path_1.resolve(path_2.dirs.root, "node_modules", name), path_1.resolve(nodeModules, name));
|
||||
link((0, path_1.resolve)(path_2.dirs.root, "node_modules", name), (0, path_1.resolve)(nodeModules, name));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ const utils_1 = require("../utils");
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const versions = path_1.dirnames.reduce((accum, dirname) => {
|
||||
const pkg = local_1.getPackage(dirname);
|
||||
const pkg = (0, local_1.getPackage)(dirname);
|
||||
accum[pkg.name] = pkg.version;
|
||||
return accum;
|
||||
}, ({}));
|
||||
@@ -25,8 +25,8 @@ const utils_1 = require("../utils");
|
||||
return;
|
||||
}
|
||||
console.log(dirname);
|
||||
const path = path_1.resolve("packages", dirname, "package.json");
|
||||
const json = utils_1.loadJson(path);
|
||||
const path = (0, path_1.resolve)("packages", dirname, "package.json");
|
||||
const json = (0, utils_1.loadJson)(path);
|
||||
for (const name in (json.dependencies || {})) {
|
||||
const version = json.dependencies[name];
|
||||
const target = (versions[name] ? ("^" + versions[name]) : version);
|
||||
@@ -35,7 +35,7 @@ const utils_1 = require("../utils");
|
||||
}
|
||||
json.dependencies[name] = target;
|
||||
}
|
||||
utils_1.saveJson(path, json, true);
|
||||
(0, utils_1.saveJson)(path, json, true);
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
0
misc/admin/lib/cmds/peg-version.d.ts
vendored
Normal file
0
misc/admin/lib/cmds/peg-version.d.ts
vendored
Normal file
16
misc/admin/lib/cmds/peg-version.js
Normal file
16
misc/admin/lib/cmds/peg-version.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
import { dirnames, getPackage } from "../local";
|
||||
import { colorify } from "../log";
|
||||
|
||||
const dirname = process.argv[2];
|
||||
if (dirname == null) {
|
||||
console.log("Usage: peg-version DIRNAME");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
(async function(dirname) {
|
||||
const { name, version } = getPackage(dirname);
|
||||
console.log(colorify.bold(`Pegging ${ name } to ${ version }...`));
|
||||
|
||||
})(dirname);
|
||||
*/
|
||||
@@ -89,10 +89,10 @@ function invalidate(cloudfront, distributionId) {
|
||||
exports.invalidate = invalidate;
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const dirnames = depgraph_1.getOrdered();
|
||||
const dirnames = (0, depgraph_1.getOrdered)();
|
||||
// @TODO: Fail if there are any untracked files or unchecked in files
|
||||
const publish = {};
|
||||
const progressUpdate = log_1.getProgressBar(log_1.colorify.bold("Finding updated packages..."));
|
||||
const progressUpdate = (0, log_1.getProgressBar)(log_1.colorify.bold("Finding updated packages..."));
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
progressUpdate(i / dirnames.length);
|
||||
let dirname = dirnames[i];
|
||||
@@ -103,8 +103,8 @@ exports.invalidate = invalidate;
|
||||
continue;
|
||||
}
|
||||
// Get the latest commit this package was modified at
|
||||
const path = path_1.resolve("packages", dirname);
|
||||
const gitHead = yield git_1.getGitTag(path);
|
||||
const path = (0, path_1.resolve)("packages", dirname);
|
||||
const gitHead = yield (0, git_1.getGitTag)(path);
|
||||
if (gitHead == null) {
|
||||
throw new Error("hmmm...");
|
||||
}
|
||||
@@ -119,7 +119,7 @@ exports.invalidate = invalidate;
|
||||
console.log(log_1.colorify.bold(`Found ${Object.keys(publish).length} updated pacakges...`));
|
||||
Object.keys(publish).forEach((dirname) => {
|
||||
const info = publish[dirname];
|
||||
console.log(` ${log_1.colorify.blue(info.name)} ${utils_1.repeat(" ", 50 - info.name.length - info.oldVersion.length)} ${info.oldVersion} ${log_1.colorify.bold("=>")} ${log_1.colorify.green(info.newVersion)}`);
|
||||
console.log(` ${log_1.colorify.blue(info.name)} ${(0, utils_1.repeat)(" ", 50 - info.name.length - info.oldVersion.length)} ${info.oldVersion} ${log_1.colorify.bold("=>")} ${log_1.colorify.green(info.newVersion)}`);
|
||||
});
|
||||
const publishNames = Object.keys(publish);
|
||||
publishNames.sort((a, b) => (dirnames.indexOf(a) - dirnames.indexOf(b)));
|
||||
@@ -149,17 +149,17 @@ exports.invalidate = invalidate;
|
||||
console.log(log_1.colorify.bold("Publishing:"));
|
||||
for (let i = 0; i < publishNames.length; i++) {
|
||||
const dirname = publishNames[i];
|
||||
const path = path_1.resolve("packages", dirname);
|
||||
const pathJson = path_1.resolve("packages", dirname, "package.json");
|
||||
const path = (0, path_1.resolve)("packages", dirname);
|
||||
const pathJson = (0, path_1.resolve)("packages", dirname, "package.json");
|
||||
const { gitHead, name, newVersion } = publish[dirname];
|
||||
console.log(` ${log_1.colorify.blue(name)} @ ${log_1.colorify.green(newVersion)}`);
|
||||
local.updateJson(pathJson, { gitHead: gitHead }, true);
|
||||
const info = utils_1.loadJson(pathJson);
|
||||
const info = (0, utils_1.loadJson)(pathJson);
|
||||
yield npm.publish(path, info, options);
|
||||
local.updateJson(pathJson, { gitHead: undefined }, true);
|
||||
}
|
||||
if (publishNames.indexOf("ethers") >= 0 || forcePublish) {
|
||||
const change = changelog_1.getLatestChange();
|
||||
const change = (0, changelog_1.getLatestChange)();
|
||||
const patchVersion = change.version.substring(1);
|
||||
const minorVersion = patchVersion.split(".").slice(0, 2).join(".");
|
||||
const awsAccessId = yield config_1.config.get("aws-upload-scripts-accesskey");
|
||||
@@ -169,8 +169,8 @@ exports.invalidate = invalidate;
|
||||
// The password above already succeeded
|
||||
const username = yield config_1.config.get("github-user");
|
||||
const password = yield config_1.config.get("github-release");
|
||||
const hash = createHash("sha384").update(fs_1.default.readFileSync(path_1.resolve("packages/ethers/dist/ethers.umd.min.js"))).digest("base64");
|
||||
const gitCommit = yield git_1.getGitTag(path_1.resolve("CHANGELOG.md"));
|
||||
const hash = createHash("sha384").update(fs_1.default.readFileSync((0, path_1.resolve)("packages/ethers/dist/ethers.umd.min.js"))).digest("base64");
|
||||
const gitCommit = yield (0, git_1.getGitTag)((0, path_1.resolve)("CHANGELOG.md"));
|
||||
let content = change.content.trim();
|
||||
content += '\n\n----\n\n';
|
||||
content += '**Embedding UMD with [SRI](https:/\/developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity):**\n';
|
||||
@@ -183,7 +183,7 @@ exports.invalidate = invalidate;
|
||||
content += '```';
|
||||
// Publish the release
|
||||
const beta = false;
|
||||
const link = yield github_1.createRelease(username, password, change.version, change.title, content, beta, gitCommit);
|
||||
const link = yield (0, github_1.createRelease)(username, password, change.version, change.title, content, beta, gitCommit);
|
||||
console.log(`${log_1.colorify.bold("Published release:")} ${link}`);
|
||||
}
|
||||
// Upload libs to the CDN (as ethers-v5.1 and ethers-5.1.x)
|
||||
@@ -244,7 +244,7 @@ exports.invalidate = invalidate;
|
||||
const { bucketName, originRoot, filename, key, suffix } = fileInfos[i];
|
||||
yield putObject(s3, {
|
||||
ACL: "public-read",
|
||||
Body: fs_1.default.readFileSync(path_1.resolve(filename)),
|
||||
Body: fs_1.default.readFileSync((0, path_1.resolve)(filename)),
|
||||
Bucket: bucketName,
|
||||
ContentType: "application/javascript; charset=utf-8",
|
||||
Key: (originRoot + key)
|
||||
|
||||
@@ -42,8 +42,8 @@ function start(root, options) {
|
||||
if (options.port == null) {
|
||||
options.port = 8000;
|
||||
}
|
||||
root = path_1.resolve(root);
|
||||
const server = http_1.createServer((req, resp) => {
|
||||
root = (0, path_1.resolve)(root);
|
||||
const server = (0, http_1.createServer)((req, resp) => {
|
||||
const url = req.url.split("?")[0];
|
||||
// Follow redirects in options
|
||||
if (options.redirects && options.redirects[url]) {
|
||||
@@ -51,7 +51,7 @@ function start(root, options) {
|
||||
resp.end();
|
||||
return;
|
||||
}
|
||||
let filename = path_1.resolve(root, "." + url);
|
||||
let filename = (0, path_1.resolve)(root, "." + url);
|
||||
// Make sure we aren't crawling out of our sandbox
|
||||
if (url[0] !== "/" || filename.substring(0, filename.length) !== filename) {
|
||||
resp.writeHead(403);
|
||||
@@ -94,7 +94,7 @@ function start(root, options) {
|
||||
return server;
|
||||
}
|
||||
exports.start = start;
|
||||
start(path_2.resolve("docs"), {
|
||||
start((0, path_2.resolve)("docs"), {
|
||||
redirects: {
|
||||
"/": "/v5/"
|
||||
}
|
||||
|
||||
@@ -19,19 +19,19 @@ const utils_1 = require("../utils");
|
||||
console.log(log_1.colorify.bold("Setting Option:"), arg);
|
||||
switch (arg) {
|
||||
case "esm":
|
||||
build_1.setupBuild(true);
|
||||
(0, build_1.setupBuild)(true);
|
||||
break;
|
||||
case "cjs":
|
||||
build_1.setupBuild(false);
|
||||
(0, build_1.setupBuild)(false);
|
||||
break;
|
||||
// This will remove the browser field entirely, so make sure
|
||||
// to set esm of cjs first as they will restore the browser
|
||||
// field
|
||||
case "browser-lang-all": {
|
||||
const filename = path_1.getPackageJsonPath("wordlists");
|
||||
const info = utils_1.loadJson(filename);
|
||||
const filename = (0, path_1.getPackageJsonPath)("wordlists");
|
||||
const info = (0, utils_1.loadJson)(filename);
|
||||
delete info.browser;
|
||||
utils_1.saveJson(filename, info, true);
|
||||
(0, utils_1.saveJson)(filename, info, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -18,7 +18,7 @@ if (process.argv.length !== 3) {
|
||||
const key = process.argv[2];
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const value = yield log_1.getPassword("Value: ");
|
||||
const value = yield (0, log_1.getPassword)("Value: ");
|
||||
yield config_1.config.set(key, value);
|
||||
});
|
||||
})().catch((error) => {
|
||||
|
||||
@@ -16,7 +16,7 @@ const fs_1 = __importDefault(require("fs"));
|
||||
const path_1 = require("../path");
|
||||
const utils_1 = require("../utils");
|
||||
function copy(src, dst, transform) {
|
||||
let data = fs_1.default.readFileSync(path_1.resolve(src));
|
||||
let data = fs_1.default.readFileSync((0, path_1.resolve)(src));
|
||||
if (transform) {
|
||||
data = Buffer.from(transform(data.toString()));
|
||||
}
|
||||
@@ -24,14 +24,14 @@ function copy(src, dst, transform) {
|
||||
}
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
yield utils_1.mkdir(path_1.resolve("output/karma"));
|
||||
copy(path_1.resolve("packages/ethers/dist/ethers.esm.js"), path_1.resolve("output/karma/ethers.esm.js"));
|
||||
copy(path_1.resolve("packages/tests/dist/tests.esm.js"), path_1.resolve("output/karma/tests.esm.js"), (data) => {
|
||||
yield (0, utils_1.mkdir)((0, path_1.resolve)("output/karma"));
|
||||
copy((0, path_1.resolve)("packages/ethers/dist/ethers.esm.js"), (0, path_1.resolve)("output/karma/ethers.esm.js"));
|
||||
copy((0, path_1.resolve)("packages/tests/dist/tests.esm.js"), (0, path_1.resolve)("output/karma/tests.esm.js"), (data) => {
|
||||
return data.replace(/^(import [^;]* from ')(ethers)(';)/, (all, prefix, id, suffix) => {
|
||||
return prefix + "./ethers.esm.js" + suffix;
|
||||
});
|
||||
});
|
||||
copy(path_1.resolve("packages/ethers/dist/ethers.umd.js"), path_1.resolve("output/karma/ethers.umd.js"));
|
||||
copy(path_1.resolve("packages/tests/dist/tests.umd.js"), path_1.resolve("output/karma/tests.umd.js"));
|
||||
copy((0, path_1.resolve)("packages/ethers/dist/ethers.umd.js"), (0, path_1.resolve)("output/karma/ethers.umd.js"));
|
||||
copy((0, path_1.resolve)("packages/tests/dist/tests.umd.js"), (0, path_1.resolve)("output/karma/tests.umd.js"));
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -22,18 +22,18 @@ const Words = fs_1.default.readFileSync("/usr/share/dict/words").toString().spli
|
||||
}, {});
|
||||
`
|
||||
// Words missing from the dictionary
|
||||
accessing addresses aligned autofill called cancelled changed censored
|
||||
clamping compiled computed configured consumed creating decoded decoding
|
||||
accessing addresses aligned autofill avatar called cancelled changed censored
|
||||
clamping compiled computed configured consumed contained creating decoded decoding
|
||||
decreased decrypt decrypted decrypting deployed deploying deprecated detected
|
||||
discontinued earliest email enabled encoded encoder encoding encrypt
|
||||
encrypted encrypting entries euro exceeded existing expected
|
||||
discontinued earliest email emitted enabled encoded encoder encoding encountered
|
||||
encrypt encrypted encrypting entries euro exceeded existing expected
|
||||
expired failed fetches formatted formatting funding generated
|
||||
hardened has highly ignoring implemented implementer imported including instantiate
|
||||
joined keyword labelled larger lookup matches mined modified modifies multi
|
||||
named needed nested neutered numeric offline optimizer overriding owned packed
|
||||
padded parsed parsing passed payload placeholder processing properties prototyping reached
|
||||
recommended recovered redacted remaining replaced required reverted
|
||||
serializes shared signed signing skipped stored supported tagging targetted
|
||||
recommended recovered recursively redacted remaining replaced repriced required reverted
|
||||
serializes shared signed signing skipped stats stored supported tagging targetted
|
||||
throttled transactions typed uninstall unstake unsubscribe untyped
|
||||
using verifies verifying website
|
||||
|
||||
@@ -41,7 +41,7 @@ using verifies verifying website
|
||||
bech BIP BIP39 BIP44 btc bzz crypto eip etc hashes hmac icap
|
||||
keccak ltc namehash ripemd RLP scrypt secp sha xdai
|
||||
|
||||
blockhash
|
||||
blockhash bnb bnbt ethprice matic txlist
|
||||
|
||||
bitcoin ethereum finney gwei kwei mwei satoshi szabo wei weth
|
||||
|
||||
@@ -56,15 +56,15 @@ ABIEncoder testcase numberish Wordlist
|
||||
|
||||
// Common Code Strings
|
||||
abi addr api app arg arrayify asm backend basex bigint bignumber bn byte
|
||||
bytecode callback calldata charset checksum ciphertext cli codepoint
|
||||
bytecode callback calldata ccip charset checksum ciphertext cli codepoint
|
||||
commify config
|
||||
contenthash ctr ctrl debug dd dklen eexist encseed eof eq ethaddr
|
||||
contenthash ctr ctrl debug dd dklen eexist encseed eof eq erc ethaddr
|
||||
ethseed ethers eval exec filename func gz gzip hid http https hw iv
|
||||
info init ipc json kdf kdfparams labelhash lang lib mm multihash nfc
|
||||
nfkc nfd nfkd nodehash notok nowait nullish oob opcode pbkdf pc plugin
|
||||
info init ipc json kdf kdfparams labelhash lang lib metadata mm multihash nfc
|
||||
nfkc nfd nfkd nodehash notok nowait nullish offchain oob opcode org pbkdf pc plugin
|
||||
pragma pre prf recid repl rpc sighash topichash solc stdin stdout subclasses
|
||||
subnode timeout todo txt typeof ufixed utc utf util url urlencoded uuid vm
|
||||
vs websocket wikipedia www wx xe xpriv xpub xx yyyy zlib
|
||||
vs websocket wikipedia wildcard wildcards www wx xe xpriv xpub xx yyyy zlib
|
||||
|
||||
// AbiV2
|
||||
abiv
|
||||
@@ -72,13 +72,14 @@ abiv
|
||||
// Query parameters
|
||||
apikey asc endblock startblock
|
||||
|
||||
alchemyapi Cloudflare Etherscan INFURA IPFS MetaMask Nodesmith
|
||||
alchemyapi ankr arbitrum Cloudflare com Etherscan INFURA IPFS IPNS MetaMask Nodesmith
|
||||
Trezor ledgerhq axic bitcoinjs browserify easyseed ethereumjs
|
||||
goerli homestead kotti kovan mainnet morden mordor rinkeby
|
||||
ropsten testnet lb
|
||||
goerli homestead kotti kovan mainnet morden mordor rinkeby kintsugi
|
||||
ropsten testnet lb maticmum
|
||||
|
||||
// Demo words
|
||||
args foo eth foo foobar ll localhost passwd ricmoo tx xxx yna
|
||||
brantly ricmoose
|
||||
|
||||
// nameprep tags
|
||||
ALCat BiDi LCat nameprep
|
||||
@@ -129,7 +130,7 @@ function getStrings(source) {
|
||||
const Include = new RegExp("packages/.*/src.ts/.*\.ts$");
|
||||
const Exclude = new RegExp("/node_modules/|src.ts/.*browser.*");
|
||||
function getAllStrings(path) {
|
||||
const Root = path_1.resolve(__dirname, path);
|
||||
const Root = (0, path_1.resolve)(__dirname, path);
|
||||
const readdir = function (path) {
|
||||
if (path.match(Exclude)) {
|
||||
return [];
|
||||
@@ -137,7 +138,7 @@ function getAllStrings(path) {
|
||||
const stat = fs_1.default.statSync(path);
|
||||
if (stat.isDirectory()) {
|
||||
return fs_1.default.readdirSync(path).reduce((result, filename) => {
|
||||
readdir(path_1.resolve(path, filename)).forEach((file) => {
|
||||
readdir((0, path_1.resolve)(path, filename)).forEach((file) => {
|
||||
result.push(file);
|
||||
});
|
||||
return result;
|
||||
@@ -174,7 +175,7 @@ function starts(text, prefix) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log(log_1.colorify.bold("Spell checking source code strings..."));
|
||||
let count = 0;
|
||||
getAllStrings(path_1.resolve(__dirname, "../../../../packages")).forEach((file) => {
|
||||
getAllStrings((0, path_1.resolve)(__dirname, "../../../../packages")).forEach((file) => {
|
||||
if (starts(file.filename, "/testcases/src.ts/generation-scripts")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,6 @@ const path_1 = require("../path");
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
console.log(log_1.colorify.bold("Updating CHANGELOG.md..."));
|
||||
fs_1.default.writeFileSync(path_1.resolve("CHANGELOG.md"), yield changelog_1.generate());
|
||||
fs_1.default.writeFileSync((0, path_1.resolve)("CHANGELOG.md"), yield (0, changelog_1.generate)());
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -14,8 +14,8 @@ const path_1 = require("../path");
|
||||
const local_1 = require("../local");
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const ordered = depgraph_1.getOrdered(true);
|
||||
local_1.updateJson(path_1.resolve("tsconfig.project.json"), {
|
||||
const ordered = (0, depgraph_1.getOrdered)(true);
|
||||
(0, local_1.updateJson)((0, path_1.resolve)("tsconfig.project.json"), {
|
||||
references: ordered.map((name) => ({ path: ("./packages/" + name) }))
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const log_1 = require("../log");
|
||||
const path_1 = require("../path");
|
||||
const sourceEthers = fs_1.default.readFileSync(path_1.resolve("packages/ethers/src.ts/ethers.ts")).toString();
|
||||
const sourceEthers = fs_1.default.readFileSync((0, path_1.resolve)("packages/ethers/src.ts/ethers.ts")).toString();
|
||||
const targets = sourceEthers.match(/export\s*{\s*((.|\s)*)}/)[1].trim();
|
||||
////////////////////
|
||||
// Begin template
|
||||
@@ -35,4 +35,4 @@ export {
|
||||
// End template
|
||||
////////////////////
|
||||
console.log(log_1.colorify.bold(`Flattening exports...`));
|
||||
fs_1.default.writeFileSync(path_1.resolve("packages/ethers/src.ts/index.ts"), output);
|
||||
fs_1.default.writeFileSync((0, path_1.resolve)("packages/ethers/src.ts/index.ts"), output);
|
||||
|
||||
@@ -14,14 +14,14 @@ const log_1 = require("../log");
|
||||
const path_1 = require("../path");
|
||||
(function () {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const progress = log_1.getProgressBar(log_1.colorify.bold("Updating package.json hashes"));
|
||||
const progress = (0, log_1.getProgressBar)(log_1.colorify.bold("Updating package.json hashes"));
|
||||
// Updating all tarball hashes now that versions have been updated
|
||||
for (let i = 0; i < path_1.dirnames.length; i++) {
|
||||
progress(i / path_1.dirnames.length);
|
||||
const dirname = path_1.dirnames[i];
|
||||
//const gitHead = await getGitTag(resolve("packages", dirname));
|
||||
const tarballHash = local_1.computeTarballHash(dirname);
|
||||
local_1.updateJson(path_1.getPackageJsonPath(dirname), { tarballHash }, true);
|
||||
const tarballHash = (0, local_1.computeTarballHash)(dirname);
|
||||
(0, local_1.updateJson)((0, path_1.getPackageJsonPath)(dirname), { tarballHash }, true);
|
||||
}
|
||||
progress(1);
|
||||
});
|
||||
|
||||
@@ -116,7 +116,7 @@ function _getFiles(result, root) {
|
||||
if (filename === '.DS_Store') {
|
||||
return;
|
||||
}
|
||||
const fullFilename = path_1.join(root, filename);
|
||||
const fullFilename = (0, path_1.join)(root, filename);
|
||||
const stat = fs_1.default.statSync(fullFilename);
|
||||
if (stat.isDirectory()) {
|
||||
_getFiles(result, fullFilename);
|
||||
@@ -150,7 +150,7 @@ function getFiles(basedir) {
|
||||
secretAccessKey: awsSecretKey
|
||||
});
|
||||
const added = [], removed = [], changed = [], upload = [];
|
||||
const basedir = path_2.resolve("docs");
|
||||
const basedir = (0, path_2.resolve)("docs");
|
||||
const local = yield getFiles(basedir);
|
||||
const remote = yield getKeys(s3, bucket);
|
||||
Object.keys(local).forEach((filename) => {
|
||||
@@ -177,7 +177,7 @@ function getFiles(basedir) {
|
||||
console.log('Changed: ', changed.length);
|
||||
for (let i = 0; i < upload.length; i++) {
|
||||
const filename = upload[i];
|
||||
const content = fs_1.default.readFileSync(path_1.join(basedir, filename));
|
||||
const content = fs_1.default.readFileSync((0, path_1.join)(basedir, filename));
|
||||
console.log(`Uploading: ${filename} (${content.length} bytes)`);
|
||||
yield putObject(s3, bucket, filename, content);
|
||||
}
|
||||
|
||||
@@ -22,15 +22,15 @@ const scrypt_js_1 = __importDefault(require("scrypt-js"));
|
||||
const log_1 = require("./log");
|
||||
function getRandomBytes(length) {
|
||||
const result = new Uint8Array(length);
|
||||
result.set(crypto_1.randomBytes(length));
|
||||
result.set((0, crypto_1.randomBytes)(length));
|
||||
return result;
|
||||
}
|
||||
function computeHmac(key, data) {
|
||||
return "0x" + crypto_1.createHmac("sha512", key).update(data).digest("hex");
|
||||
return "0x" + (0, crypto_1.createHmac)("sha512", key).update(data).digest("hex");
|
||||
}
|
||||
function getScrypt(message, password, salt) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const progress = log_1.getProgressBar(message);
|
||||
const progress = (0, log_1.getProgressBar)(message);
|
||||
return yield scrypt_js_1.default.scrypt(Buffer.from(password), Buffer.from(salt), (1 << 17), 8, 1, 64, progress);
|
||||
});
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class Config {
|
||||
}
|
||||
this.canary = data.canary || "";
|
||||
this.salt = data.salt;
|
||||
const password = yield log_1.getPassword(log_1.colorify.bold("Password (config-store): "));
|
||||
const password = yield (0, log_1.getPassword)(log_1.colorify.bold("Password (config-store): "));
|
||||
this.dkey = yield getScrypt(log_1.colorify.bold("Unlocking config"), password, this.salt);
|
||||
if (data.ciphertext) {
|
||||
const ciphertext = Buffer.from(data.ciphertext, "base64");
|
||||
@@ -113,7 +113,7 @@ class Config {
|
||||
this.salt = this.dkey = null;
|
||||
}
|
||||
}
|
||||
const _config = new Config(path_1.resolve(os_1.default.homedir(), ".ethers-dist"));
|
||||
const _config = new Config((0, path_1.resolve)(os_1.default.homedir(), ".ethers-dist"));
|
||||
exports.config = {
|
||||
get: function (key) {
|
||||
return _config.get(key);
|
||||
|
||||
@@ -47,7 +47,7 @@ function getOrdered(skipNobuild) {
|
||||
};
|
||||
for (let i = 0; i < path_1.dirnames.length; i++) {
|
||||
let dirname = path_1.dirnames[i];
|
||||
let info = local_1.getPackage(dirname);
|
||||
let info = (0, local_1.getPackage)(dirname);
|
||||
if (skipNobuild && info._ethers_nobuild) {
|
||||
continue;
|
||||
}
|
||||
@@ -91,8 +91,8 @@ exports.getOrdered = getOrdered;
|
||||
function sort(dirnames) {
|
||||
let ordered = getOrdered();
|
||||
dirnames.sort((a, b) => {
|
||||
let ai = ordered.indexOf(local_1.getPackage(a).name);
|
||||
let bi = ordered.indexOf(local_1.getPackage(b).name);
|
||||
let ai = ordered.indexOf((0, local_1.getPackage)(a).name);
|
||||
let bi = ordered.indexOf((0, local_1.getPackage)(b).name);
|
||||
if (ai === -1 || bi === -1) {
|
||||
throw new Error("unknown dirname - " + [a, b].join(", "));
|
||||
}
|
||||
|
||||
@@ -73,9 +73,9 @@ function _getUrl(href, options) {
|
||||
options = {};
|
||||
}
|
||||
// @TODO: Once we drop support for node 8, we can pass the href
|
||||
// firectly into request and skip adding the components
|
||||
// directly into request and skip adding the components
|
||||
// to this request object
|
||||
const url = url_1.parse(href);
|
||||
const url = (0, url_1.parse)(href);
|
||||
const request = {
|
||||
protocol: nonnull(url.protocol),
|
||||
hostname: nonnull(url.hostname),
|
||||
|
||||
@@ -14,7 +14,7 @@ const run_1 = require("./run");
|
||||
// Returns the most recent git commit hash for a given filename
|
||||
function getGitTag(filename) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const result = yield run_1.run("git", ["log", "-n", "1", "--", filename]);
|
||||
const result = yield (0, run_1.run)("git", ["log", "-n", "1", "--", filename]);
|
||||
if (!result.ok) {
|
||||
throw new Error(`git log error`);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ function _fetchGitHub(user, password, getUrlFunc, url) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const result = [];
|
||||
while (true) {
|
||||
const filename = path_1.resolve("github-cache", Buffer.from(js_sha3_1.keccak_256.create().update(Buffer.from(url)).digest()).toString("hex").substring(0, 12));
|
||||
const filename = (0, path_1.resolve)("github-cache", Buffer.from(js_sha3_1.keccak_256.create().update(Buffer.from(url)).digest()).toString("hex").substring(0, 12));
|
||||
const headers = {
|
||||
"User-Agent": "ethers-io",
|
||||
};
|
||||
@@ -41,7 +41,7 @@ function _fetchGitHub(user, password, getUrlFunc, url) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const response = yield geturl_1.getUrl(url, { headers, user, password });
|
||||
const response = yield (0, geturl_1.getUrl)(url, { headers, user, password });
|
||||
console.log(response.statusCode);
|
||||
// Cached response is good; use it!
|
||||
if (response.statusCode !== 304) {
|
||||
@@ -129,7 +129,7 @@ function syncIssues(user, password) {
|
||||
exports.syncIssues = syncIssues;
|
||||
function createRelease(user, password, tagName, title, body, prerelease, commit) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const result = yield geturl_1.getUrl("https:/\/api.github.com/repos/ethers-io/ethers.js/releases", {
|
||||
const result = yield (0, geturl_1.getUrl)("https:/\/api.github.com/repos/ethers-io/ethers.js/releases", {
|
||||
body: Buffer.from(JSON.stringify({
|
||||
tag_name: tagName,
|
||||
target_commitish: (commit || "master"),
|
||||
|
||||
@@ -9,7 +9,7 @@ const path_1 = require("./path");
|
||||
const run_1 = require("./run");
|
||||
const utils_1 = require("./utils");
|
||||
function getPackage(name) {
|
||||
const value = utils_1.loadJson(path_1.getPackageJsonPath(name));
|
||||
const value = (0, utils_1.loadJson)((0, path_1.getPackageJsonPath)(name));
|
||||
return {
|
||||
name: value.name,
|
||||
version: value.version,
|
||||
@@ -23,7 +23,7 @@ function getPackage(name) {
|
||||
}
|
||||
exports.getPackage = getPackage;
|
||||
function updateJson(path, replace, sort) {
|
||||
const values = utils_1.loadJson(path);
|
||||
const values = (0, utils_1.loadJson)(path);
|
||||
Object.keys(replace).forEach((key) => {
|
||||
const value = replace[key];
|
||||
if (value === undefined) {
|
||||
@@ -33,12 +33,12 @@ function updateJson(path, replace, sort) {
|
||||
values[key] = replace[key];
|
||||
}
|
||||
});
|
||||
utils_1.saveJson(path, values, !!sort);
|
||||
(0, utils_1.saveJson)(path, values, !!sort);
|
||||
}
|
||||
exports.updateJson = updateJson;
|
||||
function getDependencies(name, filter) {
|
||||
if (name) {
|
||||
return utils_1.sortRecords(getPackage(name).dependencies);
|
||||
return (0, utils_1.sortRecords)(getPackage(name).dependencies);
|
||||
}
|
||||
// Find all versions for each package dependency
|
||||
const deps = path_1.dirnames.reduce((accum, dirname) => {
|
||||
@@ -55,7 +55,7 @@ function getDependencies(name, filter) {
|
||||
return accum;
|
||||
}, {});
|
||||
// Make sure each package dependency only has 1 version
|
||||
return utils_1.sortRecords(Object.keys(deps).reduce((accum, name) => {
|
||||
return (0, utils_1.sortRecords)(Object.keys(deps).reduce((accum, name) => {
|
||||
const versions = Object.keys(deps[name]);
|
||||
if (versions.length > 1) {
|
||||
throw new Error(`cannot depend on multiple versions for ${JSON.stringify(name)}: ${versions.map(v => JSON.stringify(v)).join(", ")}`);
|
||||
@@ -66,7 +66,7 @@ function getDependencies(name, filter) {
|
||||
}
|
||||
exports.getDependencies = getDependencies;
|
||||
function getPackList(name) {
|
||||
const result = run_1.run("npm", ["pack", "--json", path_1.getPackagePath(name), "--dry-run"]);
|
||||
const result = (0, run_1.run)("npm", ["pack", "--json", (0, path_1.getPackagePath)(name), "--dry-run"]);
|
||||
if (!result.ok) {
|
||||
const error = new Error(`failed to run npm pack: ${name}`);
|
||||
error.result = result;
|
||||
@@ -118,9 +118,9 @@ function computeTarballHash(name) {
|
||||
const files = getPackList(name);
|
||||
files.sort();
|
||||
// Compute the hash for each file
|
||||
const packageRoot = path_1.getPackagePath(name);
|
||||
const packageRoot = (0, path_1.getPackagePath)(name);
|
||||
const hashes = files.reduce((accum, filename) => {
|
||||
let content = fs_1.default.readFileSync(path_1.resolve(packageRoot, filename));
|
||||
let content = fs_1.default.readFileSync((0, path_1.resolve)(packageRoot, filename));
|
||||
// The package.json includes the hash, so we need to nix it to get a consistent hash
|
||||
if (filename === "package.json") {
|
||||
const info = JSON.parse(content.toString());
|
||||
@@ -128,10 +128,10 @@ function computeTarballHash(name) {
|
||||
delete info.tarballHash;
|
||||
content = Buffer.from(JSON.stringify(info, null, 2));
|
||||
}
|
||||
accum[filename] = utils_1.sha256(content);
|
||||
accum[filename] = (0, utils_1.sha256)(content);
|
||||
return accum;
|
||||
}, {});
|
||||
return utils_1.sha256(Buffer.from("{" + files.map((filename) => {
|
||||
return (0, utils_1.sha256)(Buffer.from("{" + files.map((filename) => {
|
||||
return `${JSON.stringify(filename)}:"${hashes[filename]}"`;
|
||||
}).join(",") + "}"));
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ function _getPrompt(prompt, options, callback) {
|
||||
(process.stdout).clearLine();
|
||||
(process.stdout).cursorTo(0);
|
||||
if (options.mask) {
|
||||
process.stdout.write(prompt + utils_1.repeat(options.mask, message.length));
|
||||
process.stdout.write(prompt + (0, utils_1.repeat)(options.mask, message.length));
|
||||
}
|
||||
else {
|
||||
process.stdout.write(prompt + message);
|
||||
|
||||
@@ -22,10 +22,10 @@ const cache = {};
|
||||
function getPackageInfo(name) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
// Convert dirname to package if needed
|
||||
name = local_1.getPackage(name).name;
|
||||
name = (0, local_1.getPackage)(name).name;
|
||||
if (!cache[name]) {
|
||||
try {
|
||||
const result = yield geturl_1.getUrl("http:/" + "/registry.npmjs.org/" + name);
|
||||
const result = yield (0, geturl_1.getUrl)("https:/\/registry.npmjs.org/" + name);
|
||||
cache[name] = JSON.parse(Buffer.from(result.body).toString("utf8"));
|
||||
}
|
||||
catch (error) {
|
||||
@@ -47,7 +47,11 @@ function getPackage(name, version) {
|
||||
if (version == null) {
|
||||
const versions = Object.keys(infos.versions);
|
||||
versions.sort(semver_1.default.compare);
|
||||
version = versions.pop();
|
||||
// HACK: So v5 continues working while v6 is managed by reticulate
|
||||
version = "6.0.0";
|
||||
while (version.indexOf("beta") >= 0 || semver_1.default.gte(version, "6.0.0")) {
|
||||
version = versions.pop();
|
||||
}
|
||||
}
|
||||
const info = infos.versions[version];
|
||||
return {
|
||||
@@ -66,12 +70,12 @@ exports.getPackage = getPackage;
|
||||
function publish(path, manifest, options) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
yield libnpmpublish_1.publish(path, manifest, options);
|
||||
yield (0, libnpmpublish_1.publish)(path, manifest, options);
|
||||
}
|
||||
catch (error) {
|
||||
// We need an OTP
|
||||
if (error.code === "EOTP") {
|
||||
const otp = yield log_1.getPrompt(log_1.colorify.bold("Enter OTP: "));
|
||||
const otp = yield (0, log_1.getPrompt)(log_1.colorify.bold("Enter OTP: "));
|
||||
options.otp = otp.replace(" ", "");
|
||||
// Retry with the new OTP
|
||||
return yield publish(path, manifest, options);
|
||||
|
||||
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isEthers = exports.getPackageJsonPath = exports.getDirname = exports.getPackagePath = exports.packages = exports.dirnames = exports.dirs = exports.resolve = exports.root = void 0;
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const path_1 = require("path");
|
||||
exports.root = path_1.resolve(__dirname, "../../../");
|
||||
exports.root = (0, path_1.resolve)(__dirname, "../../../");
|
||||
function resolve(...args) {
|
||||
args.unshift(exports.root);
|
||||
return path_1.resolve.apply(null, args);
|
||||
@@ -23,8 +23,8 @@ exports.dirnames = Object.freeze(fs_1.default.readdirSync(exports.dirs.packages)
|
||||
return (dirname[0] !== ".");
|
||||
}));
|
||||
const packageLookup = exports.dirnames.reduce((accum, dirname) => {
|
||||
const packagePath = path_1.resolve(exports.dirs.packages, dirname);
|
||||
const packageJsonPath = path_1.resolve(packagePath, "package.json");
|
||||
const packagePath = (0, path_1.resolve)(exports.dirs.packages, dirname);
|
||||
const packageJsonPath = (0, path_1.resolve)(packagePath, "package.json");
|
||||
const info = JSON.parse(fs_1.default.readFileSync(packageJsonPath).toString());
|
||||
const packageName = info.name;
|
||||
const version = info.version;
|
||||
|
||||
@@ -10,7 +10,7 @@ function run(progname, args, currentWorkingDirectory) {
|
||||
if (currentWorkingDirectory) {
|
||||
options.cwd = currentWorkingDirectory;
|
||||
}
|
||||
const child = child_process_1.spawnSync(progname, args, options);
|
||||
const child = (0, child_process_1.spawnSync)(progname, args, options);
|
||||
const result = {
|
||||
_stderr: child.stderr,
|
||||
stderr: (child.stderr.toString() || null),
|
||||
|
||||
@@ -28,7 +28,7 @@ function repeat(char, length) {
|
||||
}
|
||||
exports.repeat = repeat;
|
||||
function sha256(content) {
|
||||
const hasher = crypto_1.createHash("sha256");
|
||||
const hasher = (0, crypto_1.createHash)("sha256");
|
||||
hasher.update(content);
|
||||
return "0x" + hasher.digest("hex");
|
||||
}
|
||||
@@ -43,7 +43,7 @@ function sortRecords(record) {
|
||||
}
|
||||
exports.sortRecords = sortRecords;
|
||||
function atomicWrite(path, value) {
|
||||
const tmp = path_1.resolve(__dirname, "../../../.atomic-tmp");
|
||||
const tmp = (0, path_1.resolve)(__dirname, "../../../.atomic-tmp");
|
||||
fs_1.default.writeFileSync(tmp, value);
|
||||
fs_1.default.renameSync(tmp, path);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ function mkdir(path) {
|
||||
break;
|
||||
}
|
||||
dirs.push(path);
|
||||
path = path_1.dirname(path);
|
||||
path = (0, path_1.dirname)(path);
|
||||
}
|
||||
while (dirs.length) {
|
||||
fs_1.default.mkdirSync(dirs.pop());
|
||||
|
||||
@@ -52,7 +52,7 @@ async function alias(name: string): Promise<void> {
|
||||
if (replace) {
|
||||
inputFilename = replace;
|
||||
transform = function(content: string) {
|
||||
content = content.replace(/(\/\/# sourceMappingURL=)(.*)$/g, (all, prefix, mapFilename) => {
|
||||
content = content.replace(/^(\/\/# sourceMappingURL=)(.*)$/mg, (all, prefix, mapFilename) => {
|
||||
return prefix + filename + ".map";
|
||||
});
|
||||
return content;
|
||||
@@ -132,7 +132,7 @@ async function alias(name: string): Promise<void> {
|
||||
console.log(colorify.bold(`Aliasing Node ESM to Browser ESM...`));
|
||||
const dirnames = getOrdered(true);
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
//if (dirnames[i] !== "base64") { continue; }
|
||||
//if (dirnames[i] !== "signing-key") { continue; }
|
||||
await alias(dirnames[i]);
|
||||
}
|
||||
})();
|
||||
|
||||
16
misc/admin/src.ts/cmds/peg-version.ts
Normal file
16
misc/admin/src.ts/cmds/peg-version.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
import { dirnames, getPackage } from "../local";
|
||||
import { colorify } from "../log";
|
||||
|
||||
const dirname = process.argv[2];
|
||||
if (dirname == null) {
|
||||
console.log("Usage: peg-version DIRNAME");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
(async function(dirname) {
|
||||
const { name, version } = getPackage(dirname);
|
||||
console.log(colorify.bold(`Pegging ${ name } to ${ version }...`));
|
||||
|
||||
})(dirname);
|
||||
*/
|
||||
@@ -13,18 +13,18 @@ const Words = fs.readFileSync("/usr/share/dict/words").toString().split("\n").re
|
||||
|
||||
`
|
||||
// Words missing from the dictionary
|
||||
accessing addresses aligned autofill called cancelled changed censored
|
||||
clamping compiled computed configured consumed creating decoded decoding
|
||||
accessing addresses aligned autofill avatar called cancelled changed censored
|
||||
clamping compiled computed configured consumed contained creating decoded decoding
|
||||
decreased decrypt decrypted decrypting deployed deploying deprecated detected
|
||||
discontinued earliest email enabled encoded encoder encoding encrypt
|
||||
encrypted encrypting entries euro exceeded existing expected
|
||||
discontinued earliest email emitted enabled encoded encoder encoding encountered
|
||||
encrypt encrypted encrypting entries euro exceeded existing expected
|
||||
expired failed fetches formatted formatting funding generated
|
||||
hardened has highly ignoring implemented implementer imported including instantiate
|
||||
joined keyword labelled larger lookup matches mined modified modifies multi
|
||||
named needed nested neutered numeric offline optimizer overriding owned packed
|
||||
padded parsed parsing passed payload placeholder processing properties prototyping reached
|
||||
recommended recovered redacted remaining replaced required reverted
|
||||
serializes shared signed signing skipped stored supported tagging targetted
|
||||
recommended recovered recursively redacted remaining replaced repriced required reverted
|
||||
serializes shared signed signing skipped stats stored supported tagging targetted
|
||||
throttled transactions typed uninstall unstake unsubscribe untyped
|
||||
using verifies verifying website
|
||||
|
||||
@@ -32,7 +32,7 @@ using verifies verifying website
|
||||
bech BIP BIP39 BIP44 btc bzz crypto eip etc hashes hmac icap
|
||||
keccak ltc namehash ripemd RLP scrypt secp sha xdai
|
||||
|
||||
blockhash
|
||||
blockhash bnb bnbt ethprice matic txlist
|
||||
|
||||
bitcoin ethereum finney gwei kwei mwei satoshi szabo wei weth
|
||||
|
||||
@@ -47,15 +47,15 @@ ABIEncoder testcase numberish Wordlist
|
||||
|
||||
// Common Code Strings
|
||||
abi addr api app arg arrayify asm backend basex bigint bignumber bn byte
|
||||
bytecode callback calldata charset checksum ciphertext cli codepoint
|
||||
bytecode callback calldata ccip charset checksum ciphertext cli codepoint
|
||||
commify config
|
||||
contenthash ctr ctrl debug dd dklen eexist encseed eof eq ethaddr
|
||||
contenthash ctr ctrl debug dd dklen eexist encseed eof eq erc ethaddr
|
||||
ethseed ethers eval exec filename func gz gzip hid http https hw iv
|
||||
info init ipc json kdf kdfparams labelhash lang lib mm multihash nfc
|
||||
nfkc nfd nfkd nodehash notok nowait nullish oob opcode pbkdf pc plugin
|
||||
info init ipc json kdf kdfparams labelhash lang lib metadata mm multihash nfc
|
||||
nfkc nfd nfkd nodehash notok nowait nullish offchain oob opcode org pbkdf pc plugin
|
||||
pragma pre prf recid repl rpc sighash topichash solc stdin stdout subclasses
|
||||
subnode timeout todo txt typeof ufixed utc utf util url urlencoded uuid vm
|
||||
vs websocket wikipedia www wx xe xpriv xpub xx yyyy zlib
|
||||
vs websocket wikipedia wildcard wildcards www wx xe xpriv xpub xx yyyy zlib
|
||||
|
||||
// AbiV2
|
||||
abiv
|
||||
@@ -63,13 +63,14 @@ abiv
|
||||
// Query parameters
|
||||
apikey asc endblock startblock
|
||||
|
||||
alchemyapi Cloudflare Etherscan INFURA IPFS MetaMask Nodesmith
|
||||
alchemyapi ankr arbitrum Cloudflare com Etherscan INFURA IPFS IPNS MetaMask Nodesmith
|
||||
Trezor ledgerhq axic bitcoinjs browserify easyseed ethereumjs
|
||||
goerli homestead kotti kovan mainnet morden mordor rinkeby
|
||||
ropsten testnet lb
|
||||
goerli homestead kotti kovan mainnet morden mordor rinkeby kintsugi
|
||||
ropsten testnet lb maticmum
|
||||
|
||||
// Demo words
|
||||
args foo eth foo foobar ll localhost passwd ricmoo tx xxx yna
|
||||
brantly ricmoose
|
||||
|
||||
// nameprep tags
|
||||
ALCat BiDi LCat nameprep
|
||||
|
||||
@@ -79,7 +79,7 @@ async function _getUrl(href: string, options?: Options): Promise<GetUrlResponse>
|
||||
if (options == null) { options = { }; }
|
||||
|
||||
// @TODO: Once we drop support for node 8, we can pass the href
|
||||
// firectly into request and skip adding the components
|
||||
// directly into request and skip adding the components
|
||||
// to this request object
|
||||
const url = parse(href);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ async function getPackageInfo(name: string): Promise<any> {
|
||||
|
||||
if (!cache[name]) {
|
||||
try {
|
||||
const result = await getUrl("http:/" + "/registry.npmjs.org/" + name);
|
||||
const result = await getUrl("https:/\/registry.npmjs.org/" + name);
|
||||
cache[name] = JSON.parse(Buffer.from(result.body).toString("utf8"));
|
||||
} catch (error) {
|
||||
if (error.status === 404) { return null; }
|
||||
@@ -32,7 +32,12 @@ export async function getPackage(name: string, version?: string): Promise<Packag
|
||||
if (version == null) {
|
||||
const versions = Object.keys(infos.versions);
|
||||
versions.sort(semver.compare);
|
||||
version = versions.pop();
|
||||
|
||||
// HACK: So v5 continues working while v6 is managed by reticulate
|
||||
version = "6.0.0";
|
||||
while (version.indexOf("beta") >= 0 || semver.gte(version, "6.0.0")) {
|
||||
version = versions.pop();
|
||||
}
|
||||
}
|
||||
|
||||
const info = infos.versions[version];
|
||||
|
||||
2693
package-lock.json
generated
2693
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -65,22 +65,22 @@
|
||||
"@types/node": "^12.7.4",
|
||||
"@types/semver": "^7.3.4",
|
||||
"aes-js": "3.0.0",
|
||||
"aws-sdk": "2.137.0",
|
||||
"aws-sdk": "2.1039.0",
|
||||
"diff": "4.0.1",
|
||||
"flatworm": "0.0.2-beta.5",
|
||||
"flatworm": "0.0.2-beta.7",
|
||||
"jison": "0.4.18",
|
||||
"karma": "6.3.2",
|
||||
"karma": "6.3.17",
|
||||
"karma-chrome-launcher": "3.1.0",
|
||||
"karma-mocha": "2.0.1",
|
||||
"libnpmpublish": "3.0.1",
|
||||
"mocha": "^7.1.1",
|
||||
"mocha": "^9.1.3",
|
||||
"nyc": "15.1.0",
|
||||
"rollup": "2.33.2",
|
||||
"rollup-plugin-node-polyfills": "0.2.1",
|
||||
"rollup-plugin-sourcemaps": "0.6.3",
|
||||
"scrypt-js": "3.0.1",
|
||||
"semver": "^5.6.0",
|
||||
"typescript": "4.2.2",
|
||||
"typescript": "4.4.4",
|
||||
"uglify-es": "3.3.9"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -92,13 +92,13 @@
|
||||
"@types/mocha": "^5.2.0",
|
||||
"aes-js": "3.0.0",
|
||||
"bech32": "1.1.4",
|
||||
"bn.js": "^4.4.0",
|
||||
"bn.js": "^4.11.9",
|
||||
"elliptic": "6.5.4",
|
||||
"hash.js": "1.1.3",
|
||||
"js-sha3": "0.5.7",
|
||||
"hash.js": "1.1.7",
|
||||
"js-sha3": "0.8.0",
|
||||
"scrypt-js": "3.0.1",
|
||||
"solc": "0.7.1",
|
||||
"tiny-inflate": "1.0.3",
|
||||
"ws": "7.2.3"
|
||||
"ws": "7.4.6"
|
||||
}
|
||||
}
|
||||
|
||||
2
packages/abi/lib.esm/_version.d.ts
vendored
2
packages/abi/lib.esm/_version.d.ts
vendored
@@ -1,2 +1,2 @@
|
||||
export declare const version = "abi/5.2.0";
|
||||
export declare const version = "abi/5.6.1";
|
||||
//# sourceMappingURL=_version.d.ts.map
|
||||
@@ -1,2 +1,2 @@
|
||||
export const version = "abi/5.2.0";
|
||||
export const version = "abi/5.6.1";
|
||||
//# sourceMappingURL=_version.js.map
|
||||
@@ -11,7 +11,7 @@ export class AddressCoder extends Coder {
|
||||
}
|
||||
encode(writer, value) {
|
||||
try {
|
||||
getAddress(value);
|
||||
value = getAddress(value);
|
||||
}
|
||||
catch (error) {
|
||||
this._throwError(error.message, value);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user