Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b1d3fcee6 | ||
|
|
81fd628292 | ||
|
|
f9dd0996ca | ||
|
|
87ceaed4be | ||
|
|
0e1721b130 | ||
|
|
c47d2eba4d | ||
|
|
1db4ce12d4 | ||
|
|
6c43e20e7a | ||
|
|
b2ecffb0c8 | ||
|
|
a953f71752 | ||
|
|
c5a53d6911 | ||
|
|
bcda16df1d | ||
|
|
d937668dc1 | ||
|
|
8279120e0a | ||
|
|
243beffa4f | ||
|
|
3a76d69a16 | ||
|
|
5b41675f33 | ||
|
|
80cde06bcc | ||
|
|
7d0b33dc42 | ||
|
|
173f4d44bf | ||
|
|
73e94349de | ||
|
|
796954f880 | ||
|
|
f0a88f551f | ||
|
|
f4b97c00ed | ||
|
|
38eccc8b9d | ||
|
|
a3b5f7132c | ||
|
|
a1e7db4abe | ||
|
|
689459c1fd | ||
|
|
755fc72094 | ||
|
|
620b7b91a1 | ||
|
|
fb9eea6c7e | ||
|
|
d83c583412 | ||
|
|
3f97b94d15 | ||
|
|
0ae9ac6f98 | ||
|
|
2333b6cfd2 | ||
|
|
73b31b371f | ||
|
|
fd0cf2cc54 | ||
|
|
27a981c84b | ||
|
|
29be1e37bc | ||
|
|
e727efc33e | ||
|
|
4af2c19f45 | ||
|
|
4f67ecdf62 | ||
|
|
3396846a30 | ||
|
|
5c27b45ac9 | ||
|
|
20f6e16394 | ||
|
|
2df9dd1120 | ||
|
|
74470defda | ||
|
|
8175c83026 | ||
|
|
e0ccafb140 | ||
|
|
20335e96c2 | ||
|
|
a56a0a3336 | ||
|
|
4ad47b1b43 | ||
|
|
0e6cc9a9a8 | ||
|
|
21c6c7ddb6 | ||
|
|
8efbfc6afa | ||
|
|
8e3cfd8517 | ||
|
|
0a6c15e691 | ||
|
|
d3b1ac046a | ||
|
|
86b413750d | ||
|
|
70c2b1b300 | ||
|
|
5cb418cf7d | ||
|
|
8e4ee887b9 | ||
|
|
ef09361539 | ||
|
|
6e36447aa0 | ||
|
|
1c4259881a | ||
|
|
ba00df1ab7 | ||
|
|
45a2902874 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,3 +25,5 @@ packages/testcases/input/nameprep/**
|
||||
.nyc_output/**
|
||||
|
||||
output/**
|
||||
|
||||
misc/testing/**
|
||||
|
||||
72
CHANGELOG.md
72
CHANGELOG.md
@@ -3,6 +3,76 @@ Changelog
|
||||
|
||||
This change log is managed by `admin/cmds/update-versions` but may be manually updated.
|
||||
|
||||
ethers/v5.1.0 (2021-03-30 14:44)
|
||||
--------------------------------
|
||||
|
||||
- Added BigNumber.toBigInt method. ([#1415](https://github.com/ethers-io/ethers.js/issues/1415); [81fd628](https://github.com/ethers-io/ethers.js/commit/81fd628292b7dde90fe5115074fa68476a872dbf))
|
||||
- Abstracted Contract with BaseContract without meta-class properties for easier extensions. ([#1384](https://github.com/ethers-io/ethers.js/issues/1384); [87ceaed](https://github.com/ethers-io/ethers.js/commit/87ceaed4be21283619da74678cf371c228c918b7))
|
||||
- Fixed Contract properties that collide with null member properties. ([#1393](https://github.com/ethers-io/ethers.js/issues/1393); [0e1721b](https://github.com/ethers-io/ethers.js/commit/0e1721b13084dacf63089e47116f7d5331be4f36))
|
||||
- Added EIP-2930 support. ([#1364](https://github.com/ethers-io/ethers.js/issues/1364); [c47d2eb](https://github.com/ethers-io/ethers.js/commit/c47d2eba4dc741eb5cb754c3ef5064b8ea7ac7cc))
|
||||
- Added abstraction for EIP-2718 support. ([1db4ce1](https://github.com/ethers-io/ethers.js/commit/1db4ce12d49e235a7155de24ee153f409e7e7370))
|
||||
|
||||
ethers/v5.0.32 (2021-03-07 18:17)
|
||||
---------------------------------
|
||||
|
||||
- Bumped TypeScript to 4.2.2. ([#1288](https://github.com/ethers-io/ethers.js/issues/1288); [b2ecffb](https://github.com/ethers-io/ethers.js/commit/b2ecffb0c8d44c8ee65199e7866dc744abae4e6e))
|
||||
- Fixed shims from not displaying debug information. ([a953f71](https://github.com/ethers-io/ethers.js/commit/a953f717523a844a3a45810a5acc6630383884d3))
|
||||
- Force TypedData numbers to be in decimal. ([#1193](https://github.com/ethers-io/ethers.js/issues/1193); [c5a53d6](https://github.com/ethers-io/ethers.js/commit/c5a53d6911d7c41dd03a290b550e80f2919e9379))
|
||||
|
||||
ethers/v5.0.31 (2021-02-12 19:04)
|
||||
---------------------------------
|
||||
|
||||
- Prevent unhandled rejections when passing nullish into Contract constructor. ([#1234](https://github.com/ethers-io/ethers.js/issues/1234); [d937668](https://github.com/ethers-io/ethers.js/commit/d937668dc1d39cc293f64bbd30b99b29614d1607))
|
||||
- Better error messaging when provider backends give bogus responses. ([#1243](https://github.com/ethers-io/ethers.js/issues/1243); [8279120](https://github.com/ethers-io/ethers.js/commit/8279120e0ad1cbb7aeabd32c08e168a4228abbec))
|
||||
- Prevent unconfigured ENS names from making an init tx. ([#1290](https://github.com/ethers-io/ethers.js/issues/1290); [243beff](https://github.com/ethers-io/ethers.js/commit/243beffa4f83c910f5f1c5e0554531e5dcf3ab93))
|
||||
|
||||
ethers/v5.0.30 (2021-02-08 15:22)
|
||||
---------------------------------
|
||||
|
||||
- When in Status trigger personal_sign instead of eth_sign. ([#1285](https://github.com/ethers-io/ethers.js/issues/1285); [73e9434](https://github.com/ethers-io/ethers.js/commit/73e94349de94d2969ccb21c834119525ddfcb961))
|
||||
- Bump elliptic version for CVE-2020-28498. ([#1284](https://github.com/ethers-io/ethers.js/issues/1284); [796954f](https://github.com/ethers-io/ethers.js/commit/796954f8807b0c464c7baa8f7ff299e22685e192))
|
||||
|
||||
ethers/v5.0.29 (2021-02-03 14:36)
|
||||
---------------------------------
|
||||
|
||||
- Fixed typos in JSON ABI formatting. ([#1275](https://github.com/ethers-io/ethers.js/issues/1275); [73b31b3](https://github.com/ethers-io/ethers.js/commit/73b31b371fa47bacc4f5f6bed01d0d1e5d66fa2c))
|
||||
|
||||
ethers/v5.0.28 (2021-02-02 17:12)
|
||||
---------------------------------
|
||||
|
||||
- Added load balancer support to PocketProvider. ([#1052](https://github.com/ethers-io/ethers.js/issues/1052); [27a981c](https://github.com/ethers-io/ethers.js/commit/27a981c84b578feb762fdb37dd5325d9c335bd59))
|
||||
|
||||
ethers/v5.0.27 (2021-02-01 15:55)
|
||||
---------------------------------
|
||||
|
||||
- Added support for networks with slightly incorrect EIP-658 implementations. ([#952](https://github.com/ethers-io/ethers.js/issues/952), [#1251](https://github.com/ethers-io/ethers.js/issues/1251); [e727efc](https://github.com/ethers-io/ethers.js/commit/e727efc33eaa31c3af6adbb64a893caf354d0ba7))
|
||||
- Added Pocket network to the default provider. ([#1030](https://github.com/ethers-io/ethers.js/issues/1030), [#1052](https://github.com/ethers-io/ethers.js/issues/1052); [4af2c19](https://github.com/ethers-io/ethers.js/commit/4af2c19f455bb43406d3cc5421c3b3fdda75f78f))
|
||||
- Added TypeScript declaration maps. ([#401](https://github.com/ethers-io/ethers.js/issues/401); [3396846](https://github.com/ethers-io/ethers.js/commit/3396846a30a4be0ed58fe449589e7e4e54f3d32e))
|
||||
|
||||
ethers/v5.0.26 (2021-01-13 14:47)
|
||||
---------------------------------
|
||||
|
||||
- Fixed abundant UnhandledRejectErrors in provider polling. ([#1084](https://github.com/ethers-io/ethers.js/issues/1084), [#1208](https://github.com/ethers-io/ethers.js/issues/1208), [#1221](https://github.com/ethers-io/ethers.js/issues/1221), [#1235](https://github.com/ethers-io/ethers.js/issues/1235); [74470de](https://github.com/ethers-io/ethers.js/commit/74470defda5170338735bbbe676c207cdd5cc1cf), [20f6e16](https://github.com/ethers-io/ethers.js/commit/20f6e16394909a43498c1ac6c73152957bd121bd))
|
||||
- Fixed non-checksum address comparisons in abstract Signer. ([#1236](https://github.com/ethers-io/ethers.js/issues/1236); [8175c83](https://github.com/ethers-io/ethers.js/commit/8175c83026436b6335800780ca12b7257e1b490f))
|
||||
|
||||
ethers/v5.0.25 (2021-01-08 03:31)
|
||||
---------------------------------
|
||||
|
||||
- Safety check on digest length for signing. ([20335e9](https://github.com/ethers-io/ethers.js/commit/20335e96c2429e851081b72031ea3fd4cd677904))
|
||||
- Fixed listenerCount for contract when requesting for all events. ([#1205](https://github.com/ethers-io/ethers.js/issues/1205); [a56a0a3](https://github.com/ethers-io/ethers.js/commit/a56a0a33366ea9276fba5bc45f1e4678dd723fa6))
|
||||
- Lock package versions for the ESM builds. ([#1009](https://github.com/ethers-io/ethers.js/issues/1009); [0e6cc9a](https://github.com/ethers-io/ethers.js/commit/0e6cc9a9a8ebceae4529ccbb7c107618eb54490a))
|
||||
|
||||
ethers/v5.0.24 (2020-12-08 01:43)
|
||||
---------------------------------
|
||||
|
||||
- Fixed EIP-712 getPayload dropping EIP712Domain from types for JSON-RPC calls. ([#687](https://github.com/ethers-io/ethers.js/issues/687); [d3b1ac0](https://github.com/ethers-io/ethers.js/commit/d3b1ac046aaf2a46f6c3efbd93c55adb0cb8f16d))
|
||||
- Remvoed dead files. ([70c2b1b](https://github.com/ethers-io/ethers.js/commit/70c2b1b3002f44c39f4fd87fc2cfc3f5dc6555ed))
|
||||
|
||||
ethers/v5.0.23 (2020-11-25 15:25)
|
||||
---------------------------------
|
||||
|
||||
- Fix BigNumber when passed something with a length property. ([#1172](https://github.com/ethers-io/ethers.js/issues/1172); [45a2902](https://github.com/ethers-io/ethers.js/commit/45a2902874e828a16396a253548bcb00bceccf95))
|
||||
|
||||
ethers/v5.0.22 (2020-11-23 19:16)
|
||||
---------------------------------
|
||||
|
||||
@@ -10,7 +80,7 @@ ethers/v5.0.22 (2020-11-23 19:16)
|
||||
- Add ABI coder function to compute default values. ([#1101](https://github.com/ethers-io/ethers.js/issues/1101); [a8e3380](https://github.com/ethers-io/ethers.js/commit/a8e3380ed547b6368be5fe40b48be6e31b5cdd93))
|
||||
- Fix for new versions of Geth which return formatted data on revert rather than standard data. ([#949](https://github.com/ethers-io/ethers.js/issues/949); [4a8d579](https://github.com/ethers-io/ethers.js/commit/4a8d579dcaf026d0c232e20176605d34cba4767d))
|
||||
- Addd missing sideEffects flag to some packages. ([20defec](https://github.com/ethers-io/ethers.js/commit/20defec9f1683487b6ea9c8730d2ab7b3745bfa5))
|
||||
- Allow base-10 to be passed into BigNumbner.toString and improve errors for other radices. ([#1164](https://github.com/ethers-io/ethers.js/issues/1164); [c8bb77d](https://github.com/ethers-io/ethers.js/commit/c8bb77d8af85d2f9f9df82f1afbe7516ab296e98), [#1164](https://github.com/ethers-io/ethers.js/issues/1164); [fbbe4ad](https://github.com/ethers-io/ethers.js/commit/fbbe4ad638e06089cdd976a7f4ffd51b85a31558))
|
||||
- Allow base-10 to be passed into BigNumbner.toString and improve errors for other radices. ([#1164](https://github.com/ethers-io/ethers.js/issues/1164); [c8bb77d](https://github.com/ethers-io/ethers.js/commit/c8bb77d8af85d2f9f9df82f1afbe7516ab296e98), [fbbe4ad](https://github.com/ethers-io/ethers.js/commit/fbbe4ad638e06089cdd976a7f4ffd51b85a31558))
|
||||
- Allow private keys to Wallet to omit the 0x prefix. ([#1166](https://github.com/ethers-io/ethers.js/issues/1166); [29f6c34](https://github.com/ethers-io/ethers.js/commit/29f6c34343d75fa42023bdcd07632f49a450570c))
|
||||
|
||||
ethers/v5.0.21 (2020-11-19 18:52)
|
||||
|
||||
@@ -52,7 +52,7 @@ Installing
|
||||
|
||||
```
|
||||
<script type="module">
|
||||
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.0.umd.min.js";
|
||||
import { ethers } from "https://cdn.ethers.io/lib/ethers-5.0.esm.min.js";
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -80,9 +80,9 @@ everyone else with packages they do not need.
|
||||
|
||||
We will keep a list of useful packages here.
|
||||
|
||||
- `@ethersproject/experimental` ([documentation](https://docs.ethers.io))
|
||||
- `@ethersproject/cli` ([documentation](https://docs.ethers.io))
|
||||
- `@ethersproject/hardware-wallets` ([documentation](https://docs.ethers.io))
|
||||
- `@ethersproject/experimental` ([documentation](https://docs.ethers.io/v5/api/experimental/))
|
||||
- `@ethersproject/cli` ([documentation](https://docs.ethers.io/v5/cli/))
|
||||
- `@ethersproject/hardware-wallets` ([documentation](https://docs.ethers.io/v5/api/other/hardware/))
|
||||
|
||||
|
||||
License
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
Admin Tool
|
||||
==========
|
||||
|
||||
This tool is meant for admin tasks related to ethers.js.
|
||||
|
||||
|
||||
Workflow
|
||||
--------
|
||||
|
||||
After a new series of changes have been made and tested:
|
||||
|
||||
1. Run `npm run update-versions` to update and build all packages
|
||||
2. Make any human-necessary changes to the automatically updated `CHANGELOG.md`
|
||||
3. Run `git add .`
|
||||
4. Run `git commit -S -m "Updated dist files."`
|
||||
5. Run `git push`
|
||||
6. Wait for TravisCI to complete running test cases
|
||||
7. Run `npm run publish-all` to publish changed packages to NPM and tag GitHub
|
||||
|
||||
|
||||
Update Dependency Graph: admin/cmds/update-depgraph
|
||||
---------------------------------------------------
|
||||
|
||||
This is run as part of `npm run bootstrap` before running lerna bootstrap.
|
||||
It recomputes the dependency graph and writes out the ordered
|
||||
**tsconfig.project.json**
|
||||
|
||||
|
||||
Update Versions: admin/cmds/update-versions
|
||||
-------------------------------------------
|
||||
|
||||
Run using the `npm run update-versions`, which also cleans, bootstraps and
|
||||
rebuilds the project before running the script.
|
||||
|
||||
For each package that has changed from the version in NPM (the published
|
||||
tarballs are compared):
|
||||
|
||||
- Update the `version` in the **package.json**
|
||||
- Update the `src.ts/_version.ts` (matches the **package.json**)
|
||||
- Updates the `tarballHash` in the **package.json**
|
||||
- Compiles the TypeScript (which updates the `_version.js` and `_version.d.js`)
|
||||
- Lists all changed files (highlighting src.ts files)
|
||||
|
||||
Then:
|
||||
|
||||
- Generate the distribution files
|
||||
- Update the `CHANGELOG.md`
|
||||
|
||||
|
||||
Publish: admin/cmds/publish
|
||||
---------------------------
|
||||
|
||||
Run using `npm run publish-all`. This requires a password for the secure
|
||||
local config and the OTP for NPM.
|
||||
|
||||
- Publish (in dependency order) changed files to NPM
|
||||
- The `gitHead` is updated in **only** the NPM **package.json**
|
||||
- @TODO: Cut a release on GitHub including the relevant CHANGELOG entry
|
||||
|
||||
111
admin/build.js
111
admin/build.js
@@ -1,111 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const resolve = require("path").resolve;
|
||||
const spawn = require("child_process").spawn;
|
||||
|
||||
const { dirnames } = require("./local");
|
||||
const { loadPackage, savePackage } = require("./local");
|
||||
const { loadJson, saveJson } = require("./utils");
|
||||
|
||||
function run(progname, args, ignoreErrorStream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn(progname, args);
|
||||
|
||||
let stdout = Buffer.from([]);
|
||||
let stderr = Buffer.from([]);
|
||||
|
||||
proc.stdout.on("data", (data) => {
|
||||
stdout = Buffer.concat([ stdout, data ]);
|
||||
});
|
||||
|
||||
proc.stderr.on("data", (data) => {
|
||||
stderr = Buffer.concat([ stdout, data ]);
|
||||
});
|
||||
|
||||
proc.on("error", (error) => {
|
||||
console.log("ERROR");
|
||||
console.log(stderr.toString());
|
||||
error.stderr = stderr.toString();
|
||||
error.stdout = stdout.toString();
|
||||
reject(error);
|
||||
});
|
||||
|
||||
proc.on("close", (code) => {
|
||||
if ((stderr.length && !ignoreErrorStream) || code !== 0) {
|
||||
console.log("ERROR");
|
||||
console.log(stderr.toString());
|
||||
|
||||
let error = new Error(`stderr not empty: ${ progname } ${ JSON.stringify(args) }`);
|
||||
error.stderr = stderr.toString();
|
||||
error.stdout = stdout.toString();
|
||||
error.statusCode = code;
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(stdout.toString());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setupConfig(outDir, moduleType, targetType) {
|
||||
|
||||
// Configure the tsconfit.package.json...
|
||||
const path = resolve(__dirname, "../tsconfig.package.json");
|
||||
const content = loadJson(path);
|
||||
content.compilerOptions.module = moduleType;
|
||||
content.compilerOptions.target = targetType;
|
||||
saveJson(path, content);
|
||||
|
||||
// Configure the browser field for every pacakge, copying the
|
||||
// browser.umd filed for UMD and browser.esm for ESM
|
||||
dirnames.forEach((dirname) => {
|
||||
let info = loadPackage(dirname);
|
||||
|
||||
if (info._ethers_nobuild) { return; }
|
||||
|
||||
if (targetType === "es2015") {
|
||||
if (info["browser.esm"]) {
|
||||
info.browser = info["browser.esm"];
|
||||
}
|
||||
} else if (targetType === "es5") {
|
||||
if (info["browser.umd"]) {
|
||||
info.browser = info["browser.umd"];
|
||||
}
|
||||
} else {
|
||||
throw new Error("unsupported target");
|
||||
}
|
||||
savePackage(dirname, info);
|
||||
|
||||
let path = resolve(__dirname, "../packages", dirname, "tsconfig.json");
|
||||
let content = loadJson(path);
|
||||
content.compilerOptions.outDir = outDir;
|
||||
saveJson(path, content);
|
||||
});
|
||||
}
|
||||
|
||||
function setupBuild(buildModule) {
|
||||
if (buildModule) {
|
||||
setupConfig("./lib.esm/", "es2015", "es2015");
|
||||
} else {
|
||||
setupConfig("./lib/", "commonjs", "es5");
|
||||
}
|
||||
}
|
||||
|
||||
function runBuild(buildModule) {
|
||||
setupBuild(buildModule);
|
||||
|
||||
// Compile
|
||||
return run("npx", [ "tsc", "--build", resolve(__dirname, "../tsconfig.project.json"), "--force" ]);
|
||||
}
|
||||
|
||||
function runDist() {
|
||||
return run("npm", [ "run", "_dist" ], true);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
run: run,
|
||||
runDist: runDist,
|
||||
runBuild: runBuild,
|
||||
setupBuild: setupBuild
|
||||
};
|
||||
@@ -1,145 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const resolve = require("path").resolve;
|
||||
|
||||
const git = require("./git");
|
||||
const local = require("./local");
|
||||
const npm = require("./npm");
|
||||
const utils = require("./utils");
|
||||
|
||||
const ChangelogPath = resolve(__dirname, "../CHANGELOG.md");
|
||||
|
||||
async function generate() {
|
||||
|
||||
// Get each section of the Changelog
|
||||
let existing = fs.readFileSync(ChangelogPath).toString().split("\n");
|
||||
let sections = [ ];
|
||||
let lastLine = existing[0];
|
||||
existing.slice(1).forEach((line) => {
|
||||
if (line.substring(0, 5) === "=====" || line.substring(0, 5) === "-----") {
|
||||
sections.push({
|
||||
title: lastLine,
|
||||
underline: line.substring(0, 1),
|
||||
body: [ ]
|
||||
});
|
||||
lastLine = null;
|
||||
return;
|
||||
} else if (lastLine) {
|
||||
sections[sections.length - 1].body.push(lastLine);
|
||||
}
|
||||
lastLine = line;
|
||||
});
|
||||
sections[sections.length - 1].body.push(lastLine);
|
||||
|
||||
let lastVersion = await npm.getPackageVersion("ethers");
|
||||
|
||||
let logs = await git.run([ "log", (lastVersion.gitHead + "..") ]);
|
||||
|
||||
let changes = [ ];
|
||||
logs.split("\n").forEach((line) => {
|
||||
if (line.toLowerCase().substring(0, 6) === "commit") {
|
||||
changes.push({
|
||||
commit: line.substring(6).trim(),
|
||||
body: [ ]
|
||||
});
|
||||
} else if (line.toLowerCase().substring(0, 5) === "date:") {
|
||||
changes[changes.length - 1].date = utils.getDateTime(new Date(line.substring(5).trim()));
|
||||
} else if (line.substring(0, 1) === " ") {
|
||||
line = line.trim();
|
||||
if (line === "") { return; }
|
||||
changes[changes.length - 1].body += line + " ";
|
||||
}
|
||||
});
|
||||
|
||||
// @TODO:
|
||||
// ethers/version ([date](tag))
|
||||
let newSection = {
|
||||
title: `ethers/v${ local.loadPackage("ethers").version } (${utils.getDateTime(new Date())})`,
|
||||
underline: "-",
|
||||
body: [ ]
|
||||
}
|
||||
|
||||
// Delete duplicate sections for the same version (ran update multiple times)
|
||||
while (sections[1].title === newSection.title) {
|
||||
sections.splice(1, 1);
|
||||
}
|
||||
|
||||
changes.forEach((change) => {
|
||||
let body = change.body.trim();
|
||||
let link = body.match(/(\((.*#.*)\))/)
|
||||
let commit = `[${ change.commit.substring(0, 7) }](https://github.com/ethers-io/ethers.js/commit/${ change.commit })`;
|
||||
if (link) {
|
||||
body = body.replace(/ *(\(.*#.*)\) */, "");
|
||||
link = link[2].replace(/#([0-9]+)/g, (all, issue) => {
|
||||
return `[#${ issue }](https://github.com/ethers-io/ethers.js/issues/${ issue })`;
|
||||
}) + "; " + commit;
|
||||
} else {
|
||||
link = commit;
|
||||
}
|
||||
newSection.body.push(` - ${ body } (${ link })`);
|
||||
});
|
||||
|
||||
sections.splice(1, 0, newSection);
|
||||
|
||||
|
||||
let formatted = [ ];
|
||||
sections.forEach((section) => {
|
||||
formatted.push(section.title);
|
||||
formatted.push(utils.repeat(section.underline, section.title.length));
|
||||
formatted.push("");
|
||||
section.body.forEach((line) => {
|
||||
line = line.trim();
|
||||
if (line === "") { return; }
|
||||
if (line.substring(0, 1) === "-") {
|
||||
line = "- " + line.substring(1).trim();
|
||||
}
|
||||
if (section.underline === "-") {
|
||||
line = " " + line;
|
||||
}
|
||||
formatted.push(line);
|
||||
});
|
||||
formatted.push("");
|
||||
});
|
||||
|
||||
return formatted.join("\n") + "\n";
|
||||
}
|
||||
|
||||
function getChanges() {
|
||||
const changes = [ ];
|
||||
|
||||
let lastLine = null;
|
||||
fs.readFileSync(ChangelogPath).toString().split("\n").forEach((line) => {
|
||||
line = line.trim();
|
||||
if (line === "") { return; }
|
||||
|
||||
if (line.substring(0, 5) === "-----") {
|
||||
changes.push({ title: lastLine, lines: [ ] });
|
||||
} else if (line.substring(0, 1) === "-" && changes.length) {
|
||||
changes[changes.length - 1].lines.push(line);
|
||||
}
|
||||
lastLine = line;
|
||||
});
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
function latestChange() {
|
||||
const recent = getChanges()[0];
|
||||
|
||||
const match = recent.title.match(/ethers\/([^\(]*)\(([^\)]*)\)/);
|
||||
|
||||
return {
|
||||
title: recent.title,
|
||||
version: match[1].trim(),
|
||||
data: match[2].trim(),
|
||||
content: recent.lines.join("\n")
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generate: generate,
|
||||
latestChange: latestChange,
|
||||
ChangelogPath: ChangelogPath,
|
||||
}
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const { colorify } = require("../log");
|
||||
const { getIssues } = require("../github");
|
||||
const { repeat } = require("../utils");
|
||||
|
||||
const Options = {
|
||||
"body": 1,
|
||||
"end": 1,
|
||||
"issue": 1,
|
||||
"start": 1,
|
||||
"title": 1,
|
||||
"user": 1,
|
||||
};
|
||||
|
||||
const Flags = {
|
||||
"open": 1,
|
||||
"match-case": 1,
|
||||
};
|
||||
|
||||
(async function() {
|
||||
const options = { };
|
||||
for (let i = 2; i < process.argv.length; i++) {
|
||||
const option = process.argv[i];
|
||||
if (option.substring(0, 2) === "--") {
|
||||
const comps = option.substring(2).split(/=/);
|
||||
if (Flags[comps[0]]) {
|
||||
if (comps[1] != null) { throw new Error("Invalid flag: " + option); }
|
||||
options[comps[0]] = true;
|
||||
} else if (Options[comps[0]]) {
|
||||
if (comps[1] == null) {
|
||||
options[comps[0]] = process.argv[++i];
|
||||
if (options[comps[0]] == null) {
|
||||
throw new Error("Missing option value: " + option);
|
||||
}
|
||||
} else {
|
||||
options[comps[0]] = comps[1];
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unexpected option: " + option);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unexpected argument: " + option);
|
||||
}
|
||||
}
|
||||
|
||||
if (options["title"]) { options.title = new RegExp(options.title, (options["match-case"] ? "": "i")); }
|
||||
if (options["body"]) { options.body = new RegExp(options.title, (options["match-case"] ? "": "i")); }
|
||||
if (options["start"]) {
|
||||
if (options["start"].match(/^[0-9]{4}-[0-9]{2}-[0-9{2}]$/)) {
|
||||
throw new Error("Expected YYYY-MM-DD");
|
||||
}
|
||||
}
|
||||
if (options["end"]) {
|
||||
if (options["end"].match(/^[0-9]{4}-[0-9]{2}-[0-9{2}]$/)) {
|
||||
throw new Error("Expected YYYY-MM-DD");
|
||||
}
|
||||
}
|
||||
|
||||
const count = { issues: 0, comments: 0, code: 0, responses: 0 };
|
||||
|
||||
const issues = await getIssues();
|
||||
issues.forEach((issue) => {
|
||||
const info = issue.issue;
|
||||
const comments = issue.comments;
|
||||
|
||||
if (options.issue && parseInt(options.issue) != info.number) { return; }
|
||||
if (options.open && info.state !== "open") { return; }
|
||||
if (options.title && !info.title.match(options.title)) { return; }
|
||||
if (options.body) {
|
||||
const body = info.body + "\n" + comments.map((c) => (c.body)).join("\n");
|
||||
if (!body.match(options.body)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (options.user) {
|
||||
const users = comments.map((c) => (c.user.login));
|
||||
users.push(info.user.login);
|
||||
if (users.indexOf(options.user) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const dates = comments.map((c) => (c.created_at.split("T")[0]));
|
||||
dates.push(info.created_at.split("T")[0]);
|
||||
|
||||
if (options.start) {
|
||||
if (dates.filter((d) => (d >= options.start)).length === 0) { return; }
|
||||
}
|
||||
if (options.end) {
|
||||
if (dates.filter((d) => (d <= options.start)).length === 0) { return; }
|
||||
}
|
||||
|
||||
count.issues++;
|
||||
|
||||
console.log(colorify(repeat("=", 70), "bold"))
|
||||
console.log(colorify("Issue:", "bold"), info.title, ` (#${ info.number })`);
|
||||
console.log(colorify("User:","bold"), colorify(info.user.login, "blue"));
|
||||
console.log(colorify("State:", "bold"), info.state);
|
||||
if (info.created_at === info.updated_at) {
|
||||
console.log(colorify("Created:", "bold"), info.created_at);
|
||||
} else {
|
||||
console.log(colorify("Created:", "bold"), info.created_at, ` (updated: ${ info.updated_at })`);
|
||||
}
|
||||
info.body.trim().split("\n").forEach((line) => {
|
||||
console.log(" " + line);
|
||||
});
|
||||
|
||||
if (comments.length) {
|
||||
comments.forEach((info) => {
|
||||
if (options.start && info.created_at < options.start) { return ; }
|
||||
if (options.end && info.created_at > options.end) { return; }
|
||||
count.comments++;
|
||||
if (options.user && info.user.login !== options.user) { return; }
|
||||
count.responses++;
|
||||
if (info.body.indexOf("`") >= 0) { count.code++; }
|
||||
console.log(colorify(repeat("-", 70), "bold"));
|
||||
console.log(colorify("User:", "bold"), colorify(info.user.login, "green"));
|
||||
if (info.created_at === info.updated_at) {
|
||||
console.log(colorify("Created:", "bold"), info.created_at);
|
||||
} else {
|
||||
console.log(colorify("Created:", "bold"), info.created_at, ` (updated: ${ info.updated_at })`);
|
||||
}
|
||||
info.body.trim().split("\n").forEach((line) => {
|
||||
console.log(" " + line);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
console.log(colorify(repeat("=", 70), "bold"))
|
||||
|
||||
// @TODO: Add stats on new/closed issues
|
||||
//if (options.user) {
|
||||
// console.log(`${ count.responses } responses (${ count.code } w/ code) on ${ count.comments } comments across ${ count.issues } issues.`);
|
||||
//} else {
|
||||
console.log(`${ count.comments } comment${ (count.comments !== 1) ? "s": "" } across ${ count.issues } issue${ (count.issues !== 1) ? "s": ""}.`);
|
||||
//}
|
||||
|
||||
})().catch((error) => {
|
||||
console.log("Error: " + error.message);
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const { getOrdered, loadPackage } = require("../depgraph");
|
||||
const { savePackage } = require("../local");
|
||||
const { log } = require("../log");
|
||||
|
||||
(async function() {
|
||||
let versions = { };
|
||||
|
||||
const dirnames = getOrdered();
|
||||
|
||||
dirnames.forEach((dirname) => {
|
||||
let info = loadPackage(dirname);
|
||||
if (info.name.split("/")[0] === "@ethersproject" || info.name === "ethers") {
|
||||
versions[info.name] = info.version;
|
||||
}
|
||||
});
|
||||
|
||||
dirnames.forEach((dirname) => {
|
||||
const info = loadPackage(dirname);
|
||||
let shown = false;
|
||||
["dependencies", "devDependencies"].forEach((key) => {
|
||||
const deps = info[key];
|
||||
if (!deps) { return; }
|
||||
Object.keys(deps).forEach((name) => {
|
||||
// Not a package in this monorepoa
|
||||
const version = versions[name];
|
||||
if (version == null) { return; }
|
||||
|
||||
const value = ((version.indexOf("beta") !== -1) ? ">=": "^") + version;
|
||||
|
||||
// No change
|
||||
if (value === deps[name]) { return; }
|
||||
|
||||
// Show a header for the first change
|
||||
if (!shown) {
|
||||
log(`<bold:Locking ${ info.name }:>`);
|
||||
shown = true;
|
||||
}
|
||||
|
||||
// Show the locked version
|
||||
log(` <green:${ name }>: ${ deps[name] } => <bold:${ value.replace(">", ">") }>`);
|
||||
deps[name] = value;
|
||||
});
|
||||
});
|
||||
savePackage(dirname, info);
|
||||
});
|
||||
|
||||
})();
|
||||
@@ -1,210 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const { basename, resolve } = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
const AWS = require('aws-sdk');
|
||||
|
||||
const config = require("../config");
|
||||
|
||||
const { ChangelogPath, latestChange } = require("../changelog");
|
||||
const { getOrdered, loadPackage } = require("../depgraph");
|
||||
const { getGitTag } = require("../git");
|
||||
const { createRelease } = require("../github");
|
||||
const { getPackageVersion, publish } = require("../npm");
|
||||
const { log } = require("../log");
|
||||
|
||||
const USER_AGENT = "ethers-dist@0.0.0";
|
||||
const TAG = "latest";
|
||||
|
||||
|
||||
let dirnames = getOrdered();
|
||||
|
||||
// Only publish specific packages
|
||||
if (process.argv.length > 2) {
|
||||
let filter = process.argv.slice(2);
|
||||
|
||||
// Verify all named packages exist
|
||||
filter.forEach((dirname) => {
|
||||
try {
|
||||
loadPackage(dirname);
|
||||
} catch (error) {
|
||||
console.log("Package not found: " + dirname);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Filter out pacakges we don't care about
|
||||
dirnames = dirnames.filter((dirname) => (filter.indexOf(dirname) >= 0));
|
||||
}
|
||||
|
||||
|
||||
function putObject(s3, info) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
s3.putObject(info, function(error, data) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve({
|
||||
name: info.Key,
|
||||
hash: data.ETag.replace(/"/g, '')
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function invalidate(cloudfront, distributionId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
cloudfront.createInvalidation({
|
||||
DistributionId: distributionId,
|
||||
InvalidationBatch: {
|
||||
CallerReference: `${ USER_AGENT }-${ parseInt(((new Date()).getTime()) / 1000) }`,
|
||||
Paths: {
|
||||
Quantity: "1",
|
||||
Items: [
|
||||
"/\*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}, function(error, data) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return;
|
||||
}
|
||||
resolve(data.Invalidation.Id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
(async function() {
|
||||
let token = null;
|
||||
|
||||
const gitCommit = await getGitTag(ChangelogPath);
|
||||
|
||||
let includeEthers = false;
|
||||
|
||||
// @TODO: Fail if there are any untracked files or unchecked in files
|
||||
|
||||
// Load the token from the encrypted store
|
||||
try {
|
||||
token = await config.get("npm-token");
|
||||
} catch (error) {
|
||||
switch (error.message) {
|
||||
case "wrong password":
|
||||
log("<bold:Wrong password>");
|
||||
break;
|
||||
case "cancelled":
|
||||
break;
|
||||
default:
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
log("<red:Aborting.>");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
token = token.trim().split("=");
|
||||
|
||||
let options = {
|
||||
npmVersion: USER_AGENT,
|
||||
tag: TAG
|
||||
};
|
||||
|
||||
// Set the authentication token
|
||||
options[token[0]] = token[1];
|
||||
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
let dirname = dirnames[i];
|
||||
|
||||
if (dirname === "ethers") {
|
||||
includeEthers = true;
|
||||
}
|
||||
|
||||
let info = loadPackage(dirname);
|
||||
let npmInfo = await getPackageVersion(info.name);
|
||||
if (!npmInfo) { npmInfo = { version: "NEW" }; }
|
||||
|
||||
if (info.tarballHash === npmInfo.tarballHash) { continue; }
|
||||
|
||||
log(`<bold:Publishing:> ${info.name}...`);
|
||||
log(` <blue:Version:> ${npmInfo.version} <bold:=\\>> ${info.version}`);
|
||||
|
||||
let success = await publish(dirname, options);
|
||||
if (!success) {
|
||||
log(" <red:FAILED! Aborting.>");
|
||||
return;
|
||||
}
|
||||
log(" <green:Done.>");
|
||||
}
|
||||
|
||||
// Publish the GitHub release
|
||||
const beta = false;
|
||||
if (includeEthers) {
|
||||
|
||||
// Get the latest change from the changelog
|
||||
const change = latestChange();
|
||||
|
||||
// Publish the release to GitHub
|
||||
{
|
||||
// The password above already succeeded
|
||||
const username = await config.get("github-user");
|
||||
const password = await config.get("github-release");
|
||||
|
||||
|
||||
// Publish the release
|
||||
const link = await createRelease(username, password, change.version, change.title, change.content, beta, gitCommit);
|
||||
log(`<bold:Published Release:> ${ link }`);
|
||||
}
|
||||
|
||||
// Upload the scripts to the CDN and refresh the edge caches
|
||||
{
|
||||
const awsAccessId = await config.get("aws-upload-scripts-accesskey");
|
||||
const awsSecretKey = await config.get("aws-upload-scripts-secretkey");
|
||||
const bucketName = await config.get("aws-upload-scripts-bucket");
|
||||
const originRoot = await config.get("aws-upload-scripts-root");
|
||||
const distributionId = await config.get("aws-upload-scripts-distribution-id");
|
||||
|
||||
const s3 = new AWS.S3({
|
||||
apiVersion: '2006-03-01',
|
||||
accessKeyId: awsAccessId,
|
||||
secretAccessKey: awsSecretKey
|
||||
});
|
||||
|
||||
// Upload the libs to ethers-v5.0 and ethers-5.0.x
|
||||
const fileInfos = [
|
||||
{ filename: "packages/ethers/dist/ethers.esm.min.js", key: `ethers-${ change.version.substring(1) }.esm.min.js` },
|
||||
{ filename: "packages/ethers/dist/ethers.umd.min.js", key: `ethers-${ change.version.substring(1) }.umd.min.js` },
|
||||
{ filename: "packages/ethers/dist/ethers.esm.min.js", key: `ethers-5.0.esm.min.js` },
|
||||
{ filename: "packages/ethers/dist/ethers.umd.min.js", key: `ethers-5.0.umd.min.js` },
|
||||
];
|
||||
|
||||
for (let i = 0; i < fileInfos.length; i++) {
|
||||
const fileInfo = fileInfos[i];
|
||||
const status = await putObject(s3, {
|
||||
ACL: 'public-read',
|
||||
Body: fs.readFileSync(resolve(__dirname, "../../", fileInfo.filename)),
|
||||
Bucket: bucketName,
|
||||
ContentType: "application/javascript; charset=utf-8",
|
||||
Key: (originRoot + fileInfo.key)
|
||||
});
|
||||
|
||||
log(`<bold:Uploaded :> https://cdn.ethers.io/lib/${ fileInfo.key }`);
|
||||
}
|
||||
|
||||
// Flush the edge caches
|
||||
{
|
||||
const cloudfront = new AWS.CloudFront({
|
||||
//apiVersion: '2006-03-01',
|
||||
accessKeyId: awsAccessId,
|
||||
secretAccessKey: awsSecretKey
|
||||
});
|
||||
|
||||
const invalidationId = await invalidate(cloudfront, distributionId);
|
||||
log(`<bold:Invalidated Cache :> ${ invalidationId }`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -1,100 +0,0 @@
|
||||
const fs = require("fs");
|
||||
const http = require("http");
|
||||
const path = require("path");
|
||||
|
||||
function getMime(filename) {
|
||||
const comps = filename.split('.');
|
||||
const ext = comps[comps.length - 1];
|
||||
switch (ext.toLowerCase()) {
|
||||
case 'css': return 'text/css';
|
||||
case 'doctree': return 'application/x-doctree';
|
||||
case 'eot': return 'application/vnd.ms-fontobject';
|
||||
case 'gif': return 'image/gif';
|
||||
case 'html': return 'text/html';
|
||||
case 'js': return 'application/javascript';
|
||||
case 'jpg': return 'image/jpeg';
|
||||
case 'jpeg': return 'image/jpeg';
|
||||
case 'md': return 'text/markdown';
|
||||
case 'pickle': return 'application/x-pickle';
|
||||
case 'png': return 'image/png';
|
||||
case 'svg': return 'image/svg+xml';
|
||||
case 'ttf': return 'application/x-font-ttf';
|
||||
case 'txt': return 'text/plain';
|
||||
case 'woff': return 'application/font-woff';
|
||||
}
|
||||
console.log('NO MIME', filename);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function start(root, options) {
|
||||
if (root == null) { throw new Error("root required"); }
|
||||
if (options == null) { options = { }; }
|
||||
if (options.port == null) { options.port = 8000; }
|
||||
root = path.resolve(root);
|
||||
|
||||
const server = http.createServer((req, resp) => {
|
||||
|
||||
// Follow redirects in options
|
||||
if (options.redirects && options.redirects[req.url]) {
|
||||
resp.writeHead(301, { Location: options.redirects[req.url] });
|
||||
resp.end();
|
||||
return;
|
||||
}
|
||||
|
||||
let filename = path.resolve(root, "." + req.url);
|
||||
|
||||
// Make sure we aren't crawling out of our sandbox
|
||||
if (req.url[0] !== "/" || filename.substring(0, filename.length) !== filename) {
|
||||
resp.writeHead(403);
|
||||
resp.end();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const stat = fs.statSync(filename);
|
||||
if (stat.isDirectory()) {
|
||||
|
||||
// Redirect bare directory to its path (i.e. "/foo" => "/foo/")
|
||||
if (req.url[req.url.length - 1] !== "/") {
|
||||
resp.writeHead(301, { Location: req.url + "/" });
|
||||
resp.end();
|
||||
return;
|
||||
}
|
||||
|
||||
filename += "/index.html";
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(filename);
|
||||
|
||||
resp.writeHead(200, {
|
||||
"Content-Length": content.length,
|
||||
"Content-Type": getMime(filename)
|
||||
});
|
||||
resp.end(content);
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
if (error.code === "ENOENT") {
|
||||
resp.writeHead(404, { });
|
||||
resp.end();
|
||||
return;
|
||||
}
|
||||
|
||||
resp.writeHead(500, { });
|
||||
resp.end();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(options.port, () => {
|
||||
console.log(`Server running on: http://localhost:${ options.port }`);
|
||||
});
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
start(path.resolve(__dirname, "../../docs"), {
|
||||
redirects: {
|
||||
"/": "/v5/"
|
||||
}
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const { prompt } = require("../../packages/cli");
|
||||
const config = require("../config");
|
||||
|
||||
if (process.argv.length !== 3) {
|
||||
console.log("Usage: set-config KEY");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const key = process.argv[2];
|
||||
|
||||
(async function() {
|
||||
const value = await prompt.getPassword("Value: ");
|
||||
await config.set(key, value);
|
||||
})();
|
||||
@@ -1,146 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
// Expected this to be run after
|
||||
// - npm run clean
|
||||
// - npm run bootstrap
|
||||
// - npm run build
|
||||
|
||||
const fs = require("fs");
|
||||
|
||||
const semver = require("semver");
|
||||
|
||||
const { runBuild, runDist } = require("../build");
|
||||
const { ChangelogPath, generate } = require("../changelog");
|
||||
const { getOrdered, loadPackage } = require("../depgraph");
|
||||
const { getDiff, getStatus, getGitTag } = require("../git");
|
||||
const { updatePackage } = require("../local");
|
||||
const { getPackageVersion } = require("../npm");
|
||||
const { resolve } = require("../utils");
|
||||
const { colorify, log } = require("../log");
|
||||
|
||||
const { prompt } = require("../../packages/cli");
|
||||
|
||||
let dirnames = getOrdered();
|
||||
|
||||
// Only publish specific packages
|
||||
if (process.argv.length > 2) {
|
||||
let filter = process.argv.slice(2);
|
||||
|
||||
// Verify all named packages exist
|
||||
filter.forEach((dirname) => {
|
||||
try {
|
||||
loadPackage(dirname);
|
||||
} catch (error) {
|
||||
console.log("Package not found: " + dirname);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
// Filter out pacakges we don't care about
|
||||
dirnames = dirnames.filter((dirname) => (filter.indexOf(dirname) >= 0));
|
||||
}
|
||||
|
||||
(async function() {
|
||||
let progress = prompt.getProgressBar(colorify("Updating versions", "bold"));
|
||||
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
progress(i / dirnames.length);
|
||||
|
||||
let dirname = dirnames[i];
|
||||
let path = resolve("packages", dirname);
|
||||
|
||||
// Get local package.json (update the tarballHash)
|
||||
let info = await updatePackage(dirname);
|
||||
|
||||
// Get the remote package.json (or sub in a placeholder for new pacakges)
|
||||
let npmInfo = await getPackageVersion(info.name);
|
||||
if (!npmInfo) { npmInfo = { version: "NEW" }; }
|
||||
|
||||
if (info.tarballHash === npmInfo.tarballHash) { continue; }
|
||||
|
||||
// Bump the version if necessary
|
||||
if (info.version === npmInfo.version) {
|
||||
let newVersion = semver.inc(info.version, "patch");
|
||||
|
||||
// Write out the _version.ts
|
||||
if (!info._ethers_nobuild) {
|
||||
let code = "export const version = " + JSON.stringify(dirname + "/" + newVersion) + ";\n";
|
||||
fs.writeFileSync(resolve(path, "src.ts/_version.ts"), code);
|
||||
}
|
||||
|
||||
// Update the package.json (we do this after _version, so if we fail,
|
||||
// this remains old; which is what triggers the version bump)
|
||||
info = await updatePackage(dirname, { version: newVersion });
|
||||
}
|
||||
}
|
||||
progress(1);
|
||||
|
||||
try {
|
||||
log("<bold:Building TypeScript source (es6)...>");
|
||||
await runBuild(true);
|
||||
log("<bold:Building TypeScript source (commonjs)...>");
|
||||
await runBuild(false);
|
||||
log("<bold:Building distribution files...>");
|
||||
let content = await runDist();
|
||||
console.log(content);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
log("<red:Aborting.>");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the tarball hash now that _version and package.json may have changed.
|
||||
progress = prompt.getProgressBar(colorify("Updating tarballHash", "bold"));
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
progress(i / dirnames.length);
|
||||
await updatePackage(dirnames[i]);
|
||||
}
|
||||
progress(1);
|
||||
|
||||
// Show the changed files (compared to npm)
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
let dirname = dirnames[i];
|
||||
|
||||
// Get local package.json
|
||||
let info = await loadPackage(dirname);
|
||||
let path = resolve("packages/", dirname);
|
||||
|
||||
// Get the remote package.json (or sub in a placeholder for new pacakges)
|
||||
let npmInfo = await getPackageVersion(info.name);
|
||||
if (!npmInfo) { npmInfo = { version: "NEW" }; }
|
||||
|
||||
// No change
|
||||
if (info.tarballHash === npmInfo.tarballHash) { continue; }
|
||||
|
||||
let gitHead = await getGitTag(path);
|
||||
|
||||
log(`<bold:Package>: ${info.name}`);
|
||||
log(` <green:Tarball Changed:> (bumping version)`);
|
||||
log(` ${npmInfo.version} => ${info.version}`)
|
||||
log(` <blue:Changed:>`);
|
||||
let filenames = await getDiff(path, npmInfo.gitHead, true);
|
||||
filenames.forEach((filename) => {
|
||||
let short = filename.split("/").slice(1).join("/");
|
||||
if (short.indexOf("/src.ts/") >= 0 || short.indexOf("/dist/") >= 0) {
|
||||
log(` <bold:${short}>`);
|
||||
} else {
|
||||
log(` ${short}`);
|
||||
}
|
||||
});
|
||||
log("");
|
||||
}
|
||||
|
||||
let existing = fs.readFileSync(ChangelogPath).toString();
|
||||
let changelog = await generate();
|
||||
if (existing !== changelog) {
|
||||
let changelogStatus = await getStatus(ChangelogPath);
|
||||
if (changelogStatus !== "unmodified") {
|
||||
log("<bold:WARNING:> There are local changes to the CHANGELOG (they will be discarded)");
|
||||
console.log(existing);
|
||||
}
|
||||
log("<bold:Updating CHANGELOG>...");
|
||||
fs.writeFileSync(ChangelogPath, changelog);
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
120
admin/config.js
120
admin/config.js
@@ -1,120 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const resolve = require("path").resolve;
|
||||
|
||||
const AES = require("aes-js");
|
||||
const scrypt = require("scrypt-js");
|
||||
|
||||
const { prompt } = require("../packages/cli");
|
||||
const randomBytes = require("../packages/random").randomBytes;
|
||||
const computeHmac = require("../packages/sha2").computeHmac;
|
||||
|
||||
const colorify = require("./log").colorify;
|
||||
|
||||
function getScrypt(message, password, salt) {
|
||||
let progressBar = prompt.getProgressBar(message);
|
||||
return scrypt.scrypt(Buffer.from(password), Buffer.from(salt), (1 << 17), 8, 1, 64, progressBar);
|
||||
}
|
||||
|
||||
function Config(filename) {
|
||||
this.salt = null;
|
||||
this.dkey = null;
|
||||
this.values = { };
|
||||
this.canary = "";
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
Config.prototype.load = async function() {
|
||||
if (this.dkey) { return; }
|
||||
|
||||
let data = null;
|
||||
if (fs.existsSync(this.filename)) {
|
||||
data = JSON.parse(fs.readFileSync(this.filename));
|
||||
} else {
|
||||
data = {
|
||||
salt: Buffer.from(randomBytes(32)).toString("hex")
|
||||
};
|
||||
}
|
||||
|
||||
this.canary = data.canary || "";
|
||||
|
||||
this.salt = data.salt;
|
||||
|
||||
const password = await prompt.getPassword(colorify("Password (config-store): ", "bold"));
|
||||
|
||||
this.dkey = await getScrypt(colorify("Unlocking config", "bold"), password, this.salt);
|
||||
|
||||
if (data.ciphertext) {
|
||||
const ciphertext = Buffer.from(data.ciphertext, "base64");
|
||||
const iv = Buffer.from(data.iv, "base64");
|
||||
const aes = new AES.ModeOfOperation.ctr(this.dkey.slice(0, 32), new AES.Counter(iv));
|
||||
const plaintext = aes.decrypt(ciphertext);
|
||||
const hmac = computeHmac("sha512", this.dkey.slice(32, 64), plaintext);
|
||||
if (hmac !== data.hmac) {
|
||||
throw new Error("wrong password");
|
||||
}
|
||||
|
||||
this.values = JSON.parse(Buffer.from(plaintext).toString());
|
||||
}
|
||||
};
|
||||
|
||||
Config.prototype.keys = async function() {
|
||||
await this.load();
|
||||
return Object.keys(this.values);
|
||||
}
|
||||
|
||||
Config.prototype.save = function() {
|
||||
this.values._junk = Buffer.from(randomBytes(16 + parseInt(Math.random() * 48))).toString("base64")
|
||||
|
||||
const plaintext = Buffer.from(JSON.stringify(this.values));
|
||||
|
||||
const iv = Buffer.from(randomBytes(16));
|
||||
const hmac = computeHmac("sha512", this.dkey.slice(32, 64), plaintext);
|
||||
|
||||
const aes = new AES.ModeOfOperation.ctr(this.dkey.slice(0, 32), new AES.Counter(iv));
|
||||
const ciphertext = Buffer.from(aes.encrypt(plaintext));
|
||||
|
||||
const data = {
|
||||
ciphertext: ciphertext.toString("base64"),
|
||||
iv: iv.toString("base64"),
|
||||
salt: this.salt,
|
||||
hmac: hmac,
|
||||
canary: this.canary
|
||||
};
|
||||
|
||||
fs.writeFileSync(this.filename, JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
Config.prototype.get = async function(key) {
|
||||
await this.load();
|
||||
return this.values[key];
|
||||
};
|
||||
|
||||
Config.prototype.set = async function(key, value) {
|
||||
await this.load();
|
||||
this.values[key] = value;
|
||||
this.save();
|
||||
};
|
||||
|
||||
Config.prototype.lock = function() {
|
||||
this.salt = this.dkey = null;
|
||||
}
|
||||
|
||||
const config = new Config(resolve(os.homedir(), ".ethers-dist"));
|
||||
|
||||
module.exports = {
|
||||
get: function(key) {
|
||||
return config.get(key);
|
||||
},
|
||||
set: function(key, value) {
|
||||
config.set(key, value);
|
||||
},
|
||||
keys: function() {
|
||||
return config.keys();
|
||||
},
|
||||
lock: function() {
|
||||
config.lock();
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
|
||||
const { loadJson, resolve } = require("./utils");
|
||||
|
||||
const ROOT = resolve("packages");
|
||||
|
||||
const dirnames = fs.readdirSync(ROOT);
|
||||
|
||||
function loadPackage(dirname) {
|
||||
return loadJson(resolve("packages", dirname, "package.json"));
|
||||
}
|
||||
|
||||
function getOrdered(skipNobuild) {
|
||||
let packages = { };
|
||||
let filenames = { };
|
||||
|
||||
let addDeps = (name, depends) => {
|
||||
Object.keys(depends).forEach((dep) => {
|
||||
// Not a package we manage
|
||||
if (packages[dep] == null) { return; }
|
||||
deps[name][dep] = true;
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
let dirname = dirnames[i];
|
||||
let info = loadPackage(dirname);
|
||||
if (skipNobuild && info._ethers_nobuild) { continue; }
|
||||
packages[info.name] = info;
|
||||
filenames[info.name] = dirname;
|
||||
}
|
||||
|
||||
// Maps names to list of dependencies; { [ name:string]: Array<name: string> }
|
||||
let deps = { };
|
||||
let depGraph = { };
|
||||
|
||||
Object.keys(packages).forEach((name) => {
|
||||
let info = packages[name];
|
||||
deps[info.name] = { };
|
||||
addDeps(info.name, info.dependencies || { });
|
||||
addDeps(info.name, info.devDependencies || { });
|
||||
deps[info.name] = Object.keys(deps[info.name]);
|
||||
deps[info.name].sort();
|
||||
});
|
||||
|
||||
let ordered = [ ];
|
||||
let remaining = Object.keys(deps);
|
||||
|
||||
let isSatisfied = (name) => {
|
||||
for (let i = 0; i < deps[name].length; i++) {
|
||||
if (ordered.indexOf(deps[name][i]) === -1) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
while (remaining.length) {
|
||||
let bail = true;
|
||||
for (let i = 0; i < remaining.length; i++) {
|
||||
if (!isSatisfied(remaining[i])) { continue; }
|
||||
bail = false;
|
||||
ordered.push(remaining[i]);
|
||||
remaining.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bail) {
|
||||
throw new Error("Nothing processed; circular dependencies...");
|
||||
}
|
||||
}
|
||||
|
||||
return ordered.map((name) => filenames[name]);
|
||||
}
|
||||
|
||||
function sort(dirnames) {
|
||||
let ordered = getOrdered();
|
||||
dirnames.sort((a, b) => {
|
||||
let ai = ordered.indexOf(local.loadPackage(a).name);
|
||||
let bi = ordered.indexOf(local.loadPackage(b).name);
|
||||
if (ai === -1 || bi === -1) {
|
||||
throw new Error("unknown dirname - " + [a, b].join(", "));
|
||||
}
|
||||
return ai - bi;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
dirnames: dirnames,
|
||||
getOrdered: getOrdered,
|
||||
loadPackage: loadPackage,
|
||||
ROOT: ROOT,
|
||||
sort: sort
|
||||
}
|
||||
186
admin/git.js
186
admin/git.js
@@ -1,186 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const resolve = require("path").resolve;
|
||||
const spawn = require("child_process").spawn;
|
||||
|
||||
const semver = require("semver");
|
||||
|
||||
const { run } = require("./build");
|
||||
const { loadPackage } = require("./local");
|
||||
|
||||
function git(args) {
|
||||
return run("git", args);
|
||||
}
|
||||
|
||||
function getStatus(filename) {
|
||||
return git([ "status", "-s", resolve(__dirname, "..", filename) ]).then((result) => {
|
||||
result = result.trim();
|
||||
if (result === "") { return "unmodified"; }
|
||||
switch (result.substring(0, 2)) {
|
||||
case 'M ': return "modified";
|
||||
case 'A ': return "added";
|
||||
case 'D ': return "deleted";
|
||||
case 'R ': return "renamed";
|
||||
case 'C ': return "copied";
|
||||
case 'U ': return "updated";
|
||||
case '??': return "untracked";
|
||||
}
|
||||
console.log(result);
|
||||
return "unknown";
|
||||
});
|
||||
}
|
||||
|
||||
async function getChanges(latest) {
|
||||
let diff = await git(["diff", "--name-only", latest ]);
|
||||
|
||||
// Map dirname => { dist: [ ], src: [ ] }
|
||||
let changes = { "_": { filename: "_", dist: [], src: [] } };
|
||||
|
||||
diff.split("\n").forEach((line) => {
|
||||
// e.g. packages/constants/index.d.ts
|
||||
let comps = line.trim().split("/");
|
||||
|
||||
// Track non-packages as dist
|
||||
if (comps.length < 2 || comps[0] !== "packages") {
|
||||
let filename = comps.join("/").trim();
|
||||
if (filename === "") { return; }
|
||||
changes._.dist.push(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
let name = loadPackage(comps[1]).name;
|
||||
|
||||
let change = changes[name];
|
||||
if (!change) {
|
||||
change = { filename: comps[1], dist: [ ], src: [ ] }
|
||||
changes[name] = change;
|
||||
}
|
||||
|
||||
// Split changes into source changes (src.ts/) or dist changes (output of TypeScript)
|
||||
if (comps[2] === "src.ts") {
|
||||
change.src.push(comps.join("/"));
|
||||
} else {
|
||||
change.dist.push(comps.join("/"));
|
||||
}
|
||||
});
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
function getLatestTag() {
|
||||
let seq = Promise.resolve();
|
||||
|
||||
// @TODO: Pull
|
||||
if (false) {
|
||||
seq = seq.then(() => {
|
||||
console.log("Pulling remote changes...");
|
||||
return git([ "pull" ]);
|
||||
});
|
||||
}
|
||||
|
||||
seq = seq.then(() => {
|
||||
return git([ "tag" ]).then((tags) => {
|
||||
tags = tags.split("\n").filter(tag => (tag.match(/^v[0-9]+\.[0-9]+\.[0-9]+\-/)));
|
||||
tags.sort(semver.compare)
|
||||
return tags.pop();
|
||||
});
|
||||
});
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
function findChanges(latest) {
|
||||
let seq = Promise.resolve();
|
||||
|
||||
seq = seq.then(() => {
|
||||
return git(["diff", "--name-only", latest, "HEAD" ]).then((result) => {
|
||||
let filenames = { };
|
||||
result.split("\n").forEach((line) => {
|
||||
// e.g. packages/constants/index.d.ts
|
||||
let comps = line.trim().split("/");
|
||||
if (comps.length < 2) { return; }
|
||||
filenames[comps[1]] = true;
|
||||
});
|
||||
return Object.keys(filenames);
|
||||
});
|
||||
});
|
||||
|
||||
seq = seq.then((filenames) => {
|
||||
return filenames.map((filename) => {
|
||||
let name = packages[filename].name;
|
||||
return {
|
||||
filename: filename,
|
||||
name: name,
|
||||
localVersion: getLocalVersion(name),
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
seq = seq.then((packages) => {
|
||||
let seq = Promise.resolve();
|
||||
packages.forEach((p) => {
|
||||
seq = seq.then(() => {
|
||||
return getNpmVersion(p.name).then((version) => {
|
||||
p.npmVersion = version;
|
||||
});
|
||||
});
|
||||
});
|
||||
return seq.then(() => packages);
|
||||
});
|
||||
return seq;
|
||||
}
|
||||
|
||||
async function getGitTag(filename) {
|
||||
let result = await git([ "log", "-n", "1", "--", filename ]);
|
||||
result = result.trim();
|
||||
if (!result) { return null; }
|
||||
result = result.match(/^commit\s+([0-9a-f]{40})\n/i);
|
||||
if (!result) { return null; }
|
||||
return result[1];
|
||||
}
|
||||
|
||||
async function getDiff(filename, tag, nameOnly) {
|
||||
if (tag == null) { tag = "HEAD"; }
|
||||
let cmd = [ "diff", "--name-only", tag, "--", filename ]
|
||||
if (!nameOnly) { cmd.splice(1, 1); }
|
||||
try {
|
||||
let result = await git(cmd);
|
||||
result = result.trim();
|
||||
if (result === "") { return [ ]; }
|
||||
return result.split("\n");
|
||||
} catch (error) {
|
||||
// This tag does not exist, so compare against beginning of time
|
||||
// This happens when there is a new history (like an orphan branch)
|
||||
if (error.stderr.trim().match(/^fatal: bad object/)) {
|
||||
console.log("Could not find history; showing all");
|
||||
let cmd = [ "rev-list", "--max-parents=0", "HEAD" ];
|
||||
let tag = await git(cmd);
|
||||
return getDiff(filename, tag.trim(), nameOnly);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function getUntracked(filename) {
|
||||
let cmd = [ "ls-files", "-o", "--exclude-standard"];
|
||||
if (filename) {
|
||||
cmd.push("--");
|
||||
cmd.push(filename);
|
||||
}
|
||||
let result = await git(cmd);
|
||||
result = result.trim();
|
||||
if (result === "") { return [ ]; }
|
||||
return result.split("\n");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
findChanges: findChanges,
|
||||
getChanges: getChanges,
|
||||
getDiff: getDiff,
|
||||
getGitTag: getGitTag,
|
||||
getLatestTag: getLatestTag,
|
||||
getStatus: getStatus,
|
||||
getUntracked: getUntracked,
|
||||
run: git,
|
||||
}
|
||||
162
admin/github.js
162
admin/github.js
@@ -1,162 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const { resolve } = require("path");
|
||||
const zlib = require("zlib");
|
||||
|
||||
const { id } = require("../packages/hash");
|
||||
const { fetchJson } = require("../packages/web");
|
||||
|
||||
const CacheDir = resolve(__dirname, "../github-cache/");
|
||||
|
||||
function addResponse(result, response) {
|
||||
return { result, response };
|
||||
}
|
||||
|
||||
function loadFile(filename) {
|
||||
return JSON.parse(zlib.gunzipSync(fs.readFileSync(filename)).toString());
|
||||
//return JSON.parse(fs.readFileSync(filename).toString());
|
||||
}
|
||||
|
||||
// @TODO: atomic
|
||||
function saveFile(filename, content) {
|
||||
fs.writeFileSync(filename, zlib.gzipSync(JSON.stringify(content)));
|
||||
//fs.writeFileSync(filename, JSON.stringify(content));
|
||||
}
|
||||
|
||||
function mockFetchJson(url, body, headers) {
|
||||
return {
|
||||
result: null,
|
||||
response: {
|
||||
statusCode: 304
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function _fetchGitHub(user, password, fetchJson, url) {
|
||||
const result = [ ];
|
||||
while (true) {
|
||||
|
||||
const filename = resolve(CacheDir, id(url).substring(2, 14));
|
||||
|
||||
const headers = {
|
||||
"User-Agent": "ethers-io",
|
||||
};
|
||||
|
||||
let items = null;
|
||||
let link = null;
|
||||
try {
|
||||
const data = loadFile(filename);
|
||||
headers["if-none-match"] = data.etag;
|
||||
items = data.items;
|
||||
link = data.link;
|
||||
} catch (error) {
|
||||
if (error.code !== "ENOENT") { throw error; }
|
||||
}
|
||||
|
||||
const fetch = await fetchJson({
|
||||
url: url,
|
||||
user: user,
|
||||
password: password,
|
||||
headers: headers
|
||||
}, null, addResponse);
|
||||
|
||||
// Cached response is good; use it!
|
||||
if (fetch.response.statusCode !== 304) {
|
||||
items = fetch.result;
|
||||
if (fetch.response.headers) {
|
||||
link = (fetch.response.headers.link || null);
|
||||
}
|
||||
if (fetch.response.headers.etag){
|
||||
saveFile(filename, {
|
||||
timestamp: (new Date()).getTime(),
|
||||
url: url,
|
||||
link: link,
|
||||
etag: fetch.response.headers.etag,
|
||||
items: items,
|
||||
version: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
items.forEach((item) => { result.push(item)});
|
||||
|
||||
url = null;
|
||||
(link || "").split(",").forEach((item) => {
|
||||
if (item.indexOf('rel="next"') >= 0) {
|
||||
const match = item.match(/<([^>]*)>/);
|
||||
if (match) { url = match[1]; }
|
||||
}
|
||||
});
|
||||
|
||||
if (!url) { break; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function fetchGitHub(user, password, url, cacheOnly) {
|
||||
if (cacheOnly) {
|
||||
return await _fetchGitHub("none", "none", mockFetchJson, url);
|
||||
}
|
||||
|
||||
const results = await _fetchGitHub(user, password, fetchJson, url);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
async function _getIssues(user, password) {
|
||||
const cacheOnly = (user == null);
|
||||
|
||||
let issues = await fetchGitHub(user, password, "https:/\/api.github.com/repos/ethers-io/ethers.js/issues?state=all&per_page=100", cacheOnly)
|
||||
if (!cacheOnly) { console.log(`Found ${ issues.length } issues`); }
|
||||
const result = [ ];
|
||||
for (let i = 0; i < issues.length; i++) {
|
||||
const issue = issues[i];
|
||||
let comments = await fetchGitHub(user, password, issue.comments_url, cacheOnly);
|
||||
result.push({ issue, comments});
|
||||
if (!cacheOnly) { console.log(` Issue ${ issue.number }: ${ comments.length } comments`); }
|
||||
}
|
||||
result.sort((a, b) => (a.issue.number - b.issue.number));
|
||||
return result;
|
||||
}
|
||||
|
||||
function getIssues() {
|
||||
return _getIssues();
|
||||
}
|
||||
|
||||
function syncIssues(user, password) {
|
||||
return _getIssues(user, password);
|
||||
}
|
||||
|
||||
async function createRelease(user, password, tagName, title, body, prerelease, commit) {
|
||||
const payload = {
|
||||
tag_name: tagName,
|
||||
target_commitish: (commit || "master"),
|
||||
name: title,
|
||||
body: body,
|
||||
//draft: true,
|
||||
draft: false,
|
||||
prerelease: !!prerelease
|
||||
};
|
||||
|
||||
const headers = {
|
||||
"User-Agent": "ethers-io",
|
||||
};
|
||||
|
||||
const result = await fetchJson({
|
||||
url: "https://api.github.com/repos/ethers-io/ethers.js/releases",
|
||||
user: user,
|
||||
password: password,
|
||||
headers: headers
|
||||
}, JSON.stringify(payload));
|
||||
|
||||
|
||||
return result.html_url;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getIssues,
|
||||
syncIssues,
|
||||
createRelease,
|
||||
}
|
||||
|
||||
401
admin/index.js
401
admin/index.js
@@ -1,401 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const resolve = require("path").resolve;
|
||||
|
||||
const diff = require("diff");
|
||||
const semver = require("semver");
|
||||
|
||||
const { prompt } = require("../packages/cli");
|
||||
|
||||
const build = require("./build");
|
||||
const changelog = require("./changelog");
|
||||
const depgraph = require("./depgraph");
|
||||
const { colorify, colorifyStatus, log } = require("./log");
|
||||
const config = require("./config")
|
||||
const git = require("./git");
|
||||
const local = require("./local");
|
||||
const npm = require("./npm");
|
||||
const utils = require("./utils");
|
||||
|
||||
/*
|
||||
async function runChanged(dirnames, callback) {
|
||||
try {
|
||||
await callback(dirname, info, npmInfo);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log(colorify("Aborting! " + error.message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (diff) {
|
||||
} else {
|
||||
*/
|
||||
|
||||
async function runDiff(dirnames) {
|
||||
// Default to all packages
|
||||
if (dirnames == null || dirnames.length === 0) { dirnames = local.dirnames; }
|
||||
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
let dirname = dirnames[i];
|
||||
|
||||
// Get local (update the tarballHash) and remote package.json
|
||||
let info = await local.loadPackage(dirname);
|
||||
let npmInfo = await npm.getPackageVersion(info.name);
|
||||
if (!npmInfo) { npmInfo = { gitHead: "HEAD", version: "NEW" }; }
|
||||
|
||||
let delta = await git.getDiff(resolve(__dirname, "../packages", dirname), npmInfo.gitHead);
|
||||
|
||||
if (delta.length === 0) { continue; }
|
||||
|
||||
// Bump the version if necessary
|
||||
if (info.version === npmInfo.version) {
|
||||
info.version = semver.inc(info.version, "patch");
|
||||
}
|
||||
|
||||
console.log(colorify("<bold:Package>: ") + info.name);
|
||||
console.log(colorify(" <green:Git Head Changed:> (run update to bump version)"));
|
||||
console.log(" " + npmInfo.gitHead)
|
||||
console.log(" " + npmInfo.version + colorify(" => ", "bold") + info.version)
|
||||
|
||||
console.log(colorify(" Diff", "bold"));
|
||||
delta.forEach((line) => {
|
||||
let color = "blue";
|
||||
switch (line.substring(0, 1)) {
|
||||
case '+':
|
||||
color = "green";
|
||||
break;
|
||||
case '-':
|
||||
color = "red";
|
||||
break;
|
||||
case ' ':
|
||||
color = "normal";
|
||||
break;
|
||||
}
|
||||
console.log(" " + colorify(line, color));
|
||||
});
|
||||
|
||||
console.log("");
|
||||
}
|
||||
|
||||
console.log("");
|
||||
}
|
||||
|
||||
async function updateChangelog() {
|
||||
let filename = resolve(local.ROOT, "../CHANGELOG.md");
|
||||
|
||||
let lastVersion = await git.getLatestTag();
|
||||
let newVersion = "v" + local.getVersion("ethers");
|
||||
|
||||
let current = fs.readFileSync(filename).toString();
|
||||
let log = await changelog.generate();
|
||||
if (log === current) { return; }
|
||||
|
||||
let changes = diff.createTwoFilesPatch("CHANGELOG-old.md", "CHANGELOG.md", current, log, lastVersion, newVersion);
|
||||
console.log(changes);
|
||||
|
||||
try {
|
||||
let response = await prompt.getChoice(colorify("Accept changes?", "bold"), "yn", "n");
|
||||
if (response === "n") { throw new Error("Not changing."); }
|
||||
} catch (error) {
|
||||
console.log("Abort: " + error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFileSync(filename, log);
|
||||
}
|
||||
|
||||
// Updates the dependency-graph (tsconfig.project.json) so the build order is correct
|
||||
async function runUpdateDepgraph() {
|
||||
log(`<bold:Updating dependency-graph build order (tsconfig.project.json)...>`);
|
||||
let ordered = depgraph.getOrdered();
|
||||
|
||||
let path = resolve(local.ROOT, "../tsconfig.project.json")
|
||||
|
||||
let projectConfig = local.loadJson(path);
|
||||
projectConfig.references = ordered.map((name) => ({ path: ("./packages/" + name) }));
|
||||
local.saveJson(path, projectConfig);
|
||||
}
|
||||
|
||||
async function runUpdate(dirnames) {
|
||||
|
||||
// Check for untracked files...
|
||||
let untracked = [ ];
|
||||
if (dirnames == null || dirnames.length === 0) {
|
||||
dirnames = local.dirnames;
|
||||
let filenames = await git.getUntracked(resolve(__dirname, ".."));
|
||||
for (let i = 0; i < filenames.length; i++) {
|
||||
untracked.push(filenames[i]);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
let filenames = await git.getUntracked(resolve(local.ROOT, dirnames[i]));
|
||||
for (let j = 0; j < filenames.length; j++) {
|
||||
untracked.push(filenames[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Untracked files! Abort.
|
||||
if (untracked.length) {
|
||||
log("<bold:Untracked Files:>");
|
||||
untracked.forEach((filename) => {
|
||||
console.log(" " + filename);
|
||||
});
|
||||
log("<red:Aborting.>");
|
||||
return;
|
||||
}
|
||||
|
||||
log(`<bold:Run TypeScript build...>`);
|
||||
await build.runBuild()
|
||||
|
||||
log("");
|
||||
|
||||
// @TODO: Root
|
||||
|
||||
// Update all the package.json and _version.ts
|
||||
let progress = prompt.getProgressBar(colorify("Updating versions", "bold"));
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
progress(i / dirnames.length);
|
||||
|
||||
let dirname = dirnames[i];
|
||||
let path = resolve(__dirname, "../packages/", dirname);
|
||||
|
||||
// Get local package.json (update the tarballHash)
|
||||
let info = await local.updatePackage(dirname);
|
||||
|
||||
// Get the remote package.json (or sub in a placeholder for new pacakges)
|
||||
let npmInfo = await npm.getPackageVersion(info.name);
|
||||
if (!npmInfo) { npmInfo = { version: "NEW" }; }
|
||||
|
||||
if (info.tarballHash === npmInfo.tarballHash) { continue; }
|
||||
|
||||
// Bump the version if necessary
|
||||
if (info.version === npmInfo.version) {
|
||||
let newVersion = semver.inc(info.version, "patch");
|
||||
|
||||
// Write out the _version.ts
|
||||
if (!info._ethers_skipPrepare) {
|
||||
let code = "export const version = " + JSON.stringify(newVersion) + ";\n";
|
||||
fs.writeFileSync(resolve(path, "src.ts/_version.ts"), code);
|
||||
}
|
||||
|
||||
// Update the package.json (we do this after _version, so if we fail,
|
||||
// this remains old; which is what triggers the version bump)
|
||||
info = await local.updatePackage(dirname, { version: newVersion });
|
||||
}
|
||||
}
|
||||
progress(1);
|
||||
|
||||
// Build the TypeScript sources
|
||||
log("<bold:Runing TypeScript build...>");
|
||||
try {
|
||||
await build.runTsc();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
log("<red:Aborting.>");
|
||||
return;
|
||||
}
|
||||
|
||||
// Run the dist
|
||||
// @TODO:
|
||||
|
||||
// Update the tarball hash now that _version and package.json may have changed.
|
||||
progress = prompt.getProgressBar(colorify("Updating tarballHash", "bold"));
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
progress(i / dirnames.length);
|
||||
await local.updatePackage(dirnames[i]);
|
||||
}
|
||||
progress(1);
|
||||
|
||||
// Show the changed files (compared to npm)
|
||||
for (let i = 0; i < dirnames.length; i++) {
|
||||
let dirname = dirnames[i];
|
||||
|
||||
// Get local package.json
|
||||
let info = await local.loadPackage(dirname);
|
||||
let path = resolve(__dirname, "../packages/", dirname);
|
||||
|
||||
// Get the remote package.json (or sub in a placeholder for new pacakges)
|
||||
let npmInfo = await npm.getPackageVersion(info.name);
|
||||
if (!npmInfo) { npmInfo = { version: "NEW" }; }
|
||||
|
||||
// No change
|
||||
if (info.tarballHash === npmInfo.tarballHash) { continue; }
|
||||
|
||||
let gitHead = await git.getGitTag(path);
|
||||
|
||||
log(`<bold:Package>: ${info.name}`);
|
||||
log(` <green:Tarball Changed:> (bumping version)`);
|
||||
log(` ${npmInfo.version} => ${info.version}`)
|
||||
log(` <blue:Changed:>`);
|
||||
let filenames = await git.getDiff(resolve(__dirname, "../packages", dirname), npmInfo.gitHead, true);
|
||||
filenames.forEach((filename) => {
|
||||
let short = filename.split("/").slice(1).join("/");
|
||||
if (short.indexOf("/src.ts/") >= 0) {
|
||||
log(` <bold:${short}>`);
|
||||
} else {
|
||||
log(` ${short}`);
|
||||
}
|
||||
});
|
||||
log("");
|
||||
}
|
||||
|
||||
// @TODO: Changelog
|
||||
await updateChangelog();
|
||||
}
|
||||
|
||||
async function runAdd(type, names) {
|
||||
let latest = await git.getLatestTag();
|
||||
console.log("");
|
||||
console.log(colorify("<bold:Latest Published>: ") + latest);
|
||||
console.log("");
|
||||
|
||||
let changes = await git.getChanges("HEAD");
|
||||
|
||||
if (!names || names.length === 0) {
|
||||
names = Object.keys(changes);
|
||||
}
|
||||
|
||||
let filenames = [ ];
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
let name = names[i];
|
||||
let change = changes[name] || changes[(packages[name] || {}).name];
|
||||
if (!change) { return; }
|
||||
change[type].forEach((filename) => {
|
||||
filenames.push(filename);
|
||||
});
|
||||
}
|
||||
|
||||
if (filenames.length === 0) {
|
||||
console.log(colorify("<bold:Nothing to add.>"));
|
||||
console.log("");
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < filenames.length; i++) {
|
||||
let filename = filenames[i];
|
||||
let status = await git.getStatus(filename);
|
||||
console.log(" " + colorifyStatus(status) + ": " + utils.repeat(" ", 10 - status.length) + filename);
|
||||
}
|
||||
|
||||
console.log("");
|
||||
|
||||
try {
|
||||
let response = await prompt.getChoice(colorify("Add these files?", "bold"), "yn", "n");
|
||||
if (response === "n") { throw new Error("Not adding."); }
|
||||
} catch (error) {
|
||||
console.log("Abort: " + error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
let params = filenames.map((f) => f); //resolve(ROOT, f));
|
||||
params.unshift("--");
|
||||
params.unshift("add");
|
||||
|
||||
console.log("git " + params.join(" "));
|
||||
|
||||
try {
|
||||
await git.run(params);
|
||||
} catch (error) {
|
||||
console.log("Error: (status: " + error.code + ")");
|
||||
console.log(" " + error.stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Added.");
|
||||
}
|
||||
|
||||
function runDist() {
|
||||
// Run npm dist
|
||||
// Generate changelog
|
||||
// run status to update all the package
|
||||
// add dist files?
|
||||
}
|
||||
|
||||
async function runPublish(dirnames) {
|
||||
|
||||
// @TODO: Make sure there are no staged files
|
||||
|
||||
// @TODO: Make sure the repo has been pushed
|
||||
|
||||
// @TODO: Run the publish in the correct order
|
||||
|
||||
// Get the authentication token from our encrypted store
|
||||
let token = await config.get("token");
|
||||
token = token.trim().split("=");
|
||||
|
||||
let options = {
|
||||
npmVersion: "ethers-dist@0.0.0",
|
||||
tag: "next"
|
||||
};
|
||||
|
||||
// Set the authentication token
|
||||
options[token[0]] = token[1];
|
||||
|
||||
if (dirnames == null || dirnames.length === 0) { dirnames = local.dirnames; }
|
||||
depgraph.sort(dirnames);
|
||||
|
||||
await runChanged(dirnames, async (dirname, info, npmInfo) => {
|
||||
console.log(colorify("<bold:Publishing:> ") + info.name + "...")
|
||||
console.log(colorify(" Version: ", "blue") + npmInfo.version + colorify(" => ", "bold") + info.version);
|
||||
|
||||
let success = await npm.publish(dirname, options);
|
||||
if (!success) {
|
||||
console.log(colorify(" <red:FAILED! Aborting.>"));
|
||||
throw new Error("");
|
||||
}
|
||||
console.log(colorify(" <green:Done.>"));
|
||||
});
|
||||
}
|
||||
|
||||
async function runTest() {
|
||||
let r = await git([ "tag", "--porcelain", "-a", "-m", "Title of Release\n\nHello\n-----\n\nTesting 4 **bold** #1\nHello World", "test6", "HEAD" ]);
|
||||
console.log(r);
|
||||
try {
|
||||
r = await git([ "push", "--tags" ])
|
||||
} catch(e) { console.log(e); }
|
||||
console.log(r);
|
||||
}
|
||||
|
||||
(function() {
|
||||
let args = process.argv.slice(2);
|
||||
switch (args[0]) {
|
||||
|
||||
// Compare published to current stage
|
||||
case "diff":
|
||||
return runDiff(args.slice(1));
|
||||
|
||||
// Add unchecked-in source files
|
||||
case "add-source":
|
||||
return runAdd("src", args.slice(1));
|
||||
|
||||
// Update all package.json. the changelog and dist files
|
||||
case "update":
|
||||
return runUpdate(args.slice(1));
|
||||
|
||||
// Update dependency graph (./tsconfig-project.json)
|
||||
case "update-depgraph":
|
||||
return runUpdateDepgraph();
|
||||
|
||||
// Add unchecked-in dist files
|
||||
case "add-dist":
|
||||
return runAdd("dist", args.slice(1));
|
||||
|
||||
|
||||
// Add unchecked-in source files
|
||||
case "changelog":
|
||||
return updateChangelog();
|
||||
|
||||
// Add unchecked-in source files
|
||||
case "publish":
|
||||
return runPublish(args.slice(1));
|
||||
|
||||
case "test":
|
||||
return runTest();
|
||||
}
|
||||
})();
|
||||
101
admin/local.js
101
admin/local.js
@@ -1,101 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const packlist = require("npm-packlist");
|
||||
const tar = require("tar");
|
||||
|
||||
const keccak256 = (function() {
|
||||
try {
|
||||
return require("../packages/keccak256").keccak256;
|
||||
} catch (error) {
|
||||
console.log("Cannot load Keccak256 (maybe not built yet? Not really a problem for most things)");
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
|
||||
const { dirnames, loadPackage, ROOT } = require("./depgraph");
|
||||
const { resolve, saveJson } = require("./utils");
|
||||
|
||||
function sorted(obj) {
|
||||
if (Array.isArray(obj)) { return obj.map(sorted); }
|
||||
if (obj == null || typeof(obj) !== "object") { return obj; }
|
||||
|
||||
const keys = Object.keys(obj);
|
||||
keys.sort();
|
||||
|
||||
const result = { };
|
||||
keys.forEach((key) => { result[key] = sorted(obj[key]); });
|
||||
return result;
|
||||
}
|
||||
|
||||
function savePackage(dirname, info) {
|
||||
return saveJson(resolve(ROOT, dirname, "package.json"), sorted(info));
|
||||
}
|
||||
|
||||
async function createTarball(dirname) {
|
||||
let base = resolve(ROOT, dirname);
|
||||
|
||||
// From NPM publish, create the packed version
|
||||
let files = await packlist({ path: base });
|
||||
files = files.map((f) => ("./" + f));
|
||||
|
||||
let options = {
|
||||
cwd: base,
|
||||
prefix: 'package/',
|
||||
portable: true,
|
||||
sync: true,
|
||||
// Provide a specific date in the 1980s for the benefit of zip,
|
||||
// which is confounded by files dated at the Unix epoch 0.
|
||||
mtime: new Date('1985-10-26T08:15:00.000Z'),
|
||||
gzip: true
|
||||
};
|
||||
|
||||
// Take the hash of the package sans
|
||||
return tar.create(options, files).read();
|
||||
}
|
||||
|
||||
async function updatePackage(dirname, values) {
|
||||
let info = loadPackage(dirname);
|
||||
|
||||
if (values) {
|
||||
for (let key in values) {
|
||||
info[key] = values[key];
|
||||
}
|
||||
}
|
||||
/*
|
||||
["dependencies", "devDependencies"].forEach((key) => {
|
||||
let deps = info[key] || [];
|
||||
for (let name in deps) {
|
||||
if (name.substring(0, "@ethersproject".length) === "@ethersproject" || name === "ethers") {
|
||||
deps[name] = ">5.0.0-beta.0";
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
//if (dirname !== "ethers") {
|
||||
// delete info.publishConfig.tag;
|
||||
//}
|
||||
|
||||
// Create a normalized version sans tarballHash to compute the tarballHash
|
||||
delete info.tarballHash;
|
||||
savePackage(dirname, info);
|
||||
|
||||
// Compute the tarballHash
|
||||
let tarball = await createTarball(dirname);
|
||||
info.tarballHash = keccak256(tarball);
|
||||
|
||||
// Save the updated package.json to disk
|
||||
savePackage(dirname, info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ROOT: ROOT,
|
||||
createTarball: createTarball,
|
||||
dirnames: dirnames,
|
||||
getVersion: function(dirname) { return ((loadPackage(dirname) || {}).version || null); },
|
||||
loadPackage: loadPackage,
|
||||
savePackage: savePackage,
|
||||
updatePackage: updatePackage,
|
||||
}
|
||||
53
admin/log.js
53
admin/log.js
@@ -1,53 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
function getColor(color) {
|
||||
if (!color || color === "normal") { return "\x1b[0m"; }
|
||||
return "\x1b[1m" + ({
|
||||
blue: "\x1b[34m",
|
||||
cyan: "\x1b[36m",
|
||||
green: "\x1b[32m",
|
||||
magenta: "\x1b[35m",
|
||||
red: "\x1b[31m",
|
||||
yellow: "\x1b[33m",
|
||||
bold: ""
|
||||
})[color];
|
||||
}
|
||||
|
||||
// See: https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color
|
||||
let disableColor = !(process.stdout.isTTY);
|
||||
function colorify(message, color) {
|
||||
if (color) {
|
||||
if (disableColor) { return message; }
|
||||
return getColor(color) + message + getColor();
|
||||
}
|
||||
|
||||
return message.replace(/<([^:]*):((?:[^<>\\]|\\.)*)>/g, (all, color, message) => {
|
||||
message = message.replace("\\>", ">");
|
||||
if (disableColor) { return message; }
|
||||
return getColor(color) + message + getColor();
|
||||
});
|
||||
}
|
||||
|
||||
function colorifyStatus(status) {
|
||||
switch (status) {
|
||||
case "modified": return colorify("<blue:" + status + ">");
|
||||
case "added": return colorify("<green:" + status + ">");
|
||||
case "deleted": return colorify("<red:" + status + ">");
|
||||
case "unmodified": return colorify("<magenta:" + status + ">");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
function log(message, color) {
|
||||
if (color) {
|
||||
console.log(colorify(message, color));
|
||||
} else {
|
||||
console.log(colorify(message));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
colorify: colorify,
|
||||
colorifyStatus: colorifyStatus,
|
||||
log: log
|
||||
}
|
||||
104
admin/npm.js
104
admin/npm.js
@@ -1,104 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const resolve = require("path").resolve;
|
||||
|
||||
const npmpub = require("libnpmpublish");
|
||||
const semver = require("semver");
|
||||
|
||||
const local = require("./local");
|
||||
|
||||
const keccak256 = require("../packages/keccak256").keccak256;
|
||||
const fetchJson = require("../packages/web").fetchJson;
|
||||
const { prompt } = require("../packages/cli");
|
||||
|
||||
const colorify = require("./log").colorify;
|
||||
const git = require("./git");
|
||||
|
||||
|
||||
let cache = { };
|
||||
|
||||
async function getPackage(name) {
|
||||
if (cache[name]) { return cache[name]; }
|
||||
|
||||
return fetchJson("http:/" + "/registry.npmjs.org/" + name).then((result) => {
|
||||
cache[name] = result;
|
||||
return result;
|
||||
}, (error) => {
|
||||
if (error.status === 404) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
async function getVersion(name) {
|
||||
return getPackage(name).then((result) => {
|
||||
if (!result) { return null; }
|
||||
let versions = Object.keys(result.versions);
|
||||
versions.sort(semver.compare)
|
||||
return versions.pop();
|
||||
});
|
||||
}
|
||||
|
||||
async function getPackageVersion(name, version) {
|
||||
let info = await getPackage(name)
|
||||
if (!info) { return null; }
|
||||
|
||||
if (version == null) {
|
||||
let versions = Object.keys(info.versions);
|
||||
versions.sort(semver.compare);
|
||||
version = versions.pop();
|
||||
}
|
||||
|
||||
return info.versions[version] || null;
|
||||
}
|
||||
|
||||
async function getTarballHash(name, version) {
|
||||
let info = await getPackageVersion(name, version);
|
||||
return (info || {}).tarballHash;
|
||||
}
|
||||
|
||||
async function _publish(info, tarball, options) {
|
||||
try {
|
||||
let result = await npmpub.publish(info, tarball, options);
|
||||
return result;
|
||||
} catch (error) {
|
||||
|
||||
// We need an OTP
|
||||
if (error.code === "EOTP") {
|
||||
try {
|
||||
let otp = await prompt.getMessage(colorify("Enter OTP: ", "bold"));
|
||||
options.otp = otp.replace(" ", "");
|
||||
} catch (error) {
|
||||
|
||||
// CTRL-C
|
||||
if (error.message === "cancelled") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Something unexpected...
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Retry with the new OTP
|
||||
return _publish(info, tarball, options);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function publish(dirname, options) {
|
||||
let info = local.loadPackage(dirname);
|
||||
info.gitHead = await git.getGitTag(resolve(__dirname, "../packages/", dirname));
|
||||
if (info.gitHead == null) { throw new Error("no git tag found - " + dirname); }
|
||||
let tarball = await local.createTarball(dirname);
|
||||
return _publish(info, tarball, options);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPackage: getPackage,
|
||||
getPackageVersion: getPackageVersion,
|
||||
getTarballHash: getTarballHash,
|
||||
getVersion: getVersion,
|
||||
publish: publish,
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"name": "DevelopmentChain",
|
||||
"engine": {
|
||||
"instantSeal": null
|
||||
},
|
||||
"params": {
|
||||
"gasLimitBoundDivisor": "0x0400",
|
||||
"accountStartNonce": "0x0",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x11",
|
||||
"registrar" : "0x0000000000000000000000000000000000001337",
|
||||
"maxCodeSize": 24576,
|
||||
"maxCodeSizeTransition": "0x0",
|
||||
"eip98Transition": "0x7fffffffffffff",
|
||||
"eip140Transition": "0x0",
|
||||
"eip145Transition": "0x0",
|
||||
"eip150Transition": "0x0",
|
||||
"eip155Transition": "0x0",
|
||||
"eip160Transition": "0x0",
|
||||
"eip161abcTransition": "0x0",
|
||||
"eip161dTransition": "0x0",
|
||||
"eip211Transition": "0x0",
|
||||
"eip214Transition": "0x0",
|
||||
"eip658Transition": "0x0",
|
||||
"wasmActivationTransition": "0x0"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
"generic": "0x0"
|
||||
},
|
||||
"difficulty": "0x20000",
|
||||
"author": "0x0000000000000000000000000000000000000000",
|
||||
"timestamp": "0x00",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"extraData": "0x",
|
||||
"gasLimit": "0x7A1200"
|
||||
},
|
||||
"accounts": {
|
||||
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
|
||||
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
|
||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||
"0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } },
|
||||
"0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } },
|
||||
"0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } },
|
||||
"0x7454a8f5a7c7555d79b172c89d20e1f4e4cc226c": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"id":"24d70b97-fff9-d322-e760-4b8cc2e21751","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"45d392cd16dbbd5c0f5b2d145c112da9"},"ciphertext":"b001ccd09fc5431dc055975b58ee61f86e85529245506c04182c902716e750e5","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"028594da27a0e864105f33b912e5dc6ce7c75ecd13c81bfc158fe963d30c93bb"},"mac":"374bf2e9144b74b889708abc19e9ebc164f90bc27e83fd9f01da4571a9f81a70"},"address":"7454a8f5a7c7555d79b172c89d20e1f4e4cc226c","name":"","meta":"{}"}
|
||||
@@ -1,64 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const _resolve = require("path").resolve;
|
||||
|
||||
function repeat(chr, length) {
|
||||
let result = chr;
|
||||
while (result.length < length) { result += chr; }
|
||||
return result;
|
||||
}
|
||||
|
||||
function zpad(value) {
|
||||
value = String(value);
|
||||
while (value.length < 2) { value = "0" + value; }
|
||||
return value;
|
||||
}
|
||||
|
||||
function getDate(date) {
|
||||
return [
|
||||
date.getFullYear(),
|
||||
zpad(date.getMonth() + 1),
|
||||
zpad(date.getDate())
|
||||
].join("-");
|
||||
}
|
||||
|
||||
function getDateTime(date) {
|
||||
return getDate(date) + " " + [
|
||||
zpad(date.getHours()) ,
|
||||
zpad(date.getMinutes() + 1)
|
||||
].join(":");
|
||||
}
|
||||
|
||||
function today() {
|
||||
return getDate(new Date());
|
||||
}
|
||||
|
||||
function loadJson(filename) {
|
||||
return JSON.parse(fs.readFileSync(filename).toString());
|
||||
}
|
||||
|
||||
// @TODO: atomic write
|
||||
function saveJson(filename, json) {
|
||||
fs.writeFileSync(filename, JSON.stringify(json, null, 2) + "\n");
|
||||
}
|
||||
|
||||
function resolve(...args) {
|
||||
args = args.slice();
|
||||
args.unshift("..");
|
||||
args.unshift(__dirname);
|
||||
return _resolve.apply(null, args);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
resolve: resolve,
|
||||
|
||||
loadJson: loadJson,
|
||||
saveJson: saveJson,
|
||||
|
||||
repeat: repeat,
|
||||
|
||||
today: today,
|
||||
getDate: getDate,
|
||||
getDateTime: getDateTime
|
||||
}
|
||||
@@ -1,24 +1,49 @@
|
||||
_section: ContractFactory @<ContractFactory> @SRC<contracts:class.ContractFactory>
|
||||
|
||||
@TODO: Fill this in, including @SRC links
|
||||
To deploy a [[Contract]], additional information is needed
|
||||
that is not available on a Contract object itself.
|
||||
|
||||
Mainly, the bytecode (more specifically the initcode) of a contract is required.
|
||||
|
||||
The **Contract Factory** sends a special type of transaction, an initcode
|
||||
transaction (i.e. the ``to`` field is null, and the ``data`` field is the
|
||||
initcode) where the initcode will be evaluated and the result becomes the
|
||||
new code to be deployed as a new contract.
|
||||
|
||||
_subsection: Creating Instances @<ContractFactory--creating>
|
||||
|
||||
_property: new ethers.ContractFactory(interface, bytecode [ , signer ]) @SRC<contracts:constructor.ContractFactory>
|
||||
|
||||
Creates a new instance of a **ContractFactory** for the contract described
|
||||
by the //interface// and //bytecode// initcode.
|
||||
|
||||
_property: ContractFactory.fromSolidity(compilerOutput [ , signer ]) => [[ContractFactory]]
|
||||
|
||||
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>
|
||||
|
||||
Returns a **new instance** of the ContractFactory with the same //interface//
|
||||
and //bytecode//, but with a different //signer//.
|
||||
|
||||
_subsection: Properties @<ContractFactory--properties>
|
||||
|
||||
_property: contractFactory.interface => [[Interface]]
|
||||
|
||||
The [[Contract]] interface.
|
||||
|
||||
_property: contractFactory.bytecode => string<[[DataHexString]]>
|
||||
|
||||
The bytecode (i.e. initcode) that this **ContractFactory** will
|
||||
use to deploy the Contract.
|
||||
|
||||
_property: contractFactory.signer => [[Signer]]
|
||||
|
||||
The [[Signer]] (if any) this ContractFactory will use to deploy instances
|
||||
of the Contract to the Blockchain.
|
||||
|
||||
|
||||
_subsection: Methods @<ContractFactory--methods>
|
||||
|
||||
@@ -29,36 +54,52 @@ same as using the [Contract constructor](Contract--creating) with
|
||||
//address// and this the //interface// and //signerOrProvider// passed
|
||||
in when creating the ContractFactory.
|
||||
|
||||
_property: contractFactory.getDeployTransaction(...args) => [[UnsignedTransaction]]
|
||||
_property: contractFactory.getDeployTransaction(...args [ , overrides ]) => [[UnsignedTransaction]]
|
||||
|
||||
Returns the unsigned transaction which would deploy this Contract with //args// passed
|
||||
to the Contract's constructor.
|
||||
|
||||
_property: contractFactory.deploy(...args) => Promise<[[Contract]]> @<ContractFactory-deploy>
|
||||
If the optional //overrides// is specified, they can be used to
|
||||
override the endowment ``value``, transaction ``nonce``, ``gasLimit`` or
|
||||
``gasPrice``.
|
||||
|
||||
_property: contractFactory.deploy(...args [ , overrides ]) => Promise<[[Contract]]> @<ContractFactory-deploy>
|
||||
|
||||
Uses the signer to deploy the Contract with //args// passed into the constructor and
|
||||
returns a Contract which is attached to the address where this contract **will** be
|
||||
returns a Contract which is attached to the address where this contract **will** be
|
||||
deployed once the transaction is mined.
|
||||
|
||||
The transaction can be found at ``contract.deployTransaction``, and no interactions
|
||||
should be made until the transaction is mined.
|
||||
|
||||
_code: Deploying a Contract
|
||||
If the optional //overrides// is specified, they can be used to
|
||||
override the endowment ``value``, transaction ``nonce``, ``gasLimit`` or
|
||||
``gasPrice``.
|
||||
|
||||
_code: Deploying a Contract @lang<javascript>
|
||||
|
||||
// <hide>
|
||||
const signer = ethers.LocalSigner();
|
||||
const signer = localSigner;
|
||||
const ContractFactory = ethers.ContractFactory;
|
||||
const bytecode = "608060405234801561001057600080fd5b5060405161012e38038061012e8339818101604052604081101561003357600080fd5b81019080805190602001909291908051906020019092919050505081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060008190555050506088806100a66000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633fa4f24514602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000805490509056fea2646970667358221220926465385af0e8706644e1ff3db7161af699dc063beaadd55405f2ccd6478d7564736f6c63430007040033";
|
||||
// </hide>
|
||||
|
||||
|
||||
// If your contract constructor requires parameters, the ABI
|
||||
// must include the constructor
|
||||
const abi = [
|
||||
"constructor(address owner, uint256 initialValue)"
|
||||
"constructor(address owner, uint256 initialValue)",
|
||||
"function value() view returns (uint)"
|
||||
];
|
||||
|
||||
const factory = new ContractFactory(abi, bytecode, signer)
|
||||
// The factory we use for deploying contracts
|
||||
factory = new ContractFactory(abi, bytecode, signer)
|
||||
|
||||
const contract = await factory.deploy("ricmoo.eth", 42);
|
||||
// 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
|
||||
@@ -69,7 +110,9 @@ contract.address
|
||||
contract.deployTransaction
|
||||
//!
|
||||
|
||||
// Wait until the transaction is mined
|
||||
// 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()
|
||||
//!
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
_section: Contract @<Contract> @SRC<contracts:class.Contract>
|
||||
|
||||
Explain contract here...
|
||||
A **Contract** is an abstraction of code that has been deployed
|
||||
to the blockchain.
|
||||
|
||||
A Contract may be sent transactions, which will trigger its code
|
||||
to be run with the input of the transaction data.
|
||||
|
||||
_subsection: Creating Instances @<Contract--creating>
|
||||
|
||||
@@ -101,7 +105,10 @@ 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.
|
||||
The type of the result depends on the ABI. If the method returns a single
|
||||
value, it will be returned directly, otherwise a [[Result]] object will
|
||||
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
|
||||
@@ -113,6 +120,25 @@ number is used. Otherwise a [[BigNumber]] is returned.
|
||||
|
||||
For bytes (both fixed length and dynamic), a [[DataHexString]] is returned.
|
||||
|
||||
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
|
||||
- ``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``);
|
||||
//most developers will not require this//
|
||||
- ``overrides.gasLimit`` - the amount of gas (theoretically) to allow a node
|
||||
to use during the execution of the code; since there is no transaction, there
|
||||
is not going to be any fee charged, but the EVM still processes gas metering
|
||||
so calls like ``gasleft`` (or ``GAS``) report meaningful values
|
||||
- ``overrides.blockTag`` - a block tag to simulate the execution at, which
|
||||
can be used for hypothetical historic analysis; note that many backends
|
||||
do not support this, or may require paid plans to access as the node database
|
||||
storage and processing requirements are much higher
|
||||
|
||||
_property: contract.functions.METHOD_NAME(...args [, overrides ]) => Promise<[[Result]]>
|
||||
|
||||
The result will always be a [[Result]], even if there is only a single
|
||||
@@ -130,6 +156,8 @@ allowing an alternate UTF-8 error strategy to be used.
|
||||
|
||||
Most developers should not require this.
|
||||
|
||||
The //overrides// are identical to the read-only operations above.
|
||||
|
||||
_heading: Write Methods (non-constant) @<Contract--write>
|
||||
|
||||
A non-constant method requires a transaction to be signed and requires
|
||||
@@ -147,6 +175,32 @@ Returns a [[providers-TransactionResponse]] for the transaction after
|
||||
it is sent to the network. This requires the **Contract** has a
|
||||
signer.
|
||||
|
||||
The //overrides// object for write methods may include any of:
|
||||
|
||||
- ``overrides.gasPrice`` - the price to pay per gas
|
||||
- ``overrides.gasLimit`` - the limit on the amount of gas to allow the transaction
|
||||
to consume; any unused gas is returned at the gasPrice
|
||||
- ``overrides.value`` - the amount of ether (in wei) to forward with the call
|
||||
- ``overrides.nonce`` - the nonce to use for the [[Signer]]
|
||||
|
||||
If the ``wait()`` method on the returned [[providers-TransactionResponse]]
|
||||
is called, there will be additional properties on the receipt:
|
||||
|
||||
- ``receipt.events`` - an array of the logs, with additional properties
|
||||
(if the ABI included a description for the events)
|
||||
- ``receipt.events[n].args`` - the parsed arguments
|
||||
- ``receipt.events[n].decode`` - a method that can be used to parse the
|
||||
log topics and data (this was used to compute ``args``)
|
||||
- ``receipt.events[n].event`` - the name of the event
|
||||
- ``receipt.events[n].eventSignature`` - the full signature of the event
|
||||
- ``receipt.removeListener()`` - a method to remove the listener that trigger
|
||||
this event
|
||||
- ``receipt.getBlock()`` - a method to return the [Block](providers-Block) this event occurred in
|
||||
- ``receipt.getTransaction()`` - a method to return the
|
||||
[Transaction](providers-TransactionResponse) this event occurred in
|
||||
- ``receipt.getTransactionReceipt()`` - a method to return the
|
||||
[Transaction Receipt](providers-TransactionReceipt) this event occurred in
|
||||
|
||||
|
||||
_heading: Write Methods Analysis @<Contract--check>
|
||||
|
||||
@@ -157,11 +211,17 @@ _property: contract.estimateGas.METHOD_NAME(...args [ , overrides ]) => Promise<
|
||||
Returns the estimate units of gas that would be required to
|
||||
execute the //METHOD_NAME// with //args// and //overrides//.
|
||||
|
||||
The //overrides// are identical to the overrides above for read-only
|
||||
or write methods, depending on the type of call of //METHOD_NAME//.
|
||||
|
||||
_property: contract.populateTransaction.METHOD_NAME(...args [ , overrides ]) => Promise<[UnsignedTx](UnsignedTransaction)> @<contract-populateTransaction>
|
||||
Returns an [[UnsignedTransaction]] which represents the transaction
|
||||
that would need to be signed and submitted to the network to execute
|
||||
//METHOD_NAME// with //args// and //overrides//.
|
||||
|
||||
The //overrides// are identical to the overrides above for read-only
|
||||
or write methods, depending on the type of call of //METHOD_NAME//.
|
||||
|
||||
_property: contract.callStatic.METHOD_NAME(...args [ , overrides ]) => Promise<any> @<contract-callStatic>
|
||||
Rather than executing the state-change of a transaction, it is possible
|
||||
to ask a node to //pretend// that a call is not state-changing and
|
||||
@@ -172,6 +232,8 @@ can be used to determine if a transaction will fail or succeed.
|
||||
|
||||
This otherwise functions the same as a [Read-Only Method](Contract--readonly).
|
||||
|
||||
The //overrides// are identical to the read-only operations above.
|
||||
|
||||
_heading: Event Filters @<Contract--filters>
|
||||
An event filter is made up of topics, which are values logged in a
|
||||
[[link-wiki-bloomfilter]], allowing efficient searching for entries
|
||||
|
||||
@@ -58,7 +58,7 @@ Set the current transaction count (nonce) for the signer.
|
||||
This may be useful in interacting with the signer outside of using
|
||||
this class.
|
||||
|
||||
_property: nonceManager.increaseTransactionCount( [ count = 1 ]) => void
|
||||
_property: nonceManager.incrementTransactionCount( [ count = 1 ]) => void
|
||||
Bump the current transaction count (nonce) by //count//.
|
||||
|
||||
This may be useful in interacting with the signer outside of using
|
||||
|
||||
@@ -5,11 +5,13 @@ with Ethereum and is available in all major Ethereum node implementations
|
||||
(e.g. [[link-geth]] and [[link-parity]]) as well as many
|
||||
third-party web services (e.g. [[link-infura]])
|
||||
|
||||
_property: new ethers.providers.JsonRpcProvider([ url [ , aNetworkish ] ]) @SRC<providers:constructor.JsonRpcProvider>
|
||||
Connect to a JSON-RPC API located at //url// using the //aNetworkish// network.
|
||||
If //url// 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.
|
||||
_property: new ethers.providers.JsonRpcProvider([ urlOrConnectionInfo [ , networkish ] ]) @SRC<providers:constructor.JsonRpcProvider>
|
||||
Connect to a JSON-RPC HTTP API using the URL or [[ConnectionInfo]] //urlOrConnectionInfo//
|
||||
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``.
|
||||
|
||||
_note: Note: Connecting to a Local Node
|
||||
Each node implementation is slightly different and may require specific
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
_section: Other Providers
|
||||
|
||||
Others...
|
||||
|
||||
_subsection: FallbackProvider @<FallbackProvider> @INHERIT<[[Provider]]> @SRC<providers/fallback-provider:class.FallbackProvider>
|
||||
|
||||
The **FallbackProvider** is the most advanced [[Provider]] available in
|
||||
@@ -11,7 +9,7 @@ It uses a quorum and connects to multiple [Providers](Provider) as backends,
|
||||
each configured with a //priority// and a //weight// .
|
||||
|
||||
When a request is made, the request is dispatched to multiple backends, randomly
|
||||
chosen (higher priority backends are always selected first) and the results from
|
||||
chosen (lower-value priority backends are always selected first) and the results from
|
||||
each are compared against the others. Only once the quorum has been reached will that
|
||||
result be accepted and returned to the caller.
|
||||
|
||||
@@ -40,9 +38,9 @@ _property: fallbackProviderConfig.provider => [[Provider]]
|
||||
The provider for this configuration.
|
||||
|
||||
_property: fallbackProviderConfig.priority => number
|
||||
The priority used for the provider. Higher priorities are favoured over lower
|
||||
priorities. If multiple providers share the same priority, they are chosen
|
||||
at random.
|
||||
The priority used for the provider. Lower-value priorities are favoured over
|
||||
higher-value priorities. If multiple providers share the same priority, they
|
||||
are chosen at random.
|
||||
|
||||
_property: fallbackProviderConfig.stallTimeout => number
|
||||
The timeout (in ms) after which another [[Provider]] will be attempted. This
|
||||
@@ -156,7 +154,7 @@ WebSockets are much more intensive on your server resources, as they must manage
|
||||
and maintain the state for each client. For this reason, many services may also
|
||||
charge additional fees for using their WebSocket endpoints.
|
||||
|
||||
_property: new ethers.provider.WebSocketProvider([ url [ , network ] ])
|
||||
_property: new ethers.providers.WebSocketProvider([ url [ , network ] ])
|
||||
Returns a new [[WebSocketProvider]] connected to //url// as the //network//.
|
||||
|
||||
If //url// is unspecified, the default ``"ws:/\/localhost:8546"`` will be used.
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
_section: Provider @<Provider>
|
||||
|
||||
Explain what a provider is...
|
||||
A **Provider** in ethers is a read-only abstraction to
|
||||
access the blockchain data.
|
||||
|
||||
_note: Coming from Web3.js?
|
||||
If you are coming from Web3.js, this is one of the biggest
|
||||
differences you will encounter using ethers.
|
||||
|
||||
The ethers library creates a strong division between the
|
||||
operation a **Provider** can perform and those of a [[Signer]],
|
||||
which Web3.js lumps together.
|
||||
|
||||
This separation of concerns and a stricted subset of Provider
|
||||
operations allows for a larger variety of backends, a more
|
||||
consistent API and ensures other libraries to operate without
|
||||
being able to rely on any underlying assumption.
|
||||
|
||||
_subsection: Accounts Methods @<Provider--account-methods>
|
||||
|
||||
@@ -73,6 +86,10 @@ reading and debugging much simpler.
|
||||
The provider offers some basic operations to help resolve and
|
||||
work with ENS names.
|
||||
|
||||
_property: provider.getResolver(name) => Promise<[[EnsResolver]]>
|
||||
Returns an EnsResolver instance which can be used to further inquire
|
||||
about specific entries for an ENS name.
|
||||
|
||||
_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
|
||||
@@ -94,6 +111,25 @@ provider.resolveName("ricmoo.firefly.eth");
|
||||
//!
|
||||
|
||||
|
||||
_subsection: EnsResolver @<EnsResolver>
|
||||
|
||||
_property: resolver.name => string
|
||||
The name of this resolver.
|
||||
|
||||
_property: resolver.address => string<[[address]]>
|
||||
The address of the Resolver.
|
||||
|
||||
_property: resolver.getAddress([ cointType = 60 ]) => Promise<string>
|
||||
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.
|
||||
|
||||
_property: resolver.getContentHash() => Promise<string>
|
||||
Returns a Promise which resolves to any stored [[link-eip-1577]] content hash.
|
||||
|
||||
_property: resolver.getText(key) => Promise<string>
|
||||
Returns a Promise which resolves to any stored [[link-eip-634]] text entry for //key//.
|
||||
|
||||
_subsection: Logs Methods @<Provider--log-methods>
|
||||
|
||||
_property: provider.getLogs(filter) => Promise<Array<[[providers-Log]]>> @<Provider-getLogs> @SRC<providers/base-provider>
|
||||
@@ -115,6 +151,13 @@ Returns the block number (or height) of the most recently mined block.
|
||||
_property: provider.getGasPrice() => Promise<[[BigNumber]]> @<Provider-getGasPrice> @SRC<providers/base-provider>
|
||||
Returns a //best guess// of the [[gas-price]] to use in a transaction.
|
||||
|
||||
_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.
|
||||
|
||||
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
|
||||
@@ -156,6 +199,21 @@ 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.
|
||||
|
||||
_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.
|
||||
|
||||
If a transaction has not been mined, this method will search the transaction
|
||||
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.
|
||||
|
||||
_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.
|
||||
|
||||
To stall until the transaction has been mined, consider the ``waitForTransaction``
|
||||
method below.
|
||||
|
||||
_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
|
||||
@@ -164,36 +222,47 @@ for the transaction).
|
||||
_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.
|
||||
|
||||
If //confirms// is 0, this method is non-blocking and if the
|
||||
transaction has not been mined returns null. Otherwise,
|
||||
this method will block until the transaction has //confirms//
|
||||
blocks mined on top of the block in which is was mined.
|
||||
|
||||
_subsection: Event Emitter Methods @<Provider--event-methods>
|
||||
|
||||
Explain events here...
|
||||
The EventEmitter API allows applications to use an
|
||||
[[link-wiki-observer-pattern]] to register callbacks for when
|
||||
various events occur.
|
||||
|
||||
This closely follows the Event Emitter provided by other JavaScript
|
||||
libraries with the exception that event names support some more
|
||||
[complex objects](Provider--events), not only strings. The objects
|
||||
are normalized internally.
|
||||
|
||||
_property: provider.on(eventName, listener) => this @<Provider-on> @SRC<providers/base-provider>
|
||||
Add a //listener// to be triggered for each //eventName//.
|
||||
Add a //listener// to be triggered for each //eventName// [event](Provider--events).
|
||||
|
||||
_property: provider.once(eventName, listener) => this @<Provider-once> @SRC<providers/base-provider>
|
||||
Add a //listener// to be triggered for only the next //eventName//,
|
||||
at which time it will be removed.
|
||||
Add a //listener// to be triggered for only the next
|
||||
//eventName// [event](Provider--events), at which time it will be removed.
|
||||
|
||||
_property: provider.emit(eventName, ...args) => boolean @<Provider-emit> @SRC<providers/base-provider>
|
||||
Notify all listeners of //eventName//, passing //args// to each listener. This
|
||||
is generally only used internally.
|
||||
Notify all listeners of the //eventName// [event](Provider--events),
|
||||
passing //args// to each listener. This is generally only used internally.
|
||||
|
||||
_property: provider.off(eventName [ , listener ]) => this @<Provider-off> @SRC<providers/base-provider>
|
||||
Remove a //listener// for //eventName//. If no //listener// is provided,
|
||||
all listeners for //eventName// are removed.
|
||||
Remove a //listener// for the //eventName// [event](Provider--events).
|
||||
If no //listener// is provided, all listeners for //eventName// are removed.
|
||||
|
||||
_property: provider.removeAllListeners([ eventName ]) => this @<Provider-removeAllListeners> @SRC<providers/base-provider>
|
||||
Remove all the listeners for //eventName//. If no //eventName// is provided,
|
||||
**all** events are removed.
|
||||
Remove all the listeners for the //eventName// [events](Provider--events).
|
||||
If no //eventName// is provided, **all** events are removed.
|
||||
|
||||
_property: provider.listenerCount([ eventName ]) => number @<Provider-listenerCount> @SRC<providers/base-provider>
|
||||
Returns the number of listeners for //eventName//. If no //eventName// is
|
||||
provided, the total number of listeners is returned.
|
||||
Returns the number of listeners for the //eventName// [events](Provider--events).
|
||||
If no //eventName// is provided, the total number of listeners is returned.
|
||||
|
||||
_property: provider.listeners(eventName) => Array<Listener> @<Provider-listeners> @SRC<providers/base-provider>
|
||||
Returns the list of Listeners for //eventName//.
|
||||
Returns the list of Listeners for the //eventName// [events](Provider--events).
|
||||
|
||||
|
||||
_heading: Events @<Provider--events>
|
||||
@@ -207,7 +276,7 @@ properties ``address`` (the source contract) and ``topics`` (a topic-set to matc
|
||||
|
||||
If ``address`` is unspecified, the filter matches any contract address.
|
||||
|
||||
See events for more information on how to specify topic-sets.
|
||||
See [EventFilters](providers-EventFilter) for more information on filtering events.
|
||||
|
||||
_definition: **Topic-Set Filter**
|
||||
|
||||
@@ -216,6 +285,8 @@ The value of a **Topic-Set Filter** is a array of Topic-Sets.
|
||||
This event is identical to a //Log Filter// with the address omitted (i.e. from
|
||||
any contract).
|
||||
|
||||
See [EventFilters](providers-EventFilter) for more information on filtering events.
|
||||
|
||||
_definition: **Transaction Filter**
|
||||
|
||||
The value of a **Transaction Filter** is any transaction hash.
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
_section: Types
|
||||
|
||||
_subsection: BlockTag @<providers-BlockTag>
|
||||
A **BlockTag** specifies a specific location in the Blockchain.
|
||||
A **BlockTag** specifies a specific block location in the Blockchain.
|
||||
|
||||
- **``"latest"``** -- The most recently mined block
|
||||
- **``"earliest"``** -- Block #0
|
||||
- **``"pending"``** -- The block currently being prepared for mining; not all
|
||||
- **``"latest"``** - The most recently mined block
|
||||
- **``"earliest"``** - Block #0
|
||||
- **``"pending"``** - The block currently being prepared for mining; not all
|
||||
operations and backends support this BlockTag
|
||||
- **//number//** -- The block at this height
|
||||
- **//a negative number//** -- The block this many blocks ago
|
||||
|
||||
_heading: EventType @<providers-EventType>
|
||||
|
||||
And **EventType** can be any of the following.
|
||||
|
||||
- **//string//** -- TODO...
|
||||
- **//Array<string<[[DataHexString]]<32>> | Array<string<[[DataHexString]]<32>>>>//** -- TODO...
|
||||
- **//[[providers-EventFilter]]//** -- TODO...
|
||||
|
||||
- **//number//** - The block at this height
|
||||
- **//a negative number//** - The block this many blocks ago
|
||||
- **//hex string//** - The block at this height (as a hexidecimal value)
|
||||
|
||||
_subsection: Networkish @<providers-Networkish>
|
||||
A **Networkish** may be any of the following:
|
||||
@@ -111,10 +103,15 @@ _heading: EventFilter @<providers-EventFilter>
|
||||
_property: filter.address => string<[[address]]>
|
||||
The address to filter by, or ``null`` to match any address.
|
||||
|
||||
_property: filter.topics => Array<string<[[DataHexString]]<32>> | Array<string<[[DataHexString]]<32>>>>
|
||||
The topics to filter by, or ``null`` to match any topics. Each entry represents an
|
||||
**AND** condition that must match, or may be ``null`` to match anything. If a given
|
||||
entry is an Array, then that entry is treated as an **OR** for any value in the entry.
|
||||
_property: filter.topics => Array<string<[Data](DataHexString)<32>> | Array<string<[Data](DataHexString)<32>>>>
|
||||
The topics to filter by or ``null`` to match any topics.
|
||||
|
||||
Each entry represents an **AND** condition that must match, or may
|
||||
be ``null`` to match anything. If a given entry is an Array, then
|
||||
that entry is treated as an **OR** for any value in the entry.
|
||||
|
||||
See [Filters](events--filters) for more details and examples
|
||||
on specifying complex filters.
|
||||
|
||||
_heading: Filter @<providers-Filter> @INHERIT<[[providers-EventFilter]]>
|
||||
|
||||
@@ -231,9 +228,18 @@ transaction was mined.
|
||||
_property: transaction.raw => string<[[DataHexString]]>
|
||||
The serialized transaction.
|
||||
|
||||
_property: transaction.wait([ confirmations = 1 ]) => Promise<[[providers-TransactionReceipt]]>
|
||||
Wait for //confirmations//. If 0, and the transaction has not been mined,
|
||||
``null`` is returned.
|
||||
_property: transaction.wait([ confirms = 1 ]) => Promise<[[providers-TransactionReceipt]]>
|
||||
Resolves to the [[providers-TransactionReceipt]] once the transaction
|
||||
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
|
||||
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``
|
||||
|
||||
_heading: TransactionReceipt @<providers-TransactionReceipt>
|
||||
|
||||
|
||||
@@ -45,13 +45,13 @@ _property: ethers.utils.getAddress(address) => string<[[address]]> @<utils-getA
|
||||
Returns //address// as a Checksum Address.
|
||||
|
||||
If //address// is an invalid 40-nibble [[HexString]] or if it contains mixed case and
|
||||
the checksum is invalid, an InvalidArgument Error is thrown.
|
||||
the checksum is invalid, an [INVALID_ARGUMENT](errors--invalid-argument) Error is thrown.
|
||||
|
||||
The value of //address// may be any supported address format.
|
||||
|
||||
_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 [utils.getAddress](utils-getAddress).
|
||||
Supports the same restrictions as [getAddress](utils-getAddress).
|
||||
|
||||
_property: ethers.utils.isAddress(address) => boolean @<utils-isAddress> @SRC<address>
|
||||
Returns true if //address// is valid (in any supported format).
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
_section: Byte Manipulation
|
||||
|
||||
Tra la la...
|
||||
While there are many high-level APIs for interacting with
|
||||
Ethereum, such as [Contracts](Contract) and [Providers](Provider),
|
||||
a lot of the low level access requires byte manipulation
|
||||
operations.
|
||||
|
||||
Many of these operations are used internally, but can also be
|
||||
used to help normalize binary data representations from the
|
||||
output of various functions and methods.
|
||||
|
||||
_subsection: Types
|
||||
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
_section: HD Wallet @<hdnodes>
|
||||
|
||||
TODO: Explain [BIP32](link-bip-32) [BIP-39](link-bip-39) and whatnot here...
|
||||
The Hierarchal Desterministic (HD) Wallet was a standard
|
||||
created for Bitcoin, but lends itself well to a wide variety of
|
||||
Blockchains which rely on secp256k1 private keys.
|
||||
|
||||
For a more detailed technical understanding:
|
||||
|
||||
- [BIP-32](link-bip-32) - the hierarchal deterministic description
|
||||
- [BIP-39](link-bip-39) - the method used to derive the BIP-32 seed
|
||||
from human-readable sequences of words (i.e. a mnemonic)
|
||||
- [BIP-44](link-bip-44) - a standard defined to make BIP-32 easy
|
||||
to adapt to any future compatible blockchain
|
||||
|
||||
_subsection: Types
|
||||
|
||||
|
||||
@@ -48,39 +48,38 @@ Throw an Error with //message// and an optional //code// and
|
||||
additional //params// set.
|
||||
|
||||
_property: logger.throwArgumentError(message, name, value) => never @SRC<logger>
|
||||
Throw an [INVALID_ARGUMENT](errors-InvalidArgument) Error with //name// and //value//.
|
||||
|
||||
Throw an [INVALID_ARGUMENT](errors--invalid-argument) Error with //name// and //value//.
|
||||
|
||||
_heading: Usage Validation
|
||||
|
||||
There can be used to ensure various properties and actions are safe.
|
||||
|
||||
_property: logger.checkAbstract(target, kind) => void @SRC<logger>
|
||||
Checks that //target// is not //kind// and performs the same operations
|
||||
as ``checkNew``. This is useful for ensuring abstract classes are not
|
||||
being instantiated.
|
||||
_property: logger.checkAbstract(target, kind) => void @<Logger-checkAbstract> @SRC<logger>
|
||||
If //target// is //kind//, throws a [UNSUPPORTED_OPERATION](errors--unsupported-operation) error
|
||||
otherwise performs the same operations as [checkNew](Logger-checkNew).
|
||||
|
||||
_property: logger.checkArgumentCount(count, expectedCount [ , message) => void @SRC<logger>
|
||||
If //count// is not equal to //expectedCount//, throws a [MISSING_ARGUMENT](errors-MissingArgument)
|
||||
or [UNEXPECTED_ARGUMENT](errors-UnexpectedArgument) error.
|
||||
This is useful for ensuring abstract classes are not being instantiated.
|
||||
|
||||
_property: logger.checkNew(target, kind) => void @SRC<logger>
|
||||
_property: logger.checkArgumentCount(count, expectedCount [ , message) => void @<Logger-checkArgumentCount> @SRC<logger>
|
||||
If //count// is not equal to //expectedCount//, throws a [MISSING_ARGUMENT](errors--missing-argument)
|
||||
or [UNEXPECTED_ARGUMENT](errors--unexpected-argument) error.
|
||||
|
||||
_property: logger.checkNew(target, kind) => void @<Logger-checkNew> @SRC<logger>
|
||||
If //target// is not a valid ``this`` or ``target`` value, throw a
|
||||
[MISSING_NEW](errors-MissingNew) error. This is useful to ensure
|
||||
[MISSING_NEW](errors--missing-new) error. This is useful to ensure
|
||||
callers of a Class are using ``new``.
|
||||
|
||||
_property: logger.checkNormalize(message) => void @SRC<logger>
|
||||
_property: logger.checkNormalize(message) => void @<Logger-checkNoralize> @SRC<logger>
|
||||
Check that the environment has a correctly functioning [[link-js-normalize]]. If not, a
|
||||
[UNSUPPORTED_OPERATION](errors-UnsupportedOperation) error is thrown.
|
||||
[UNSUPPORTED_OPERATION](errors--unsupported-operation) error is thrown.
|
||||
|
||||
_property: logger.checkSafeUint53(value [, message ]) => void @SRC<logger>
|
||||
_property: logger.checkSafeUint53(value [, message ]) => void @<Logger-checkSafeUint53> @SRC<logger>
|
||||
If //value// is not safe as a [JavaScript number](link-wiki-ieee754), throws a
|
||||
[NUMERIC_FAULT](errors-NumericFault) error.
|
||||
|
||||
[NUMERIC_FAULT](errors--numeric-fault) error.
|
||||
|
||||
_heading: Censorship @<Logger--censorship>
|
||||
|
||||
_property: Logger.setCensorship(censor [ , permanent = false ]) => void @SRC<logger>
|
||||
_property: Logger.setCensorship(censor [ , permanent = false ]) => void @<Logger-setCensorship> @SRC<logger>
|
||||
Set error censorship, optionally preventing errors from being uncensored.
|
||||
|
||||
In production applications, this prevents any error from leaking information
|
||||
@@ -88,7 +87,7 @@ by masking the message and values of errors.
|
||||
|
||||
This can impact debugging, making it substantially more difficult.
|
||||
|
||||
_property: Logger.setLogLevel(logLevel) => void @SRC<logger>
|
||||
_property: Logger.setLogLevel(logLevel) => void @<Logger-setLogLevel> @SRC<logger>
|
||||
Set the log level, to suppress logging output below a [particular log level](Logger-levels).
|
||||
|
||||
|
||||
@@ -98,76 +97,113 @@ Every error in Ethers has a ``code`` value, which is a string that will
|
||||
match one of the following error codes.
|
||||
|
||||
|
||||
_heading: Generic Error Codes
|
||||
_heading: Generic Error Codes @<errors-generic>
|
||||
|
||||
_property: Logger.errors.NOT_IMPLEMENTED
|
||||
The operation is not implemented.
|
||||
_property: Logger.errors.NOT_IMPLEMENTED @<errors--not-implemented>
|
||||
The operation is not implemented. This may occur when calling a method
|
||||
on a sub-class that has not fully implemented its abstract superclass.
|
||||
|
||||
_property: Logger.errors.SERVER_ERROR
|
||||
_property: Logger.errors.SERVER_ERROR @<errors--server-error>
|
||||
There was an error communicating with a server.
|
||||
|
||||
_property: Logger.errors.TIMEOUT @<errors-Timeout>
|
||||
This may occur for a number of reasons, for example:
|
||||
|
||||
- a [CORS](link-cors) issue; this is quite often the problem and also the
|
||||
hardest to diagnose and fix, so it is very beneficial to familiarize
|
||||
yourself with CORS; some backends allow you configure your CORS, such as
|
||||
the geth command-line or conifguration files or the INFURA and Alchemy
|
||||
dashboards by specifing allowed Origins, methods, etc.
|
||||
- an SSL issue; for example, if you are trying to connect to a local node via
|
||||
HTTP but are serving the content from a secure HTTPS website
|
||||
- a link issue; a firewall is preventing the traffic from reaching the server
|
||||
- a server issue; the server is down, or is returning 500 error codes
|
||||
- a backend DDoS mitigation proxy; for example, Etherscan operates behind a
|
||||
Cloudflare proxy, which will block traffic if the request is sent via
|
||||
specific User Agents or the client fingerprint is detected as a bot in some
|
||||
cases
|
||||
|
||||
_property: Logger.errors.TIMEOUT @<errors--timeout>
|
||||
A timeout occurred.
|
||||
|
||||
_property: Logger.errors.UNKNOWN_ERROR @<errors-UnknownError>
|
||||
_property: Logger.errors.UNKNOWN_ERROR @<errors--unknown-error>
|
||||
A generic unknown error.
|
||||
|
||||
_property: Logger.errors.UNSUPPORTED_OPERATION @<errors-UnsupportedOperation>
|
||||
_property: Logger.errors.UNSUPPORTED_OPERATION @<errors--unsupported-operation>
|
||||
The operation is not supported.
|
||||
|
||||
This can happen for a variety reasons, for example:
|
||||
|
||||
_heading: Safety Error Codes
|
||||
- Some backends do not support certain operations; such as passing a blockTag
|
||||
to an [[EtherscanProvider]] for [call](Provider-call)
|
||||
- A [[Contract]] object connected to [[Provider]] (instead of a [[Signer]]) cannot
|
||||
[sign](Signer-signTransaction) or [send](Signer-sendTransaction) transactions
|
||||
- a [[Contract]] connected to a [[Signer]] without a [[Provider]] is write-only
|
||||
and cannot estimate gas or execute static calls
|
||||
|
||||
_property: Logger.errors.BUFFER_OVERRUN
|
||||
|
||||
_heading: Safety Error Codes @<errors-safety>
|
||||
|
||||
_property: Logger.errors.BUFFER_OVERRUN @<errors--buffer-overrun>
|
||||
The amount of data needed is more than the amount of data required,
|
||||
which would cause the data buffer to read past its end.
|
||||
|
||||
_property: Logger.errors.NUMERIC_FAULT @<errors-NumericFault>
|
||||
This can occur if a contract erroneously returns invalid ABI-encoded
|
||||
data or RLP data is malformed.
|
||||
|
||||
_property: Logger.errors.NUMERIC_FAULT @<errors--numeric-fault>
|
||||
There was an invalid operation done on numeric values.
|
||||
|
||||
Common cases of this occur when there is [[link-wiki-overflow]],
|
||||
[[link-wiki-underflow]] in fixed numeric types or division by zero.
|
||||
|
||||
|
||||
_heading: Usage Error Codes
|
||||
_heading: Usage Error Codes @<errors-usage>
|
||||
|
||||
_property: Logger.errors.INVALID_ARGUMENT @<errors-InvalidArgument>
|
||||
_property: Logger.errors.INVALID_ARGUMENT @<errors--invalid-argument>
|
||||
The type or value of an argument is invalid. This will generally also
|
||||
include the ``name`` and ``value`` of the argument. Any function which
|
||||
accepts sensitive data (such as a private key) will include the string
|
||||
``[\[REDACTED]\]`` instead of the value passed in.
|
||||
``"[\[REDACTED]\]"`` instead of the value passed in.
|
||||
|
||||
_property: Logger.errors.MISSING_ARGUMENT @<errors-MissingArgument>
|
||||
_property: Logger.errors.MISSING_ARGUMENT @<errors--missing-argument>
|
||||
An expected parameter was not specified.
|
||||
|
||||
_property: Logger.errors.MISSING_NEW @<errors-MissingNew>
|
||||
An object is a Class, but is now being called with ``new``.
|
||||
_property: Logger.errors.MISSING_NEW @<errors--missing-new>
|
||||
An object is a Class, but is not being called with ``new``.
|
||||
|
||||
_property: Logger.errors.UNEXPECTED_ARGUMENT @<errors-UnexpectedArgument>
|
||||
_property: Logger.errors.UNEXPECTED_ARGUMENT @<errors--unexpected-argument>
|
||||
Too many parameters we passed into a function.
|
||||
|
||||
|
||||
_heading: Ethereum Error Codes
|
||||
_heading: Ethereum Error Codes @<errors-ethereum>
|
||||
|
||||
_property: Logger.errors.CALL_EXCEPTION
|
||||
_property: Logger.errors.CALL_EXCEPTION @<errors--call-exception>
|
||||
An attempt to call a blockchain contract (getter) resulted in a
|
||||
revert or other error.
|
||||
revert or other error, such as insufficient gas (out-of-gas) or an
|
||||
invalid opcode. This can also occur during gas estimation or if
|
||||
waiting for a [[providers-TransactionReceipt]] which failed during execution.
|
||||
|
||||
_property: Logger.errors.INSUFFICIENT_FUNDS
|
||||
Consult the contract to determine the cause, such as a failed condition
|
||||
in a ``require`` statement. The ``reason`` property may provide more
|
||||
context for the cause of this error.
|
||||
|
||||
_property: Logger.errors.INSUFFICIENT_FUNDS @<errors--insufficient-funds>
|
||||
The account is attempting to make a transaction which costs more than is
|
||||
available.
|
||||
|
||||
A sending account must have enough ether to pay for the value, the gas limit
|
||||
(at the gas price) as well as the intrinsic cost of data. The intrinsic cost
|
||||
of data is 4 gas for each zero byte and 68 gas for each non-zero byte.
|
||||
of data is 4 gas for each zero byte and 68 gas for each non-zero byte, as well
|
||||
as 35000 gas if a transaction contains no ``to`` property and is therefore
|
||||
expected to create a new account.
|
||||
|
||||
_property: Logger.errors.NETWORK_ERROR
|
||||
_property: Logger.errors.NETWORK_ERROR @<errors--network>
|
||||
An Ethereum network validation error, such as an invalid chain ID.
|
||||
|
||||
_property: Logger.errors.NONCE_EXPIRED
|
||||
_property: Logger.errors.NONCE_EXPIRED @<errors--nonce-expired>
|
||||
The nonce being specified has already been used in a mined transaction.
|
||||
|
||||
_property: Logger.errors.REPLACEMENT_UNDERPRICED
|
||||
_property: Logger.errors.REPLACEMENT_UNDERPRICED @<errors--replacement-underpriced>
|
||||
When replacing a transaction, by using a nonce which has already been sent to
|
||||
the network, but which has not been mined yet the new transaction must specify
|
||||
a higher gas price.
|
||||
@@ -175,9 +211,12 @@ a higher gas price.
|
||||
This error occurs when the gas price is insufficient to //bribe// the transaction
|
||||
pool to prefer the new transaction over the old one. Generally, the new gas price
|
||||
should be about 50% + 1 wei more, so if a gas price of 10 gwei was used, the
|
||||
replacement should be 15.000000001 gwei.
|
||||
replacement should be 15.000000001 gwei. This is not enforced by the protocol, as
|
||||
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.UNPREDICTABLE_GAS_LIMIT
|
||||
_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.
|
||||
|
||||
|
||||
@@ -1,9 +1,40 @@
|
||||
_section: Property Utilities
|
||||
|
||||
_property: ethers.utils.checkProperties() => void
|
||||
This is a collection of utility functions used for handling
|
||||
properties in a platform-safe way.
|
||||
|
||||
The next major version of ethers will no longer be compatible
|
||||
with ES3, so many of these will be removed in favor of the
|
||||
built-in options available in ES2015 and above.
|
||||
|
||||
_property: ethers.utils.checkProperties(object, check) => void
|
||||
|
||||
Checks that //object// only contains properties included
|
||||
in //check//, and throws [INVALID_ARGUMENT](errors--invalid-argument) if not.
|
||||
|
||||
_property: ethers.utils.deepCopy(anObject) => any
|
||||
|
||||
Creates a recursive copy of //anObject//. Frozen (i.e. and other known
|
||||
immutable) objects are copied by reference.
|
||||
|
||||
_property: ethers.utils.defineReadOnly(anObject, name, value) => void
|
||||
|
||||
Uses the ``Object.defineProperty`` method to set a read-only property
|
||||
on an object.
|
||||
|
||||
_property: ethers.utils.getStatic(aConstructor, key) => any
|
||||
|
||||
Recursively check for a static method //key// on an inheritance chain
|
||||
from //aConstructor// to all ancestors.
|
||||
|
||||
This is used to mimic behaviour in other languages where ``this`` in
|
||||
a static method will also search ancestors.
|
||||
|
||||
_property: ethers.utils.resolveProperties(anObject) => Promise<any> @<utils-resolveproperties> @SRC<properties>
|
||||
|
||||
Retruns a Promise which resolves all child values on //anObject//.
|
||||
|
||||
_property: ethers.utils.shallowCopy(anObject) => any
|
||||
|
||||
Returns a shallow copy of //anObject//. This is the same as
|
||||
using ``Object.assign({ }, anObject)``.
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
_section: Strings @<strings>
|
||||
|
||||
Tra la la
|
||||
A **String** is a representation of a human-readable input of output,
|
||||
which are often taken for granted.
|
||||
|
||||
When dealing with blockchains, properly handling human-readable and
|
||||
human-provided data is important to prevent loss of funds, assets,
|
||||
incorrect permissions, etc.
|
||||
|
||||
_subsection: Bytes32String @<Bytes32String>
|
||||
|
||||
|
||||
@@ -1,34 +1,40 @@
|
||||
_section: Events
|
||||
|
||||
Explain how topics and such work
|
||||
|
||||
_subsection: Solidity Topics
|
||||
|
||||
How to compute the topic...
|
||||
_section: Events @<events>
|
||||
|
||||
_subsection: Logs and Filtering
|
||||
|
||||
Example hog logs are used.
|
||||
Logs and filtering are used quite often in blockchain applications,
|
||||
since they allow for efficient queries of indexed data and provide
|
||||
lower-cost data storage when the data is not required to be
|
||||
accessed on-chain.
|
||||
|
||||
Link to provider.getLogs and contract.on
|
||||
These can be used in conjunction with the [Provider Events API](Provider--event-methods)
|
||||
and with the [Contract Events API](Contract--events).
|
||||
|
||||
_heading: Filters
|
||||
The Contract Events API also provides [higher-level methods](Contract--filters)
|
||||
to compute and query this data, which should be preferred over the lower-level filter.
|
||||
|
||||
Filter are used as a way to query ... efficient, explain bloom filters lightly
|
||||
_heading: Filters @<events--filters>
|
||||
|
||||
A filter may have up to 4 topic-sets, where each topic-set refers
|
||||
to a condition that must match the log topic in that position (i.e. each
|
||||
condition is ``AND``-ed together).
|
||||
When a Contract creates a log, it can include up to 4 pieces of
|
||||
data to be indexed by. The indexed data is hashed and included in
|
||||
a [[link-wiki-bloomfilter]], which is a data structure that allows
|
||||
for efficient filtering.
|
||||
|
||||
If a topic-set is ``null``, a log topic in that position is not filtered
|
||||
So, a filter may correspondingly have up to 4 topic-sets, where each
|
||||
topic-set refers to a condition that must match the indexed log topic
|
||||
in that position (i.e. each condition is ``AND``-ed together).
|
||||
|
||||
If a topic-set is ``null``, a log topic in that position is **not filtered**
|
||||
at all and **any value** matches.
|
||||
|
||||
If a topic-set is a single topic, a log topic in that position must match
|
||||
If a topic-set is a single topic, a log topic in that position **must** match
|
||||
**that topic**.
|
||||
|
||||
If a topic-set is an array of topics, a log topic in that position must
|
||||
match any **one** of the topics (i.e. the topic in this position are ``OR``-ed).
|
||||
match **any one** of the topics (i.e. the topic in this position are ``OR``-ed).
|
||||
|
||||
This may sound complicated at first, but is more easily understood with
|
||||
some examples.
|
||||
|
||||
_table: Example Log Matching @style<full>
|
||||
|
||||
@@ -152,6 +158,56 @@ contract.filters.Transfer(myAddress, otherAddress)
|
||||
contract.filters.Transfer(null, [ myAddress, otherAddress ])
|
||||
//!
|
||||
|
||||
|
||||
_subsection: Solidity Topics @<events-solidity>
|
||||
|
||||
This is a quick (and non-comprehensive) overview of how events are computed
|
||||
in Solidity.
|
||||
|
||||
This is likely out of the scope for most developers, but may be intersting
|
||||
to those who want to learn a bit more about the underlying technology.
|
||||
|
||||
Solidity provides two types of events, anonymous and non-anonymous. The
|
||||
default is non-anonymous, and most developers will not need to worry about
|
||||
anonymous events.
|
||||
|
||||
For non-anonymous events, up to 3 topics may be indexed (instead of 4), since
|
||||
the first topic is reserved to specify the event signature. This allows
|
||||
non-anonymous events to always be filtered by their event signature.
|
||||
|
||||
This topic hash is always in the first slot of the indexed data, and is
|
||||
computed by normalizing the Event signature and taking the keccak256 hash
|
||||
of it.
|
||||
|
||||
For anonymous events, up to 4 topics may be indexed, and there is no
|
||||
signature topic hash, so the events cannot be filtered by the event
|
||||
signature.
|
||||
|
||||
Each additional indexed property is processed depending on whether its
|
||||
length is fixed or dynamic.
|
||||
|
||||
For fixed length types (e.g. ``uint``, ``bytes5``), all of which are
|
||||
internally exactly 32 bytes (shorter types are padded with zeros;
|
||||
numeric values are padded on the left, data values padded on the right),
|
||||
these are included directly by their actual value, 32 bytes of data.
|
||||
|
||||
For dynamic types (e.g. ``string``, ``uint256[]``) , the value is hashed
|
||||
using keccak256 and this hash is used.
|
||||
|
||||
Because dynamic types are hashed, there are important consequences in
|
||||
parsing events that should be kept in mind. Mainly that the original
|
||||
value is lost in the event. So, it is possible to tell is a topic is
|
||||
equal to a given string, but if they do not match, there is no way
|
||||
to determine what the value was.
|
||||
|
||||
If a developer requires that a string value is required to be both
|
||||
able to be filtered and also able to be read, the value must be included
|
||||
in the signature twice, once indexed and once non-indexed (e.g.
|
||||
``someEvent(string indexed searchBy, string clearText)``).
|
||||
|
||||
For a more detailed description, please refer to the
|
||||
[Solidity Event Documentation](link-solidity-events).
|
||||
|
||||
_heading: Other Things? TODO
|
||||
|
||||
Explain what happens to strings and bytes, how to filter and retain the value
|
||||
|
||||
@@ -43,6 +43,8 @@ function getDefinitions(source) {
|
||||
if (depth === 3) {
|
||||
add("var", node.name.escapedText, node.name.end);
|
||||
}
|
||||
} else if (ts.isGetAccessorDeclaration(node)) {
|
||||
add("getter", (lastClass + "." + node.name.text), node.name.end);
|
||||
}
|
||||
ts.forEachChild(node, (node) => { return visit(node, depth + 1); });
|
||||
}
|
||||
@@ -129,6 +131,13 @@ function codeContextify(context) {
|
||||
context.Wallet = ethers.Wallet;
|
||||
context.provider = new ethers.providers.InfuraProvider("mainnet", "49a0efa3aaee4fd99797bfa94d8ce2f1");
|
||||
|
||||
// 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
|
||||
context.localProvider = new ethers.providers.JsonRpcProvider();
|
||||
context.localSigner = context.localProvider.getSigner();
|
||||
context.localProvider.resolveName = context.provider.resolveName.bind(context.provider);
|
||||
|
||||
context.BigNumber.prototype[inspect.custom] = function(depth, options) {
|
||||
return `{ BigNumber: ${JSON.stringify(this.toString()) } }`;
|
||||
}
|
||||
@@ -153,8 +162,11 @@ function codeContextify(context) {
|
||||
module.exports = {
|
||||
title: "ethers",
|
||||
subtitle: "v5.0",
|
||||
description: "Documentation for ethers, a complete, tiny and simple Ethereum library.",
|
||||
logo: "logo.svg",
|
||||
|
||||
socialImage: "social.jpg",
|
||||
|
||||
prefix: "/v5",
|
||||
|
||||
link: "https:/\/docs.ethers.io",
|
||||
@@ -171,6 +183,7 @@ module.exports = {
|
||||
codeRoot: "../",
|
||||
|
||||
externalLinks: {
|
||||
"link-mail": "mailto:me@ricmoo.com",
|
||||
"link-alchemy": { name: "Alchemy", url: "https:/\/alchemyapi.io" },
|
||||
"link-cloudflare": { name: "Cloudflare", url: "https:/\/developers.cloudflare.com/distributed-web/ethereum-gateway/" },
|
||||
"link-ens": { name: "ENS", url: "https:/\/ens.domains/" },
|
||||
@@ -190,7 +203,8 @@ module.exports = {
|
||||
"link-react-native": { name: "React Native", url: "https:/\/reactnative.dev" },
|
||||
"link-rtd": "https:/\/github.com/readthedocs/sphinx_rtd_theme",
|
||||
"link-semver": { name: "semver", url: "https:/\/semver.org" },
|
||||
"link-solidity": { name: "Solidity" , url: "https:/\/solidity.readthedocs.io/en/v0.6.2/" },
|
||||
"link-solidity": { name: "Solidity" , url: "https:/\/solidity.readthedocs.io/" },
|
||||
"link-solidity-events": "https:/\/docs.soliditylang.org/en/v0.8.1/abi-spec.html#events",
|
||||
"link-sphinx": { name: "Sphinx", url: "https:/\/www.sphinx-doc.org/" },
|
||||
|
||||
"link-alchemy-signup": "https:/\/dashboard.alchemyapi.io/signup?referral=55a35117-028e-4b7c-9e47-e275ad0acc6d",
|
||||
@@ -239,12 +253,16 @@ module.exports = {
|
||||
"link-eip-155": { name: "EIP-155", url: "https:/\/eips.ethereum.org/EIPS/eip-155" },
|
||||
"link-eip-191": { name: "EIP-191", url: "https:/\/eips.ethereum.org/EIPS/eip-191" },
|
||||
"link-eip-609": { name: "EIP-609", url: "https:/\/eips.ethereum.org/EIPS/eip-609" },
|
||||
"link-eip-634": { name: "EIP-634", url: "https:/\/eips.ethereum.org/EIPS/eip-634" },
|
||||
"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-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" },
|
||||
"link-bip-39": { name: "BIP-39", url: "https:/\/en.bitcoin.it/wiki/BIP_0039" },
|
||||
"link-bip-32": { name: "BIP-32", url: "https:/\/github.com/bitcoin/bips/blob/master/bip-0032.mediawiki" },
|
||||
"link-bip-44": { name: "BIP-44", url: "https:/\/en.bitcoin.it/wiki/BIP_0044" },
|
||||
|
||||
"link-npm-elliptic": { name: "elliptic", url: "https:/\/www.npmjs.com/package/elliptic" },
|
||||
"link-npm-ethersproject-shims": { name: "Shims", url: "https:/\/www.npmjs.com/package/@ethersproject/shims" },
|
||||
@@ -260,8 +278,12 @@ module.exports = {
|
||||
"link-js-proxy": "https:/\/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy",
|
||||
"link-js-typedarray": "https:/\/developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray",
|
||||
|
||||
"link-cors": { name: "CORS", url: "https:/\/developer.mozilla.org/en-US/docs/Web/HTTP/CORS" },
|
||||
|
||||
"link-ricmoo-humanreadableabi": "https:/\/blog.ricmoo.com/human-readable-contract-abis-in-ethers-js-141902f4d917",
|
||||
|
||||
"link-other-ethereum-dev-docs": "https:/\/ethereum.org/en/developers/docs/",
|
||||
|
||||
"link-wiki-basicauth": { name: "Basic Authentication", url: "https:/\/en.wikipedia.org/wiki/Basic_access_authentication" },
|
||||
"link-wiki-backoff": { name: "Exponential Backoff", url: "https:/\/en.wikipedia.org/wiki/Exponential_backoff" },
|
||||
"link-wiki-bloomfilter": { name: "Bloom Filter", url: "https:/\/en.wikipedia.org/wiki/Bloom_filter" },
|
||||
@@ -272,6 +294,7 @@ module.exports = {
|
||||
"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-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",
|
||||
|
||||
@@ -7,7 +7,7 @@ Many things are the way they are for good (at the time, at least) reasons,
|
||||
but I always welcome criticism, and am completely willing to have my mind
|
||||
changed on things.
|
||||
|
||||
So, pull requests are always welcome, but please keep a few points in mind:
|
||||
Pull requests are always welcome, but please keep a few points in mind:
|
||||
|
||||
- Backwards-compatibility-breaking changes will not be accepted; they may be
|
||||
considered for the next major version
|
||||
@@ -15,6 +15,9 @@ So, pull requests are always welcome, but please keep a few points in mind:
|
||||
arguments as to why
|
||||
- The library aims to be lean, so keep an eye on the dist/ethers.min.js
|
||||
file size before and after your changes
|
||||
- Keep the PR simple and readable; only modify files in the ``docs.wrm/``
|
||||
and ``packages/*/src.ts/`` folders, as this allows the changes to be easily
|
||||
verified
|
||||
- Add test cases for both expected and unexpected input
|
||||
- Any new features need to be supported by me (future issues, documentation,
|
||||
testing, migration), so anything that is overly complicated or specific
|
||||
@@ -27,60 +30,135 @@ have a public discussion and figure out the best way to address the problem/feat
|
||||
|
||||
_subsection: Building @<contributing--building>
|
||||
|
||||
If you wish to modify the source code, there are a few steps involved in
|
||||
setting up your environment.
|
||||
The build process for ethers is unfortunatly not super trivial, but
|
||||
I have attempted to make it as straight-forward as possible.
|
||||
|
||||
Since the library uses a monorepo, you must install an initial required
|
||||
set of libraries, which can then be used to install the remaining libraries
|
||||
used within each package, as well as link all the packages within the repo
|
||||
with each other.
|
||||
It is a mono-repo which attempts to be compatibile with a large
|
||||
number of environments, build tools and platforms, which is why
|
||||
there are a some weird things it must do.
|
||||
|
||||
_code: Preparing for builds @lang<shell>
|
||||
There are several custom scripts in the ``misc/admin`` folder
|
||||
to help manage the monorepo. Developers working on contributing
|
||||
to ethers should not generally need to worry about those, since
|
||||
they are wrapped up behind ``npm run SCRIPT`` operations.
|
||||
|
||||
_code: Installing @lang<shell>
|
||||
|
||||
# Clone the repository
|
||||
/home/ricmoo> git clone git@github.com:ethers-io/ethers.js.git
|
||||
/home/ricmoo> git clone https://github.com/ethers-io/ethers.js.git
|
||||
|
||||
/home/ricmoo> cd ethers.js
|
||||
|
||||
# Install the base dependencies
|
||||
# Install all dependencies:
|
||||
# - Hoists all sub-package dependencies in the package.json (preinstall)
|
||||
# - Installs all the (hoisted) dependencies and devDependencies (install)
|
||||
# - Build the rat-nests (in .package_node_modules) (postinstall)
|
||||
# - Create a dependency graph for the TypeScript (postinstall)
|
||||
# - Link the rat-nets into each project (postinstall)
|
||||
/home/ricmoo/ethers.js> npm install
|
||||
|
||||
# Install each module's dependencies and link the libraries
|
||||
# internally, so they reference each other
|
||||
/home/ricmoo/ethers.js> npm run bootstrap
|
||||
_heading: Making Changes @<contributing--updating>
|
||||
|
||||
|
||||
_subsection: Making your changes @<contributing--updating>
|
||||
|
||||
TODO: Add more information here.
|
||||
Once your environment is set up, you should be able to simply
|
||||
start the ``auto-build`` feature, and make changes to the
|
||||
TypeScript source.
|
||||
|
||||
_code: Watching and Building @lang<shell>
|
||||
|
||||
# Begin watching the files and re-building whenever they change
|
||||
/home/ricmoo/ethers.js> npm run auto-build
|
||||
|
||||
# Or if you do not want to watch and just build
|
||||
/home/ricmoo/ethers.js> npm run build
|
||||
|
||||
# Sometimes the issue only affects the ESM modules
|
||||
/home/ricmoo/ethers.js> npm run auto-build-esm
|
||||
_heading: Creating Browser-Ready Files
|
||||
|
||||
To create files for use directly in a browser, the distribution
|
||||
files (located in ``packages/ethers/dist``) need to be built
|
||||
which requires several intermediate builds, scripts and for
|
||||
various rollup scripts to execute.
|
||||
|
||||
# Or if you only need to run a single build
|
||||
/home/ricmoo/ethers.js> npm run _build-cjs
|
||||
/home/ricmoo/ethers.js> npm run _build-esm
|
||||
_code: Building Distribution Files @lang<shell>
|
||||
|
||||
# If you need to rebuild all the libs (esm + cjs) and dist files
|
||||
# Note: this requires node 10 or newer
|
||||
/home/ricmoo/ethers.js> npm run build-all
|
||||
|
||||
_heading: Testing
|
||||
|
||||
_code: Testing @lang<shell>
|
||||
|
||||
# Rebuilds all files and bundles testcases up for testing
|
||||
# Rebuilds all files (npm run build-all) and bundles testcases up for testing
|
||||
/home/ricmoo/ethers.js> npm test
|
||||
|
||||
# Often you don't need the full CI experience
|
||||
/home/ricmoo/ethers.js> npm run _test-node
|
||||
/home/ricmoo/ethers.js> npm run test-node
|
||||
|
||||
_heading: Distribution
|
||||
|
||||
Most developers should not ever require this step, but for people
|
||||
forking ethers and creating alternates (for example if you have
|
||||
a non-EVM compatible chain but are trying to reuse this package).
|
||||
|
||||
This script will rebuild the entire ethers project, compare it
|
||||
against npm, re-write package versions, update internal hashes,
|
||||
re-write various TypeScript files (to get around some ES+TS
|
||||
limitations for Tree Shaking and linking), re-write map files,
|
||||
bundle stripped versions of dependencies and basically just a
|
||||
whole bunch of stuff.
|
||||
|
||||
If you use this and get stuck, [message me](link-mail).
|
||||
|
||||
_code: Preparing the Distribution @lang<shell>
|
||||
|
||||
# Prepare all the distribution files
|
||||
# - Remove all generated files (i.e. npm run clean)
|
||||
# - Re-install all dependencies, hoisting, etc. (npm install)
|
||||
# - Spell check all strings in every TypeScript files
|
||||
# - Build everything from scratch with this clean install
|
||||
# - Compare local with npm, bumping the version if changed
|
||||
# - Build everything again (with the updated versions)
|
||||
# - Update the CHANGELOG.md with the git history since the last change
|
||||
/home/ricmoo/ethers.js> npm run update-version
|
||||
|
||||
_note: Do NOT check in dist files in a PR
|
||||
|
||||
For Pull Requests, please ONLY commit files in the ``docs.wrm/`` and
|
||||
``packages/*/src.ts/`` folders. I will prepare the distribution builds
|
||||
myself and keeping the PR relevant makes it easier to verify the changes.
|
||||
|
||||
_heading: Publishing
|
||||
|
||||
Again, this should not be necessary for most developers. This step
|
||||
requires using the ``misc/admin/cmds/config-set`` script for a number
|
||||
of values, including private keys, NPM session keys, AWS access keys,
|
||||
GitHub API tokens, etc.
|
||||
|
||||
The config file is encrypted with about 30 seconds of scrypt password-based
|
||||
key derivation function, so brute-forcing the file is quite expensive.
|
||||
|
||||
The config file also contains a plain-text mnemonic. This is a money-pot.
|
||||
Place a tempting amount of ether or Bitcoin on this account and set up an
|
||||
e-mail alert for this account.
|
||||
|
||||
If any attacker happens across your encrypted config, they will have instant
|
||||
access to the plain-text mnemonic, so they have the option to immediately
|
||||
steal the ether (i.e. the responsible-disclosure bond).
|
||||
|
||||
If you ever see this ether taken, your encrypted file is compromised! Rotate
|
||||
all your AWS keys, NPM session keys, etc. immedately.
|
||||
|
||||
@TODO: document all the keys that need to be set for each step
|
||||
|
||||
_code: Preparing the Distribution @lang<shell>
|
||||
|
||||
# Publish
|
||||
# - Update any changed packages to NPM
|
||||
# - Create a release on GitHub with the latest CHANGELOG.md description
|
||||
# - Upload the bundled files the the CDN
|
||||
# - Flush the CDN edge caches
|
||||
/home/ricmoo/ethers.js> npm run publish-all
|
||||
|
||||
|
||||
_subsection: Documentation @<contributing--documentation>
|
||||
|
||||
@@ -95,7 +173,7 @@ Style Guide (this section will have much more coming):
|
||||
- Prefix external links with ``link-``
|
||||
- Changing an anchor name must be well justified, as it will break all existing links
|
||||
to that section; flatworm will support symlinks in the future
|
||||
- In general, I aim for xonsistency; look to similar situations throughout the documentation
|
||||
- In general, I aim for consistency; look to similar situations throughout the documentation
|
||||
|
||||
|
||||
_heading: Building
|
||||
|
||||
@@ -17,7 +17,7 @@ _subsection: Installing @<cookbook-reactnative-shims>
|
||||
To use ethers in React Native, you must either provide shims for the needed
|
||||
missing functionality, or use the ethers.js shim.
|
||||
|
||||
It is **HIGHLY RECOMMENDED** you check out the [security section](cookbook-reactnative-security>
|
||||
It is **HIGHLY RECOMMENDED** you check out the [security section](cookbook-reactnative-security)
|
||||
below for instructions on installing packages which can affect the security
|
||||
of your application.
|
||||
|
||||
|
||||
BIN
docs.wrm/favicon.ico
Normal file
BIN
docs.wrm/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -165,7 +165,7 @@ If you are familiar with Databases, this is similar to an //Object Relational Ma
|
||||
|
||||
In order to communicate with the Contract on-chain, this class
|
||||
needs to know what methods are available and how to encode and
|
||||
decode the data, which is what the //Application Binary Interface// (API)
|
||||
decode the data, which is what the //Application Binary Interface// (ABI)
|
||||
provides.
|
||||
|
||||
This class is a //meta-class//, which means its methods are constructed
|
||||
@@ -311,14 +311,14 @@ const daiContract = new ethers.Contract("dai.tokens.ethers.eth", daiAbi, provide
|
||||
myAddress = await signer.getAddress()
|
||||
//! async myAddress
|
||||
|
||||
// Filter for all token transfers to me
|
||||
// Filter for all token transfers from me
|
||||
filterFrom = daiContract.filters.Transfer(myAddress, null);
|
||||
// <hide>
|
||||
filterFrom
|
||||
// </hide>
|
||||
//!
|
||||
|
||||
// Filter for all token transfers from me
|
||||
// Filter for all token transfers to me
|
||||
filterTo = daiContract.filters.Transfer(null, myAddress);
|
||||
// <hide>
|
||||
filterTo
|
||||
|
||||
@@ -45,6 +45,7 @@ _toc:
|
||||
migration
|
||||
testing
|
||||
contributing
|
||||
other-resources
|
||||
documentation
|
||||
license
|
||||
|
||||
|
||||
17
docs.wrm/other-resources.wrm
Normal file
17
docs.wrm/other-resources.wrm
Normal file
@@ -0,0 +1,17 @@
|
||||
_section: Other Resources
|
||||
|
||||
There is a lot of documentation on the internet to help you get started,
|
||||
learn more or cover advanced topics. Here are a few resources to check out.
|
||||
|
||||
_subsection: Ethereum Overview
|
||||
|
||||
- Official [Ethereum Developer Documentations](link-other-ethereum-dev-docs)
|
||||
- The [Solidity Documentation](link-solidity), the defactor language for smart
|
||||
contracts as well as a resource for some of the core concepts of Ethereum
|
||||
|
||||
_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
|
||||
BIN
docs.wrm/social.jpg
Normal file
BIN
docs.wrm/social.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
1
docs/api-keys/redirects.txt
Normal file
1
docs/api-keys/redirects.txt
Normal file
@@ -0,0 +1 @@
|
||||
index.html => /v5/api-keys
|
||||
9
docs/errors/redirects.txt
Normal file
9
docs/errors/redirects.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
server-error => /v5/api/utils/logger/#errors--server-error
|
||||
unsupported-operation => /v5/api/utils/logger/#errors--unsupported-operation
|
||||
numeric-fault => /v5/api/utils/logger/#errors--numeric-fault
|
||||
call-exception => /v5/api/utils/logger/#errors--numeric-fault
|
||||
insufficient-funds => /v5/api/utils/logger/#errors--insufficient-funds
|
||||
nonce-expired => /v5/api/utils/logger/#errors--nonce-expired
|
||||
replacement-underpriced => /v5/api/utils/logger/#errors--replacement-underpriced
|
||||
unpredicatable-gas-limit => /v5/api/utils/logger/#errors--unpredicatable-gas-limit
|
||||
|
||||
BIN
docs/favicon.ico
Normal file
BIN
docs/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -26,8 +26,8 @@ Developer Documentation
|
||||
* [Signing Messages](getting-started)
|
||||
* [Ethereum Basics](concepts)
|
||||
* [Events](concepts/events)
|
||||
* [Solidity Topics](concepts/events)
|
||||
* [Logs and Filtering](concepts/events)
|
||||
* [Solidity Topics](concepts/events)
|
||||
* [Gas](concepts/gas)
|
||||
* [Gas Price](concepts/gas)
|
||||
* [Gas Limit](concepts/gas)
|
||||
@@ -47,6 +47,7 @@ Developer Documentation
|
||||
* [Accounts Methods](api/providers/provider)
|
||||
* [Blocks Methods](api/providers/provider)
|
||||
* [Ethereum Naming Service (ENS) Methods](api/providers/provider)
|
||||
* [EnsResolver](api/providers/provider)
|
||||
* [Logs Methods](api/providers/provider)
|
||||
* [Network Status Methods](api/providers/provider)
|
||||
* [Transactions Methods](api/providers/provider)
|
||||
@@ -253,8 +254,10 @@ Developer Documentation
|
||||
* [Schemas](testing)
|
||||
* [Contributing and Hacking](contributing)
|
||||
* [Building](contributing)
|
||||
* [Making your changes](contributing)
|
||||
* [Documentation](contributing)
|
||||
* [Other Resources](other-resources)
|
||||
* [Ethereum Overview](other-resources)
|
||||
* [Tutorials](other-resources)
|
||||
* [Flatworm Docs](documentation)
|
||||
* [Fragments](documentation)
|
||||
* [Markdown](documentation)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,6 +12,7 @@ Application Programming Interface
|
||||
* [Accounts Methods](providers/provider)
|
||||
* [Blocks Methods](providers/provider)
|
||||
* [Ethereum Naming Service (ENS) Methods](providers/provider)
|
||||
* [EnsResolver](providers/provider)
|
||||
* [Logs Methods](providers/provider)
|
||||
* [Network Status Methods](providers/provider)
|
||||
* [Transactions Methods](providers/provider)
|
||||
|
||||
@@ -12,14 +12,17 @@ Creating Instances
|
||||
|
||||
#### **new ***ethers* . **ContractFactory**( interface , bytecode [ , signer ] )
|
||||
|
||||
Creates a new instance of a **ContractFactory** for the contract described by the *interface* and *bytecode* initcode.
|
||||
|
||||
|
||||
#### *ContractFactory* . **fromSolidity**( compilerOutput [ , signer ] ) => *[ContractFactory](/v5/api/contract/contract-factory/)*
|
||||
|
||||
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.
|
||||
|
||||
|
||||
#### *contractFactory* . **connect**( signer ) => *[Contract](/v5/api/contract/contract/)*
|
||||
|
||||
Returns a **new instance** of the ContractFactory with the same *interface* and *bytecode*, but with a different *signer*.
|
||||
|
||||
|
||||
Properties
|
||||
@@ -27,14 +30,17 @@ Properties
|
||||
|
||||
#### *contractFactory* . **interface** => *[Interface](/v5/api/utils/abi/interface/)*
|
||||
|
||||
The [Contract](/v5/api/contract/contract/) interface.
|
||||
|
||||
|
||||
#### *contractFactory* . **bytecode** => *string< [DataHexString](/v5/api/utils/bytes/#DataHexString) >*
|
||||
|
||||
The bytecode (i.e. initcode) that this **ContractFactory** will use to deploy the Contract.
|
||||
|
||||
|
||||
#### *contractFactory* . **signer** => *[Signer](/v5/api/signer/#Signer)*
|
||||
|
||||
The [Signer](/v5/api/signer/#Signer) (if any) this ContractFactory will use to deploy instances of the Contract to the Blockchain.
|
||||
|
||||
|
||||
Methods
|
||||
@@ -45,49 +51,87 @@ Methods
|
||||
Return an instance of a [Contract](/v5/api/contract/contract/) attached to *address*. This is the same as using the [Contract constructor](/v5/api/contract/contract/#Contract--creating) with *address* and this the *interface* and *signerOrProvider* passed in when creating the ContractFactory.
|
||||
|
||||
|
||||
#### *contractFactory* . **getDeployTransaction**( ...args ) => *[UnsignedTransaction](/v5/api/utils/transactions/#UnsignedTransaction)*
|
||||
#### *contractFactory* . **getDeployTransaction**( ...args [ , overrides ] ) => *[UnsignedTransaction](/v5/api/utils/transactions/#UnsignedTransaction)*
|
||||
|
||||
Returns the unsigned transaction which would deploy this Contract with *args* passed to the Contract's constructor.
|
||||
|
||||
If the optional *overrides* is specified, they can be used to override the endowment `value`, transaction `nonce`, `gasLimit` or `gasPrice`.
|
||||
|
||||
#### *contractFactory* . **deploy**( ...args ) => *Promise< [Contract](/v5/api/contract/contract/) >*
|
||||
|
||||
#### *contractFactory* . **deploy**( ...args [ , overrides ] ) => *Promise< [Contract](/v5/api/contract/contract/) >*
|
||||
|
||||
Uses the signer to deploy the Contract with *args* passed into the constructor and returns a Contract which is attached to the address where this contract **will** be deployed once the transaction is mined.
|
||||
|
||||
The transaction can be found at `contract.deployTransaction`, and no interactions should be made until the transaction is mined.
|
||||
|
||||
If the optional *overrides* is specified, they can be used to override the endowment `value`, transaction `nonce`, `gasLimit` or `gasPrice`.
|
||||
|
||||
```
|
||||
// <hide>
|
||||
const signer = ethers.LocalSigner();
|
||||
const ContractFactory = ethers.ContractFactory;
|
||||
// </hide>
|
||||
|
||||
```javascript
|
||||
// If your contract constructor requires parameters, the ABI
|
||||
// must include the constructor
|
||||
const abi = [
|
||||
"constructor(address owner, uint256 initialValue)"
|
||||
"constructor(address owner, uint256 initialValue)",
|
||||
"function value() view returns (uint)"
|
||||
];
|
||||
|
||||
const factory = new ContractFactory(abi, bytecode, signer)
|
||||
// The factory we use for deploying contracts
|
||||
factory = new ContractFactory(abi, bytecode, signer)
|
||||
|
||||
const contract = await factory.deploy("ricmoo.eth", 42);
|
||||
// Deploy an instance of the contract
|
||||
contract = await factory.deploy("ricmoo.eth", 42);
|
||||
|
||||
// The address is available immediately, but the contract
|
||||
// is NOT deployed yet
|
||||
contract.address
|
||||
//!
|
||||
// '0x26E9685C018Bf3A401DFA632827e7e6C7D96b1C0'
|
||||
|
||||
// The transaction that the signer sent to deploy
|
||||
contract.deployTransaction
|
||||
//!
|
||||
// {
|
||||
// blockHash: null,
|
||||
// blockNumber: null,
|
||||
// chainId: 1337,
|
||||
// confirmations: 0,
|
||||
// creates: '0x26E9685C018Bf3A401DFA632827e7e6C7D96b1C0',
|
||||
// data: '0x608060405234801561001057600080fd5b5060405161012e38038061012e8339818101604052604081101561003357600080fd5b81019080805190602001909291908051906020019092919050505081600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060008190555050506088806100a66000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80633fa4f24514602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000805490509056fea2646970667358221220926465385af0e8706644e1ff3db7161af699dc063beaadd55405f2ccd6478d7564736f6c63430007040033000000000000000000000000ab7c8803962c0f2f5bbbe3fa8bf41cd82aa1923c000000000000000000000000000000000000000000000000000000000000002a',
|
||||
// from: '0xf3e6942b256A60B596B24F633caE8aDB4983fCA6',
|
||||
// gasLimit: { BigNumber: "126462" },
|
||||
// gasPrice: { BigNumber: "1" },
|
||||
// hash: '0x4037630fdadbbe0aac0bf90eba61118e35ee5fc28329e2134bb2bad0bfc12684',
|
||||
// nonce: 1,
|
||||
// r: '0xc3bb79ea4600864cd110fe74d31d38bb3702c327fd5aef9feddf66903cc87a4f',
|
||||
// s: '0x35cc2ffe352c02b5fcfbbcd2e348001af670f64438d7a9b2c34756ec293a0784',
|
||||
// to: null,
|
||||
// transactionIndex: null,
|
||||
// v: 2709,
|
||||
// value: { BigNumber: "0" },
|
||||
// wait: [Function]
|
||||
// }
|
||||
|
||||
// Wait until the transaction is mined
|
||||
// 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()
|
||||
//!
|
||||
// { Promise: {
|
||||
// blockHash: '0x1715de2bdfec15a7f64fb79a8254699274be6776df244d24a04945a3218543e6',
|
||||
// blockNumber: 2,
|
||||
// byzantium: true,
|
||||
// confirmations: 1,
|
||||
// contractAddress: '0x26E9685C018Bf3A401DFA632827e7e6C7D96b1C0',
|
||||
// cumulativeGasUsed: { BigNumber: "126462" },
|
||||
// from: '0xf3e6942b256A60B596B24F633caE8aDB4983fCA6',
|
||||
// gasUsed: { BigNumber: "126462" },
|
||||
// logs: [],
|
||||
// logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
// status: 1,
|
||||
// to: null,
|
||||
// transactionHash: '0x4037630fdadbbe0aac0bf90eba61118e35ee5fc28329e2134bb2bad0bfc12684',
|
||||
// transactionIndex: 0
|
||||
// } }
|
||||
|
||||
// Now the contract is safe to interact with
|
||||
contract.value()
|
||||
//!
|
||||
// { Promise: { BigNumber: "42" } }
|
||||
```
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -117,7 +117,7 @@ Meta-Class
|
||||
|
||||
#### *contract* . **METHOD_NAME**( ...args [ , overrides ] ) => *Promise< any >*
|
||||
|
||||
The type of the result depends on the ABI.
|
||||
The type of the result depends on the ABI. If the method returns a single value, it will be returned directly, otherwise a [Result](/v5/api/utils/abi/interface/#Result) object will 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 and booleans.
|
||||
|
||||
@@ -125,6 +125,16 @@ For numbers, if the **type** is in the JavaScript safe range (i.e. less than 53
|
||||
|
||||
For bytes (both fixed length and dynamic), a [DataHexString](/v5/api/utils/bytes/#DataHexString) is returned.
|
||||
|
||||
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
|
||||
- `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`); *most developers will not require this*
|
||||
- `overrides.gasLimit` - the amount of gas (theoretically) to allow a node to use during the execution of the code; since there is no transaction, there is not going to be any fee charged, but the EVM still processes gas metering so calls like `gasleft` (or `GAS`) report meaningful values
|
||||
- `overrides.blockTag` - a block tag to simulate the execution at, which can be used for hypothetical historic analysis; note that many backends do not support this, or may require paid plans to access as the node database storage and processing requirements are much higher
|
||||
|
||||
|
||||
|
||||
|
||||
#### *contract* . *functions* . **METHOD_NAME**( ...args [ , overrides ] ) => *Promise< [Result](/v5/api/utils/abi/interface/#Result) >*
|
||||
|
||||
@@ -136,6 +146,8 @@ Another use for this method is for error recovery. For example, if a function re
|
||||
|
||||
Most developers should not require this.
|
||||
|
||||
The *overrides* are identical to the read-only operations above.
|
||||
|
||||
|
||||
### Write Methods (non-constant)
|
||||
|
||||
@@ -143,6 +155,29 @@ Most developers should not require this.
|
||||
|
||||
Returns a [TransactionResponse](/v5/api/providers/types/#providers-TransactionResponse) for the transaction after it is sent to the network. This requires the **Contract** has a signer.
|
||||
|
||||
The *overrides* object for write methods may include any of:
|
||||
|
||||
- `overrides.gasPrice` - the price to pay per gas
|
||||
- `overrides.gasLimit` - the limit on the amount of gas to allow the transaction to consume; any unused gas is returned at the gasPrice
|
||||
- `overrides.value` - the amount of ether (in wei) to forward with the call
|
||||
- `overrides.nonce` - the nonce to use for the [Signer](/v5/api/signer/#Signer)
|
||||
|
||||
|
||||
|
||||
If the `wait()` method on the returned [TransactionResponse](/v5/api/providers/types/#providers-TransactionResponse) is called, there will be additional properties on the receipt:
|
||||
|
||||
- `receipt.events` - an array of the logs, with additional properties (if the ABI included a description for the events)
|
||||
- `receipt.events[n].args` - the parsed arguments
|
||||
- `receipt.events[n].decode` - a method that can be used to parse the log topics and data (this was used to compute `args`)
|
||||
- `receipt.events[n].event` - the name of the event
|
||||
- `receipt.events[n].eventSignature` - the full signature of the event
|
||||
- `receipt.removeListener()` - a method to remove the listener that trigger this event
|
||||
- `receipt.getBlock()` - a method to return the [Block](/v5/api/providers/types/#providers-Block) this event occurred in
|
||||
- `receipt.getTransaction()` - a method to return the [Transaction](/v5/api/providers/types/#providers-TransactionResponse) this event occurred in
|
||||
- `receipt.getTransactionReceipt()` - a method to return the [Transaction Receipt](/v5/api/providers/types/#providers-TransactionReceipt) this event occurred in
|
||||
|
||||
|
||||
|
||||
|
||||
### Write Methods Analysis
|
||||
|
||||
@@ -150,11 +185,15 @@ Returns a [TransactionResponse](/v5/api/providers/types/#providers-TransactionRe
|
||||
|
||||
Returns the estimate units of gas that would be required to execute the *METHOD_NAME* with *args* and *overrides*.
|
||||
|
||||
The *overrides* are identical to the overrides above for read-only or write methods, depending on the type of call of *METHOD_NAME*.
|
||||
|
||||
|
||||
#### *contract* . *populateTransaction* . **METHOD_NAME**( ...args [ , overrides ] ) => *Promise< [UnsignedTx](/v5/api/utils/transactions/#UnsignedTransaction) >*
|
||||
|
||||
Returns an [UnsignedTransaction](/v5/api/utils/transactions/#UnsignedTransaction) which represents the transaction that would need to be signed and submitted to the network to execute *METHOD_NAME* with *args* and *overrides*.
|
||||
|
||||
The *overrides* are identical to the overrides above for read-only or write methods, depending on the type of call of *METHOD_NAME*.
|
||||
|
||||
|
||||
#### *contract* . *callStatic* . **METHOD_NAME**( ...args [ , overrides ] ) => *Promise< any >*
|
||||
|
||||
@@ -164,6 +203,8 @@ This does not actually change any state, but is free. This in some cases can be
|
||||
|
||||
This otherwise functions the same as a [Read-Only Method](/v5/api/contract/contract/#Contract--readonly).
|
||||
|
||||
The *overrides* are identical to the read-only operations above.
|
||||
|
||||
|
||||
### Event Filters
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -48,7 +48,7 @@ Set the current transaction count (nonce) for the signer.
|
||||
This may be useful in interacting with the signer outside of using this class.
|
||||
|
||||
|
||||
#### *nonceManager* . **increaseTransactionCount**( [ count = 1 ] ) => *void*
|
||||
#### *nonceManager* . **incrementTransactionCount**( [ count = 1 ] ) => *void*
|
||||
|
||||
Bump the current transaction count (nonce) by *count*.
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -54,6 +54,7 @@ Provider Documentation
|
||||
* [Accounts Methods](provider)
|
||||
* [Blocks Methods](provider)
|
||||
* [Ethereum Naming Service (ENS) Methods](provider)
|
||||
* [EnsResolver](provider)
|
||||
* [Logs Methods](provider)
|
||||
* [Network Status Methods](provider)
|
||||
* [Transactions Methods](provider)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -7,9 +7,11 @@ Documentation: [html](https://docs.ethers.io/)
|
||||
JsonRpcProvider
|
||||
===============
|
||||
|
||||
#### **new ***ethers* . *providers* . **JsonRpcProvider**( [ url [ , aNetworkish ] ] )
|
||||
#### **new ***ethers* . *providers* . **JsonRpcProvider**( [ urlOrConnectionInfo [ , networkish ] ] )
|
||||
|
||||
Connect to a JSON-RPC API located at *url* using the *aNetworkish* network. If *url* 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.
|
||||
Connect to a JSON-RPC HTTP API using the URL or [ConnectionInfo](/v5/api/utils/web/#ConnectionInfo) *urlOrConnectionInfo* 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`.
|
||||
|
||||
|
||||
#### Note: Connecting to a Local Node
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -36,7 +36,7 @@ The provider for this configuration.
|
||||
|
||||
#### *fallbackProviderConfig* . **priority** => *number*
|
||||
|
||||
The priority used for the provider. Higher priorities are favoured over lower priorities. If multiple providers share the same priority, they are chosen at random.
|
||||
The priority used for the provider. Lower-value priorities are favoured over higher-value priorities. If multiple providers share the same priority, they are chosen at random.
|
||||
|
||||
|
||||
#### *fallbackProviderConfig* . **stallTimeout** => *number*
|
||||
@@ -123,7 +123,7 @@ This is identical to `sendAsync`. Historically, this used a synchronous web requ
|
||||
WebSocketProvider
|
||||
-----------------
|
||||
|
||||
#### **new ***ethers* . *provider* . **WebSocketProvider**( [ url [ , network ] ] )
|
||||
#### **new ***ethers* . *providers* . **WebSocketProvider**( [ url [ , network ] ] )
|
||||
|
||||
Returns a new [WebSocketProvider](/v5/api/providers/other/#WebSocketProvider) connected to *url* as the *network*.
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -7,6 +7,15 @@ Documentation: [html](https://docs.ethers.io/)
|
||||
Provider
|
||||
========
|
||||
|
||||
#### Coming from Web3.js?
|
||||
|
||||
If you are coming from Web3.js, this is one of the biggest differences you will encounter using ethers.
|
||||
|
||||
The ethers library creates a strong division between the operation a **Provider** can perform and those of a [Signer](/v5/api/signer/#Signer), which Web3.js lumps together.
|
||||
|
||||
This separation of concerns and a stricted subset of Provider operations allows for a larger variety of backends, a more consistent API and ensures other libraries to operate without being able to rely on any underlying assumption.
|
||||
|
||||
|
||||
Accounts Methods
|
||||
----------------
|
||||
|
||||
@@ -33,7 +42,7 @@ Returns the number of transactions *address* has ever **sent**, as of *blockTag*
|
||||
```javascript
|
||||
// Get the balance for an account...
|
||||
provider.getBalance("ricmoo.firefly.eth");
|
||||
// { Promise: { BigNumber: "284831012276355695" } }
|
||||
// { Promise: { BigNumber: "25334210474552466902" } }
|
||||
|
||||
// Get the code for a contract...
|
||||
provider.getCode("registrar.firefly.eth");
|
||||
@@ -45,7 +54,7 @@ provider.getStorageAt("registrar.firefly.eth", 0)
|
||||
|
||||
// Get transaction count of an account...
|
||||
provider.getTransactionCount("ricmoo.firefly.eth");
|
||||
// { Promise: 689 }
|
||||
// { Promise: 712 }
|
||||
```
|
||||
|
||||
Blocks Methods
|
||||
@@ -96,7 +105,7 @@ provider.getBlockWithTransactions(100004)
|
||||
// blockHash: '0xf93283571ae16dcecbe1816adc126954a739350cd1523a1559eabeae155fbb63',
|
||||
// blockNumber: 100004,
|
||||
// chainId: 0,
|
||||
// confirmations: 11212224,
|
||||
// confirmations: 11717911,
|
||||
// creates: null,
|
||||
// data: '0x',
|
||||
// from: '0xcf00A85f3826941e7A25BFcF9Aac575d40410852',
|
||||
@@ -118,6 +127,11 @@ provider.getBlockWithTransactions(100004)
|
||||
Ethereum Naming Service (ENS) Methods
|
||||
-------------------------------------
|
||||
|
||||
#### *provider* . **getResolver**( name ) => *Promise< [EnsResolver](/v5/api/providers/provider/#EnsResolver) >*
|
||||
|
||||
Returns an EnsResolver instance which can be used to further inquire about specific entries for an ENS name.
|
||||
|
||||
|
||||
#### *provider* . **lookupAddress**( address ) => *Promise< string >*
|
||||
|
||||
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.
|
||||
@@ -138,6 +152,34 @@ provider.resolveName("ricmoo.firefly.eth");
|
||||
// { Promise: '0x8ba1f109551bD432803012645Ac136ddd64DBA72' }
|
||||
```
|
||||
|
||||
EnsResolver
|
||||
-----------
|
||||
|
||||
#### *resolver* . **name** => *string*
|
||||
|
||||
The name of this resolver.
|
||||
|
||||
|
||||
#### *resolver* . **address** => *string< [Address](/v5/api/utils/address/#address) >*
|
||||
|
||||
The address of the Resolver.
|
||||
|
||||
|
||||
#### *resolver* . **getAddress**( [ cointType = 60 ] ) => *Promise< string >*
|
||||
|
||||
Returns a Promise which resolves to the [EIP-2304](https://eips.ethereum.org/EIPS/eip-2304) multicoin address stored for the *coinType*. By default an Ethereum [Address](/v5/api/utils/address/#address) (`coinType = 60`) will be returned.
|
||||
|
||||
|
||||
#### *resolver* . **getContentHash**( ) => *Promise< string >*
|
||||
|
||||
Returns a Promise which resolves to any stored [EIP-1577](https://eips.ethereum.org/EIPS/eip-1577) content hash.
|
||||
|
||||
|
||||
#### *resolver* . **getText**( key ) => *Promise< string >*
|
||||
|
||||
Returns a Promise which resolves to any stored [EIP-634](https://eips.ethereum.org/EIPS/eip-634) text entry for *key*.
|
||||
|
||||
|
||||
Logs Methods
|
||||
------------
|
||||
|
||||
@@ -166,6 +208,13 @@ Returns the block number (or height) of the most recently mined block.
|
||||
Returns a *best guess* of the [Gas Price](/v5/concepts/gas/#gas-price) to use in a transaction.
|
||||
|
||||
|
||||
#### *provider* . **ready** => *Promise< [Network](/v5/api/providers/types/#providers-Network) >*
|
||||
|
||||
Returns a Promise which will stall until the network has heen established, 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.
|
||||
|
||||
|
||||
```javascript
|
||||
// The network information
|
||||
provider.getNetwork()
|
||||
@@ -177,16 +226,16 @@ provider.getNetwork()
|
||||
|
||||
// The current block number
|
||||
provider.getBlockNumber()
|
||||
// { Promise: 11312227 }
|
||||
// { Promise: 11817914 }
|
||||
|
||||
// Get the current suggested gas price (in wei)...
|
||||
gasPrice = await provider.getGasPrice()
|
||||
// { BigNumber: "46200000000" }
|
||||
// { BigNumber: "207000000000" }
|
||||
|
||||
// ...often this gas price is easier to understand or
|
||||
// display to the user in gwei (giga-wei, or 1e9 wei)
|
||||
utils.formatUnits(gasPrice, "gwei")
|
||||
// '46.2'
|
||||
// '207.0'
|
||||
```
|
||||
|
||||
Transactions Methods
|
||||
@@ -204,6 +253,20 @@ Returns an estimate of the amount of gas that would be required to submit *trans
|
||||
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.
|
||||
|
||||
|
||||
#### *provider* . **getTransaction**( hash ) => *Promise< [TransactionResponse](/v5/api/providers/types/#providers-TransactionResponse) >*
|
||||
|
||||
Returns the transaction with *hash* or null if the transaction is unknown.
|
||||
|
||||
If a transaction has not been mined, this method will search the transaction 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.
|
||||
|
||||
|
||||
#### *provider* . **getTransactionReceipt**( hash ) => *Promise< [TransactionReceipt](/v5/api/providers/types/#providers-TransactionReceipt) >*
|
||||
|
||||
Returns the transaction receipt for *hash* or null if the transaction has not been mined.
|
||||
|
||||
To stall until the transaction has been mined, consider the `waitForTransaction` method below.
|
||||
|
||||
|
||||
#### *provider* . **sendTransaction**( transaction ) => *Promise< [TransactionResponse](/v5/api/providers/types/#providers-TransactionResponse) >*
|
||||
|
||||
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).
|
||||
@@ -213,43 +276,45 @@ Submits *transaction* to the network to be mined. The *transaction* **must** be
|
||||
|
||||
Returns a Promise which will not resolve until *transactionHash* is mined.
|
||||
|
||||
If *confirms* is 0, this method is non-blocking and if the transaction has not been mined returns null. Otherwise, this method will block until the transaction has *confirms* blocks mined on top of the block in which is was mined.
|
||||
|
||||
|
||||
Event Emitter Methods
|
||||
---------------------
|
||||
|
||||
#### *provider* . **on**( eventName , listener ) => *this*
|
||||
|
||||
Add a *listener* to be triggered for each *eventName*.
|
||||
Add a *listener* to be triggered for each *eventName* [event](/v5/api/providers/provider/#Provider--events).
|
||||
|
||||
|
||||
#### *provider* . **once**( eventName , listener ) => *this*
|
||||
|
||||
Add a *listener* to be triggered for only the next *eventName*, at which time it will be removed.
|
||||
Add a *listener* to be triggered for only the next *eventName* [event](/v5/api/providers/provider/#Provider--events), at which time it will be removed.
|
||||
|
||||
|
||||
#### *provider* . **emit**( eventName , ...args ) => *boolean*
|
||||
|
||||
Notify all listeners of *eventName*, passing *args* to each listener. This is generally only used internally.
|
||||
Notify all listeners of the *eventName* [event](/v5/api/providers/provider/#Provider--events), passing *args* to each listener. This is generally only used internally.
|
||||
|
||||
|
||||
#### *provider* . **off**( eventName [ , listener ] ) => *this*
|
||||
|
||||
Remove a *listener* for *eventName*. If no *listener* is provided, all listeners for *eventName* are removed.
|
||||
Remove a *listener* for the *eventName* [event](/v5/api/providers/provider/#Provider--events). If no *listener* is provided, all listeners for *eventName* are removed.
|
||||
|
||||
|
||||
#### *provider* . **removeAllListeners**( [ eventName ] ) => *this*
|
||||
|
||||
Remove all the listeners for *eventName*. If no *eventName* is provided, **all** events are removed.
|
||||
Remove all the listeners for the *eventName* [events](/v5/api/providers/provider/#Provider--events). If no *eventName* is provided, **all** events are removed.
|
||||
|
||||
|
||||
#### *provider* . **listenerCount**( [ eventName ] ) => *number*
|
||||
|
||||
Returns the number of listeners for *eventName*. If no *eventName* is provided, the total number of listeners is returned.
|
||||
Returns the number of listeners for the *eventName* [events](/v5/api/providers/provider/#Provider--events). If no *eventName* is provided, the total number of listeners is returned.
|
||||
|
||||
|
||||
#### *provider* . **listeners**( eventName ) => *Array< Listener >*
|
||||
|
||||
Returns the list of Listeners for *eventName*.
|
||||
Returns the list of Listeners for the *eventName* [events](/v5/api/providers/provider/#Provider--events).
|
||||
|
||||
|
||||
### Events
|
||||
@@ -260,7 +325,7 @@ A filter is an object, representing a contract log Filter, which has the optiona
|
||||
|
||||
If `address` is unspecified, the filter matches any contract address.
|
||||
|
||||
See events for more information on how to specify topic-sets.
|
||||
See [EventFilters](/v5/api/providers/types/#providers-EventFilter) for more information on filtering events.
|
||||
|
||||
|
||||
#### **Topic-Set Filter**
|
||||
@@ -269,6 +334,8 @@ The value of a **Topic-Set Filter** is a array of Topic-Sets.
|
||||
|
||||
This event is identical to a *Log Filter* with the address omitted (i.e. from any contract).
|
||||
|
||||
See [EventFilters](/v5/api/providers/types/#providers-EventFilter) for more information on filtering events.
|
||||
|
||||
|
||||
#### **Transaction Filter**
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,8 +10,6 @@ Types
|
||||
BlockTag
|
||||
--------
|
||||
|
||||
### EventType
|
||||
|
||||
Networkish
|
||||
----------
|
||||
|
||||
@@ -118,9 +116,13 @@ Events and Logs
|
||||
The address to filter by, or `null` to match any address.
|
||||
|
||||
|
||||
#### *filter* . **topics** => *Array< string< [DataHexString](/v5/api/utils/bytes/#DataHexString)< 32 > > | Array< string< [DataHexString](/v5/api/utils/bytes/#DataHexString)< 32 > > > >*
|
||||
#### *filter* . **topics** => *Array< string< [Data](/v5/api/utils/bytes/#DataHexString)< 32 > > | Array< string< [Data](/v5/api/utils/bytes/#DataHexString)< 32 > > > >*
|
||||
|
||||
The topics to filter by, or `null` to match any topics. Each entry represents an **AND** condition that must match, or may be `null` to match anything. If a given entry is an Array, then that entry is treated as an **OR** for any value in the entry.
|
||||
The topics to filter by or `null` to match any topics.
|
||||
|
||||
Each entry represents an **AND** condition that must match, or may be `null` to match anything. If a given entry is an Array, then that entry is treated as an **OR** for any value in the entry.
|
||||
|
||||
See [Filters](/v5/concepts/events/#events--filters) for more details and examples on specifying complex filters.
|
||||
|
||||
|
||||
### Filter
|
||||
@@ -268,9 +270,17 @@ The number of blocks that have been mined (including the initial block) since th
|
||||
The serialized transaction.
|
||||
|
||||
|
||||
#### *transaction* . **wait**( [ confirmations = 1 ] ) => *Promise< [TransactionReceipt](/v5/api/providers/types/#providers-TransactionReceipt) >*
|
||||
#### *transaction* . **wait**( [ confirms = 1 ] ) => *Promise< [TransactionReceipt](/v5/api/providers/types/#providers-TransactionReceipt) >*
|
||||
|
||||
Resolves to the [TransactionReceipt](/v5/api/providers/types/#providers-TransactionReceipt) once the transaction 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](/v5/api/utils/logger/#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`
|
||||
|
||||
|
||||
Wait for *confirmations*. If 0, and the transaction has not been mined, `null` is returned.
|
||||
|
||||
|
||||
### TransactionReceipt
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -273,7 +273,7 @@ walletMnemonic.publicKey
|
||||
walletMnemonic.mnemonic
|
||||
// {
|
||||
// locale: 'en',
|
||||
// path: 'm/44\'/60\'/0\'/0/0',
|
||||
// path: "m/44'/60'/0'/0/0",
|
||||
// phrase: 'announce room limb pattern dry unit scale effort smooth jazz weasel alcohol'
|
||||
// }
|
||||
|
||||
@@ -335,7 +335,7 @@ contract = new ethers.Contract("dai.tokens.ethers.eth", abi, signer)
|
||||
|
||||
// Get the number of tokens for this account
|
||||
tokens = await contract.balanceOf(signer.getAddress())
|
||||
// { BigNumber: "15923148775162018481031" }
|
||||
// { BigNumber: "198172622063578627973" }
|
||||
|
||||
//
|
||||
// Pre-flight (check for revert) on DAI from the signer
|
||||
@@ -352,7 +352,7 @@ contract.callStatic.transfer("donations.ethers.eth", tokens)
|
||||
|
||||
// This will fail since it is greater than the token balance
|
||||
contract.callStatic.transfer("donations.ethers.eth", tokens.add(1))
|
||||
// Error: call revert exception (method="transfer(address,uint256)", errorSignature="Error(string)", errorArgs=["Dai/insufficient-balance"], reason="Dai/insufficient-balance", code=CALL_EXCEPTION, version=abi/5.0.9)
|
||||
// Error: call revert exception (method="transfer(address,uint256)", errorSignature="Error(string)", errorArgs=["Dai/insufficient-balance"], reason="Dai/insufficient-balance", code=CALL_EXCEPTION, version=abi/5.0.12)
|
||||
```
|
||||
|
||||
ExternallyOwnedAccount
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -21,14 +21,14 @@ Converting and Verifying
|
||||
|
||||
Returns *address* as a Checksum Address.
|
||||
|
||||
If *address* is an invalid 40-nibble [HexString](/v5/api/utils/bytes/#HexString) or if it contains mixed case and the checksum is invalid, an InvalidArgument Error is thrown.
|
||||
If *address* is an invalid 40-nibble [HexString](/v5/api/utils/bytes/#HexString) or if it contains mixed case and the checksum is invalid, an [INVALID_ARGUMENT](/v5/api/utils/logger/#errors--invalid-argument) Error is thrown.
|
||||
|
||||
The value of *address* may be any supported address format.
|
||||
|
||||
|
||||
#### *ethers* . *utils* . **getIcapAddress**( address ) => *string< [IcapAddress](/v5/api/utils/address/#address-icap) >*
|
||||
|
||||
Returns *address* as an [ICAP address](https://github.com/ethereum/wiki/wiki/Inter-exchange-Client-Address-Protocol-%28ICAP%29). Supports the same restrictions as [utils.getAddress](/v5/api/utils/address/#utils-getAddress).
|
||||
Returns *address* as an [ICAP address](https://github.com/ethereum/wiki/wiki/Inter-exchange-Client-Address-Protocol-%28ICAP%29). Supports the same restrictions as [getAddress](/v5/api/utils/address/#utils-getAddress).
|
||||
|
||||
|
||||
#### *ethers* . *utils* . **isAddress**( address ) => *boolean*
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -85,7 +85,7 @@ BigNumber.from(42n)
|
||||
|
||||
// Numbers outside the safe range fail:
|
||||
BigNumber.from(Number.MAX_SAFE_INTEGER);
|
||||
// Error: overflow (fault="overflow", operation="BigNumber.from", value=9007199254740991, code=NUMERIC_FAULT, version=bignumber/5.0.11)
|
||||
// Error: overflow (fault="overflow", operation="BigNumber.from", value=9007199254740991, code=NUMERIC_FAULT, version=bignumber/5.0.14)
|
||||
```
|
||||
|
||||
Methods
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -164,20 +164,20 @@ Return a copy of *array* shuffled using [Fisher-Yates Shuffle](https://en.wikipe
|
||||
|
||||
```javascript
|
||||
utils.randomBytes(8)
|
||||
// Uint8Array [ 82, 221, 254, 37, 192, 138, 147, 109 ]
|
||||
// Uint8Array [ 97, 223, 223, 186, 224, 0, 90, 28 ]
|
||||
|
||||
const data = [ 1, 2, 3, 4, 5, 6, 7 ];
|
||||
|
||||
// Returns a new Array
|
||||
utils.shuffled(data);
|
||||
// [
|
||||
// 6,
|
||||
// 5,
|
||||
// 3,
|
||||
// 2,
|
||||
// 7,
|
||||
// 1,
|
||||
// 4,
|
||||
// 1
|
||||
// 6,
|
||||
// 7,
|
||||
// 2
|
||||
// ]
|
||||
|
||||
// The Original is unscathed...
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -52,7 +52,7 @@ utils.keccak256("0x1234")
|
||||
|
||||
// Do NOT use UTF-8 strings that are not a DataHexstring
|
||||
utils.keccak256("hello world")
|
||||
// Error: invalid arrayify value (argument="value", value="hello world", code=INVALID_ARGUMENT, version=bytes/5.0.6)
|
||||
// Error: invalid arrayify value (argument="value", value="hello world", code=INVALID_ARGUMENT, version=bytes/5.0.10)
|
||||
|
||||
// If needed, convert strings to bytes first:
|
||||
utils.keccak256(utils.toUtf8Bytes("hello world"))
|
||||
@@ -300,6 +300,24 @@ TypedDataEncoder.getPayload(domain, types, value)
|
||||
// },
|
||||
// primaryType: 'Mail',
|
||||
// types: {
|
||||
// EIP712Domain: [
|
||||
// {
|
||||
// name: 'name',
|
||||
// type: 'string'
|
||||
// },
|
||||
// {
|
||||
// name: 'version',
|
||||
// type: 'string'
|
||||
// },
|
||||
// {
|
||||
// name: 'chainId',
|
||||
// type: 'uint256'
|
||||
// },
|
||||
// {
|
||||
// name: 'verifyingContract',
|
||||
// type: 'address'
|
||||
// }
|
||||
// ],
|
||||
// Mail: [
|
||||
// {
|
||||
// name: 'from',
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -51,34 +51,36 @@ Throw an Error with *message* and an optional *code* and additional *params* set
|
||||
|
||||
#### *logger* . **throwArgumentError**( message , name , value ) => *never*
|
||||
|
||||
Throw an [INVALID_ARGUMENT](/v5/api/utils/logger/#errors-InvalidArgument) Error with *name* and *value*.
|
||||
Throw an [INVALID_ARGUMENT](/v5/api/utils/logger/#errors--invalid-argument) Error with *name* and *value*.
|
||||
|
||||
|
||||
### Usage Validation
|
||||
|
||||
#### *logger* . **checkAbstract**( target , kind ) => *void*
|
||||
|
||||
Checks that *target* is not *kind* and performs the same operations as `checkNew`. This is useful for ensuring abstract classes are not being instantiated.
|
||||
If *target* is *kind*, throws a [UNSUPPORTED_OPERATION](/v5/api/utils/logger/#errors--unsupported-operation) error otherwise performs the same operations as [checkNew](/v5/api/utils/logger/#Logger-checkNew).
|
||||
|
||||
This is useful for ensuring abstract classes are not being instantiated.
|
||||
|
||||
|
||||
#### *logger* . **checkArgumentCount**( count , expectedCount [ , message ) => *void*
|
||||
|
||||
If *count* is not equal to *expectedCount*, throws a [MISSING_ARGUMENT](/v5/api/utils/logger/#errors-MissingArgument) or [UNEXPECTED_ARGUMENT](/v5/api/utils/logger/#errors-UnexpectedArgument) error.
|
||||
If *count* is not equal to *expectedCount*, throws a [MISSING_ARGUMENT](/v5/api/utils/logger/#errors--missing-argument) or [UNEXPECTED_ARGUMENT](/v5/api/utils/logger/#errors--unexpected-argument) error.
|
||||
|
||||
|
||||
#### *logger* . **checkNew**( target , kind ) => *void*
|
||||
|
||||
If *target* is not a valid `this` or `target` value, throw a [MISSING_NEW](/v5/api/utils/logger/#errors-MissingNew) error. This is useful to ensure callers of a Class are using `new`.
|
||||
If *target* is not a valid `this` or `target` value, throw a [MISSING_NEW](/v5/api/utils/logger/#errors--missing-new) error. This is useful to ensure callers of a Class are using `new`.
|
||||
|
||||
|
||||
#### *logger* . **checkNormalize**( message ) => *void*
|
||||
|
||||
Check that the environment has a correctly functioning [String.normalize](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize). If not, a [UNSUPPORTED_OPERATION](/v5/api/utils/logger/#errors-UnsupportedOperation) error is thrown.
|
||||
Check that the environment has a correctly functioning [String.normalize](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize). If not, a [UNSUPPORTED_OPERATION](/v5/api/utils/logger/#errors--unsupported-operation) error is thrown.
|
||||
|
||||
|
||||
#### *logger* . **checkSafeUint53**( value [ , message ] ) => *void*
|
||||
|
||||
If *value* is not safe as a [JavaScript number](https://en.wikipedia.org/wiki/Double-precision_floating-point_format), throws a [NUMERIC_FAULT](/v5/api/utils/logger/#errors-NumericFault) error.
|
||||
If *value* is not safe as a [JavaScript number](https://en.wikipedia.org/wiki/Double-precision_floating-point_format), throws a [NUMERIC_FAULT](/v5/api/utils/logger/#errors--numeric-fault) error.
|
||||
|
||||
|
||||
### Censorship
|
||||
@@ -104,13 +106,23 @@ Errors
|
||||
|
||||
#### *Logger* . *errors* . **NOT_IMPLEMENTED**
|
||||
|
||||
The operation is not implemented.
|
||||
The operation is not implemented. This may occur when calling a method on a sub-class that has not fully implemented its abstract superclass.
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **SERVER_ERROR**
|
||||
|
||||
There was an error communicating with a server.
|
||||
|
||||
This may occur for a number of reasons, for example:
|
||||
|
||||
- a [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) issue; this is quite often the problem and also the hardest to diagnose and fix, so it is very beneficial to familiarize yourself with CORS; some backends allow you configure your CORS, such as the geth command-line or conifguration files or the INFURA and Alchemy dashboards by specifing allowed Origins, methods, etc.
|
||||
- an SSL issue; for example, if you are trying to connect to a local node via HTTP but are serving the content from a secure HTTPS website
|
||||
- a link issue; a firewall is preventing the traffic from reaching the server
|
||||
- a server issue; the server is down, or is returning 500 error codes
|
||||
- a backend DDoS mitigation proxy; for example, Etherscan operates behind a Cloudflare proxy, which will block traffic if the request is sent via specific User Agents or the client fingerprint is detected as a bot in some cases
|
||||
|
||||
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **TIMEOUT**
|
||||
|
||||
@@ -126,6 +138,14 @@ A generic unknown error.
|
||||
|
||||
The operation is not supported.
|
||||
|
||||
This can happen for a variety reasons, for example:
|
||||
|
||||
- Some backends do not support certain operations; such as passing a blockTag to an [EtherscanProvider](/v5/api/providers/api-providers/#EtherscanProvider) for [call](/v5/api/providers/provider/#Provider-call)
|
||||
- A [Contract](/v5/api/contract/contract/) object connected to [Provider](/v5/api/providers/provider/) (instead of a [Signer](/v5/api/signer/#Signer)) cannot [sign](/v5/api/signer/#Signer-signTransaction) or [send](/v5/api/signer/#Signer-sendTransaction) transactions
|
||||
- a [Contract](/v5/api/contract/contract/) connected to a [Signer](/v5/api/signer/#Signer) without a [Provider](/v5/api/providers/provider/) is write-only and cannot estimate gas or execute static calls
|
||||
|
||||
|
||||
|
||||
|
||||
### Safety Error Codes
|
||||
|
||||
@@ -133,6 +153,8 @@ The operation is not supported.
|
||||
|
||||
The amount of data needed is more than the amount of data required, which would cause the data buffer to read past its end.
|
||||
|
||||
This can occur if a contract erroneously returns invalid ABI-encoded data or RLP data is malformed.
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **NUMERIC_FAULT**
|
||||
|
||||
@@ -145,7 +167,7 @@ Common cases of this occur when there is [overflow](https://en.wikipedia.org/wik
|
||||
|
||||
#### *Logger* . *errors* . **INVALID_ARGUMENT**
|
||||
|
||||
The type or value of an argument is invalid. This will generally also include the `name` and `value` of the argument. Any function which accepts sensitive data (such as a private key) will include the string `[[REDACTED]]` instead of the value passed in.
|
||||
The type or value of an argument is invalid. This will generally also include the `name` and `value` of the argument. Any function which accepts sensitive data (such as a private key) will include the string `"[[REDACTED]]"` instead of the value passed in.
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **MISSING_ARGUMENT**
|
||||
@@ -155,7 +177,7 @@ An expected parameter was not specified.
|
||||
|
||||
#### *Logger* . *errors* . **MISSING_NEW**
|
||||
|
||||
An object is a Class, but is now being called with `new`.
|
||||
An object is a Class, but is not being called with `new`.
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **UNEXPECTED_ARGUMENT**
|
||||
@@ -167,14 +189,16 @@ Too many parameters we passed into a function.
|
||||
|
||||
#### *Logger* . *errors* . **CALL_EXCEPTION**
|
||||
|
||||
An attempt to call a blockchain contract (getter) resulted in a revert or other error.
|
||||
An attempt to call a blockchain contract (getter) resulted in a revert or other error, such as insufficient gas (out-of-gas) or an invalid opcode. This can also occur during gas estimation or if waiting for a [TransactionReceipt](/v5/api/providers/types/#providers-TransactionReceipt) which failed during execution.
|
||||
|
||||
Consult the contract to determine the cause, such as a failed condition in a `require` statement. The `reason` property may provide more context for the cause of this error.
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **INSUFFICIENT_FUNDS**
|
||||
|
||||
The account is attempting to make a transaction which costs more than is available.
|
||||
|
||||
A sending account must have enough ether to pay for the value, the gas limit (at the gas price) as well as the intrinsic cost of data. The intrinsic cost of data is 4 gas for each zero byte and 68 gas for each non-zero byte.
|
||||
A sending account must have enough ether to pay for the value, the gas limit (at the gas price) as well as the intrinsic cost of data. The intrinsic cost of data is 4 gas for each zero byte and 68 gas for each non-zero byte, as well as 35000 gas if a transaction contains no `to` property and is therefore expected to create a new account.
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **NETWORK_ERROR**
|
||||
@@ -191,7 +215,7 @@ The nonce being specified has already been used in a mined transaction.
|
||||
|
||||
When replacing a transaction, by using a nonce which has already been sent to the network, but which has not been mined yet the new transaction must specify a higher gas price.
|
||||
|
||||
This error occurs when the gas price is insufficient to *bribe* the transaction pool to prefer the new transaction over the old one. Generally, the new gas price should be about 50% + 1 wei more, so if a gas price of 10 gwei was used, the replacement should be 15.000000001 gwei.
|
||||
This error occurs when the gas price is insufficient to *bribe* the transaction pool to prefer the new transaction over the old one. Generally, the new gas price should be about 50% + 1 wei more, so if a gas price of 10 gwei was used, the replacement should be 15.000000001 gwei. This is not enforced by the protocol, as 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.
|
||||
|
||||
|
||||
#### *Logger* . *errors* . **UNPREDICTABLE_GAS_LIMIT**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user