Updated dist files.

This commit is contained in:
Richard Moore 2020-09-16 19:44:55 -04:00
parent de8a717b4c
commit a3821f6c4b
No known key found for this signature in database
GPG Key ID: 665176BE8E9DC651
6 changed files with 720 additions and 581 deletions

@ -12,7 +12,7 @@ const Words = fs.readFileSync("/usr/share/dict/words").toString().split("\n").re
// Words missing from the dictionary // Words missing from the dictionary
accessing addresses aligned autofill called cancelled changed censored accessing addresses aligned autofill called cancelled changed censored
clamping compiled computed configured consumed creating decoded decoding clamping compiled computed configured consumed creating decoded decoding
decrypt decrypted decrypting deployed deploying deprecated detected decreased decrypt decrypted decrypting deployed deploying deprecated detected
discontinued earliest email enabled encoded encoding encrypt discontinued earliest email enabled encoded encoding encrypt
encrypted encrypting entries euro exceeded existing expected encrypted encrypting entries euro exceeded existing expected
expired failed fetches formatted formatting funding generated expired failed fetches formatted formatting funding generated
@ -47,9 +47,9 @@ bytecode callback calldata checksum ciphertext cli codepoint commify config
contenthash ctr ctrl debug dd dklen eexist encseed eof ethaddr contenthash ctr ctrl debug dd dklen eexist encseed eof ethaddr
ethseed ethers eval exec filename func gz hid http https hw iv ethseed ethers eval exec filename func gz hid http https hw iv
info init ipc json kdf kdfparams labelhash lang lib mm multihash nfc info init ipc json kdf kdfparams labelhash lang lib mm multihash nfc
nfkc nfd nfkd nodehash notok nullish oob opcode pbkdf pc plugin pragma pre prf nfkc nfd nfkd nodehash notok nowait nullish oob opcode pbkdf pc plugin
repl rpc sighash topichash solc stdin stdout subclasses subnode pragma pre prf repl rpc sighash topichash solc stdin stdout subclasses
timeout todo txt ufixed utc utf util url uuid vm vs websocket subnode timeout todo txt ufixed utc utf util url uuid vm vs websocket
wikipedia wx xe xpriv xpub xx yyyy zlib wikipedia wx xe xpriv xpub xx yyyy zlib
// AbiV2 // AbiV2

@ -65,7 +65,7 @@ const blockchainData = {
s: "0x269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54", s: "0x269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54",
v: 38, v: 38,
creates: null, creates: null,
raw: "0xf8d2808504a817c8008303d090946fc21092da55b392b045ed78f4732bff3c580e2c880186cc6acd4b0000b864f2c298be000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067269636d6f6f000000000000000000000000000000000000000000000000000026a01e5605197a03e3f0a168f14749168dfeefc44c9228312dacbffdcbbb13263265a0269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54", //raw: "0xf8d2808504a817c8008303d090946fc21092da55b392b045ed78f4732bff3c580e2c880186cc6acd4b0000b864f2c298be000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067269636d6f6f000000000000000000000000000000000000000000000000000026a01e5605197a03e3f0a168f14749168dfeefc44c9228312dacbffdcbbb13263265a0269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54",
chainId: 1 chainId: 1
} }
], ],
@ -364,6 +364,8 @@ function equals(name, actual, expected) {
if (actual == null) { if (actual == null) {
assert.ok(false, name + " - actual big number null"); assert.ok(false, name + " - actual big number null");
} }
expected = ethers.BigNumber.from(expected);
actual = ethers.BigNumber.from(actual);
assert.ok(expected.eq(actual), name + " matches"); assert.ok(expected.eq(actual), name + " matches");
} }
else if (Array.isArray(expected)) { else if (Array.isArray(expected)) {
@ -398,33 +400,104 @@ function equals(name, actual, expected) {
} }
function waiter(duration) { function waiter(duration) {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(resolve, duration); const timer = setTimeout(resolve, duration);
if (timer.unref) {
timer.unref();
}
}); });
} }
function testProvider(providerName, networkName) { const allNetworks = ["default", "homestead", "ropsten", "rinkeby", "kovan", "goerli"];
// Delay (ms) after each test case to prevent the backends from throttling const providerFunctions = [
const delay = 1000; {
describe(("Read-Only " + providerName + " (" + networkName + ")"), function () { name: "getDefaultProvider",
this.retries(3); networks: allNetworks,
// Get the Provider based on the name of the provider we are testing and the network create: (network) => {
let provider = null; if (network == "default") {
if (networkName === "default") { return ethers.getDefaultProvider();
if (providerName === "getDefaultProvider") {
provider = ethers.getDefaultProvider();
} }
else { return ethers.getDefaultProvider(network);
provider = new (ethers.providers)[providerName](); }
},
{
name: "AlchemyProvider",
networks: allNetworks,
create: (network) => {
if (network == "default") {
return new ethers.providers.AlchemyProvider();
}
return new ethers.providers.AlchemyProvider(network);
}
},
{
name: "CloudflareProvider",
networks: ["homestead"],
create: (network) => {
return new ethers.providers.AlchemyProvider(network);
}
},
{
name: "InfuraProvider",
networks: allNetworks,
create: (network) => {
if (network == "default") {
return new ethers.providers.InfuraProvider();
}
return new ethers.providers.InfuraProvider(network);
}
},
{
name: "EtherscanProvider",
networks: allNetworks,
create: (network) => {
if (network == "default") {
return new ethers.providers.EtherscanProvider();
}
return new ethers.providers.EtherscanProvider(network);
}
},
{
name: "NodesmithProvider",
networks: [],
create: (network) => {
throw new Error("not tested");
}
},
{
name: "Web3Provider",
networks: [],
create: (network) => {
throw new Error("not tested");
} }
} }
else { ];
if (providerName === "getDefaultProvider") { // This wallet can be funded and used for various test cases
provider = ethers.getDefaultProvider(networkName); const fundWallet = ethers.Wallet.createRandom();
const testFunctions = [];
Object.keys(blockchainData).forEach((network) => {
function addSimpleTest(name, func, expected) {
testFunctions.push({
name: name,
networks: [network],
execute: (provider) => __awaiter(this, void 0, void 0, function* () {
const value = yield func(provider);
equals(name, expected, value);
})
});
} }
else { function addObjectTest(name, func, expected, checkSkip) {
provider = new (ethers.providers)[providerName](networkName); testFunctions.push({
name,
networks: [network],
checkSkip,
execute: (provider) => __awaiter(this, void 0, void 0, function* () {
const value = yield func(provider);
Object.keys(expected).forEach((key) => {
equals(`${name}.${key}`, value[key], expected[key]);
});
})
});
} }
} const tests = blockchainData[network];
const tests = blockchainData[networkName];
// And address test case can have any of the following: // And address test case can have any of the following:
// - balance // - balance
// - code // - code
@ -432,126 +505,88 @@ function testProvider(providerName, networkName) {
// - ENS name // - ENS name
tests.addresses.forEach((test) => { tests.addresses.forEach((test) => {
if (test.balance) { if (test.balance) {
it(`fetches address balance: ${test.address}`, function () { addSimpleTest(`fetches account balance: ${test.address}`, (provider) => {
// Note: These tests could be fiddled with if someone sends ether return provider.getBalance(test.address);
// to our address; we just have to live with jerks sending us }, test.balance);
// money. *smile emoji*
this.timeout(60000);
return provider.getBalance(test.address).then((balance) => {
equals("Balance", test.balance, balance);
return waiter(delay);
});
});
} }
if (test.code) { if (test.code) {
it(`fetches address code: ${test.address}`, function () { addSimpleTest(`fetches account code: ${test.address}`, (provider) => {
this.timeout(60000); return provider.getCode(test.address);
return provider.getCode(test.address).then((code) => { }, test.code);
equals("Code", test.code, code);
return waiter(delay);
});
});
} }
if (test.storage) { if (test.storage) {
Object.keys(test.storage).forEach((position) => { Object.keys(test.storage).forEach((position) => {
it(`fetches storage: ${test.address}:${position}`, function () { addSimpleTest(`fetches storage: ${test.address}:${position}`, (provider) => {
this.timeout(60000); return provider.getStorageAt(test.address, bnify(position));
return provider.getStorageAt(test.address, bnify(position)).then((value) => { }, test.storage[position]);
equals("Storage", test.storage[position], value);
return waiter(delay);
});
});
}); });
} }
if (test.name) { if (test.name) {
it(`fetches the ENS name: ${test.name}`, function () { addSimpleTest(`fetches ENS name: ${test.address}`, (provider) => {
this.timeout(60000); return provider.resolveName(test.name);
return provider.resolveName(test.name).then((address) => { }, test.address);
equals("ENS Name", test.address, address);
return waiter(delay);
});
});
} }
}); });
tests.blocks.forEach((test) => { tests.blocks.forEach((test) => {
function checkBlock(promise) { addObjectTest(`fetches block (by number) #${test.number}`, (provider) => {
return promise.then((block) => { return provider.getBlock(test.number);
for (let key in test) { }, test);
equals("Block " + key, block[key], test[key]);
}
return waiter(delay);
}); });
} tests.blocks.forEach((test) => {
it(`fetches block (by number) #${test.number}`, function () { addObjectTest(`fetches block (by hash) ${test.hash}`, (provider) => {
this.timeout(60000); return provider.getBlock(test.hash);
return checkBlock(provider.getBlock(test.number)); }, test, (provider, network, test) => {
}); return (provider === "EtherscanProvider");
// Etherscan does not support getBlockByBlockhash... *sad emoji*
if (providerName === "EtherscanProvider") {
return;
}
it(`fetches block (by hash) ${test.hash}`, function () {
this.timeout(60000);
return checkBlock(provider.getBlock(test.hash));
}); });
}); });
tests.transactions.forEach((test) => { tests.transactions.forEach((test) => {
function testTransaction(expected) { addObjectTest(`fetches transaction ${test.hash}`, (provider) => __awaiter(void 0, void 0, void 0, function* () {
const title = ("Transaction " + expected.hash.substring(0, 10) + " - "); const tx = yield provider.getTransaction(test.hash);
return provider.getTransaction(expected.hash).then((tx) => {
// This changes with every block // This changes with every block
assert.equal(typeof (tx.confirmations), "number", "confirmations is a number"); assert.equal(typeof (tx.confirmations), "number", "confirmations is a number");
delete tx.confirmations; delete tx.confirmations;
assert.equal(typeof (tx.wait), "function", "wait is a function"); assert.equal(typeof (tx.wait), "function", "wait is a function");
delete tx.wait; delete tx.wait;
for (const key in tx) { return tx;
equals((title + key), tx[key], expected[key]); }), test, (provider, network, test) => {
} return (provider === "EtherscanProvider");
return waiter(delay);
});
}
it(`fetches transaction: ${test.hash}`, function () {
this.timeout(60000);
return testTransaction(test);
}); });
}); });
tests.transactionReceipts.forEach((test) => { tests.transactionReceipts.forEach((test) => {
function testTransactionReceipt(expected) { addObjectTest(`fetches transaction receipt ${test.transactionHash}`, (provider) => __awaiter(void 0, void 0, void 0, function* () {
const title = ("Receipt " + expected.transactionHash.substring(0, 10) + " - "); const receipt = yield provider.getTransactionReceipt(test.transactionHash);
return provider.getTransactionReceipt(expected.transactionHash).then(function (receipt) { if (test.status === null) {
assert.ok(receipt.status === undefined, "no status");
receipt.status = null;
}
// This changes with every block; so just make sure it is a number // This changes with every block; so just make sure it is a number
assert.equal(typeof (receipt.confirmations), "number", "confirmations is a number"); assert.equal(typeof (receipt.confirmations), "number", "confirmations is a number");
delete receipt.confirmations; delete receipt.confirmations;
for (const key in receipt) { return receipt;
equals((title + key), receipt[key], expected[key]); }), test);
}
//equals(("Receipt " + expected.transactionHash.substring(0, 10)), receipt, expected);
return waiter(delay);
}); });
} });
it(`fetches transaction receipt: ${test.transactionHash}`, function () { (function () {
this.timeout(60000); function addErrorTest(code, func) {
return testTransactionReceipt(test); testFunctions.push({
}); name: `throws correct ${code} error`,
}); networks: ["ropsten"],
if (networkName === "ropsten") { execute: (provider) => __awaiter(this, void 0, void 0, function* () {
it("throws correct NONCE_EXPIRED errors", function () {
return __awaiter(this, void 0, void 0, function* () {
this.timeout(60000);
try { try {
const tx = yield provider.sendTransaction("0xf86480850218711a0082520894000000000000000000000000000000000000000002801ba038aaddcaaae7d3fa066dfd6f196c8348e1bb210f2c121d36cb2c24ef20cea1fba008ae378075d3cd75aae99ab75a70da82161dffb2c8263dabc5d8adecfa9447fa"); const value = yield func(provider);
console.log(tx); console.log(value);
assert.ok(false); assert.ok(false, "did not throw");
} }
catch (error) { catch (error) {
assert.equal(error.code, ethers.utils.Logger.errors.NONCE_EXPIRED); assert.equal(error.code, code, "incorrect error thrown");
} }
yield waiter(delay); })
}); });
}); }
it("throws correct INSUFFICIENT_FUNDS errors", function () { addErrorTest(ethers.utils.Logger.errors.NONCE_EXPIRED, (provider) => __awaiter(this, void 0, void 0, function* () {
return __awaiter(this, void 0, void 0, function* () { return provider.sendTransaction("0xf86480850218711a0082520894000000000000000000000000000000000000000002801ba038aaddcaaae7d3fa066dfd6f196c8348e1bb210f2c121d36cb2c24ef20cea1fba008ae378075d3cd75aae99ab75a70da82161dffb2c8263dabc5d8adecfa9447fa");
this.timeout(60000); }));
addErrorTest(ethers.utils.Logger.errors.INSUFFICIENT_FUNDS, (provider) => __awaiter(this, void 0, void 0, function* () {
const txProps = { const txProps = {
to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72", to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
gasPrice: 9000000000, gasPrice: 9000000000,
@ -560,19 +595,9 @@ function testProvider(providerName, networkName) {
}; };
const wallet = ethers.Wallet.createRandom(); const wallet = ethers.Wallet.createRandom();
const tx = yield wallet.signTransaction(txProps); const tx = yield wallet.signTransaction(txProps);
try { return provider.sendTransaction(tx);
yield provider.sendTransaction(tx); }));
assert.ok(false); addErrorTest(ethers.utils.Logger.errors.INSUFFICIENT_FUNDS, (provider) => __awaiter(this, void 0, void 0, function* () {
}
catch (error) {
assert.equal(error.code, ethers.utils.Logger.errors.INSUFFICIENT_FUNDS);
}
yield waiter(delay);
});
});
it("throws correct INSUFFICIENT_FUNDS errors (signer)", function () {
return __awaiter(this, void 0, void 0, function* () {
this.timeout(60000);
const txProps = { const txProps = {
to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72", to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
gasPrice: 9000000000, gasPrice: 9000000000,
@ -580,83 +605,110 @@ function testProvider(providerName, networkName) {
value: 1 value: 1
}; };
const wallet = ethers.Wallet.createRandom().connect(provider); const wallet = ethers.Wallet.createRandom().connect(provider);
try { return wallet.sendTransaction(txProps);
yield wallet.sendTransaction(txProps); }));
assert.ok(false); addErrorTest(ethers.utils.Logger.errors.UNPREDICTABLE_GAS_LIMIT, (provider) => __awaiter(this, void 0, void 0, function* () {
} return provider.estimateGas({
catch (error) { to: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" // ENS contract
assert.equal(error.code, ethers.utils.Logger.errors.INSUFFICIENT_FUNDS);
}
yield waiter(delay);
}); });
}); }));
it("throws correct UNPREDICTABLE_GAS_LIMIT errors", function () { })();
return __awaiter(this, void 0, void 0, function* () { testFunctions.push({
this.timeout(60000); name: "sends a transaction",
try { extras: ["funding"],
yield provider.estimateGas({ timeout: 300,
to: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" // ENS; no payable fallback networks: ["ropsten"],
}); execute: (provider) => __awaiter(void 0, void 0, void 0, function* () {
assert.ok(false); const wallet = fundWallet.connect(provider);
}
catch (error) {
assert.equal(error.code, ethers.utils.Logger.errors.UNPREDICTABLE_GAS_LIMIT);
}
yield waiter(delay);
});
});
it("sends a transaction", function () {
return __awaiter(this, void 0, void 0, function* () {
this.timeout(360000);
const wallet = ethers.Wallet.createRandom().connect(provider);
const funder = yield ethers.utils.fetchJson(`https:/\/api.ethers.io/api/v1/?action=fundAccount&address=${wallet.address.toLowerCase()}`);
yield provider.waitForTransaction(funder.hash);
const addr = "0x8210357f377E901f18E45294e86a2A32215Cc3C9"; const addr = "0x8210357f377E901f18E45294e86a2A32215Cc3C9";
const gasPrice = 9000000000; const b0 = yield provider.getBalance(wallet.address);
let balance = yield provider.getBalance(wallet.address); assert.ok(b0.gt(ethers.constants.Zero), "balance is non-zero");
assert.ok(balance.eq(ethers.utils.parseEther("3.141592653589793238")), "balance is pi after funding");
const tx = yield wallet.sendTransaction({ const tx = yield wallet.sendTransaction({
to: addr, to: addr,
gasPrice: gasPrice, value: 123
value: balance.sub(21000 * gasPrice)
}); });
yield tx.wait(); yield tx.wait();
balance = yield provider.getBalance(wallet.address); const b1 = yield provider.getBalance(wallet.address);
assert.ok(balance.eq(ethers.constants.Zero), "balance is zero after after sweeping"); assert.ok(b0.gt(b1), "balance is decreased");
yield waiter(delay); })
});
describe("Test Provider Methods", function () {
let fundReceipt = null;
const faucet = "0x8210357f377E901f18E45294e86a2A32215Cc3C9";
before(function () {
return __awaiter(this, void 0, void 0, function* () {
// Get some ether from the faucet
const provider = ethers.getDefaultProvider("ropsten");
const funder = yield ethers.utils.fetchJson(`https:/\/api.ethers.io/api/v1/?action=fundAccount&address=${fundWallet.address.toLowerCase()}`);
fundReceipt = provider.waitForTransaction(funder.hash);
fundReceipt.then((receipt) => {
console.log(`*** Funded: ${fundWallet.address}`);
}); });
}); });
}
// Obviously many more cases to add here
// - getTransactionCount
// - getBlockNumber
// - getGasPrice
// - estimateGas
// - sendTransaction
// - call
// - getLogs
//
// Many of these are tLegacyParametersested in run-providers, which uses nodeunit, but
// also creates a local private key which must then be funded to
// execute the tests. I am working on a better test contract to deploy
// to all the networks to help test these.
}); });
} after(function () {
["default", "homestead", "ropsten", "rinkeby", "kovan", "goerli"].forEach(function (networkName) { return __awaiter(this, void 0, void 0, function* () {
["getDefaultProvider", "AlchemyProvider", "CloudflareProvider", "InfuraProvider", "EtherscanProvider", "NodesmithProvider", "Web3Provider"].forEach(function (providerName) { // Wait until the funding is complete
if (providerName === "NodesmithProvider") { yield fundReceipt;
// Refund all unused ether to the faucet
const provider = ethers.getDefaultProvider("ropsten");
const gasPrice = yield provider.getGasPrice();
const balance = yield provider.getBalance(fundWallet.address);
fundWallet.connect(provider).sendTransaction({
to: faucet,
gasLimit: 21000,
gasPrice: gasPrice,
value: balance.sub(gasPrice.mul(21000))
});
});
});
providerFunctions.forEach(({ name, networks, create }) => {
networks.forEach((network) => {
const provider = create(network);
testFunctions.forEach((test) => {
// Skip tests not supported on this network
if (test.networks.indexOf(network) === -1) {
return; return;
} }
if (providerName === "CloudflareProvider") { if (test.checkSkip && test.checkSkip(name, network, test)) {
return; return;
} }
if (providerName === "Web3Provider") { // How many attempts to try?
return; const attempts = (test.attempts != null) ? test.attempts : 3;
const timeout = (test.timeout != null) ? test.timeout : 60;
const extras = (test.extras || []).reduce((accum, key) => {
accum[key] = true;
return accum;
}, {});
it(`${name}.${network ? network : "default"} ${test.name}`, function () {
return __awaiter(this, void 0, void 0, function* () {
this.timeout(timeout * 1000 * attempts);
// Wait for the funding transaction to be mined
if (extras.funding) {
yield fundReceipt;
} }
if ((networkName !== "homestead" && networkName !== "default") && providerName === "CloudflareProvider") { // We wait at least 1 seconds between tests
return; if (!extras.nowait) {
yield waiter(1000);
} }
testProvider(providerName, networkName); let error = null;
for (let attempt = 0; attempt < attempts; attempt++) {
try {
return yield Promise.race([
test.execute(provider),
waiter(timeout * 1000).then((resolve) => { throw new Error("timeout"); })
]);
}
catch (attemptError) {
console.log(`*** Failed attempt ${attempt + 1}: ${attemptError.message}`);
error = attemptError;
}
}
throw error;
});
});
});
});
}); });
}); });
/* /*
@ -679,7 +731,7 @@ describe("Test extra Etherscan operations", function() {
}); });
*/ */
describe("Test Basic Authentication", function () { describe("Test Basic Authentication", function () {
this.retries(3); //this.retries(3);
function test(name, url) { function test(name, url) {
it("tests " + name, function () { it("tests " + name, function () {
this.timeout(60000); this.timeout(60000);

File diff suppressed because one or more lines are too long

@ -96,7 +96,7 @@ var blockchainData = {
s: "0x269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54", s: "0x269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54",
v: 38, v: 38,
creates: null, creates: null,
raw: "0xf8d2808504a817c8008303d090946fc21092da55b392b045ed78f4732bff3c580e2c880186cc6acd4b0000b864f2c298be000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067269636d6f6f000000000000000000000000000000000000000000000000000026a01e5605197a03e3f0a168f14749168dfeefc44c9228312dacbffdcbbb13263265a0269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54", //raw: "0xf8d2808504a817c8008303d090946fc21092da55b392b045ed78f4732bff3c580e2c880186cc6acd4b0000b864f2c298be000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067269636d6f6f000000000000000000000000000000000000000000000000000026a01e5605197a03e3f0a168f14749168dfeefc44c9228312dacbffdcbbb13263265a0269c3e5b3558267ad91b0a887d51f9f10098771c67b82ea6cb74f29638754f54",
chainId: 1 chainId: 1
} }
], ],
@ -395,6 +395,8 @@ function equals(name, actual, expected) {
if (actual == null) { if (actual == null) {
assert_1.default.ok(false, name + " - actual big number null"); assert_1.default.ok(false, name + " - actual big number null");
} }
expected = ethers_1.ethers.BigNumber.from(expected);
actual = ethers_1.ethers.BigNumber.from(actual);
assert_1.default.ok(expected.eq(actual), name + " matches"); assert_1.default.ok(expected.eq(actual), name + " matches");
} }
else if (Array.isArray(expected)) { else if (Array.isArray(expected)) {
@ -429,33 +431,122 @@ function equals(name, actual, expected) {
} }
function waiter(duration) { function waiter(duration) {
return new Promise(function (resolve) { return new Promise(function (resolve) {
setTimeout(resolve, duration); var timer = setTimeout(resolve, duration);
if (timer.unref) {
timer.unref();
}
}); });
} }
function testProvider(providerName, networkName) { var allNetworks = ["default", "homestead", "ropsten", "rinkeby", "kovan", "goerli"];
// Delay (ms) after each test case to prevent the backends from throttling var providerFunctions = [
var delay = 1000; {
describe(("Read-Only " + providerName + " (" + networkName + ")"), function () { name: "getDefaultProvider",
this.retries(3); networks: allNetworks,
// Get the Provider based on the name of the provider we are testing and the network create: function (network) {
var provider = null; if (network == "default") {
if (networkName === "default") { return ethers_1.ethers.getDefaultProvider();
if (providerName === "getDefaultProvider") {
provider = ethers_1.ethers.getDefaultProvider();
} }
else { return ethers_1.ethers.getDefaultProvider(network);
provider = new (ethers_1.ethers.providers)[providerName](); }
},
{
name: "AlchemyProvider",
networks: allNetworks,
create: function (network) {
if (network == "default") {
return new ethers_1.ethers.providers.AlchemyProvider();
}
return new ethers_1.ethers.providers.AlchemyProvider(network);
}
},
{
name: "CloudflareProvider",
networks: ["homestead"],
create: function (network) {
return new ethers_1.ethers.providers.AlchemyProvider(network);
}
},
{
name: "InfuraProvider",
networks: allNetworks,
create: function (network) {
if (network == "default") {
return new ethers_1.ethers.providers.InfuraProvider();
}
return new ethers_1.ethers.providers.InfuraProvider(network);
}
},
{
name: "EtherscanProvider",
networks: allNetworks,
create: function (network) {
if (network == "default") {
return new ethers_1.ethers.providers.EtherscanProvider();
}
return new ethers_1.ethers.providers.EtherscanProvider(network);
}
},
{
name: "NodesmithProvider",
networks: [],
create: function (network) {
throw new Error("not tested");
}
},
{
name: "Web3Provider",
networks: [],
create: function (network) {
throw new Error("not tested");
} }
} }
else { ];
if (providerName === "getDefaultProvider") { // This wallet can be funded and used for various test cases
provider = ethers_1.ethers.getDefaultProvider(networkName); var fundWallet = ethers_1.ethers.Wallet.createRandom();
var testFunctions = [];
Object.keys(blockchainData).forEach(function (network) {
function addSimpleTest(name, func, expected) {
var _this = this;
testFunctions.push({
name: name,
networks: [network],
execute: function (provider) { return __awaiter(_this, void 0, void 0, function () {
var value;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, func(provider)];
case 1:
value = _a.sent();
equals(name, expected, value);
return [2 /*return*/];
} }
else { });
provider = new (ethers_1.ethers.providers)[providerName](networkName); }); }
});
} }
function addObjectTest(name, func, expected, checkSkip) {
var _this = this;
testFunctions.push({
name: name,
networks: [network],
checkSkip: checkSkip,
execute: function (provider) { return __awaiter(_this, void 0, void 0, function () {
var value;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, func(provider)];
case 1:
value = _a.sent();
Object.keys(expected).forEach(function (key) {
equals(name + "." + key, value[key], expected[key]);
});
return [2 /*return*/];
} }
var tests = blockchainData[networkName]; });
}); }
});
}
var tests = blockchainData[network];
// And address test case can have any of the following: // And address test case can have any of the following:
// - balance // - balance
// - code // - code
@ -463,144 +554,120 @@ function testProvider(providerName, networkName) {
// - ENS name // - ENS name
tests.addresses.forEach(function (test) { tests.addresses.forEach(function (test) {
if (test.balance) { if (test.balance) {
it("fetches address balance: " + test.address, function () { addSimpleTest("fetches account balance: " + test.address, function (provider) {
// Note: These tests could be fiddled with if someone sends ether return provider.getBalance(test.address);
// to our address; we just have to live with jerks sending us }, test.balance);
// money. *smile emoji*
this.timeout(60000);
return provider.getBalance(test.address).then(function (balance) {
equals("Balance", test.balance, balance);
return waiter(delay);
});
});
} }
if (test.code) { if (test.code) {
it("fetches address code: " + test.address, function () { addSimpleTest("fetches account code: " + test.address, function (provider) {
this.timeout(60000); return provider.getCode(test.address);
return provider.getCode(test.address).then(function (code) { }, test.code);
equals("Code", test.code, code);
return waiter(delay);
});
});
} }
if (test.storage) { if (test.storage) {
Object.keys(test.storage).forEach(function (position) { Object.keys(test.storage).forEach(function (position) {
it("fetches storage: " + test.address + ":" + position, function () { addSimpleTest("fetches storage: " + test.address + ":" + position, function (provider) {
this.timeout(60000); return provider.getStorageAt(test.address, bnify(position));
return provider.getStorageAt(test.address, bnify(position)).then(function (value) { }, test.storage[position]);
equals("Storage", test.storage[position], value);
return waiter(delay);
});
});
}); });
} }
if (test.name) { if (test.name) {
it("fetches the ENS name: " + test.name, function () { addSimpleTest("fetches ENS name: " + test.address, function (provider) {
this.timeout(60000); return provider.resolveName(test.name);
return provider.resolveName(test.name).then(function (address) { }, test.address);
equals("ENS Name", test.address, address);
return waiter(delay);
});
});
} }
}); });
tests.blocks.forEach(function (test) { tests.blocks.forEach(function (test) {
function checkBlock(promise) { addObjectTest("fetches block (by number) #" + test.number, function (provider) {
return promise.then(function (block) { return provider.getBlock(test.number);
for (var key in test) { }, test);
equals("Block " + key, block[key], test[key]);
}
return waiter(delay);
}); });
} tests.blocks.forEach(function (test) {
it("fetches block (by number) #" + test.number, function () { addObjectTest("fetches block (by hash) " + test.hash, function (provider) {
this.timeout(60000); return provider.getBlock(test.hash);
return checkBlock(provider.getBlock(test.number)); }, test, function (provider, network, test) {
}); return (provider === "EtherscanProvider");
// Etherscan does not support getBlockByBlockhash... *sad emoji*
if (providerName === "EtherscanProvider") {
return;
}
it("fetches block (by hash) " + test.hash, function () {
this.timeout(60000);
return checkBlock(provider.getBlock(test.hash));
}); });
}); });
tests.transactions.forEach(function (test) { tests.transactions.forEach(function (test) {
function testTransaction(expected) { addObjectTest("fetches transaction " + test.hash, function (provider) { return __awaiter(void 0, void 0, void 0, function () {
var title = ("Transaction " + expected.hash.substring(0, 10) + " - "); var tx;
return provider.getTransaction(expected.hash).then(function (tx) { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, provider.getTransaction(test.hash)];
case 1:
tx = _a.sent();
// This changes with every block // This changes with every block
assert_1.default.equal(typeof (tx.confirmations), "number", "confirmations is a number"); assert_1.default.equal(typeof (tx.confirmations), "number", "confirmations is a number");
delete tx.confirmations; delete tx.confirmations;
assert_1.default.equal(typeof (tx.wait), "function", "wait is a function"); assert_1.default.equal(typeof (tx.wait), "function", "wait is a function");
delete tx.wait; delete tx.wait;
for (var key in tx) { return [2 /*return*/, tx];
equals((title + key), tx[key], expected[key]);
} }
return waiter(delay);
}); });
} }); }, test, function (provider, network, test) {
it("fetches transaction: " + test.hash, function () { return (provider === "EtherscanProvider");
this.timeout(60000);
return testTransaction(test);
}); });
}); });
tests.transactionReceipts.forEach(function (test) { tests.transactionReceipts.forEach(function (test) {
function testTransactionReceipt(expected) { addObjectTest("fetches transaction receipt " + test.transactionHash, function (provider) { return __awaiter(void 0, void 0, void 0, function () {
var title = ("Receipt " + expected.transactionHash.substring(0, 10) + " - "); var receipt;
return provider.getTransactionReceipt(expected.transactionHash).then(function (receipt) { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, provider.getTransactionReceipt(test.transactionHash)];
case 1:
receipt = _a.sent();
if (test.status === null) {
assert_1.default.ok(receipt.status === undefined, "no status");
receipt.status = null;
}
// This changes with every block; so just make sure it is a number // This changes with every block; so just make sure it is a number
assert_1.default.equal(typeof (receipt.confirmations), "number", "confirmations is a number"); assert_1.default.equal(typeof (receipt.confirmations), "number", "confirmations is a number");
delete receipt.confirmations; delete receipt.confirmations;
for (var key in receipt) { return [2 /*return*/, receipt];
equals((title + key), receipt[key], expected[key]);
} }
//equals(("Receipt " + expected.transactionHash.substring(0, 10)), receipt, expected);
return waiter(delay);
}); });
} }); }, test);
it("fetches transaction receipt: " + test.transactionHash, function () {
this.timeout(60000);
return testTransactionReceipt(test);
}); });
}); });
if (networkName === "ropsten") { (function () {
it("throws correct NONCE_EXPIRED errors", function () { var _this = this;
return __awaiter(this, void 0, void 0, function () { function addErrorTest(code, func) {
var tx, error_1; var _this = this;
testFunctions.push({
name: "throws correct " + code + " error",
networks: ["ropsten"],
execute: function (provider) { return __awaiter(_this, void 0, void 0, function () {
var value, error_1;
return __generator(this, function (_a) { return __generator(this, function (_a) {
switch (_a.label) { switch (_a.label) {
case 0: case 0:
this.timeout(60000); _a.trys.push([0, 2, , 3]);
_a.label = 1; return [4 /*yield*/, func(provider)];
case 1: case 1:
_a.trys.push([1, 3, , 4]); value = _a.sent();
return [4 /*yield*/, provider.sendTransaction("0xf86480850218711a0082520894000000000000000000000000000000000000000002801ba038aaddcaaae7d3fa066dfd6f196c8348e1bb210f2c121d36cb2c24ef20cea1fba008ae378075d3cd75aae99ab75a70da82161dffb2c8263dabc5d8adecfa9447fa")]; console.log(value);
assert_1.default.ok(false, "did not throw");
return [3 /*break*/, 3];
case 2: case 2:
tx = _a.sent();
console.log(tx);
assert_1.default.ok(false);
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent(); error_1 = _a.sent();
assert_1.default.equal(error_1.code, ethers_1.ethers.utils.Logger.errors.NONCE_EXPIRED); assert_1.default.equal(error_1.code, code, "incorrect error thrown");
return [3 /*break*/, 4]; return [3 /*break*/, 3];
case 4: return [4 /*yield*/, waiter(delay)]; case 3: return [2 /*return*/];
case 5:
_a.sent();
return [2 /*return*/];
} }
}); });
}); }
}); });
}
addErrorTest(ethers_1.ethers.utils.Logger.errors.NONCE_EXPIRED, function (provider) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, provider.sendTransaction("0xf86480850218711a0082520894000000000000000000000000000000000000000002801ba038aaddcaaae7d3fa066dfd6f196c8348e1bb210f2c121d36cb2c24ef20cea1fba008ae378075d3cd75aae99ab75a70da82161dffb2c8263dabc5d8adecfa9447fa")];
}); });
it("throws correct INSUFFICIENT_FUNDS errors", function () { }); });
return __awaiter(this, void 0, void 0, function () { addErrorTest(ethers_1.ethers.utils.Logger.errors.INSUFFICIENT_FUNDS, function (provider) { return __awaiter(_this, void 0, void 0, function () {
var txProps, wallet, tx, error_2; var txProps, wallet, tx;
return __generator(this, function (_a) { return __generator(this, function (_a) {
switch (_a.label) { switch (_a.label) {
case 0: case 0:
this.timeout(60000);
txProps = { txProps = {
to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72", to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
gasPrice: 9000000000, gasPrice: 9000000000,
@ -611,33 +678,13 @@ function testProvider(providerName, networkName) {
return [4 /*yield*/, wallet.signTransaction(txProps)]; return [4 /*yield*/, wallet.signTransaction(txProps)];
case 1: case 1:
tx = _a.sent(); tx = _a.sent();
_a.label = 2; return [2 /*return*/, provider.sendTransaction(tx)];
case 2:
_a.trys.push([2, 4, , 5]);
return [4 /*yield*/, provider.sendTransaction(tx)];
case 3:
_a.sent();
assert_1.default.ok(false);
return [3 /*break*/, 5];
case 4:
error_2 = _a.sent();
assert_1.default.equal(error_2.code, ethers_1.ethers.utils.Logger.errors.INSUFFICIENT_FUNDS);
return [3 /*break*/, 5];
case 5: return [4 /*yield*/, waiter(delay)];
case 6:
_a.sent();
return [2 /*return*/];
} }
}); });
}); }); });
}); addErrorTest(ethers_1.ethers.utils.Logger.errors.INSUFFICIENT_FUNDS, function (provider) { return __awaiter(_this, void 0, void 0, function () {
it("throws correct INSUFFICIENT_FUNDS errors (signer)", function () { var txProps, wallet;
return __awaiter(this, void 0, void 0, function () {
var txProps, wallet, error_3;
return __generator(this, function (_a) { return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.timeout(60000);
txProps = { txProps = {
to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72", to: "0x8ba1f109551bD432803012645Ac136ddd64DBA72",
gasPrice: 9000000000, gasPrice: 9000000000,
@ -645,128 +692,168 @@ function testProvider(providerName, networkName) {
value: 1 value: 1
}; };
wallet = ethers_1.ethers.Wallet.createRandom().connect(provider); wallet = ethers_1.ethers.Wallet.createRandom().connect(provider);
_a.label = 1; return [2 /*return*/, wallet.sendTransaction(txProps)];
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, wallet.sendTransaction(txProps)];
case 2:
_a.sent();
assert_1.default.ok(false);
return [3 /*break*/, 4];
case 3:
error_3 = _a.sent();
assert_1.default.equal(error_3.code, ethers_1.ethers.utils.Logger.errors.INSUFFICIENT_FUNDS);
return [3 /*break*/, 4];
case 4: return [4 /*yield*/, waiter(delay)];
case 5:
_a.sent();
return [2 /*return*/];
}
}); });
}); }); });
}); addErrorTest(ethers_1.ethers.utils.Logger.errors.UNPREDICTABLE_GAS_LIMIT, function (provider) { return __awaiter(_this, void 0, void 0, function () {
it("throws correct UNPREDICTABLE_GAS_LIMIT errors", function () {
return __awaiter(this, void 0, void 0, function () {
var error_4;
return __generator(this, function (_a) { return __generator(this, function (_a) {
switch (_a.label) { return [2 /*return*/, provider.estimateGas({
case 0: to: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" // ENS contract
this.timeout(60000);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, provider.estimateGas({
to: "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e" // ENS; no payable fallback
})]; })];
case 2:
_a.sent();
assert_1.default.ok(false);
return [3 /*break*/, 4];
case 3:
error_4 = _a.sent();
assert_1.default.equal(error_4.code, ethers_1.ethers.utils.Logger.errors.UNPREDICTABLE_GAS_LIMIT);
return [3 /*break*/, 4];
case 4: return [4 /*yield*/, waiter(delay)];
case 5:
_a.sent();
return [2 /*return*/];
}
}); });
}); }); });
}); })();
it("sends a transaction", function () { testFunctions.push({
return __awaiter(this, void 0, void 0, function () { name: "sends a transaction",
var wallet, funder, addr, gasPrice, balance, tx; extras: ["funding"],
timeout: 300,
networks: ["ropsten"],
execute: function (provider) { return __awaiter(void 0, void 0, void 0, function () {
var wallet, addr, b0, tx, b1;
return __generator(this, function (_a) { return __generator(this, function (_a) {
switch (_a.label) { switch (_a.label) {
case 0: case 0:
this.timeout(360000); wallet = fundWallet.connect(provider);
wallet = ethers_1.ethers.Wallet.createRandom().connect(provider);
return [4 /*yield*/, ethers_1.ethers.utils.fetchJson("https://api.ethers.io/api/v1/?action=fundAccount&address=" + wallet.address.toLowerCase())];
case 1:
funder = _a.sent();
return [4 /*yield*/, provider.waitForTransaction(funder.hash)];
case 2:
_a.sent();
addr = "0x8210357f377E901f18E45294e86a2A32215Cc3C9"; addr = "0x8210357f377E901f18E45294e86a2A32215Cc3C9";
gasPrice = 9000000000;
return [4 /*yield*/, provider.getBalance(wallet.address)]; return [4 /*yield*/, provider.getBalance(wallet.address)];
case 3: case 1:
balance = _a.sent(); b0 = _a.sent();
assert_1.default.ok(balance.eq(ethers_1.ethers.utils.parseEther("3.141592653589793238")), "balance is pi after funding"); assert_1.default.ok(b0.gt(ethers_1.ethers.constants.Zero), "balance is non-zero");
return [4 /*yield*/, wallet.sendTransaction({ return [4 /*yield*/, wallet.sendTransaction({
to: addr, to: addr,
gasPrice: gasPrice, value: 123
value: balance.sub(21000 * gasPrice)
})]; })];
case 4: case 2:
tx = _a.sent(); tx = _a.sent();
return [4 /*yield*/, tx.wait()]; return [4 /*yield*/, tx.wait()];
case 5: case 3:
_a.sent(); _a.sent();
return [4 /*yield*/, provider.getBalance(wallet.address)]; return [4 /*yield*/, provider.getBalance(wallet.address)];
case 6: case 4:
balance = _a.sent(); b1 = _a.sent();
assert_1.default.ok(balance.eq(ethers_1.ethers.constants.Zero), "balance is zero after after sweeping"); assert_1.default.ok(b0.gt(b1), "balance is decreased");
return [4 /*yield*/, waiter(delay)]; return [2 /*return*/];
case 7: }
_a.sent(); });
}); }
});
describe("Test Provider Methods", function () {
var fundReceipt = null;
var faucet = "0x8210357f377E901f18E45294e86a2A32215Cc3C9";
before(function () {
return __awaiter(this, void 0, void 0, function () {
var provider, funder;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
provider = ethers_1.ethers.getDefaultProvider("ropsten");
return [4 /*yield*/, ethers_1.ethers.utils.fetchJson("https://api.ethers.io/api/v1/?action=fundAccount&address=" + fundWallet.address.toLowerCase())];
case 1:
funder = _a.sent();
fundReceipt = provider.waitForTransaction(funder.hash);
fundReceipt.then(function (receipt) {
console.log("*** Funded: " + fundWallet.address);
});
return [2 /*return*/]; return [2 /*return*/];
} }
}); });
}); });
}); });
} after(function () {
// Obviously many more cases to add here return __awaiter(this, void 0, void 0, function () {
// - getTransactionCount var provider, gasPrice, balance;
// - getBlockNumber return __generator(this, function (_a) {
// - getGasPrice switch (_a.label) {
// - estimateGas case 0:
// - sendTransaction // Wait until the funding is complete
// - call return [4 /*yield*/, fundReceipt];
// - getLogs case 1:
// // Wait until the funding is complete
// Many of these are tLegacyParametersested in run-providers, which uses nodeunit, but _a.sent();
// also creates a local private key which must then be funded to provider = ethers_1.ethers.getDefaultProvider("ropsten");
// execute the tests. I am working on a better test contract to deploy return [4 /*yield*/, provider.getGasPrice()];
// to all the networks to help test these. case 2:
gasPrice = _a.sent();
return [4 /*yield*/, provider.getBalance(fundWallet.address)];
case 3:
balance = _a.sent();
fundWallet.connect(provider).sendTransaction({
to: faucet,
gasLimit: 21000,
gasPrice: gasPrice,
value: balance.sub(gasPrice.mul(21000))
}); });
} return [2 /*return*/];
["default", "homestead", "ropsten", "rinkeby", "kovan", "goerli"].forEach(function (networkName) { }
["getDefaultProvider", "AlchemyProvider", "CloudflareProvider", "InfuraProvider", "EtherscanProvider", "NodesmithProvider", "Web3Provider"].forEach(function (providerName) { });
if (providerName === "NodesmithProvider") { });
});
providerFunctions.forEach(function (_a) {
var name = _a.name, networks = _a.networks, create = _a.create;
networks.forEach(function (network) {
var provider = create(network);
testFunctions.forEach(function (test) {
// Skip tests not supported on this network
if (test.networks.indexOf(network) === -1) {
return; return;
} }
if (providerName === "CloudflareProvider") { if (test.checkSkip && test.checkSkip(name, network, test)) {
return; return;
} }
if (providerName === "Web3Provider") { // How many attempts to try?
return; var attempts = (test.attempts != null) ? test.attempts : 3;
var timeout = (test.timeout != null) ? test.timeout : 60;
var extras = (test.extras || []).reduce(function (accum, key) {
accum[key] = true;
return accum;
}, {});
it(name + "." + (network ? network : "default") + " " + test.name, function () {
return __awaiter(this, void 0, void 0, function () {
var error, attempt, attemptError_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.timeout(timeout * 1000 * attempts);
if (!extras.funding) return [3 /*break*/, 2];
return [4 /*yield*/, fundReceipt];
case 1:
_a.sent();
_a.label = 2;
case 2:
if (!!extras.nowait) return [3 /*break*/, 4];
return [4 /*yield*/, waiter(1000)];
case 3:
_a.sent();
_a.label = 4;
case 4:
error = null;
attempt = 0;
_a.label = 5;
case 5:
if (!(attempt < attempts)) return [3 /*break*/, 10];
_a.label = 6;
case 6:
_a.trys.push([6, 8, , 9]);
return [4 /*yield*/, Promise.race([
test.execute(provider),
waiter(timeout * 1000).then(function (resolve) { throw new Error("timeout"); })
])];
case 7: return [2 /*return*/, _a.sent()];
case 8:
attemptError_1 = _a.sent();
console.log("*** Failed attempt " + (attempt + 1) + ": " + attemptError_1.message);
error = attemptError_1;
return [3 /*break*/, 9];
case 9:
attempt++;
return [3 /*break*/, 5];
case 10: throw error;
} }
if ((networkName !== "homestead" && networkName !== "default") && providerName === "CloudflareProvider") { });
return; });
} });
testProvider(providerName, networkName); });
});
}); });
}); });
/* /*
@ -789,7 +876,7 @@ describe("Test extra Etherscan operations", function() {
}); });
*/ */
describe("Test Basic Authentication", function () { describe("Test Basic Authentication", function () {
this.retries(3); //this.retries(3);
function test(name, url) { function test(name, url) {
it("tests " + name, function () { it("tests " + name, function () {
this.timeout(60000); this.timeout(60000);

File diff suppressed because one or more lines are too long

@ -39,7 +39,7 @@
"scripts": { "scripts": {
"test": "exit 1" "test": "exit 1"
}, },
"tarballHash": "0xeba001b6d7814b9df776d8a5b395ba7080d99ea8a6dfc8fad70888a5f7d01f3e", "tarballHash": "0x71309e6063699613deb6d5d29f7c87963ee1d71e252f006cdd3ad930e187e47c",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",
"version": "5.0.8" "version": "5.0.8"
} }