admin: update dist files

This commit is contained in:
Richard Moore 2022-09-27 03:45:27 -04:00
parent 4d435cd56e
commit a6faed5098
153 changed files with 5084 additions and 3491 deletions

3
.gitignore vendored

@ -1,3 +1,6 @@
node_modules/**
output/**
misc/**
**/*.swp
dist/*.gz

2475
dist/ethers.js vendored

File diff suppressed because it is too large Load Diff

2
dist/ethers.js.map vendored

File diff suppressed because one or more lines are too long

2
dist/ethers.min.js vendored

File diff suppressed because one or more lines are too long

@ -145,7 +145,7 @@ const u64 = {
add, add3L, add3H, add4L, add4H, add5H, add5L,
};
const version = "6.0.0-beta-exports.1";
const version = "6.0.0-beta-exports.2";
function defineReadOnly(object, name, value) {
Object.defineProperty(object, name, {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -638,7 +638,7 @@ class Fragment {
case "function": return FunctionFragment.fromObject(obj);
case "struct": return StructFragment.fromObject(obj);
}
throw new Error("not implemented yet");
throw new Error(`not implemented yet: ${obj.type}`);
}
static fromString(text) {
try {
@ -727,6 +727,9 @@ class ErrorFragment extends NamedFragment {
result.push(this.name + joinParams(format, this.inputs));
return result.join(" ");
}
static fromObject(obj) {
return new ErrorFragment(_guard, obj.name, obj.inputs ? obj.inputs.map(ParamType.fromObject) : []);
}
static fromString(text) {
return ErrorFragment.fromTokens(lex(text));
}
@ -766,6 +769,9 @@ class EventFragment extends NamedFragment {
}
return result.join(" ");
}
static fromObject(obj) {
return new EventFragment(_guard, obj.name, obj.inputs ? obj.inputs.map(ParamType.fromObject) : [], !!obj.anonymous);
}
static fromString(text) {
return EventFragment.fromTokens(lex(text));
}
@ -807,12 +813,12 @@ class ConstructorFragment extends Fragment {
}
return result.join(" ");
}
static fromObject(obj) {
return new ConstructorFragment(_guard, "constructor", obj.inputs ? obj.inputs.map(ParamType.fromObject) : [], !!obj.payable, (obj.gas != null) ? obj.gas : null);
}
static fromString(text) {
return ConstructorFragment.fromTokens(lex(text));
}
static fromObject(obj) {
throw new Error("TODO");
}
static fromTokens(tokens) {
consumeKeywords(tokens, setify(["constructor"]));
const inputs = consumeParams(tokens);
@ -871,6 +877,10 @@ class FunctionFragment extends NamedFragment {
}
return result.join(" ");
}
static fromObject(obj) {
// @TODO: verifyState for stateMutability
return new FunctionFragment(_guard, obj.name, obj.stateMutability, obj.inputs ? obj.inputs.map(ParamType.fromObject) : [], obj.outputs ? obj.outputs.map(ParamType.fromObject) : [], (obj.gas != null) ? obj.gas : null);
}
static fromString(text) {
return FunctionFragment.fromTokens(lex(text));
}

File diff suppressed because one or more lines are too long

@ -125,8 +125,15 @@ class Interface {
this.#errors = new Map();
this.#events = new Map();
// this.#structs = new Map();
const frags = [];
for (const a of abi) {
try {
frags.push(fragments_js_1.Fragment.from(a));
}
catch (error) { }
}
(0, index_js_3.defineProperties)(this, {
fragments: Object.freeze(abi.map((f) => fragments_js_1.Fragment.from(f)).filter((f) => (f != null))),
fragments: Object.freeze(frags)
});
this.#abiCoder = this.getAbiCoder();
// Add all fragments by their signature

File diff suppressed because one or more lines are too long

@ -170,6 +170,8 @@ class WrappedMethod extends _WrappedMethodBase() {
}
const tx = await runner.sendTransaction(await this.populateTransaction(...args));
const provider = getProvider(this._contract.runner);
// @TODO: the provider can be null; make a custom dummy provider that will throw a
// meaningful error
return new wrappers_js_1.ContractTransactionResponse(this._contract.interface, provider, tx);
}
async estimateGas(...args) {
@ -387,6 +389,8 @@ class BaseContract {
let deployTx = null;
if (_deployTx) {
const provider = getProvider(runner);
// @TODO: the provider can be null; make a custom dummy provider that will throw a
// meaningful error
deployTx = new wrappers_js_1.ContractTransactionResponse(this.interface, provider, _deployTx);
}
let subs = new Map();

File diff suppressed because one or more lines are too long

@ -1 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src.ts/contract/types.ts"],"names":[],"mappings":";;AAeC,CAAC;AAiBqE,CAAC;AAkDvE,CAAC"}
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src.ts/contract/types.ts"],"names":[],"mappings":";;AAeC,CAAC;AAiB4E,CAAC;AAkD9E,CAAC"}

@ -1 +1 @@
{"version":3,"file":"wrappers.js","sourceRoot":"","sources":["../../src.ts/contract/wrappers.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"wrappers.js","sourceRoot":"","sources":["../../src.ts/contract/wrappers.ts"],"names":[],"mappings":"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"}

@ -7,16 +7,20 @@
// migrate the listener to the static event. We also need to maintain a map
// of Signer/ENS name to address so we can sync respond to listenerCount.
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractProvider = exports.copyRequest = exports.UnmanagedSubscriber = void 0;
exports.AbstractProvider = exports.UnmanagedSubscriber = void 0;
const index_js_1 = require("../address/index.js");
const index_js_2 = require("../utils/index.js");
const ens_resolver_js_1 = require("./ens-resolver.js");
const format_js_1 = require("./format.js");
const network_js_1 = require("./network.js");
const provider_js_1 = require("./provider.js");
const subscriber_polling_js_1 = require("./subscriber-polling.js");
// Constants
const BN_2 = BigInt(2);
const MAX_CCIP_REDIRECTS = 10;
function isPromise(value) {
return (value && typeof (value.then) === "function");
}
function getTag(prefix, value) {
return prefix + ":" + JSON.stringify(value, (k, v) => {
if (typeof (v) === "bigint") {
@ -54,10 +58,6 @@ function concisify(items) {
items.sort();
return items;
}
// Normalize a ProviderEvent into a Subscription
// @TODO: Make events sync if possible; like block
//function getSyncSubscription(_event: ProviderEvent): Subscription {
//}
async function getSubscription(_event, provider) {
if (_event == null) {
throw new Error("invalid event");
@ -127,11 +127,6 @@ async function getSubscription(_event, provider) {
return (0, index_js_2.throwArgumentError)("unknown ProviderEvent", "event", _event);
}
function getTime() { return (new Date()).getTime(); }
function copyRequest(tx) {
// @TODO: copy the copy from contracts and use it from this
return tx;
}
exports.copyRequest = copyRequest;
class AbstractProvider {
#subs;
#plugins;
@ -140,6 +135,8 @@ class AbstractProvider {
#networkPromise;
#anyNetwork;
#performCache;
// The most recent block number if running an event or -1 if no "block" event
#lastBlockNumber;
#nextTimer;
#timers;
#disableCcipRead;
@ -160,6 +157,7 @@ class AbstractProvider {
this.#anyNetwork = false;
this.#networkPromise = null;
}
this.#lastBlockNumber = -1;
this.#performCache = new Map();
this.#subs = new Map();
this.#plugins = new Map();
@ -248,8 +246,20 @@ class AbstractProvider {
transaction: tx, info: { urls, errorMessages }
});
}
_wrapTransaction(tx, hash, blockNumber) {
return tx;
_wrapBlock(value, network) {
return new provider_js_1.Block((0, format_js_1.formatBlock)(value), this);
}
_wrapBlockWithTransactions(value, network) {
return new provider_js_1.Block((0, format_js_1.formatBlock)(value), this);
}
_wrapLog(value, network) {
return new provider_js_1.Log((0, format_js_1.formatLog)(value), this);
}
_wrapTransactionReceipt(value, network) {
return new provider_js_1.TransactionReceipt((0, format_js_1.formatTransactionReceipt)(value), this);
}
_wrapTransactionResponse(tx, network) {
return new provider_js_1.TransactionResponse(tx, this);
}
_detectNetwork() {
return (0, index_js_2.throwError)("sub-classes must implement this", "UNSUPPORTED_OPERATION", {
@ -266,20 +276,14 @@ class AbstractProvider {
}
// State
async getBlockNumber() {
return (0, index_js_2.getNumber)(await this.#perform({ method: "getBlockNumber" }), "%response");
const blockNumber = (0, index_js_2.getNumber)(await this.#perform({ method: "getBlockNumber" }), "%response");
if (this.#lastBlockNumber >= 0) {
this.#lastBlockNumber = blockNumber;
}
return blockNumber;
}
// @TODO: Make this string | Promsie<string> so no await needed if sync is possible
_getAddress(address) {
return (0, index_js_1.resolveAddress)(address, this);
/*
if (typeof(address) === "string") {
if (address.match(/^0x[0-9a-f]+$/i)) { return address; }
const resolved = await this.resolveName(address);
if (resolved == null) { throw new Error("not confiugred @TODO"); }
return resolved;
}
return address.getAddress();
*/
}
_getBlockTag(blockTag) {
if (blockTag == null) {
@ -304,236 +308,13 @@ class AbstractProvider {
if (blockTag >= 0) {
return (0, index_js_2.toQuantity)(blockTag);
}
if (this.#lastBlockNumber >= 0) {
return (0, index_js_2.toQuantity)(this.#lastBlockNumber + blockTag);
}
return this.getBlockNumber().then((b) => (0, index_js_2.toQuantity)(b + blockTag));
}
return (0, index_js_2.throwArgumentError)("invalid blockTag", "blockTag", blockTag);
}
async getNetwork() {
// No explicit network was set and this is our first time
if (this.#networkPromise == null) {
// Detect the current network (shared with all calls)
const detectNetwork = this._detectNetwork().then((network) => {
this.emit("network", network, null);
return network;
}, (error) => {
// Reset the networkPromise on failure, so we will try again
if (this.#networkPromise === detectNetwork) {
this.#networkPromise = null;
}
throw error;
});
this.#networkPromise = detectNetwork;
return await detectNetwork;
}
const networkPromise = this.#networkPromise;
const [expected, actual] = await Promise.all([
networkPromise,
this._detectNetwork() // The actual connected network
]);
if (expected.chainId !== actual.chainId) {
if (this.#anyNetwork) {
// The "any" network can change, so notify listeners
this.emit("network", actual, expected);
// Update the network if something else hasn't already changed it
if (this.#networkPromise === networkPromise) {
this.#networkPromise = Promise.resolve(actual);
}
}
else {
// Otherwise, we do not allow changes to the underlying network
(0, index_js_2.throwError)(`network changed: ${expected.chainId} => ${actual.chainId} `, "NETWORK_ERROR", {
event: "changed"
});
}
}
return expected.clone().freeze();
}
async getFeeData() {
const { block, gasPrice } = await (0, index_js_2.resolveProperties)({
block: this.getBlock("latest"),
gasPrice: ((async () => {
try {
const gasPrice = await this.#perform({ method: "getGasPrice" });
return (0, index_js_2.getBigInt)(gasPrice, "%response");
}
catch (error) { }
return null;
})())
});
let maxFeePerGas = null, maxPriorityFeePerGas = null;
if (block && block.baseFeePerGas) {
// We may want to compute this more accurately in the future,
// using the formula "check if the base fee is correct".
// See: https://eips.ethereum.org/EIPS/eip-1559
maxPriorityFeePerGas = BigInt("1500000000");
// Allow a network to override their maximum priority fee per gas
//const priorityFeePlugin = (await this.getNetwork()).getPlugin<MaxPriorityFeePlugin>("org.ethers.plugins.max-priority-fee");
//if (priorityFeePlugin) {
// maxPriorityFeePerGas = await priorityFeePlugin.getPriorityFee(this);
//}
maxFeePerGas = (block.baseFeePerGas * BN_2) + maxPriorityFeePerGas;
}
return new provider_js_1.FeeData(gasPrice, maxFeePerGas, maxPriorityFeePerGas);
}
async _getTransaction(_request) {
const network = await this.getNetwork();
// Fill in any addresses
const request = Object.assign({}, _request, await (0, index_js_2.resolveProperties)({
to: (_request.to ? (0, index_js_1.resolveAddress)(_request.to, this) : undefined),
from: (_request.from ? (0, index_js_1.resolveAddress)(_request.from, this) : undefined),
}));
return network.formatter.transactionRequest(request);
}
async estimateGas(_tx) {
const transaction = await this._getTransaction(_tx);
return (0, index_js_2.getBigInt)(await this.#perform({
method: "estimateGas", transaction
}), "%response");
}
async #call(tx, blockTag, attempt) {
if (attempt >= MAX_CCIP_REDIRECTS) {
(0, index_js_2.throwError)("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
reason: "TOO_MANY_REDIRECTS",
transaction: Object.assign({}, tx, { blockTag, enableCcipRead: true })
});
}
const transaction = copyRequest(tx);
try {
return (0, index_js_2.hexlify)(await this._perform({ method: "call", transaction, blockTag }));
}
catch (error) {
// CCIP Read OffchainLookup
if (!this.disableCcipRead && (0, index_js_2.isCallException)(error) && attempt >= 0 && blockTag === "latest" && transaction.to != null && (0, index_js_2.dataSlice)(error.data, 0, 4) === "0x556f1830") {
const data = error.data;
const txSender = await (0, index_js_1.resolveAddress)(transaction.to, this);
// Parse the CCIP Read Arguments
let ccipArgs;
try {
ccipArgs = parseOffchainLookup((0, index_js_2.dataSlice)(error.data, 4));
}
catch (error) {
return (0, index_js_2.throwError)(error.message, "OFFCHAIN_FAULT", {
reason: "BAD_DATA",
transaction, info: { data }
});
}
// Check the sender of the OffchainLookup matches the transaction
if (ccipArgs.sender.toLowerCase() !== txSender.toLowerCase()) {
return (0, index_js_2.throwError)("CCIP Read sender mismatch", "CALL_EXCEPTION", {
data, transaction,
errorSignature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
errorName: "OffchainLookup",
errorArgs: ccipArgs.errorArgs
});
}
const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
if (ccipResult == null) {
return (0, index_js_2.throwError)("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
reason: "FETCH_FAILED",
transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
});
}
return this.#call({
to: txSender,
data: (0, index_js_2.concat)([
ccipArgs.selector, encodeBytes([ccipResult, ccipArgs.extraData])
]),
}, blockTag, attempt + 1);
}
throw error;
}
}
async call(_tx) {
const [tx, blockTag] = await Promise.all([
this._getTransaction(_tx), this._getBlockTag(_tx.blockTag)
]);
return this.#call(tx, blockTag, _tx.enableCcipRead ? 0 : -1);
}
// Account
async #getAccountValue(request, _address, _blockTag) {
let address = this._getAddress(_address);
let blockTag = this._getBlockTag(_blockTag);
if (typeof (address) !== "string" || typeof (blockTag) !== "string") {
[address, blockTag] = await Promise.all([address, blockTag]);
}
return await this.#perform(Object.assign(request, { address, blockTag }));
}
async getBalance(address, blockTag) {
return (0, index_js_2.getBigInt)(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
}
async getTransactionCount(address, blockTag) {
return (0, index_js_2.getNumber)(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
}
async getCode(address, blockTag) {
return (0, index_js_2.hexlify)(await this.#getAccountValue({ method: "getCode" }, address, blockTag));
}
async getStorageAt(address, _position, blockTag) {
const position = (0, index_js_2.getBigInt)(_position, "position");
return (0, index_js_2.hexlify)(await this.#getAccountValue({ method: "getStorageAt", position }, address, blockTag));
}
// Write
async broadcastTransaction(signedTx) {
throw new Error();
return {};
}
async #getBlock(block, includeTransactions) {
if ((0, index_js_2.isHexString)(block, 32)) {
return await this.#perform({
method: "getBlock", blockHash: block, includeTransactions
});
}
let blockTag = this._getBlockTag(block);
if (typeof (blockTag) !== "string") {
blockTag = await blockTag;
}
return await this.#perform({
method: "getBlock", blockTag, includeTransactions
});
}
// Queries
async getBlock(block) {
const [network, params] = await Promise.all([
this.getNetwork(), this.#getBlock(block, false)
]);
if (params == null) {
return null;
}
return network.formatter.block(params, this);
}
async getBlockWithTransactions(block) {
const format = (await this.getNetwork()).formatter;
const params = this.#getBlock(block, true);
if (params == null) {
return null;
}
return format.blockWithTransactions(params, this);
}
async getTransaction(hash) {
const format = (await this.getNetwork()).formatter;
const params = await this.#perform({ method: "getTransaction", hash });
return format.transactionResponse(params, this);
}
async getTransactionReceipt(hash) {
const format = (await this.getNetwork()).formatter;
const receipt = await this.#perform({ method: "getTransactionReceipt", hash });
if (receipt == null) {
return null;
}
// Some backends did not backfill the effectiveGasPrice into old transactions
// in the receipt, so we look it up manually and inject it.
if (receipt.gasPrice == null && receipt.effectiveGasPrice == null) {
const tx = await this.#perform({ method: "getTransaction", hash });
receipt.effectiveGasPrice = tx.gasPrice;
}
return format.receipt(receipt, this);
}
async getTransactionResult(hash) {
const result = await this.#perform({ method: "getTransactionResult", hash });
if (result == null) {
return null;
}
return (0, index_js_2.hexlify)(result);
}
_getFilter(filter) {
// Create a canonical representation of the topics
const topics = (filter.topics || []).map((t) => {
@ -609,15 +390,295 @@ class AbstractProvider {
}
return resolve(address, fromBlock, toBlock);
}
_getTransactionRequest(_request) {
const request = (0, provider_js_1.copyRequest)(_request);
const promises = [];
["to", "from"].forEach((key) => {
if (request[key] == null) {
return;
}
const addr = (0, index_js_1.resolveAddress)(request[key]);
if (isPromise(addr)) {
promises.push((async function () { request[key] = await addr; })());
}
else {
request[key] = addr;
}
});
if (request.blockTag != null) {
const blockTag = this._getBlockTag(request.blockTag);
if (isPromise(blockTag)) {
promises.push((async function () { request.blockTag = await blockTag; })());
}
else {
request.blockTag = blockTag;
}
}
if (promises.length) {
return (async function () {
await Promise.all(promises);
return request;
})();
}
return request;
}
async getNetwork() {
// No explicit network was set and this is our first time
if (this.#networkPromise == null) {
// Detect the current network (shared with all calls)
const detectNetwork = this._detectNetwork().then((network) => {
this.emit("network", network, null);
return network;
}, (error) => {
// Reset the networkPromise on failure, so we will try again
if (this.#networkPromise === detectNetwork) {
this.#networkPromise = null;
}
throw error;
});
this.#networkPromise = detectNetwork;
return (await detectNetwork).clone();
}
const networkPromise = this.#networkPromise;
const [expected, actual] = await Promise.all([
networkPromise,
this._detectNetwork() // The actual connected network
]);
if (expected.chainId !== actual.chainId) {
if (this.#anyNetwork) {
// The "any" network can change, so notify listeners
this.emit("network", actual, expected);
// Update the network if something else hasn't already changed it
if (this.#networkPromise === networkPromise) {
this.#networkPromise = Promise.resolve(actual);
}
}
else {
// Otherwise, we do not allow changes to the underlying network
(0, index_js_2.throwError)(`network changed: ${expected.chainId} => ${actual.chainId} `, "NETWORK_ERROR", {
event: "changed"
});
}
}
return expected.clone();
}
async getFeeData() {
const { block, gasPrice } = await (0, index_js_2.resolveProperties)({
block: this.getBlock("latest"),
gasPrice: ((async () => {
try {
const gasPrice = await this.#perform({ method: "getGasPrice" });
return (0, index_js_2.getBigInt)(gasPrice, "%response");
}
catch (error) { }
return null;
})())
});
let maxFeePerGas = null, maxPriorityFeePerGas = null;
if (block && block.baseFeePerGas) {
// We may want to compute this more accurately in the future,
// using the formula "check if the base fee is correct".
// See: https://eips.ethereum.org/EIPS/eip-1559
maxPriorityFeePerGas = BigInt("1500000000");
// Allow a network to override their maximum priority fee per gas
//const priorityFeePlugin = (await this.getNetwork()).getPlugin<MaxPriorityFeePlugin>("org.ethers.plugins.max-priority-fee");
//if (priorityFeePlugin) {
// maxPriorityFeePerGas = await priorityFeePlugin.getPriorityFee(this);
//}
maxFeePerGas = (block.baseFeePerGas * BN_2) + maxPriorityFeePerGas;
}
return new provider_js_1.FeeData(gasPrice, maxFeePerGas, maxPriorityFeePerGas);
}
async estimateGas(_tx) {
let tx = this._getTransactionRequest(_tx);
if (isPromise(tx)) {
tx = await tx;
}
return (0, index_js_2.getBigInt)(await this.#perform({
method: "estimateGas", transaction: tx
}), "%response");
}
async #call(tx, blockTag, attempt) {
if (attempt >= MAX_CCIP_REDIRECTS) {
(0, index_js_2.throwError)("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
reason: "TOO_MANY_REDIRECTS",
transaction: Object.assign({}, tx, { blockTag, enableCcipRead: true })
});
}
// This came in as a PerformActionTransaction, so to/from are safe; we can cast
const transaction = (0, provider_js_1.copyRequest)(tx);
try {
return (0, index_js_2.hexlify)(await this._perform({ method: "call", transaction, blockTag }));
}
catch (error) {
// CCIP Read OffchainLookup
if (!this.disableCcipRead && (0, index_js_2.isCallException)(error) && attempt >= 0 && blockTag === "latest" && transaction.to != null && (0, index_js_2.dataSlice)(error.data, 0, 4) === "0x556f1830") {
const data = error.data;
const txSender = await (0, index_js_1.resolveAddress)(transaction.to, this);
// Parse the CCIP Read Arguments
let ccipArgs;
try {
ccipArgs = parseOffchainLookup((0, index_js_2.dataSlice)(error.data, 4));
}
catch (error) {
return (0, index_js_2.throwError)(error.message, "OFFCHAIN_FAULT", {
reason: "BAD_DATA",
transaction, info: { data }
});
}
// Check the sender of the OffchainLookup matches the transaction
if (ccipArgs.sender.toLowerCase() !== txSender.toLowerCase()) {
return (0, index_js_2.throwError)("CCIP Read sender mismatch", "CALL_EXCEPTION", {
data, transaction,
errorSignature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
errorName: "OffchainLookup",
errorArgs: ccipArgs.errorArgs
});
}
const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
if (ccipResult == null) {
return (0, index_js_2.throwError)("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
reason: "FETCH_FAILED",
transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
});
}
return this.#call({
to: txSender,
data: (0, index_js_2.concat)([
ccipArgs.selector, encodeBytes([ccipResult, ccipArgs.extraData])
]),
}, blockTag, attempt + 1);
}
throw error;
}
}
async #checkNetwork(promise) {
const { value } = await (0, index_js_2.resolveProperties)({
network: this.getNetwork(),
value: promise
});
return value;
}
async call(_tx) {
const { tx, blockTag } = await (0, index_js_2.resolveProperties)({
tx: this._getTransactionRequest(_tx),
blockTag: this._getBlockTag(_tx.blockTag)
});
return await this.#checkNetwork(this.#call(tx, blockTag, _tx.enableCcipRead ? 0 : -1));
}
// Account
async #getAccountValue(request, _address, _blockTag) {
let address = this._getAddress(_address);
let blockTag = this._getBlockTag(_blockTag);
if (typeof (address) !== "string" || typeof (blockTag) !== "string") {
[address, blockTag] = await Promise.all([address, blockTag]);
}
return await this.#checkNetwork(this.#perform(Object.assign(request, { address, blockTag })));
}
async getBalance(address, blockTag) {
return (0, index_js_2.getBigInt)(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
}
async getTransactionCount(address, blockTag) {
return (0, index_js_2.getNumber)(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
}
async getCode(address, blockTag) {
return (0, index_js_2.hexlify)(await this.#getAccountValue({ method: "getCode" }, address, blockTag));
}
async getStorageAt(address, _position, blockTag) {
const position = (0, index_js_2.getBigInt)(_position, "position");
return (0, index_js_2.hexlify)(await this.#getAccountValue({ method: "getStorageAt", position }, address, blockTag));
}
// Write
async broadcastTransaction(signedTx) {
throw new Error();
return {};
}
async #getBlock(block, includeTransactions) {
// @TODO: Add CustomBlockPlugin check
if ((0, index_js_2.isHexString)(block, 32)) {
return await this.#perform({
method: "getBlock", blockHash: block, includeTransactions
});
}
let blockTag = this._getBlockTag(block);
if (typeof (blockTag) !== "string") {
blockTag = await blockTag;
}
return await this.#perform({
method: "getBlock", blockTag, includeTransactions
});
}
// Queries
async getBlock(block) {
const { network, params } = await (0, index_js_2.resolveProperties)({
network: this.getNetwork(),
params: this.#getBlock(block, false)
});
if (params == null) {
return null;
}
return this._wrapBlock((0, format_js_1.formatBlock)(params), network);
}
async getBlockWithTransactions(block) {
const { network, params } = await (0, index_js_2.resolveProperties)({
network: this.getNetwork(),
params: this.#getBlock(block, true)
});
if (params == null) {
return null;
}
return this._wrapBlockWithTransactions((0, format_js_1.formatBlockWithTransactions)(params), network);
}
async getTransaction(hash) {
const { network, params } = await (0, index_js_2.resolveProperties)({
network: this.getNetwork(),
params: this.#perform({ method: "getTransaction", hash })
});
if (params == null) {
return null;
}
return this._wrapTransactionResponse((0, format_js_1.formatTransactionResponse)(params), network);
}
async getTransactionReceipt(hash) {
const { network, params } = await (0, index_js_2.resolveProperties)({
network: this.getNetwork(),
params: this.#perform({ method: "getTransactionReceipt", hash })
});
if (params == null) {
return null;
}
// Some backends did not backfill the effectiveGasPrice into old transactions
// in the receipt, so we look it up manually and inject it.
if (params.gasPrice == null && params.effectiveGasPrice == null) {
const tx = await this.#perform({ method: "getTransaction", hash });
if (tx == null) {
throw new Error("report this; could not find tx or effectiveGasPrice");
}
params.effectiveGasPrice = tx.gasPrice;
}
return this._wrapTransactionReceipt((0, format_js_1.formatTransactionReceipt)(params), network);
}
async getTransactionResult(hash) {
const { result } = await (0, index_js_2.resolveProperties)({
network: this.getNetwork(),
result: this.#perform({ method: "getTransactionResult", hash })
});
if (result == null) {
return null;
}
return (0, index_js_2.hexlify)(result);
}
// Bloom-filter Queries
async getLogs(_filter) {
const { network, filter } = await (0, index_js_2.resolveProperties)({
let filter = this._getFilter(_filter);
if (isPromise(filter)) {
filter = await filter;
}
const { network, params } = await (0, index_js_2.resolveProperties)({
network: this.getNetwork(),
filter: this._getFilter(_filter)
});
return (await this.#perform({ method: "getLogs", filter })).map((l) => {
return network.formatter.log(l, this);
params: this.#perform({ method: "getLogs", filter })
});
return params.map((p) => this._wrapLog((0, format_js_1.formatLog)(p), network));
}
// ENS
_getProvider(chainId) {
@ -927,6 +988,7 @@ class AbstractProvider {
}
}
pause(dropWhilePaused) {
this.#lastBlockNumber = -1;
if (this.#pausedState != null) {
if (this.#pausedState == !!dropWhilePaused) {
return;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -6,7 +6,7 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.Network = exports.injectCommonNetworks = void 0;
const plugins_network_js_1 = require("./plugins-network.js");
const provider_etherscan_js_1 = require("./provider-etherscan.js");
const provider_etherscan_base_js_1 = require("./provider-etherscan-base.js");
const network_js_1 = require("./network.js");
Object.defineProperty(exports, "Network", { enumerable: true, get: function () { return network_js_1.Network; } });
// See: https://chainlist.org
@ -24,7 +24,7 @@ function injectCommonNetworks() {
}
if (options.etherscan) {
const { url, apiKey } = options.etherscan;
network.attachPlugin(new provider_etherscan_js_1.EtherscanPlugin(url, apiKey));
network.attachPlugin(new provider_etherscan_base_js_1.EtherscanPlugin(url, apiKey));
}
network.attachPlugin(new plugins_network_js_1.GasCostPlugin());
return network;

@ -1 +1 @@
{"version":3,"file":"common-networks.js","sourceRoot":"","sources":["../../src.ts/providers/common-networks.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"common-networks.js","sourceRoot":"","sources":["../../src.ts/providers/common-networks.ts"],"names":[],"mappings":"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"}

@ -1,31 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EnsResolver = exports.BasicMulticoinProviderPlugin = exports.MulticoinProviderPlugin = void 0;
const index_js_1 = require("../address/index.js");
const hashes_js_1 = require("../constants/hashes.js");
const index_js_1 = require("../hash/index.js");
const index_js_2 = require("../utils/index.js");
const index_js_2 = require("../hash/index.js");
const index_js_3 = require("../utils/index.js");
const BN_1 = BigInt(1);
const Empty = new Uint8Array([]);
function parseBytes(result, start) {
if (result === "0x") {
return null;
}
const offset = (0, index_js_2.toNumber)((0, index_js_2.dataSlice)(result, start, start + 32));
const length = (0, index_js_2.toNumber)((0, index_js_2.dataSlice)(result, offset, offset + 32));
return (0, index_js_2.dataSlice)(result, offset + 32, offset + 32 + length);
const offset = (0, index_js_3.toNumber)((0, index_js_3.dataSlice)(result, start, start + 32));
const length = (0, index_js_3.toNumber)((0, index_js_3.dataSlice)(result, offset, offset + 32));
return (0, index_js_3.dataSlice)(result, offset + 32, offset + 32 + length);
}
function parseString(result, start) {
try {
const bytes = parseBytes(result, start);
if (bytes != null) {
return (0, index_js_2.toUtf8String)(bytes);
return (0, index_js_3.toUtf8String)(bytes);
}
}
catch (error) { }
return null;
}
function numPad(value) {
const result = (0, index_js_2.toArray)(value);
const result = (0, index_js_3.toArray)(value);
if (result.length > 32) {
throw new Error("internal; should not happen");
}
@ -51,7 +52,7 @@ function encodeBytes(datas) {
byteCount += 32;
}
for (let i = 0; i < datas.length; i++) {
const data = (0, index_js_2.getBytes)(datas[i]);
const data = (0, index_js_3.getBytes)(datas[i]);
// Update the bytes offset
result[i] = numPad(byteCount);
// The length and padded value of data
@ -59,7 +60,13 @@ function encodeBytes(datas) {
result.push(bytesPad(data));
byteCount += 32 + Math.ceil(data.length / 32) * 32;
}
return (0, index_js_2.concat)(result);
return (0, index_js_3.concat)(result);
}
function callAddress(value) {
if (value.length !== 66 || (0, index_js_3.dataSlice)(value, 0, 12) !== "0x000000000000000000000000") {
(0, index_js_3.throwArgumentError)("invalid call address", "value", value);
}
return (0, index_js_1.getAddress)("0x" + value.substring(26));
}
// @TODO: This should use the fetch-data:ipfs gateway
// Trim off the ipfs:// prefix and return the default gateway URL
@ -71,7 +78,7 @@ function getIpfsLink(link) {
link = link.substring(7);
}
else {
(0, index_js_2.throwArgumentError)("unsupported IPFS format", "link", link);
(0, index_js_3.throwArgumentError)("unsupported IPFS format", "link", link);
}
return `https:/\/gateway.ipfs.io/ipfs/${link}`;
}
@ -80,7 +87,7 @@ function getIpfsLink(link) {
class MulticoinProviderPlugin {
name;
constructor(name) {
(0, index_js_2.defineProperties)(this, { name });
(0, index_js_3.defineProperties)(this, { name });
}
validate(proivder) {
return this;
@ -117,7 +124,7 @@ class EnsResolver {
// For EIP-2544 names, the ancestor that provided the resolver
#supports2544;
constructor(provider, address, name) {
(0, index_js_2.defineProperties)(this, { provider, address, name });
(0, index_js_3.defineProperties)(this, { provider, address, name });
this.#supports2544 = null;
}
async supportsWildcard() {
@ -127,7 +134,7 @@ class EnsResolver {
to: this.address,
data: "0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000"
}).then((result) => {
return ((0, index_js_2.getBigInt)(result) === BN_1);
return ((0, index_js_3.getBigInt)(result) === BN_1);
}).catch((error) => {
if (error.code === "CALL_EXCEPTION") {
return false;
@ -141,7 +148,7 @@ class EnsResolver {
}
async _fetch(selector, parameters = "0x") {
// e.g. keccak256("addr(bytes32,uint256)")
const addrData = (0, index_js_2.concat)([selector, (0, index_js_1.namehash)(this.name), parameters]);
const addrData = (0, index_js_3.concat)([selector, (0, index_js_2.namehash)(this.name), parameters]);
const tx = {
to: this.address,
enableCcipRead: true,
@ -152,12 +159,12 @@ class EnsResolver {
if (await this.supportsWildcard()) {
wrapped = true;
// selector("resolve(bytes,bytes)")
tx.data = (0, index_js_2.concat)(["0x9061b923", encodeBytes([(0, index_js_1.dnsEncode)(this.name), addrData])]);
tx.data = (0, index_js_3.concat)(["0x9061b923", encodeBytes([(0, index_js_2.dnsEncode)(this.name), addrData])]);
}
try {
let data = await this.provider.call(tx);
if (((0, index_js_2.getBytes)(data).length % 32) === 4) {
return (0, index_js_2.throwError)("resolver threw error", "CALL_EXCEPTION", {
if (((0, index_js_3.getBytes)(data).length % 32) === 4) {
return (0, index_js_3.throwError)("resolver threw error", "CALL_EXCEPTION", {
transaction: tx, data
});
}
@ -179,11 +186,10 @@ class EnsResolver {
// keccak256("addr(bytes32)")
const result = await this._fetch("0x3b3b57de");
// No address
if (result === "0x" || result === hashes_js_1.ZeroHash) {
if (result == null || result === "0x" || result === hashes_js_1.ZeroHash) {
return null;
}
const network = await this.provider.getNetwork();
return network.formatter.callAddress(result);
return callAddress(result);
}
catch (error) {
if (error.code === "CALL_EXCEPTION") {
@ -216,22 +222,22 @@ class EnsResolver {
if (address != null) {
return address;
}
return (0, index_js_2.throwError)(`invalid coin data`, "UNSUPPORTED_OPERATION", {
return (0, index_js_3.throwError)(`invalid coin data`, "UNSUPPORTED_OPERATION", {
operation: `getAddress(${coinType})`,
info: { coinType, data }
});
}
async getText(key) {
// The key encoded as parameter to fetchBytes
let keyBytes = (0, index_js_2.toUtf8Bytes)(key);
let keyBytes = (0, index_js_3.toUtf8Bytes)(key);
// The nodehash consumes the first slot, so the string pointer targets
// offset 64, with the length at offset 64 and data starting at offset 96
const calldata = (0, index_js_2.getBytes)((0, index_js_2.concat)([numPad(64), numPad(keyBytes.length), keyBytes]));
const calldata = (0, index_js_3.getBytes)((0, index_js_3.concat)([numPad(64), numPad(keyBytes.length), keyBytes]));
const hexBytes = parseBytes((await this._fetch("0x59d1d43c", bytesPad(calldata))) || "0x", 0);
if (hexBytes == null || hexBytes === "0x") {
return null;
}
return (0, index_js_2.toUtf8String)(hexBytes);
return (0, index_js_3.toUtf8String)(hexBytes);
}
async getContentHash() {
// keccak256("contenthash()")
@ -246,7 +252,7 @@ class EnsResolver {
const scheme = (ipfs[1] === "e3010170") ? "ipfs" : "ipns";
const length = parseInt(ipfs[4], 16);
if (ipfs[5].length === length * 2) {
return `${scheme}:/\/${(0, index_js_2.encodeBase58)("0x" + ipfs[2])}`;
return `${scheme}:/\/${(0, index_js_3.encodeBase58)("0x" + ipfs[2])}`;
}
}
// Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
@ -254,7 +260,7 @@ class EnsResolver {
if (swarm && swarm[1].length === 64) {
return `bzz:/\/${swarm[1]}`;
}
return (0, index_js_2.throwError)(`invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
return (0, index_js_3.throwError)(`invalid or unsupported content hash data`, "UNSUPPORTED_OPERATION", {
operation: "getContentHash()",
info: { data: hexBytes }
});
@ -306,14 +312,13 @@ class EnsResolver {
linkage.push({ type: `!${scheme}caip`, value: (match[2] || "") });
throw new Error("!caip");
}
const formatter = (await this.provider.getNetwork()).formatter;
const addr = formatter.address(comps[0]);
const addr = (0, index_js_1.getAddress)(comps[0]);
const tokenId = numPad(comps[1]);
// Check that this account owns the token
if (scheme === "erc721") {
// ownerOf(uint256 tokenId)
const tokenOwner = formatter.callAddress(await this.provider.call({
to: addr, data: (0, index_js_2.concat)(["0x6352211e", tokenId])
const tokenOwner = callAddress(await this.provider.call({
to: addr, data: (0, index_js_3.concat)(["0x6352211e", tokenId])
}));
if (owner !== tokenOwner) {
linkage.push({ type: "!owner", value: tokenOwner });
@ -323,8 +328,8 @@ class EnsResolver {
}
else if (scheme === "erc1155") {
// balanceOf(address owner, uint256 tokenId)
const balance = (0, index_js_2.getBigInt)(await this.provider.call({
to: addr, data: (0, index_js_2.concat)(["0x00fdd58e", (0, index_js_2.zeroPadValue)(owner, 32), tokenId])
const balance = (0, index_js_3.getBigInt)(await this.provider.call({
to: addr, data: (0, index_js_3.concat)(["0x00fdd58e", (0, index_js_3.zeroPadValue)(owner, 32), tokenId])
}));
if (!balance) {
linkage.push({ type: "!balance", value: "0" });
@ -335,7 +340,7 @@ class EnsResolver {
// Call the token contract for the metadata URL
const tx = {
to: comps[0],
data: (0, index_js_2.concat)([selector, tokenId])
data: (0, index_js_3.concat)([selector, tokenId])
};
let metadataUrl = parseString(await this.provider.call(tx), 0);
if (metadataUrl == null) {
@ -345,7 +350,7 @@ class EnsResolver {
linkage.push({ type: "metadata-url-base", value: metadataUrl });
// ERC-1155 allows a generic {id} in the URL
if (scheme === "erc1155") {
metadataUrl = metadataUrl.replace("{id}", (0, index_js_2.hexlify)(tokenId).substring(2));
metadataUrl = metadataUrl.replace("{id}", (0, index_js_3.hexlify)(tokenId).substring(2));
linkage.push({ type: "metadata-url-expanded", value: metadataUrl });
}
// Transform IPFS metadata links
@ -355,7 +360,7 @@ class EnsResolver {
linkage.push({ type: "metadata-url", value: metadataUrl });
// Get the token metadata
let metadata = {};
const response = await (new index_js_2.FetchRequest(metadataUrl)).send();
const response = await (new index_js_3.FetchRequest(metadataUrl)).send();
response.assertOk();
try {
metadata = response.bodyJson;
@ -367,7 +372,7 @@ class EnsResolver {
catch (error) {
const bytes = response.body;
if (bytes) {
linkage.push({ type: "!metadata", value: (0, index_js_2.hexlify)(bytes) });
linkage.push({ type: "!metadata", value: (0, index_js_3.hexlify)(bytes) });
}
throw error;
}
@ -413,7 +418,7 @@ class EnsResolver {
const ensPlugin = network.getPlugin("org.ethers.network-plugins.ens");
// No ENS...
if (!ensPlugin) {
return (0, index_js_2.throwError)("network does not support ENS", "UNSUPPORTED_OPERATION", {
return (0, index_js_3.throwError)("network does not support ENS", "UNSUPPORTED_OPERATION", {
operation: "getResolver", info: { network: network.name }
});
}
@ -421,11 +426,11 @@ class EnsResolver {
// keccak256("resolver(bytes32)")
const addrData = await provider.call({
to: ensPlugin.address,
data: (0, index_js_2.concat)(["0x0178b8bf", (0, index_js_1.namehash)(name)]),
data: (0, index_js_3.concat)(["0x0178b8bf", (0, index_js_2.namehash)(name)]),
enableCcipRead: true
});
const addr = network.formatter.callAddress(addrData);
if (addr === (0, index_js_2.dataSlice)(hashes_js_1.ZeroHash, 0, 20)) {
const addr = callAddress(addrData);
if (addr === (0, index_js_3.dataSlice)(hashes_js_1.ZeroHash, 0, 20)) {
return null;
}
return addr;

File diff suppressed because one or more lines are too long

@ -0,0 +1,240 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatTransactionResponse = exports.formatTransactionReceipt = exports.formatReceiptLog = exports.formatBlockWithTransactions = exports.formatBlock = exports.formatLog = exports.formatUint256 = exports.formatHash = exports.formatData = exports.formatBoolean = exports.object = exports.arrayOf = exports.allowNull = void 0;
const index_js_1 = require("../address/index.js");
const index_js_2 = require("../transaction/index.js");
const index_js_3 = require("../utils/index.js");
const BN_0 = BigInt(0);
function allowNull(format, nullValue) {
return (function (value) {
if (value == null) {
return nullValue;
}
return format(value);
});
}
exports.allowNull = allowNull;
function arrayOf(format) {
return ((array) => {
if (!Array.isArray(array)) {
throw new Error("not an array");
}
return array.map((i) => format(i));
});
}
exports.arrayOf = arrayOf;
// Requires an object which matches a fleet of other formatters
// Any FormatFunc may return `undefined` to have the value omitted
// from the result object. Calls preserve `this`.
function object(format, altNames) {
return ((value) => {
const result = {};
for (const key in format) {
let srcKey = key;
if (altNames && key in altNames && !(srcKey in value)) {
for (const altKey of altNames[key]) {
if (altKey in value) {
srcKey = altKey;
break;
}
}
}
try {
const nv = format[key](value[srcKey]);
if (nv !== undefined) {
result[key] = nv;
}
}
catch (error) {
const message = (error instanceof Error) ? error.message : "not-an-error";
(0, index_js_3.throwError)(`invalid value for value.${key} (${message})`, "BAD_DATA", { value });
}
}
return result;
});
}
exports.object = object;
function formatBoolean(value) {
switch (value) {
case true:
case "true":
return true;
case false:
case "false":
return false;
}
return (0, index_js_3.throwArgumentError)(`invalid boolean; ${JSON.stringify(value)}`, "value", value);
}
exports.formatBoolean = formatBoolean;
function formatData(value) {
if (!(0, index_js_3.isHexString)(value, true)) {
(0, index_js_3.throwArgumentError)("", "value", value);
}
return value;
}
exports.formatData = formatData;
function formatHash(value) {
if (!(0, index_js_3.isHexString)(value, 32)) {
(0, index_js_3.throwArgumentError)("", "value", value);
}
return value;
}
exports.formatHash = formatHash;
function formatUint256(value) {
if (!(0, index_js_3.isHexString)(value)) {
throw new Error("invalid uint256");
}
return (0, index_js_3.zeroPadValue)(value, 32);
}
exports.formatUint256 = formatUint256;
exports.formatLog = object({
address: index_js_1.getAddress,
blockHash: formatHash,
blockNumber: index_js_3.getNumber,
data: formatData,
index: index_js_3.getNumber,
removed: formatBoolean,
topics: arrayOf(formatHash),
transactionHash: formatHash,
transactionIndex: index_js_3.getNumber,
}, {
index: ["logIndex"]
});
function _formatBlock(txFunc) {
return object({
hash: allowNull(formatHash),
parentHash: formatHash,
number: index_js_3.getNumber,
timestamp: index_js_3.getNumber,
nonce: allowNull(formatData),
difficulty: index_js_3.getBigInt,
gasLimit: index_js_3.getBigInt,
gasUsed: index_js_3.getBigInt,
miner: allowNull(index_js_1.getAddress),
extraData: formatData,
transactions: arrayOf(txFunc),
baseFeePerGas: allowNull(index_js_3.getBigInt)
});
}
exports.formatBlock = _formatBlock(formatHash);
exports.formatBlockWithTransactions = _formatBlock(formatTransactionResponse);
exports.formatReceiptLog = object({
transactionIndex: index_js_3.getNumber,
blockNumber: index_js_3.getNumber,
transactionHash: formatHash,
address: index_js_1.getAddress,
topics: arrayOf(formatHash),
data: formatData,
logIndex: index_js_3.getNumber,
blockHash: formatHash,
});
exports.formatTransactionReceipt = object({
to: allowNull(index_js_1.getAddress, null),
from: allowNull(index_js_1.getAddress, null),
contractAddress: allowNull(index_js_1.getAddress, null),
transactionIndex: index_js_3.getNumber,
// should be allowNull(hash), but broken-EIP-658 support is handled in receipt
root: allowNull(index_js_3.hexlify),
gasUsed: index_js_3.getBigInt,
logsBloom: allowNull(formatData),
blockHash: formatHash,
transactionHash: formatHash,
logs: arrayOf(exports.formatReceiptLog),
blockNumber: index_js_3.getNumber,
confirmations: allowNull(index_js_3.getNumber, null),
cumulativeGasUsed: index_js_3.getBigInt,
effectiveGasPrice: allowNull(index_js_3.getBigInt),
status: allowNull(index_js_3.getNumber),
type: index_js_3.getNumber
}, {
effectiveGasPrice: ["gasPrice"]
});
function formatTransactionResponse(value) {
// Some clients (TestRPC) do strange things like return 0x0 for the
// 0 address; correct this to be a real address
if (value.to && (0, index_js_3.getBigInt)(value.to) === BN_0) {
value.to = "0x0000000000000000000000000000000000000000";
}
const result = object({
hash: formatHash,
type: (value) => {
if (value === "0x" || value == null) {
return 0;
}
return (0, index_js_3.getNumber)(value);
},
accessList: allowNull(index_js_2.accessListify, null),
blockHash: allowNull(formatHash, null),
blockNumber: allowNull(index_js_3.getNumber, null),
transactionIndex: allowNull(index_js_3.getNumber, null),
confirmations: allowNull(index_js_3.getNumber, null),
from: index_js_1.getAddress,
// either (gasPrice) or (maxPriorityFeePerGas + maxFeePerGas) must be set
gasPrice: allowNull(index_js_3.getBigInt),
maxPriorityFeePerGas: allowNull(index_js_3.getBigInt),
maxFeePerGas: allowNull(index_js_3.getBigInt),
gasLimit: index_js_3.getBigInt,
to: allowNull(index_js_1.getAddress, null),
value: index_js_3.getBigInt,
nonce: index_js_3.getNumber,
data: formatData,
r: allowNull(formatUint256),
s: allowNull(formatUint256),
v: allowNull(index_js_3.getNumber),
creates: allowNull(index_js_1.getAddress, null),
chainId: allowNull(index_js_3.getBigInt, null)
}, {
data: ["input"],
gasLimit: ["gas"]
})(value);
// If to and creates are empty, populate the creates from the value
if (result.to == null && result.creates == null) {
result.creates = (0, index_js_1.getCreateAddress)(result);
}
// @TODO: Check fee data
// Add an access list to supported transaction types
if ((value.type === 1 || value.type === 2) && value.accessList == null) {
value.accessList = [];
}
// @TODO: check chainID
/*
if (value.chainId != null) {
let chainId = value.chainId;
if (isHexString(chainId)) {
chainId = BigNumber.from(chainId).toNumber();
}
result.chainId = chainId;
} else {
let chainId = value.networkId;
// geth-etc returns chainId
if (chainId == null && result.v == null) {
chainId = value.chainId;
}
if (isHexString(chainId)) {
chainId = BigNumber.from(chainId).toNumber();
}
if (typeof(chainId) !== "number" && result.v != null) {
chainId = (result.v - 35) / 2;
if (chainId < 0) { chainId = 0; }
chainId = parseInt(chainId);
}
if (typeof(chainId) !== "number") { chainId = 0; }
result.chainId = chainId;
}
*/
// 0x0000... should actually be null
if (result.blockHash && (0, index_js_3.getBigInt)(result.blockHash) === BN_0) {
result.blockHash = null;
}
return result;
}
exports.formatTransactionResponse = formatTransactionResponse;
//# sourceMappingURL=format.js.map

File diff suppressed because one or more lines are too long

@ -1,8 +1,6 @@
"use strict";
// Belongs to Networks; requires abstract-provider
// provider requires abstract-provider and network
Object.defineProperty(exports, "__esModule", { value: true });
exports.Formatter = void 0;
/**
* Formatter
*
@ -16,26 +14,56 @@ exports.Formatter = void 0;
* Network object this allows exotic (non-Ethereum) networks
* to be fairly simple to adapt to ethers.
*/
const index_js_1 = require("../address/index.js");
const index_js_2 = require("../utils/index.js");
const signature_js_1 = require("../crypto/signature.js");
const index_js_3 = require("../transaction/index.js");
const provider_js_1 = require("./provider.js");
/*
import { getAddress, getCreateAddress } from "../address/index.js";
import {
dataLength, dataSlice, getBigInt, getNumber, isHexString, toQuantity,
throwArgumentError, throwError
} from "../utils/index.js";
import { Signature } from "../crypto/signature.js";
import { accessListify } from "../transaction/index.js";
import { Block, Log, TransactionReceipt, TransactionResponse } from "./provider.js";
import type { AccessList } from "../transaction/index.js";
import type { PerformActionTransaction } from "./abstract-provider.js";
import type { Filter, Provider } from "./provider.js";
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
export type FormatFunc = (value: any) => any;
//export type AccessListSet = { address: string, storageKeys: Array<string> };
//export type AccessList = Array<AccessListSet>;
//export type AccessListish = AccessList |
// Array<[ string, Array<string> ]> |
// Record<string, Array<string>>;
function stringify(value) {
if (typeof (value) !== "string") {
throw new Error("invalid string");
}
function stringify(value: any): string {
if (typeof(value) !== "string") { throw new Error("invalid string"); }
return value;
}
class Formatter {
#format;
#baseBlock;
export class Formatter {
#format: {
address: FormatFunc,
bigNumber: FormatFunc,
blockTag: FormatFunc,
data: FormatFunc,
filter: FormatFunc,
hash: FormatFunc,
number: FormatFunc,
topics: FormatFunc,
transactionRequest: FormatFunc,
transactionResponse: FormatFunc,
uint256: FormatFunc,
};
#baseBlock: FormatFunc;
constructor() {
const address = this.address.bind(this);
const bigNumber = this.bigNumber.bind(this);
@ -44,7 +72,9 @@ class Formatter {
const hash = this.hash.bind(this);
const number = this.number.bind(this);
const uint256 = this.uint256.bind(this);
const topics = this.arrayOf(hash);
this.#format = {
address,
bigNumber,
@ -53,7 +83,9 @@ class Formatter {
hash,
number,
uint256,
topics,
filter: this.object({
fromBlock: this.allowNull(blockTag, undefined),
toBlock: this.allowNull(blockTag, undefined),
@ -61,6 +93,7 @@ class Formatter {
address: this.allowNull(address, undefined),
topics: this.allowNull(topics, undefined)
}),
transactionRequest: this.object({
from: this.allowNull(address),
type: this.allowNull(number),
@ -73,21 +106,29 @@ class Formatter {
data: this.allowNull(data),
value: this.allowNull(uint256),
}),
transactionResponse: this.object({
hash: hash,
index: number,
type: this.allowNull(number, 0),
// These can be null for pending blocks
blockHash: this.allowNull(hash),
blockNumber: this.allowNull(number),
// For Legacy transactions, this comes from the v
chainId: this.allowNull(number),
from: address,
to: this.address,
gasLimit: bigNumber,
gasPrice: this.allowNull(bigNumber),
maxFeePerGas: this.allowNull(bigNumber),
maxPriorityFeePerGas: this.allowNull(bigNumber),
value: bigNumber,
data: data,
nonce: number,
@ -96,92 +137,102 @@ class Formatter {
v: number,
accessList: this.allowNull(this.accessList)
}, {
index: ["transactionIndex"]
index: [ "transactionIndex" ]
}),
};
this.#baseBlock = this.object({
number: number,
hash: this.allowNull(hash, null),
timestamp: number,
parentHash: hash,
nonce: this.allowNull(stringify, "0x0000000000000000"),
difficulty: bigNumber,
gasLimit: bigNumber,
gasUsed: bigNumber,
miner: this.allowNull(address, "0x0000000000000000000000000000000000000000"),
extraData: stringify,
baseFeePerGas: this.allowNull(bigNumber),
});
}
// An address
address(value) {
return (0, index_js_1.getAddress)(value);
address(value: any): string {
return getAddress(value);
}
// An address from a call result; may be zero-padded
callAddress(value) {
if ((0, index_js_2.dataLength)(value) !== 32 || (0, index_js_2.dataSlice)(value, 0, 12) !== "0x000000000000000000000000") {
(0, index_js_2.throwArgumentError)("invalid call address", "value", value);
callAddress(value: any): string {
if (dataLength(value) !== 32 || dataSlice(value, 0, 12) !== "0x000000000000000000000000") {
throwArgumentError("invalid call address", "value", value);
}
return this.address((0, index_js_2.dataSlice)(value, 12));
return this.address(dataSlice(value, 12));
}
// An address from a transaction (e.g. { from: string, nonce: number })
contractAddress(value) {
return (0, index_js_1.getCreateAddress)({
contractAddress(value: any): string {
return getCreateAddress({
from: this.address(value.from),
nonce: (0, index_js_2.getNumber)(value.nonce, "value.nonce")
nonce: getNumber(value.nonce, "value.nonce")
});
}
// Block Tag
blockTag(value) {
if (value == null) {
return "latest";
}
blockTag(value?: any): string {
if (value == null) { return "latest"; }
switch (value) {
case "earliest":
return "0x0";
case "latest":
case "pending":
case "safe":
case "finalized":
case "latest": case "pending": case "safe": case "finalized":
return value;
}
if (typeof (value) === "number" || ((0, index_js_2.isHexString)(value) && (0, index_js_2.dataLength)(value) < 32)) {
return (0, index_js_2.toQuantity)(value);
if (typeof(value) === "number" || (isHexString(value) && dataLength(value) < 32)) {
return toQuantity(value);
}
return (0, index_js_2.throwArgumentError)("invalid blockTag", "value", value);
return throwArgumentError("invalid blockTag", "value", value);
}
// Block objects
block(value, provider) {
block(value: any, provider?: Provider): Block<string> {
const params = this.#baseBlock(value);
params.transactions = value.transactions.map((t) => this.hash(t));
return new provider_js_1.Block(params, provider);
params.transactions = value.transactions.map((t: any) => this.hash(t));
return new Block(params, provider);
}
blockWithTransactions(value, provider) {
blockWithTransactions(value: any, provider?: Provider): Block<TransactionResponse> {
throw new Error();
}
// Transactions
transactionRequest(value, provider) {
transactionRequest(value: any, provider?: Provider): PerformActionTransaction {
return this.#format.transactionRequest(value);
}
transactionResponse(value, provider) {
value = Object.assign({}, value);
transactionResponse(value: any, provider?: Provider): TransactionResponse {
value = Object.assign({ }, value);
// @TODO: Use the remap feature
if (value.data == null && value.input != null) {
value.data = value.input;
}
if (value.gasLimit == null && value.gas) {
value.gasLimit = value.gas;
}
if (value.data == null && value.input != null) { value.data = value.input; }
if (value.gasLimit == null && value.gas) { value.gasLimit = value.gas; }
value = this.#format.transactionResponse(value);
const sig = signature_js_1.Signature.from({ r: value.r, s: value.s, v: value.v });
const sig = Signature.from({ r: value.r, s: value.s, v: value.v });
value.signature = sig;
if (value.chainId == null) {
value.chainId = sig.legacyChainId;
}
return new provider_js_1.TransactionResponse(value, provider);
if (value.chainId == null) { value.chainId = sig.legacyChainId; }
return new TransactionResponse(value, provider);
}
// Receipts
log(value, provider) {
log(value: any, provider?: Provider): Log {
const log = this.object({
address: this.address,
blockHash: this.hash,
@ -193,11 +244,12 @@ class Formatter {
transactionHash: this.hash,
transactionIndex: this.number,
}, {
index: ["logIndex"]
index: [ "logIndex" ]
})(value);
return new provider_js_1.Log(log, provider);
return new Log(log, provider);
}
receipt(value, provider) {
receipt(value: any, provider?: Provider): TransactionReceipt {
const receipt = this.object({
blockHash: this.hash,
blockNumber: this.number,
@ -205,7 +257,7 @@ class Formatter {
cumulativeGasUsed: this.bigNumber,
from: this.address,
gasUsed: this.bigNumber,
logs: this.arrayOf((v) => (this.log(v, provider))),
logs: this.arrayOf((v: any) => (this.log(v, provider))),
logsBloom: this.data,
root: this.allowNull(this.data),
status: this.allowNull(this.number),
@ -215,10 +267,11 @@ class Formatter {
index: this.number,
type: this.allowNull(this.number, 0),
}, {
hash: ["transactionHash"],
gasPrice: ["effectiveGasPrice"],
index: ["transactionIndex"]
hash: [ "transactionHash" ],
gasPrice: [ "effectiveGasPrice" ],
index: [ "transactionIndex" ]
})(value);
// RSK incorrectly implemented EIP-658, so we munge things a bit here for it
if (receipt.root != null) {
if (receipt.root.length <= 4) {
@ -227,137 +280,144 @@ class Formatter {
if (value === 0 || value === 1) {
// Make sure if both are specified, they match
if (receipt.status != null && receipt.status !== value) {
return (0, index_js_2.throwError)("alt-root-status/status mismatch", "BAD_DATA", {
return throwError("alt-root-status/status mismatch", "BAD_DATA", {
value: { root: receipt.root, status: receipt.status }
});
}
receipt.status = value;
delete receipt.root;
}
else {
return (0, index_js_2.throwError)("invalid alt-root-status", "BAD_DATA", {
} else {
return throwError("invalid alt-root-status", "BAD_DATA", {
value: receipt.root
});
}
}
else if (!(0, index_js_2.isHexString)(receipt.root, 32)) {
} else if (!isHexString(receipt.root, 32)) {
// Must be a valid bytes32
return (0, index_js_2.throwError)("invalid receipt root hash", "BAD_DATA", {
return throwError("invalid receipt root hash", "BAD_DATA", {
value: receipt.root
});
}
}
//receipt.byzantium = (receipt.root == null);
return new provider_js_1.TransactionReceipt(receipt, provider);
return new TransactionReceipt(receipt, provider);
}
// Fitlers
topics(value) {
topics(value: any): Array<string> {
return this.#format.topics(value);
}
filter(value) {
filter(value: any): Filter {
return this.#format.filter(value);
}
filterLog(value) {
filterLog(value: any): any {
console.log("ME", value);
return null;
}
// Converts a serialized transaction to a TransactionResponse
transaction(value) {
transaction(value: any): TransactionResponse {
throw new Error();
}
// Useful utility formatters functions, which if need be use the
// methods within the formatter to ensure internal compatibility
// Access List; converts an AccessListish to an AccessList
accessList(value) {
return (0, index_js_3.accessListify)(value);
accessList(value: any): AccessList {
return accessListify(value);
}
// Converts falsish values to a specific value, otherwise use the formatter. Calls preserve `this`.
allowFalsish(format, ifFalse) {
return ((value) => {
if (!value) {
return ifFalse;
}
allowFalsish(format: FormatFunc, ifFalse: any): FormatFunc {
return ((value: any) => {
if (!value) { return ifFalse; }
return format.call(this, value);
});
}
// Allows null, optionally replacing it with a default value. Calls preserve `this`.
allowNull(format, ifNull) {
return ((value) => {
if (value == null) {
return ifNull;
}
allowNull(format: FormatFunc, ifNull?: any): FormatFunc {
return ((value: any) => {
if (value == null) { return ifNull; }
return format.call(this, value);
});
}
// Requires an Array satisfying the formatter. Calls preserves `this`.
arrayOf(format) {
return ((array) => {
if (!Array.isArray(array)) {
throw new Error("not an array");
}
arrayOf(format: FormatFunc): FormatFunc {
return ((array: any) => {
if (!Array.isArray(array)) { throw new Error("not an array"); }
return array.map((i) => format.call(this, i));
});
}
// Requires a value which is a value BigNumber
bigNumber(value) {
return (0, index_js_2.getBigInt)(value, "value");
bigNumber(value: any): bigint {
return getBigInt(value, "value");
}
uint256(value) {
uint256(value: any): bigint {
const result = this.bigNumber(value);
if (result < 0 || result > BN_MAX_UINT256) {
(0, index_js_2.throwArgumentError)("invalid uint256", "value", value);
throwArgumentError("invalid uint256", "value", value);
}
return result;
}
// Requires a value which is a value boolean or string equivalent
boolean(value) {
boolean(value: any): boolean {
switch (value) {
case true:
case "true":
case true: case "true":
return true;
case false:
case "false":
case false: case "false":
return false;
}
return (0, index_js_2.throwArgumentError)(`invalid boolean; ${JSON.stringify(value)}`, "value", value);
return throwArgumentError(`invalid boolean; ${ JSON.stringify(value) }`, "value", value);
}
// Requires a value which is a valid hexstring. If dataOrLength is true,
// the length must be even (i.e. a datahexstring) or if it is a number,
// specifies teh number of bytes value must represent
_hexstring(dataOrLength) {
if (dataOrLength == null) {
dataOrLength = false;
}
return (function (value) {
if ((0, index_js_2.isHexString)(value, dataOrLength)) {
_hexstring(dataOrLength?: boolean | number): FormatFunc {
if (dataOrLength == null) { dataOrLength = false; }
return (function(value: any) {
if (isHexString(value, dataOrLength)) {
return value.toLowerCase();
}
throw new Error("bad hexstring");
});
}
data(value) {
if ((0, index_js_2.dataLength)(value) == null) {
(0, index_js_2.throwArgumentError)("", "value", value);
data(value: string): string {
if (dataLength(value) == null) {
throwArgumentError("", "value", value);
}
return value;
}
// Requires a network-native hash
hash(value) {
if ((0, index_js_2.dataLength)(value) !== 32) {
(0, index_js_2.throwArgumentError)("", "value", value);
hash(value: any): string {
if (dataLength(value) !== 32) {
throwArgumentError("", "value", value);
}
return this.#format.data(value);
}
// Requires a valid number, within the IEEE 754 safe range
number(value) {
return (0, index_js_2.getNumber)(value);
number(value: any): number {
return getNumber(value);
}
// Requires an object which matches a fleet of other formatters
// Any FormatFunc may return `undefined` to have the value omitted
// from the result object. Calls preserve `this`.
object(format, altNames) {
return ((value) => {
const result = {};
object(format: Record<string, FormatFunc>, altNames?: Record<string, Array<string>>): FormatFunc {
return ((value: any) => {
const result: any = { };
for (const key in format) {
let srcKey = key;
if (altNames && key in altNames && !(srcKey in value)) {
@ -368,20 +428,18 @@ class Formatter {
}
}
}
try {
const nv = format[key].call(this, value[srcKey]);
if (nv !== undefined) {
result[key] = nv;
}
}
catch (error) {
const message = (error instanceof Error) ? error.message : "not-an-error";
(0, index_js_2.throwError)(`invalid value for value.${key} (${message})`, "BAD_DATA", { value });
if (nv !== undefined) { result[key] = nv; }
} catch (error) {
const message = (error instanceof Error) ? error.message: "not-an-error";
throwError(`invalid value for value.${ key } (${ message })`, "BAD_DATA", { value })
}
}
return result;
});
}
}
exports.Formatter = Formatter;
*/
//# sourceMappingURL=formatter.js.map

File diff suppressed because one or more lines are too long

@ -1,7 +1,7 @@
"use strict";
/////
Object.defineProperty(exports, "__esModule", { value: true });
exports.SocketEventSubscriber = exports.SocketPendingSubscriber = exports.SocketBlockSubscriber = exports.SocketSubscriber = exports.WebSocketProvider = exports.SocketProvider = exports.IpcSocketProvider = exports.InfuraProvider = exports.EtherscanProvider = exports.CloudflareProvider = exports.AnkrProvider = exports.AlchemyProvider = exports.JsonRpcSigner = exports.JsonRpcProvider = exports.JsonRpcApiProvider = exports.FallbackProvider = exports.copyRequest = exports.dummyProvider = exports.TransactionResponse = exports.TransactionReceipt = exports.Log = exports.FeeData = exports.Block = exports.EnsPlugin = exports.GasCostPlugin = exports.NetworkPlugin = exports.Network = exports.Formatter = exports.WrappedSigner = exports.VoidSigner = exports.AbstractSigner = exports.UnmanagedSubscriber = exports.AbstractProvider = void 0;
exports.SocketEventSubscriber = exports.SocketPendingSubscriber = exports.SocketBlockSubscriber = exports.SocketSubscriber = exports.WebSocketProvider = exports.SocketProvider = exports.IpcSocketProvider = exports.InfuraProvider = exports.EtherscanProvider = exports.EtherscanPlugin = exports.BaseEtherscanProvider = exports.CloudflareProvider = exports.AnkrProvider = exports.AlchemyProvider = exports.JsonRpcSigner = exports.JsonRpcProvider = exports.JsonRpcApiProvider = exports.FallbackProvider = exports.copyRequest = exports.TransactionResponse = exports.TransactionReceipt = exports.Log = exports.FeeData = exports.Block = exports.EnsPlugin = exports.GasCostPlugin = exports.NetworkPlugin = exports.Network = exports.WrappedSigner = exports.VoidSigner = exports.AbstractSigner = exports.UnmanagedSubscriber = exports.AbstractProvider = void 0;
var abstract_provider_js_1 = require("./abstract-provider.js");
Object.defineProperty(exports, "AbstractProvider", { enumerable: true, get: function () { return abstract_provider_js_1.AbstractProvider; } });
Object.defineProperty(exports, "UnmanagedSubscriber", { enumerable: true, get: function () { return abstract_provider_js_1.UnmanagedSubscriber; } });
@ -18,8 +18,6 @@ export { getDefaultProvider } from "./default-provider.js";
export { EnsResolver } from "./ens-resolver.js";
*/
var formatter_js_1 = require("./formatter.js");
Object.defineProperty(exports, "Formatter", { enumerable: true, get: function () { return formatter_js_1.Formatter; } });
var common_networks_js_1 = require("./common-networks.js");
Object.defineProperty(exports, "Network", { enumerable: true, get: function () { return common_networks_js_1.Network; } });
var plugins_network_js_1 = require("./plugins-network.js");
@ -32,7 +30,6 @@ Object.defineProperty(exports, "FeeData", { enumerable: true, get: function () {
Object.defineProperty(exports, "Log", { enumerable: true, get: function () { return provider_js_1.Log; } });
Object.defineProperty(exports, "TransactionReceipt", { enumerable: true, get: function () { return provider_js_1.TransactionReceipt; } });
Object.defineProperty(exports, "TransactionResponse", { enumerable: true, get: function () { return provider_js_1.TransactionResponse; } });
Object.defineProperty(exports, "dummyProvider", { enumerable: true, get: function () { return provider_js_1.dummyProvider; } });
Object.defineProperty(exports, "copyRequest", { enumerable: true, get: function () { return provider_js_1.copyRequest; } });
var provider_fallback_js_1 = require("./provider-fallback.js");
Object.defineProperty(exports, "FallbackProvider", { enumerable: true, get: function () { return provider_fallback_js_1.FallbackProvider; } });
@ -46,6 +43,9 @@ var provider_ankr_js_1 = require("./provider-ankr.js");
Object.defineProperty(exports, "AnkrProvider", { enumerable: true, get: function () { return provider_ankr_js_1.AnkrProvider; } });
var provider_cloudflare_js_1 = require("./provider-cloudflare.js");
Object.defineProperty(exports, "CloudflareProvider", { enumerable: true, get: function () { return provider_cloudflare_js_1.CloudflareProvider; } });
var provider_etherscan_base_js_1 = require("./provider-etherscan-base.js");
Object.defineProperty(exports, "BaseEtherscanProvider", { enumerable: true, get: function () { return provider_etherscan_base_js_1.BaseEtherscanProvider; } });
Object.defineProperty(exports, "EtherscanPlugin", { enumerable: true, get: function () { return provider_etherscan_base_js_1.EtherscanPlugin; } });
var provider_etherscan_js_1 = require("./provider-etherscan.js");
Object.defineProperty(exports, "EtherscanProvider", { enumerable: true, get: function () { return provider_etherscan_js_1.EtherscanProvider; } });
var provider_infura_js_1 = require("./provider-infura.js");

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src.ts/providers/index.ts"],"names":[],"mappings":";AAGA,KAAK;;;AAEL,+DAEgC;AAD5B,wHAAA,gBAAgB,OAAA;AAAE,2HAAA,mBAAmB,OAAA;AAGzC,2DAI8B;AAH1B,oHAAA,cAAc,OAAA;AACd,gHAAA,UAAU,OAAA;AACV,mHAAA,aAAa,OAAA;AAEjB;;;;;;;;EAQE;AAEF,+CAA2C;AAAlC,yGAAA,SAAS,OAAA;AAElB,2DAA+C;AAAtC,6GAAA,OAAO,OAAA;AAEhB,2DAO8B;AAN1B,mHAAA,aAAa,OAAA;AACb,mHAAA,aAAa,OAAA;AACb,+GAAA,SAAS,OAAA;AAMb,6CAWuB;AAVnB,oGAAA,KAAK,OAAA;AACL,sGAAA,OAAO,OAAA;AACP,kGAAA,GAAG,OAAA;AACH,iHAAA,kBAAkB,OAAA;AAClB,kHAAA,mBAAmB,OAAA;AAEnB,4GAAA,aAAa,OAAA;AAEb,0GAAA,WAAW,OAAA;AAIf,+DAA0D;AAAjD,wHAAA,gBAAgB,OAAA;AACzB,6DAA0F;AAAjF,yHAAA,kBAAkB,OAAA;AAAE,sHAAA,eAAe,OAAA;AAAE,oHAAA,aAAa,OAAA;AAE3D,6DAAwD;AAA/C,sHAAA,eAAe,OAAA;AACxB,uDAAkD;AAAzC,gHAAA,YAAY,OAAA;AACrB,mEAA8D;AAArD,4HAAA,kBAAkB,OAAA;AAC3B,iEAA4D;AAAnD,0HAAA,iBAAiB,OAAA;AAC1B,2DAAsD;AAA7C,oHAAA,cAAc,OAAA;AACvB,wDAAwD;AAExD,mEAA4D,CAAC,YAAY;AAChE,kGADA,yCAAiB,OACA;AAC1B,2DAAsD;AAA7C,oHAAA,cAAc,OAAA;AACvB,iEAA4D;AAAnD,0HAAA,iBAAiB,OAAA;AAE1B,2DAG8B;AAF1B,sHAAA,gBAAgB,OAAA;AAAE,2HAAA,qBAAqB,OAAA;AAAE,6HAAA,uBAAuB,OAAA;AAChE,2HAAA,qBAAqB,OAAA"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src.ts/providers/index.ts"],"names":[],"mappings":";AAGA,KAAK;;;AAEL,+DAEgC;AAD5B,wHAAA,gBAAgB,OAAA;AAAE,2HAAA,mBAAmB,OAAA;AAGzC,2DAI8B;AAH1B,oHAAA,cAAc,OAAA;AACd,gHAAA,UAAU,OAAA;AACV,mHAAA,aAAa,OAAA;AAEjB;;;;;;;;EAQE;AAEF,2DAA+C;AAAtC,6GAAA,OAAO,OAAA;AAEhB,2DAO8B;AAN1B,mHAAA,aAAa,OAAA;AACb,mHAAA,aAAa,OAAA;AACb,+GAAA,SAAS,OAAA;AAMb,6CASuB;AARnB,oGAAA,KAAK,OAAA;AACL,sGAAA,OAAO,OAAA;AACP,kGAAA,GAAG,OAAA;AACH,iHAAA,kBAAkB,OAAA;AAClB,kHAAA,mBAAmB,OAAA;AAEnB,0GAAA,WAAW,OAAA;AAIf,+DAA0D;AAAjD,wHAAA,gBAAgB,OAAA;AACzB,6DAA0F;AAAjF,yHAAA,kBAAkB,OAAA;AAAE,sHAAA,eAAe,OAAA;AAAE,oHAAA,aAAa,OAAA;AAE3D,6DAAwD;AAA/C,sHAAA,eAAe,OAAA;AACxB,uDAAkD;AAAzC,gHAAA,YAAY,OAAA;AACrB,mEAA8D;AAArD,4HAAA,kBAAkB,OAAA;AAC3B,2EAAsF;AAA7E,mIAAA,qBAAqB,OAAA;AAAE,6HAAA,eAAe,OAAA;AAC/C,iEAA4D;AAAnD,0HAAA,iBAAiB,OAAA;AAC1B,2DAAsD;AAA7C,oHAAA,cAAc,OAAA;AACvB,wDAAwD;AAExD,mEAA4D,CAAC,YAAY;AAChE,kGADA,yCAAiB,OACA;AAC1B,2DAAsD;AAA7C,oHAAA,cAAc,OAAA;AACvB,iEAA4D;AAAnD,0HAAA,iBAAiB,OAAA;AAE1B,2DAG8B;AAF1B,sHAAA,gBAAgB,OAAA;AAAE,2HAAA,qBAAqB,OAAA;AAAE,6HAAA,uBAAuB,OAAA;AAChE,2HAAA,qBAAqB,OAAA"}

@ -1,8 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Network = void 0;
const index_js_1 = require("../utils/index.js");
const formatter_js_1 = require("./formatter.js");
const index_js_1 = require("../transaction/index.js");
const index_js_2 = require("../utils/index.js");
const plugins_network_js_1 = require("./plugins-network.js");
/* * * *
// Networks which operation against an L2 can use this plugin to
@ -55,37 +55,29 @@ export class CcipPreflightPlugin extends NetworkPlugin {
}
*/
const Networks = new Map();
const defaultFormatter = new formatter_js_1.Formatter();
// @TODO: Add a _ethersNetworkObj variable to better detect network ovjects
class Network {
#props;
constructor(name, _chainId, formatter) {
const chainId = (0, index_js_1.getBigInt)(_chainId);
if (formatter == null) {
formatter = defaultFormatter;
}
constructor(name, _chainId) {
const chainId = (0, index_js_2.getBigInt)(_chainId);
const plugins = new Map();
this.#props = { name, chainId, formatter, plugins };
this.#props = { name, chainId, plugins };
}
toJSON() {
return { name: this.name, chainId: this.chainId };
}
get name() { return (0, index_js_1.getStore)(this.#props, "name"); }
set name(value) { (0, index_js_1.setStore)(this.#props, "name", value); }
get chainId() { return (0, index_js_1.getStore)(this.#props, "chainId"); }
set chainId(value) { (0, index_js_1.setStore)(this.#props, "chainId", (0, index_js_1.getBigInt)(value, "chainId")); }
get formatter() { return (0, index_js_1.getStore)(this.#props, "formatter"); }
set formatter(value) { (0, index_js_1.setStore)(this.#props, "formatter", value); }
get name() { return (0, index_js_2.getStore)(this.#props, "name"); }
set name(value) { (0, index_js_2.setStore)(this.#props, "name", value); }
get chainId() { return (0, index_js_2.getStore)(this.#props, "chainId"); }
set chainId(value) { (0, index_js_2.setStore)(this.#props, "chainId", (0, index_js_2.getBigInt)(value, "chainId")); }
get plugins() {
return Array.from(this.#props.plugins.values());
}
attachPlugin(plugin) {
if (this.isFrozen()) {
throw new Error("frozen");
}
if (this.#props.plugins.get(plugin.name)) {
throw new Error(`cannot replace existing plugin: ${plugin.name} `);
}
this.#props.plugins.set(plugin.name, plugin.validate(this));
this.#props.plugins.set(plugin.name, plugin.clone());
return this;
}
getPlugin(name) {
@ -96,19 +88,22 @@ class Network {
return (this.plugins.filter((p) => (p.name.split("#")[0] === basename)));
}
clone() {
const clone = new Network(this.name, this.chainId, this.formatter);
const clone = new Network(this.name, this.chainId);
this.plugins.forEach((plugin) => {
clone.attachPlugin(plugin.clone());
});
return clone;
}
freeze() {
/*
freeze(): Frozen<Network> {
Object.freeze(this.#props);
return this;
}
isFrozen() {
isFrozen(): boolean {
return Object.isFrozen(this.#props);
}
*/
computeIntrinsicGas(tx) {
const costs = this.getPlugin("org.ethers.gas-cost") || (new plugins_network_js_1.GasCostPlugin());
let gas = costs.txBase;
@ -126,7 +121,7 @@ class Network {
}
}
if (tx.accessList) {
const accessList = this.formatter.accessList(tx.accessList);
const accessList = (0, index_js_1.accessListify)(tx.accessList);
for (const addr in accessList) {
gas += costs.txAccessListAddress + costs.txAccessListStorageKey * accessList[addr].storageKeys.length;
}
@ -153,7 +148,7 @@ class Network {
if (typeof (network) === "bigint") {
return new Network("unknown", network);
}
(0, index_js_1.throwArgumentError)("unknown network", "network", network);
(0, index_js_2.throwArgumentError)("unknown network", "network", network);
}
// Clonable with network-like abilities
if (typeof (network.clone) === "function") {
@ -165,7 +160,7 @@ class Network {
// Networkish
if (typeof (network) === "object") {
if (typeof (network.name) !== "string" || typeof (network.chainId) !== "number") {
(0, index_js_1.throwArgumentError)("invalid network object name or chainId", "network", network);
(0, index_js_2.throwArgumentError)("invalid network object name or chainId", "network", network);
}
const custom = new Network((network.name), (network.chainId));
if (network.ensAddress || network.ensNetwork != null) {
@ -176,7 +171,7 @@ class Network {
//}
return custom;
}
return (0, index_js_1.throwArgumentError)("invalid network", "network", network);
return (0, index_js_2.throwArgumentError)("invalid network", "network", network);
}
/**
* Register %%nameOrChainId%% with a function which returns
@ -188,7 +183,7 @@ class Network {
}
const existing = Networks.get(nameOrChainId);
if (existing) {
(0, index_js_1.throwArgumentError)(`conflicting network for ${JSON.stringify(existing.name)}`, "nameOrChainId", nameOrChainId);
(0, index_js_2.throwArgumentError)(`conflicting network for ${JSON.stringify(existing.name)}`, "nameOrChainId", nameOrChainId);
}
Networks.set(nameOrChainId, networkFunc);
}

File diff suppressed because one or more lines are too long

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FeeDataNetworkPlugin = exports.EnsPlugin = exports.GasCostPlugin = exports.NetworkPlugin = void 0;
exports.CustomBlockNetworkPlugin = exports.FeeDataNetworkPlugin = exports.EnsPlugin = exports.GasCostPlugin = exports.NetworkPlugin = void 0;
const properties_js_1 = require("../utils/properties.js");
const index_js_1 = require("../utils/index.js");
const EnsAddress = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
@ -12,9 +12,6 @@ class NetworkPlugin {
clone() {
return new NetworkPlugin(this.name);
}
validate(network) {
return this;
}
}
exports.NetworkPlugin = NetworkPlugin;
class GasCostPlugin extends NetworkPlugin {
@ -68,10 +65,6 @@ class EnsPlugin extends NetworkPlugin {
clone() {
return new EnsPlugin(this.address, this.targetNetwork);
}
validate(network) {
network.formatter.address(this.address);
return this;
}
}
exports.EnsPlugin = EnsPlugin;
/*
@ -109,4 +102,23 @@ class FeeDataNetworkPlugin extends NetworkPlugin {
}
}
exports.FeeDataNetworkPlugin = FeeDataNetworkPlugin;
class CustomBlockNetworkPlugin extends NetworkPlugin {
#blockFunc;
#blockWithTxsFunc;
constructor(blockFunc, blockWithTxsFunc) {
super("org.ethers.network-plugins.custom-block");
this.#blockFunc = blockFunc;
this.#blockWithTxsFunc = blockWithTxsFunc;
}
async getBlock(provider, block) {
return await this.#blockFunc(provider, block);
}
async getBlockWithTransactions(provider, block) {
return await this.#blockWithTxsFunc(provider, block);
}
clone() {
return new CustomBlockNetworkPlugin(this.#blockFunc, this.#blockWithTxsFunc);
}
}
exports.CustomBlockNetworkPlugin = CustomBlockNetworkPlugin;
//# sourceMappingURL=plugins-network.js.map

@ -1 +1 @@
{"version":3,"file":"plugins-network.js","sourceRoot":"","sources":["../../src.ts/providers/plugins-network.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"plugins-network.js","sourceRoot":"","sources":["../../src.ts/providers/plugins-network.ts"],"names":[],"mappings":"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"}

@ -0,0 +1,432 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseEtherscanProvider = exports.EtherscanPlugin = void 0;
const index_js_1 = require("../transaction/index.js");
const index_js_2 = require("../utils/index.js");
const abstract_provider_js_1 = require("./abstract-provider.js");
const network_js_1 = require("./network.js");
const plugins_network_js_1 = require("./plugins-network.js");
const community_js_1 = require("./community.js");
const THROTTLE = 2000;
const EtherscanPluginId = "org.ethers.plugins.etherscan";
class EtherscanPlugin extends plugins_network_js_1.NetworkPlugin {
baseUrl;
communityApiKey;
constructor(baseUrl, communityApiKey) {
super(EtherscanPluginId);
//if (communityApiKey == null) { communityApiKey = null; }
(0, index_js_2.defineProperties)(this, { baseUrl, communityApiKey });
}
clone() {
return new EtherscanPlugin(this.baseUrl, this.communityApiKey);
}
}
exports.EtherscanPlugin = EtherscanPlugin;
let nextId = 1;
class BaseEtherscanProvider extends abstract_provider_js_1.AbstractProvider {
network;
apiKey;
#plugin;
constructor(_network, apiKey) {
super();
const network = network_js_1.Network.from(_network);
this.#plugin = network.getPlugin(EtherscanPluginId);
if (apiKey == null && this.#plugin) {
apiKey = this.#plugin.communityApiKey;
}
(0, index_js_2.defineProperties)(this, { apiKey, network });
// Test that the network is supported by Etherscan
this.getBaseUrl();
}
getBaseUrl() {
if (this.#plugin) {
return this.#plugin.baseUrl;
}
switch (this.network.name) {
case "homestead":
return "https:/\/api.etherscan.io";
case "ropsten":
return "https:/\/api-ropsten.etherscan.io";
case "rinkeby":
return "https:/\/api-rinkeby.etherscan.io";
case "kovan":
return "https:/\/api-kovan.etherscan.io";
case "goerli":
return "https:/\/api-goerli.etherscan.io";
default:
}
return (0, index_js_2.throwArgumentError)("unsupported network", "network", this.network);
}
getUrl(module, params) {
const query = Object.keys(params).reduce((accum, key) => {
const value = params[key];
if (value != null) {
accum += `&${key}=${value}`;
}
return accum;
}, "");
const apiKey = ((this.apiKey) ? `&apikey=${this.apiKey}` : "");
return `${this.getBaseUrl()}/api?module=${module}${query}${apiKey}`;
}
getPostUrl() {
return `${this.getBaseUrl()}/api`;
}
getPostData(module, params) {
params.module = module;
params.apikey = this.apiKey;
return params;
}
async detectNetwork() {
return this.network;
}
async fetch(module, params, post) {
const id = nextId++;
const url = (post ? this.getPostUrl() : this.getUrl(module, params));
const payload = (post ? this.getPostData(module, params) : null);
this.emit("debug", { action: "sendRequest", id, url, payload: payload });
const request = new index_js_2.FetchRequest(url);
request.setThrottleParams({ slotInterval: 1000 });
request.retryFunc = (req, resp, attempt) => {
if (this.isCommunityResource()) {
(0, community_js_1.showThrottleMessage)("Etherscan");
}
return Promise.resolve(true);
};
request.processFunc = async (request, response) => {
const result = response.hasBody() ? JSON.parse((0, index_js_2.toUtf8String)(response.body)) : {};
const throttle = ((typeof (result.result) === "string") ? result.result : "").toLowerCase().indexOf("rate limit") >= 0;
if (module === "proxy") {
// This JSON response indicates we are being throttled
if (result && result.status == 0 && result.message == "NOTOK" && throttle) {
this.emit("debug", { action: "receiveError", id, reason: "proxy-NOTOK", error: result });
response.throwThrottleError(result.result, THROTTLE);
}
}
else {
if (throttle) {
this.emit("debug", { action: "receiveError", id, reason: "null result", error: result.result });
response.throwThrottleError(result.result, THROTTLE);
}
}
return response;
};
if (payload) {
request.setHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
request.body = Object.keys(payload).map((k) => `${k}=${payload[k]}`).join("&");
}
const response = await request.send();
try {
response.assertOk();
}
catch (error) {
this.emit("debug", { action: "receiveError", id, error, reason: "assertOk" });
}
if (!response.hasBody()) {
this.emit("debug", { action: "receiveError", id, error: "missing body", reason: "null body" });
throw new Error();
}
const result = JSON.parse((0, index_js_2.toUtf8String)(response.body));
if (module === "proxy") {
if (result.jsonrpc != "2.0") {
this.emit("debug", { action: "receiveError", id, result, reason: "invalid JSON-RPC" });
const error = new Error("invalid response");
error.result = JSON.stringify(result);
throw error;
}
if (result.error) {
this.emit("debug", { action: "receiveError", id, result, reason: "JSON-RPC error" });
const error = new Error(result.error.message || "unknown error");
if (result.error.code) {
error.code = result.error.code;
}
if (result.error.data) {
error.data = result.error.data;
}
throw error;
}
this.emit("debug", { action: "receiveRequest", id, result });
return result.result;
}
else {
// getLogs, getHistory have weird success responses
if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
this.emit("debug", { action: "receiveRequest", id, result });
return result.result;
}
if (result.status != 1 || (typeof (result.message) === "string" && !result.message.match(/^OK/))) {
this.emit("debug", { action: "receiveError", id, result });
const error = new Error("invalid response");
error.result = JSON.stringify(result);
// if ((result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
// error.throttleRetry = true;
// }
throw error;
}
this.emit("debug", { action: "receiveRequest", id, result });
return result.result;
}
}
// The transaction has already been sanitized by the calls in Provider
_getTransactionPostData(transaction) {
const result = {};
for (let key in transaction) {
if (transaction[key] == null) {
continue;
}
let value = transaction[key];
if (key === "type" && value === 0) {
continue;
}
// Quantity-types require no leading zero, unless 0
if ({ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true }[key]) {
value = (0, index_js_2.toQuantity)((0, index_js_2.hexlify)(value));
}
else if (key === "accessList") {
value = "[" + (0, index_js_1.accessListify)(value).map((set) => {
return `{address:"${set.address}",storageKeys:["${set.storageKeys.join('","')}"]}`;
}).join(",") + "]";
}
else {
value = (0, index_js_2.hexlify)(value);
}
result[key] = value;
}
return result;
}
_checkError(req, error, transaction) {
/*
let body = "";
if (isError(error, Logger.Errors.SERVER_ERROR) && error.response && error.response.hasBody()) {
body = toUtf8String(error.response.body);
}
console.log(body);
// Undo the "convenience" some nodes are attempting to prevent backwards
// incompatibility; maybe for v6 consider forwarding reverts as errors
if (method === "call" && body) {
// Etherscan keeps changing their string
if (body.match(/reverted/i) || body.match(/VM execution error/i)) {
// Etherscan prefixes the data like "Reverted 0x1234"
let data = e.data;
if (data) { data = "0x" + data.replace(/^.*0x/i, ""); }
if (!isHexString(data)) { data = "0x"; }
logger.throwError("call exception", Logger.Errors.CALL_EXCEPTION, {
error, data
});
}
}
// Get the message from any nested error structure
let message = error.message;
if (isError(error, Logger.Errors.SERVER_ERROR)) {
if (error.error && typeof(error.error.message) === "string") {
message = error.error.message;
} else if (typeof(error.body) === "string") {
message = error.body;
} else if (typeof(error.responseText) === "string") {
message = error.responseText;
}
}
message = (message || "").toLowerCase();
// "Insufficient funds. The account you tried to send transaction from
// does not have enough funds. Required 21464000000000 and got: 0"
if (message.match(/insufficient funds/)) {
logger.throwError("insufficient funds for intrinsic transaction cost", Logger.Errors.INSUFFICIENT_FUNDS, {
error, transaction, info: { method }
});
}
// "Transaction with the same hash was already imported."
if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
logger.throwError("nonce has already been used", Logger.Errors.NONCE_EXPIRED, {
error, transaction, info: { method }
});
}
// "Transaction gas price is too low. There is another transaction with
// same nonce in the queue. Try increasing the gas price or incrementing the nonce."
if (message.match(/another transaction with same nonce/)) {
logger.throwError("replacement fee too low", Logger.Errors.REPLACEMENT_UNDERPRICED, {
error, transaction, info: { method }
});
}
if (message.match(/execution failed due to an exception|execution reverted/)) {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.Errors.UNPREDICTABLE_GAS_LIMIT, {
error, transaction, info: { method }
});
}
*/
throw error;
}
async _detectNetwork() {
return this.network;
}
async _perform(req) {
switch (req.method) {
case "chainId":
return this.network.chainId;
case "getBlockNumber":
return this.fetch("proxy", { action: "eth_blockNumber" });
case "getGasPrice":
return this.fetch("proxy", { action: "eth_gasPrice" });
case "getBalance":
// Returns base-10 result
return this.fetch("account", {
action: "balance",
address: req.address,
tag: req.blockTag
});
case "getTransactionCount":
return this.fetch("proxy", {
action: "eth_getTransactionCount",
address: req.address,
tag: req.blockTag
});
case "getCode":
return this.fetch("proxy", {
action: "eth_getCode",
address: req.address,
tag: req.blockTag
});
case "getStorageAt":
return this.fetch("proxy", {
action: "eth_getStorageAt",
address: req.address,
position: req.position,
tag: req.blockTag
});
case "broadcastTransaction":
return this.fetch("proxy", {
action: "eth_sendRawTransaction",
hex: req.signedTransaction
}, true).catch((error) => {
return this._checkError(req, error, req.signedTransaction);
});
case "getBlock":
if ("blockTag" in req) {
return this.fetch("proxy", {
action: "eth_getBlockByNumber",
tag: req.blockTag,
boolean: (req.includeTransactions ? "true" : "false")
});
}
return (0, index_js_2.throwError)("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
operation: "getBlock(blockHash)"
});
case "getTransaction":
return this.fetch("proxy", {
action: "eth_getTransactionByHash",
txhash: req.hash
});
case "getTransactionReceipt":
return this.fetch("proxy", {
action: "eth_getTransactionReceipt",
txhash: req.hash
});
case "call": {
if (req.blockTag !== "latest") {
throw new Error("EtherscanProvider does not support blockTag for call");
}
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_call";
try {
return await this.fetch("proxy", postData, true);
}
catch (error) {
return this._checkError(req, error, req.transaction);
}
}
case "estimateGas": {
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_estimateGas";
try {
return await this.fetch("proxy", postData, true);
}
catch (error) {
return this._checkError(req, error, req.transaction);
}
}
/*
case "getLogs": {
// Needs to complain if more than one address is passed in
const args: Record<string, any> = { action: "getLogs" }
if (params.filter.fromBlock) {
args.fromBlock = checkLogTag(params.filter.fromBlock);
}
if (params.filter.toBlock) {
args.toBlock = checkLogTag(params.filter.toBlock);
}
if (params.filter.address) {
args.address = params.filter.address;
}
// @TODO: We can handle slightly more complicated logs using the logs API
if (params.filter.topics && params.filter.topics.length > 0) {
if (params.filter.topics.length > 1) {
logger.throwError("unsupported topic count", Logger.Errors.UNSUPPORTED_OPERATION, { topics: params.filter.topics });
}
if (params.filter.topics.length === 1) {
const topic0 = params.filter.topics[0];
if (typeof(topic0) !== "string" || topic0.length !== 66) {
logger.throwError("unsupported topic format", Logger.Errors.UNSUPPORTED_OPERATION, { topic0: topic0 });
}
args.topic0 = topic0;
}
}
const logs: Array<any> = await this.fetch("logs", args);
// Cache txHash => blockHash
let blocks: { [tag: string]: string } = {};
// Add any missing blockHash to the logs
for (let i = 0; i < logs.length; i++) {
const log = logs[i];
if (log.blockHash != null) { continue; }
if (blocks[log.blockNumber] == null) {
const block = await this.getBlock(log.blockNumber);
if (block) {
blocks[log.blockNumber] = block.hash;
}
}
log.blockHash = blocks[log.blockNumber];
}
return logs;
}
*/
default:
break;
}
return super._perform(req);
}
async getNetwork() {
return this.network;
}
async getEtherPrice() {
if (this.network.name !== "homestead") {
return 0.0;
}
return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd);
}
isCommunityResource() {
const plugin = this.network.getPlugin(EtherscanPluginId);
if (plugin) {
return (plugin.communityApiKey === this.apiKey);
}
return (this.apiKey == null);
}
}
exports.BaseEtherscanProvider = BaseEtherscanProvider;
//# sourceMappingURL=provider-etherscan-base.js.map

File diff suppressed because one or more lines are too long

@ -1,459 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EtherscanProvider = exports.EtherscanPlugin = void 0;
const index_js_1 = require("../utils/index.js");
const abstract_provider_js_1 = require("./abstract-provider.js");
const network_js_1 = require("./network.js");
const plugins_network_js_1 = require("./plugins-network.js");
const defaultApiKey = "9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB";
const EtherscanPluginId = "org.ethers.plugins.etherscan";
class EtherscanPlugin extends plugins_network_js_1.NetworkPlugin {
baseUrl;
communityApiKey;
constructor(baseUrl, communityApiKey) {
super(EtherscanPluginId);
//if (communityApiKey == null) { communityApiKey = null; }
(0, index_js_1.defineProperties)(this, { baseUrl, communityApiKey });
}
clone() {
return new EtherscanPlugin(this.baseUrl, this.communityApiKey);
}
exports.EtherscanProvider = void 0;
const provider_etherscan_base_js_1 = require("./provider-etherscan-base.js");
const index_js_1 = require("../contract/index.js");
function isPromise(value) {
return (value && typeof (value.then) === "function");
}
exports.EtherscanPlugin = EtherscanPlugin;
class EtherscanProvider extends abstract_provider_js_1.AbstractProvider {
network;
apiKey;
constructor(_network, apiKey) {
super();
const network = network_js_1.Network.from(_network);
if (apiKey == null) {
const plugin = network.getPlugin(EtherscanPluginId);
if (plugin) {
apiKey = plugin.communityApiKey;
class EtherscanProvider extends provider_etherscan_base_js_1.BaseEtherscanProvider {
async getContract(_address) {
let address = this._getAddress(_address);
if (isPromise(address)) {
address = await address;
}
else {
apiKey = defaultApiKey;
}
}
(0, index_js_1.defineProperties)(this, { apiKey, network });
// Test that the network is supported by Etherscan
this.getBaseUrl();
}
getBaseUrl() {
const plugin = this.network.getPlugin(EtherscanPluginId);
if (plugin) {
return plugin.baseUrl;
}
switch (this.network.name) {
case "homestead":
return "https:/\/api.etherscan.io";
case "ropsten":
return "https:/\/api-ropsten.etherscan.io";
case "rinkeby":
return "https:/\/api-rinkeby.etherscan.io";
case "kovan":
return "https:/\/api-kovan.etherscan.io";
case "goerli":
return "https:/\/api-goerli.etherscan.io";
default:
}
return (0, index_js_1.throwArgumentError)("unsupported network", "network", this.network);
}
getUrl(module, params) {
const query = Object.keys(params).reduce((accum, key) => {
const value = params[key];
if (value != null) {
accum += `&${key}=${value}`;
}
return accum;
}, "");
const apiKey = ((this.apiKey) ? `&apikey=${this.apiKey}` : "");
return `${this.getBaseUrl()}/api?module=${module}${query}${apiKey}`;
}
getPostUrl() {
return `${this.getBaseUrl()}/api`;
}
getPostData(module, params) {
params.module = module;
params.apikey = this.apiKey;
return params;
}
async detectNetwork() {
return this.network;
}
async fetch(module, params, post) {
const url = (post ? this.getPostUrl() : this.getUrl(module, params));
const payload = (post ? this.getPostData(module, params) : null);
/*
this.emit("debug", {
action: "request",
request: url,
provider: this
});
*/
const request = new index_js_1.FetchRequest(url);
request.processFunc = async (request, response) => {
const result = response.hasBody() ? JSON.parse((0, index_js_1.toUtf8String)(response.body)) : {};
const throttle = ((typeof (result.result) === "string") ? result.result : "").toLowerCase().indexOf("rate limit") >= 0;
if (module === "proxy") {
// This JSON response indicates we are being throttled
if (result && result.status == 0 && result.message == "NOTOK" && throttle) {
response.throwThrottleError(result.result);
}
}
else {
if (throttle) {
response.throwThrottleError(result.result);
}
}
return response;
};
// @TODO:
//throttleSlotInterval: 1000,
if (payload) {
request.setHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
request.body = Object.keys(payload).map((k) => `${k}=${payload[k]}`).join("&");
}
const response = await request.send();
response.assertOk();
if (!response.hasBody()) {
throw new Error();
}
/*
this.emit("debug", {
action: "response",
request: url,
response: deepCopy(result),
provider: this
});
*/
const result = JSON.parse((0, index_js_1.toUtf8String)(response.body));
if (module === "proxy") {
if (result.jsonrpc != "2.0") {
// @TODO: not any
const error = new Error("invalid response");
error.result = JSON.stringify(result);
throw error;
}
if (result.error) {
// @TODO: not any
const error = new Error(result.error.message || "unknown error");
if (result.error.code) {
error.code = result.error.code;
}
if (result.error.data) {
error.data = result.error.data;
}
throw error;
}
return result.result;
}
else {
// getLogs, getHistory have weird success responses
if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
return result.result;
}
if (result.status != 1 || result.message != "OK") {
const error = new Error("invalid response");
error.result = JSON.stringify(result);
// if ((result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
// error.throttleRetry = true;
// }
throw error;
}
return result.result;
}
}
// The transaction has already been sanitized by the calls in Provider
_getTransactionPostData(transaction) {
const result = {};
for (let key in transaction) {
if (transaction[key] == null) {
continue;
}
let value = transaction[key];
if (key === "type" && value === 0) {
continue;
}
// Quantity-types require no leading zero, unless 0
if ({ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true }[key]) {
value = (0, index_js_1.toQuantity)((0, index_js_1.hexlify)(value));
}
else if (key === "accessList") {
value = "[" + this.network.formatter.accessList(value).map((set) => {
return `{address:"${set.address}",storageKeys:["${set.storageKeys.join('","')}"]}`;
}).join(",") + "]";
}
else {
value = (0, index_js_1.hexlify)(value);
}
result[key] = value;
}
return result;
}
_checkError(req, error, transaction) {
/*
let body = "";
if (isError(error, Logger.Errors.SERVER_ERROR) && error.response && error.response.hasBody()) {
body = toUtf8String(error.response.body);
}
console.log(body);
// Undo the "convenience" some nodes are attempting to prevent backwards
// incompatibility; maybe for v6 consider forwarding reverts as errors
if (method === "call" && body) {
// Etherscan keeps changing their string
if (body.match(/reverted/i) || body.match(/VM execution error/i)) {
// Etherscan prefixes the data like "Reverted 0x1234"
let data = e.data;
if (data) { data = "0x" + data.replace(/^.*0x/i, ""); }
if (!isHexString(data)) { data = "0x"; }
logger.throwError("call exception", Logger.Errors.CALL_EXCEPTION, {
error, data
});
}
}
// Get the message from any nested error structure
let message = error.message;
if (isError(error, Logger.Errors.SERVER_ERROR)) {
if (error.error && typeof(error.error.message) === "string") {
message = error.error.message;
} else if (typeof(error.body) === "string") {
message = error.body;
} else if (typeof(error.responseText) === "string") {
message = error.responseText;
}
}
message = (message || "").toLowerCase();
// "Insufficient funds. The account you tried to send transaction from
// does not have enough funds. Required 21464000000000 and got: 0"
if (message.match(/insufficient funds/)) {
logger.throwError("insufficient funds for intrinsic transaction cost", Logger.Errors.INSUFFICIENT_FUNDS, {
error, transaction, info: { method }
});
}
// "Transaction with the same hash was already imported."
if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
logger.throwError("nonce has already been used", Logger.Errors.NONCE_EXPIRED, {
error, transaction, info: { method }
});
}
// "Transaction gas price is too low. There is another transaction with
// same nonce in the queue. Try increasing the gas price or incrementing the nonce."
if (message.match(/another transaction with same nonce/)) {
logger.throwError("replacement fee too low", Logger.Errors.REPLACEMENT_UNDERPRICED, {
error, transaction, info: { method }
});
}
if (message.match(/execution failed due to an exception|execution reverted/)) {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.Errors.UNPREDICTABLE_GAS_LIMIT, {
error, transaction, info: { method }
});
}
*/
throw error;
}
async _detectNetwork() {
return this.network;
}
async _perform(req) {
switch (req.method) {
case "chainId":
return this.network.chainId;
case "getBlockNumber":
return this.fetch("proxy", { action: "eth_blockNumber" });
case "getGasPrice":
return this.fetch("proxy", { action: "eth_gasPrice" });
case "getBalance":
// Returns base-10 result
return this.fetch("account", {
action: "balance",
address: req.address,
tag: req.blockTag
});
case "getTransactionCount":
return this.fetch("proxy", {
action: "eth_getTransactionCount",
address: req.address,
tag: req.blockTag
});
case "getCode":
return this.fetch("proxy", {
action: "eth_getCode",
address: req.address,
tag: req.blockTag
});
case "getStorageAt":
return this.fetch("proxy", {
action: "eth_getStorageAt",
address: req.address,
position: req.position,
tag: req.blockTag
});
case "broadcastTransaction":
return this.fetch("proxy", {
action: "eth_sendRawTransaction",
hex: req.signedTransaction
}, true).catch((error) => {
return this._checkError(req, error, req.signedTransaction);
});
case "getBlock":
if ("blockTag" in req) {
return this.fetch("proxy", {
action: "eth_getBlockByNumber",
tag: req.blockTag,
boolean: (req.includeTransactions ? "true" : "false")
});
}
return (0, index_js_1.throwError)("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
operation: "getBlock(blockHash)"
});
case "getTransaction":
return this.fetch("proxy", {
action: "eth_getTransactionByHash",
txhash: req.hash
});
case "getTransactionReceipt":
return this.fetch("proxy", {
action: "eth_getTransactionReceipt",
txhash: req.hash
});
case "call": {
if (req.blockTag !== "latest") {
throw new Error("EtherscanProvider does not support blockTag for call");
}
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_call";
try {
return await this.fetch("proxy", postData, true);
const resp = await this.fetch("contract", { action: "getabi", address });
const abi = JSON.parse(resp);
return new index_js_1.Contract(address, abi, this);
}
catch (error) {
return this._checkError(req, error, req.transaction);
return null;
}
}
case "estimateGas": {
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_estimateGas";
try {
return await this.fetch("proxy", postData, true);
}
catch (error) {
return this._checkError(req, error, req.transaction);
}
}
/*
case "getLogs": {
// Needs to complain if more than one address is passed in
const args: Record<string, any> = { action: "getLogs" }
if (params.filter.fromBlock) {
args.fromBlock = checkLogTag(params.filter.fromBlock);
}
if (params.filter.toBlock) {
args.toBlock = checkLogTag(params.filter.toBlock);
}
if (params.filter.address) {
args.address = params.filter.address;
}
// @TODO: We can handle slightly more complicated logs using the logs API
if (params.filter.topics && params.filter.topics.length > 0) {
if (params.filter.topics.length > 1) {
logger.throwError("unsupported topic count", Logger.Errors.UNSUPPORTED_OPERATION, { topics: params.filter.topics });
}
if (params.filter.topics.length === 1) {
const topic0 = params.filter.topics[0];
if (typeof(topic0) !== "string" || topic0.length !== 66) {
logger.throwError("unsupported topic format", Logger.Errors.UNSUPPORTED_OPERATION, { topic0: topic0 });
}
args.topic0 = topic0;
}
}
const logs: Array<any> = await this.fetch("logs", args);
// Cache txHash => blockHash
let blocks: { [tag: string]: string } = {};
// Add any missing blockHash to the logs
for (let i = 0; i < logs.length; i++) {
const log = logs[i];
if (log.blockHash != null) { continue; }
if (blocks[log.blockNumber] == null) {
const block = await this.getBlock(log.blockNumber);
if (block) {
blocks[log.blockNumber] = block.hash;
}
}
log.blockHash = blocks[log.blockNumber];
}
return logs;
}
*/
default:
break;
}
return super._perform(req);
}
async getNetwork() {
return this.network;
}
async getEtherPrice() {
if (this.network.name !== "homestead") {
return 0.0;
}
return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd);
}
isCommunityResource() {
const plugin = this.network.getPlugin(EtherscanPluginId);
if (plugin) {
return (plugin.communityApiKey === this.apiKey);
}
return (defaultApiKey === this.apiKey);
}
}
exports.EtherscanProvider = EtherscanProvider;
/*
(async function() {
const provider = new EtherscanProvider();
console.log(provider);
console.log(await provider.getBlockNumber());
/ *
provider.on("block", (b) => {
console.log("BB", b);
});
console.log(await provider.getTransactionReceipt("0xa5ded92f548e9f362192f9ab7e5b3fbc9b5a919a868e29247f177d49ce38de6e"));
provider.once("0xa5ded92f548e9f362192f9ab7e5b3fbc9b5a919a868e29247f177d49ce38de6e", (tx) => {
console.log("TT", tx);
});
* /
try {
console.log(await provider.getBlock(100));
} catch (error) {
console.log(error);
}
try {
console.log(await provider.getBlock(13821768));
} catch (error) {
console.log(error);
}
})();
*/
//# sourceMappingURL=provider-etherscan.js.map

File diff suppressed because one or more lines are too long

@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.FallbackProvider = void 0;
const index_js_1 = require("../utils/index.js");
const abstract_provider_js_1 = require("./abstract-provider.js");
const format_js_1 = require("./format.js");
const network_js_1 = require("./network.js");
//const BN_0 = BigInt("0");
const BN_1 = BigInt("1");
@ -43,7 +44,7 @@ async function waitForSync(config, blockNumber) {
}
// Normalizes a result to a string that can be used to compare against
// other results using normal string equality
function normalize(network, value, req) {
function normalize(provider, value, req) {
switch (req.method) {
case "chainId":
return (0, index_js_1.getBigInt)(value).toString();
@ -61,19 +62,19 @@ function normalize(network, value, req) {
return (0, index_js_1.hexlify)(value);
case "getBlock":
if (req.includeTransactions) {
return JSON.stringify(network.formatter.blockWithTransactions(value));
return JSON.stringify((0, format_js_1.formatBlockWithTransactions)(value));
}
return JSON.stringify(network.formatter.block(value));
return JSON.stringify((0, format_js_1.formatBlock)(value));
case "getTransaction":
return JSON.stringify(network.formatter.transactionResponse(value));
return JSON.stringify((0, format_js_1.formatTransactionResponse)(value));
case "getTransactionReceipt":
return JSON.stringify(network.formatter.receipt(value));
return JSON.stringify((0, format_js_1.formatTransactionReceipt)(value));
case "call":
return (0, index_js_1.hexlify)(value);
case "estimateGas":
return (0, index_js_1.getBigInt)(value).toString();
case "getLogs":
return JSON.stringify(value.map((v) => network.formatter.log(v)));
return JSON.stringify(value.map((v) => (0, format_js_1.formatLog)(v)));
}
return (0, index_js_1.throwError)("unsupported method", "UNSUPPORTED_OPERATION", {
operation: `_perform(${JSON.stringify(req.method)})`
@ -177,7 +178,7 @@ class FallbackProvider extends abstract_provider_js_1.AbstractProvider {
return this.#configs.slice();
}
async _detectNetwork() {
return network_js_1.Network.from((0, index_js_1.getBigInt)(await this._perform({ method: "chainId" }))).freeze();
return network_js_1.Network.from((0, index_js_1.getBigInt)(await this._perform({ method: "chainId" })));
}
// @TODO: Add support to select providers to be the event subscriber
//_getSubscriber(sub: Subscription): Subscriber {
@ -272,7 +273,7 @@ class FallbackProvider extends abstract_provider_js_1.AbstractProvider {
const result = runner.result.result;
results.push({
result,
normal: normalize((runner.config._network), result, req),
normal: normalize(runner.config.provider, result, req),
weight: runner.config.weight
});
}

File diff suppressed because one or more lines are too long

@ -24,7 +24,15 @@ class IpcSocketProvider extends provider_socket_js_1.SocketProvider {
constructor(path, network) {
super(network);
this.#socket = (0, net_1.connect)(path);
this.socket.on("ready", () => { this._start(); });
this.socket.on("ready", async () => {
try {
await this._start();
}
catch (error) {
console.log("failed to start IpcSocketProvider", error);
// @TODO: Now what? Restart?
}
});
let response = Buffer.alloc(0);
this.socket.on("data", (data) => {
response = Buffer.concat([response, data]);

@ -1 +1 @@
{"version":3,"file":"provider-ipcsocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-ipcsocket.ts"],"names":[],"mappings":";;;AACA,6BAA8B;AAC9B,6DAAsD;AAMtD,yEAAyE;AACzE,0CAA0C;AAC1C,SAAS,WAAW,CAAC,IAAY;IAC7B,MAAM,QAAQ,GAAkB,EAAG,CAAC;IAEpC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,IAAI,EAAE;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE;YAAE,MAAM;SAAE;QACzB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC;KACtB;IAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAa,iBAAkB,SAAQ,mCAAc;IACjD,OAAO,CAAS;IAChB,IAAI,MAAM,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAE7C,YAAY,IAAY,EAAE,OAAoB;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,IAAA,aAAO,EAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAElD,IAAI,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5B,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAE,QAAQ,EAAE,IAAI,CAAE,CAAC,CAAC;YAC7C,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACtD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACzB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;YACH,QAAQ,GAAG,SAAS,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,IAAI;QACA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;CACJ;AApCD,8CAoCC;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCE"}
{"version":3,"file":"provider-ipcsocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-ipcsocket.ts"],"names":[],"mappings":";;;AACA,6BAA8B;AAC9B,6DAAsD;AAMtD,yEAAyE;AACzE,0CAA0C;AAC1C,SAAS,WAAW,CAAC,IAAY;IAC7B,MAAM,QAAQ,GAAkB,EAAG,CAAC;IAEpC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,IAAI,EAAE;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE;YAAE,MAAM;SAAE;QACzB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC;KACtB;IAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAa,iBAAkB,SAAQ,mCAAc;IACjD,OAAO,CAAS;IAChB,IAAI,MAAM,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAE7C,YAAY,IAAY,EAAE,OAAoB;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,IAAA,aAAO,EAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;YAC/B,IAAI;gBACA,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;aACvB;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;gBACxD,4BAA4B;aAC/B;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5B,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAE,QAAQ,EAAE,IAAI,CAAE,CAAC,CAAC;YAC7C,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACtD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACzB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;YACH,QAAQ,GAAG,SAAS,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,IAAI;QACA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;CACJ;AA3CD,8CA2CC;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCE"}

@ -33,6 +33,9 @@ function deepCopy(value) {
}
throw new Error(`should not happen: ${value} (${typeof (value)})`);
}
function stall(duration) {
return new Promise((resolve) => { setTimeout(resolve, duration); });
}
function getLowerCase(value) {
if (value) {
return value.toLowerCase();
@ -123,7 +126,7 @@ class JsonRpcSigner extends abstract_signer_js_1.AbstractSigner {
// Try getting the transaction
const tx = await this.provider.getTransaction(hash);
if (tx != null) {
resolve(this.provider._wrapTransaction(tx, hash, blockNumber));
resolve(tx.replaceableTransaction(blockNumber));
return;
}
// Wait another 4 seconds
@ -188,23 +191,36 @@ exports.JsonRpcSigner = JsonRpcSigner;
* sub-classed.
*
* It provides the base for all JSON-RPC-based Provider interaction.
*
* Sub-classing Notes:
* - a sub-class MUST override _send
* - a sub-class MUST call the `_start()` method once connected
*/
class JsonRpcApiProvider extends abstract_provider_js_1.AbstractProvider {
#options;
#nextId;
#payloads;
#ready;
#starting;
#drainTimer;
#network;
constructor(network, options) {
super(network);
this.#ready = false;
this.#starting = null;
this.#nextId = 1;
this.#options = Object.assign({}, defaultOptions, options || {});
this.#payloads = [];
this.#drainTimer = null;
this.#network = null;
// This could be relaxed in the future to just check equivalent networks
const staticNetwork = this._getOption("staticNetwork");
if (staticNetwork && staticNetwork !== network) {
if (staticNetwork) {
if (staticNetwork !== network) {
(0, index_js_4.throwArgumentError)("staticNetwork MUST match network object", "options", options);
}
this.#network = staticNetwork;
}
}
/**
* Returns the value associated with the option %%key%%.
@ -214,8 +230,40 @@ class JsonRpcApiProvider extends abstract_provider_js_1.AbstractProvider {
_getOption(key) {
return this.#options[key];
}
get _network() {
if (!this.#network) {
(0, index_js_4.throwError)("network is not available yet", "NETWORK_ERROR");
}
return this.#network;
}
get ready() { return this.#ready; }
async _start() {
if (this.#ready) {
return;
}
if (this.#starting) {
return this.#starting;
}
this.#starting = (async () => {
// Bootstrap the network
if (this.#network == null) {
try {
this.#network = await this._detectNetwork();
}
catch (error) {
console.log("JsonRpcProvider failed to startup; retry in 1s");
await stall(1000);
this.#starting = null;
}
}
this.#ready = true;
this.#starting = null;
// Start dispatching requests
this.#scheduleDrain();
})();
}
#scheduleDrain() {
if (this.#drainTimer) {
if (this.#drainTimer || !this.ready) {
return;
}
// If we aren't using batching, no hard in sending it immeidately
@ -272,7 +320,6 @@ class JsonRpcApiProvider extends abstract_provider_js_1.AbstractProvider {
}
}, stallTime);
}
// Sub-classes should **NOT** override this
/**
* Requests the %%method%% with %%params%% via the JSON-RPC protocol
* over the underlying channel. This can be used to call methods
@ -331,25 +378,44 @@ class JsonRpcApiProvider extends abstract_provider_js_1.AbstractProvider {
}
return new JsonRpcSigner(this, accounts[address]);
}
const [network, accounts] = await Promise.all([this.getNetwork(), accountsPromise]);
const { accounts } = await (0, index_js_4.resolveProperties)({
network: this.getNetwork(),
accounts: accountsPromise
});
// Account address
address = network.formatter.address(address);
address = (0, index_js_1.getAddress)(address);
for (const account of accounts) {
if (network.formatter.address(account) === account) {
if ((0, index_js_1.getAddress)(account) === account) {
return new JsonRpcSigner(this, account);
}
}
throw new Error("invalid account");
}
// Sub-classes can override this; it detects the *actual* network we
// are connected to
/** Sub-classes can override this; it detects the *actual* network that
* we are **currently** connected to.
*
* Keep in mind that [[send]] may only be used once [[ready]].
*/
async _detectNetwork() {
// We have a static network (like INFURA)
const network = this._getOption("staticNetwork");
if (network) {
return network;
}
return network_js_1.Network.from((0, index_js_4.getBigInt)(await this._perform({ method: "chainId" })));
// If we are ready, use ``send``, which enabled requests to be batched
if (this.ready) {
return network_js_1.Network.from((0, index_js_4.getBigInt)(await this.send("eth_chainId", [])));
}
// We are not ready yet; use the primitive _send
const payload = {
id: this.#nextId++, method: "eth_chainId", params: [], jsonrpc: "2.0"
};
this.emit("debug", { action: "sendRpcPayload", payload });
const result = (await this._send(payload))[0];
this.emit("debug", { action: "receiveRpcResult", result });
if ("result" in result) {
return network_js_1.Network.from((0, index_js_4.getBigInt)(result.result));
}
throw this.getRpcError(payload, result);
}
/**
* Return a Subscriber that will manage the %%sub%%.
@ -602,6 +668,13 @@ class JsonRpcProvider extends JsonRpcApiProvider {
}
this.#pollingInterval = 4000;
}
async send(method, params) {
// All requests are over HTTP, so we can just start handling requests
// We do this here rather than the constructor so that we don't send any
// requests to the network until we absolutely have to.
await this._start();
return await super.send(method, params);
}
async _send(payload) {
// Configure a POST connection for the requested method
const request = this.#connect.clone();

File diff suppressed because one or more lines are too long

@ -101,21 +101,17 @@ exports.SocketPendingSubscriber = SocketPendingSubscriber;
class SocketEventSubscriber extends SocketSubscriber {
#logFilter;
get logFilter() { return JSON.parse(this.#logFilter); }
#formatter;
constructor(provider, filter) {
super(provider, ["logs", filter]);
this.#logFilter = JSON.stringify(filter);
this.#formatter = provider.getNetwork().then((network) => network.formatter);
}
async _emit(provider, message) {
const formatter = await this.#formatter;
provider.emit(this.#logFilter, formatter.log(message, provider));
provider.emit(this.#logFilter, provider._wrapLog(message, provider._network));
}
}
exports.SocketEventSubscriber = SocketEventSubscriber;
class SocketProvider extends provider_jsonrpc_js_1.JsonRpcApiProvider {
#callbacks;
#ready;
// Maps each filterId to its subscriber
#subs;
// If any events come in before a subscriber has finished
@ -124,10 +120,18 @@ class SocketProvider extends provider_jsonrpc_js_1.JsonRpcApiProvider {
constructor(network) {
super(network, { batchMaxCount: 1 });
this.#callbacks = new Map();
this.#ready = false;
this.#subs = new Map();
this.#pending = new Map();
}
// This value is only valid after _start has been called
/*
get _network(): Network {
if (this.#network == null) {
throw new Error("this shouldn't happen");
}
return this.#network.clone();
}
*/
_getSubscriber(sub) {
switch (sub.type) {
case "close":
@ -164,21 +168,23 @@ class SocketProvider extends provider_jsonrpc_js_1.JsonRpcApiProvider {
const promise = new Promise((resolve, reject) => {
this.#callbacks.set(payload.id, { payload, resolve, reject });
});
if (this.#ready) {
await this._write(JSON.stringify(payload));
}
return [await promise];
}
// Sub-classes must call this once they are connected
async _start() {
if (this.#ready) {
return;
}
this.#ready = true;
/*
async _start(): Promise<void> {
if (this.#ready) { return; }
for (const { payload } of this.#callbacks.values()) {
await this._write(JSON.stringify(payload));
}
this.#ready = (async function() {
await super._start();
})();
}
*/
// Sub-classes must call this for each message
async _processMessage(message) {
const result = (JSON.parse(message));

File diff suppressed because one or more lines are too long

@ -15,8 +15,14 @@ class WebSocketProvider extends provider_socket_js_1.SocketProvider {
else {
this.#websocket = url;
}
this.websocket.onopen = () => {
this._start();
this.websocket.onopen = async () => {
try {
await this._start();
}
catch (error) {
console.log("failed to start WebsocketProvider", error);
// @TODO: now what? Attempt reconnect?
}
};
this.websocket.onmessage = (message) => {
this._processMessage(message.data);

@ -1 +1 @@
{"version":3,"file":"provider-websocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-websocket.ts"],"names":[],"mappings":";;;AAEA,mCAAkD,CAAC,YAAY;AAE/D,6DAAsD;AAetD,MAAa,iBAAkB,SAAQ,mCAAc;IACjD,GAAG,CAAU;IAEb,UAAU,CAAgB;IAC1B,IAAI,SAAS,KAAoB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAE1D,YAAY,GAA2B,EAAE,OAAoB;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,OAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE;YAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,iBAAU,CAAC,GAAG,CAAC,CAAC;SACzC;aAAM;YACH,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;SACzB;QAED,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG,EAAE;YACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QAClB,CAAC,CAAC;QAEF,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,OAAyB,EAAE,EAAE;YACrD,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACJ;AA1BD,8CA0BC"}
{"version":3,"file":"provider-websocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-websocket.ts"],"names":[],"mappings":";;;AAEA,mCAAkD,CAAC,YAAY;AAE/D,6DAAsD;AAetD,MAAa,iBAAkB,SAAQ,mCAAc;IACjD,GAAG,CAAU;IAEb,UAAU,CAAgB;IAC1B,IAAI,SAAS,KAAoB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAE1D,YAAY,GAA2B,EAAE,OAAoB;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,OAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE;YAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,iBAAU,CAAC,GAAG,CAAC,CAAC;SACzC;aAAM;YACH,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;SACzB;QAED,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,KAAK,IAAI,EAAE;YAC/B,IAAI;gBACA,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;aACtB;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;gBACxD,sCAAsC;aACzC;QACL,CAAC,CAAC;QAEF,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,OAAyB,EAAE,EAAE;YACrD,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACJ;AA/BD,8CA+BC"}

@ -1,9 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.dummyProvider = exports.TransactionResponse = exports.TransactionReceipt = exports.Log = exports.Block = exports.copyRequest = exports.FeeData = void 0;
exports.TransactionResponse = exports.TransactionReceipt = exports.Log = exports.Block = exports.copyRequest = exports.FeeData = void 0;
//import { resolveAddress } from "@ethersproject/address";
const index_js_1 = require("../utils/index.js");
const index_js_2 = require("../transaction/index.js");
const BN_0 = BigInt(0);
// -----------------------
function getValue(value) {
if (value == null) {
@ -98,9 +99,6 @@ class Block {
baseFeePerGas;
#transactions;
constructor(block, provider) {
if (provider == null) {
provider = exports.dummyProvider;
}
this.#transactions = Object.freeze(block.transactions.map((tx) => {
if (typeof (tx) !== "string" && tx.provider !== provider) {
throw new Error("provider mismatch");
@ -196,9 +194,6 @@ class Log {
index;
transactionIndex;
constructor(log, provider) {
if (provider == null) {
provider = exports.dummyProvider;
}
this.provider = provider;
const topics = Object.freeze(log.topics.slice());
(0, index_js_1.defineProperties)(this, {
@ -269,9 +264,6 @@ class TransactionReceipt {
root;
#logs;
constructor(tx, provider) {
if (provider == null) {
provider = exports.dummyProvider;
}
this.#logs = Object.freeze(tx.logs.map((log) => {
if (provider !== log.provider) {
//return log.connect(provider);
@ -381,10 +373,8 @@ class TransactionResponse {
chainId;
signature;
accessList;
#startBlock;
constructor(tx, provider) {
if (provider == null) {
provider = exports.dummyProvider;
}
this.provider = provider;
this.blockNumber = (tx.blockNumber != null) ? tx.blockNumber : null;
this.blockHash = (tx.blockHash != null) ? tx.blockHash : null;
@ -403,10 +393,8 @@ class TransactionResponse {
this.chainId = tx.chainId;
this.signature = tx.signature;
this.accessList = (tx.accessList != null) ? tx.accessList : null;
this.#startBlock = -1;
}
//connect(provider: Provider): TransactionResponse {
// return new TransactionResponse(this, provider);
//}
toJSON() {
const { blockNumber, blockHash, index, hash, type, to, from, nonce, data, signature, accessList } = this;
return {
@ -443,8 +431,153 @@ class TransactionResponse {
async getTransaction() {
return this.provider.getTransaction(this.hash);
}
async wait(confirms) {
return this.provider.waitForTransaction(this.hash, confirms);
async wait(_confirms, _timeout) {
const confirms = (_confirms == null) ? 1 : _confirms;
const timeout = (_timeout == null) ? 0 : _timeout;
let startBlock = this.#startBlock;
let nextScan = -1;
let stopScanning = (startBlock === -1) ? true : false;
const checkReplacement = async () => {
// Get the current transaction count for this sender
if (stopScanning) {
return null;
}
const { blockNumber, nonce } = await (0, index_js_1.resolveProperties)({
blockNumber: this.provider.getBlockNumber(),
nonce: this.provider.getTransactionCount(this.from)
});
// No transaction for our nonce has been mined yet; but we can start
// scanning later when we do start
if (nonce < this.nonce) {
startBlock = blockNumber;
return;
}
// We were mined; no replacement
if (stopScanning) {
return null;
}
const mined = await this.getTransaction();
if (mined && mined.blockNumber != null) {
return;
}
// We were replaced; start scanning for that transaction
// Starting to scan; look back a few extra blocks for safety
if (nextScan === -1) {
nextScan = startBlock - 3;
if (nextScan < this.#startBlock) {
nextScan = this.#startBlock;
}
}
while (nextScan <= blockNumber) {
// Get the next block to scan
if (stopScanning) {
return null;
}
const block = await this.provider.getBlockWithTransactions(nextScan);
// This should not happen; but we'll try again shortly
if (block == null) {
return;
}
for (const tx of block.transactions) {
// We were mined; no replacement
if (tx.hash === this.hash) {
return;
}
if (tx.from === this.from && tx.nonce === this.nonce) {
// Get the receipt
if (stopScanning) {
return null;
}
const receipt = await this.provider.getTransactionReceipt(tx.hash);
// This should not happen; but we'll try again shortly
if (receipt == null) {
return;
}
// We will retry this on the next block (this case could be optimized)
if ((blockNumber - receipt.blockNumber + 1) < confirms) {
return;
}
// The reason we were replaced
let reason = "replaced";
if (tx.data === this.data && tx.to === this.to && tx.value === this.value) {
reason = "repriced";
}
else if (tx.data === "0x" && tx.from === tx.to && tx.value === BN_0) {
reason = "cancelled";
}
(0, index_js_1.throwError)("transaction was replaced", "TRANSACTION_REPLACED", {
cancelled: (reason === "replaced" || reason === "cancelled"),
reason,
replacement: tx.replaceableTransaction(startBlock),
hash: tx.hash,
receipt
});
}
}
nextScan++;
}
return;
};
const receipt = await this.provider.getTransactionReceipt(this.hash);
if (receipt) {
if ((await receipt.confirmations()) >= confirms) {
return receipt;
}
}
else {
// Check for a replacement; throws if a replacement was found
await checkReplacement();
// Allow null only when the confirms is 0
if (confirms === 0) {
return null;
}
}
const waiter = new Promise((resolve, reject) => {
// List of things to cancel when we have a result (one way or the other)
const cancellers = [];
const cancel = () => { cancellers.forEach((c) => c()); };
// On cancel, stop scanning for replacements
cancellers.push(() => { stopScanning = true; });
// Set up any timeout requested
if (timeout > 0) {
const timer = setTimeout(() => {
cancel();
reject((0, index_js_1.makeError)("wait for transaction timeout", "TIMEOUT"));
}, timeout);
cancellers.push(() => { clearTimeout(timer); });
}
const txListener = async (receipt) => {
// Done; return it!
if ((await receipt.confirmations()) >= confirms) {
cancel();
resolve(receipt);
}
};
cancellers.push(() => { this.provider.off(this.hash, txListener); });
this.provider.on(this.hash, txListener);
// We support replacement detection; start checking
if (startBlock >= 0) {
const replaceListener = async () => {
try {
// Check for a replacement; this throws only if one is found
await checkReplacement();
}
catch (error) {
// We were replaced (with enough confirms); re-throw the error
if ((0, index_js_1.isError)(error, "TRANSACTION_REPLACED")) {
cancel();
reject(error);
return;
}
}
// Rescheudle a check on the next block
this.provider.once("block", replaceListener);
};
cancellers.push(() => { this.provider.off("block", replaceListener); });
this.provider.once("block", replaceListener);
}
});
return await waiter;
}
isMined() {
return (this.blockHash != null);
@ -479,6 +612,21 @@ class TransactionResponse {
}
return createReorderedTransactionFilter(this, other);
}
/**
* Returns a new TransactionResponse instance which has the ability to
* detect (and throw an error) if the transaction is replaced, which
* will begin scanning at %%startBlock%%.
*
* This should generally not be used by developers and is intended
* primarily for internal use. Setting an incorrect %%startBlock%% can
* have devastating performance consequences if used incorrectly.
*/
replaceableTransaction(startBlock) {
(0, index_js_1.assertArgument)(Number.isInteger(startBlock) && startBlock >= 0, "invalid startBlock", "startBlock", startBlock);
const tx = new TransactionResponse(this, this.provider);
tx.#startBlock = startBlock;
return tx;
}
}
exports.TransactionResponse = TransactionResponse;
function createOrphanedBlockFilter(block) {
@ -501,80 +649,4 @@ function createRemovedLogFilter(log) {
index: log.index
} };
}
// @TODO: I think I can drop T
function fail() {
throw new Error("this provider should not be used");
}
class DummyProvider {
get provider() { return this; }
async getNetwork() { return fail(); }
async getFeeData() { return fail(); }
async estimateGas(tx) { return fail(); }
async call(tx) { return fail(); }
async resolveName(name) { return fail(); }
// State
async getBlockNumber() { return fail(); }
// Account
async getBalance(address, blockTag) {
return fail();
}
async getTransactionCount(address, blockTag) {
return fail();
}
async getCode(address, blockTag) {
return fail();
}
async getStorageAt(address, position, blockTag) {
return fail();
}
// Write
async broadcastTransaction(signedTx) { return fail(); }
// Queries
async getBlock(blockHashOrBlockTag) {
return fail();
}
async getBlockWithTransactions(blockHashOrBlockTag) {
return fail();
}
async getTransaction(hash) {
return fail();
}
async getTransactionReceipt(hash) {
return fail();
}
async getTransactionResult(hash) {
return fail();
}
// Bloom-filter Queries
async getLogs(filter) {
return fail();
}
// ENS
async lookupAddress(address) {
return fail();
}
async waitForTransaction(hash, confirms, timeout) {
return fail();
}
async waitForBlock(blockTag) {
return fail();
}
// EventEmitterable
async on(event, listener) { return fail(); }
async once(event, listener) { return fail(); }
async emit(event, ...args) { return fail(); }
async listenerCount(event) { return fail(); }
async listeners(event) { return fail(); }
async off(event, listener) { return fail(); }
async removeAllListeners(event) { return fail(); }
async addListener(event, listener) { return fail(); }
async removeListener(event, listener) { return fail(); }
}
/**
* A singleton [[Provider]] instance that can be used as a placeholder. This
* allows API that have a Provider added later to not require a null check.
*
* All operations performed on this [[Provider]] will throw.
*/
exports.dummyProvider = new DummyProvider();
//# sourceMappingURL=provider.js.map

File diff suppressed because one or more lines are too long

@ -88,10 +88,8 @@ class FilterIdEventSubscriber extends FilterIdSubscriber {
return filterId;
}
async _emitResults(provider, results) {
const network = await provider.getNetwork();
for (const result of results) {
const log = network.formatter.log(result, provider);
provider.emit(this.#event, log);
provider.emit(this.#event, provider._wrapLog(result, provider._network));
}
}
}
@ -101,9 +99,8 @@ class FilterIdPendingSubscriber extends FilterIdSubscriber {
return await provider.send("eth_newPendingTransactionFilter", []);
}
async _emitResults(provider, results) {
const network = await provider.getNetwork();
for (const result of results) {
provider.emit("pending", network.formatter.hash(result));
provider.emit("pending", result);
}
}
}

@ -1 +1 @@
{"version":3,"file":"subscriber-filterid.js","sourceRoot":"","sources":["../../src.ts/providers/subscriber-filterid.ts"],"names":[],"mappings":";;;AAAA,mEAAiE;AAUjE,SAAS,IAAI,CAAC,GAAQ;IAClB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAa,kBAAkB;IAC3B,SAAS,CAAqB;IAE9B,gBAAgB,CAAyB;IACzC,OAAO,CAA+B;IAEtC,QAAQ,CAAyB;IAEjC,YAAY,QAA4B;QACpC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAE1B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAErC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,UAAU,CAAC,QAA4B;QACnC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACrD,CAAC;IAED,YAAY,CAAC,QAA0B,EAAE,MAAkB;QACvD,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACrD,CAAC;IAED,QAAQ,CAAC,QAA0B;QAC/B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,WAAmB;QAC3B,IAAI;YACA,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,EAAE;gBAC/B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;aAC3D;YAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC;YAC7C,IAAI,QAAQ,IAAI,IAAI,EAAE;gBAClB,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;gBACvE,OAAO;aACV;YAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;YAClD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAAE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;aAAE;YAEhD,IAAK,IAAI,CAAC,QAAoB,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE;gBACxD,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;aACpC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAE,QAAQ,CAAE,CAAC,CAAC;YAC/E,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;SACnD;QAAC,OAAO,KAAK,EAAE;YAAE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;SAAE;QAEhD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,SAAS;QACL,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC9C,IAAI,eAAe,EAAE;YACjB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,eAAe,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;gBAC9B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAE,QAAQ,CAAE,CAAC,CAAC;YAC7D,CAAC,CAAC,CAAC;SACN;IACL,CAAC;IAED,KAAK,KAAW,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjC,IAAI;QACA,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,eAAyB;QAC3B,IAAI,eAAe,EAAC;YAAE,IAAI,CAAC,SAAS,EAAE,CAAC;SAAE;QACzC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,KAAW,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;CACnC;AA9ED,gDA8EC;AAED,MAAa,uBAAwB,SAAQ,kBAAkB;IAC3D,MAAM,CAAc;IAEpB,YAAY,QAA4B,EAAE,MAAmB;QACzD,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,QAAQ,CAAC,QAA0B;QAC/B,OAAO,IAAI,8CAAsB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,QAA4B;QACzC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,CAAE,IAAI,CAAC,MAAM,CAAE,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACjC,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAA4B,EAAE,OAAmB;QAChE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;YAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACpD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;SACnC;IACL,CAAC;CACJ;AAzBD,0DAyBC;AAED,MAAa,yBAA0B,SAAQ,kBAAkB;IAC7D,KAAK,CAAC,UAAU,CAAC,QAA4B;QACzC,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAG,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAA4B,EAAE,OAAmB;QAChE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;YAC1B,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;SAC5D;IACL,CAAC;CACJ;AAXD,8DAWC"}
{"version":3,"file":"subscriber-filterid.js","sourceRoot":"","sources":["../../src.ts/providers/subscriber-filterid.ts"],"names":[],"mappings":"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"}

@ -118,6 +118,7 @@ class FetchRequest {
#process;
#retry;
#signal;
#throttle;
/**
* The fetch URI to requrest.
*/
@ -338,10 +339,22 @@ class FetchRequest {
this.#gzip = false;
this.#headers = {};
this.#method = "";
this.#timeout = 300;
this.#timeout = 300000;
this.#throttle = {
slotInterval: SLOT_INTERVAL,
maxAttempts: MAX_ATTEMPTS
};
}
setThrottleParams(params) {
if (params.slotInterval != null) {
this.#throttle.slotInterval = params.slotInterval;
}
if (params.maxAttempts != null) {
this.#throttle.maxAttempts = params.maxAttempts;
}
}
async #send(attempt, expires, delay, _request, _response) {
if (attempt >= MAX_ATTEMPTS) {
if (attempt >= this.#throttle.maxAttempts) {
return _response.makeServerError("exceeded maximum retry limit");
}
if (getTime() > expires) {
@ -396,7 +409,7 @@ class FetchRequest {
// Throttle
if (this.retryFunc == null || (await this.retryFunc(req, response, attempt))) {
const retryAfter = response.headers["retry-after"];
let delay = SLOT_INTERVAL * Math.trunc(Math.random() * Math.pow(2, attempt));
let delay = this.#throttle.slotInterval * Math.trunc(Math.random() * Math.pow(2, attempt));
if (typeof (retryAfter) === "string" && retryAfter.match(/^[1-9][0-9]*$/)) {
delay = parseInt(retryAfter);
}
@ -414,7 +427,7 @@ class FetchRequest {
response.makeServerError("error in post-processing function", error).assertOk();
}
// Throttle
let delay = SLOT_INTERVAL * Math.trunc(Math.random() * Math.pow(2, attempt));
let delay = this.#throttle.slotInterval * Math.trunc(Math.random() * Math.pow(2, attempt));
;
if (error.stall >= 0) {
delay = error.stall;

File diff suppressed because one or more lines are too long

@ -0,0 +1,80 @@
import fs from "fs";
import semver from "semver";
import { keccak256 } from "../crypto/index.js";
import { FetchRequest } from "../utils/index.js";
import { loadJson, saveJson } from "./utils/json.js";
import { getGitTag } from "./utils/git.js";
import { resolve } from "./utils/path.js";
import { run } from "./utils/run.js";
const cache = {};
async function getNpmPackage(name) {
if (!cache[name]) {
const resp = await (new FetchRequest("https:/\/registry.npmjs.org/" + name)).send();
resp.assertOk();
cache[name] = resp.bodyJson;
}
return cache[name] || null;
}
function getPackList() {
const result = run("npm", ["pack", "--json", resolve("."), "--dry-run"]);
if (!result.ok) {
const error = new Error("failed to run npm pack");
error.result = result;
throw error;
}
return JSON.parse(result.stdout)[0].files.map((info) => info.path);
}
function computeTarballHash() {
// Sort the files to get a consistent hash
const files = getPackList();
files.sort();
const hashes = files.reduce((accum, filename) => {
let content = fs.readFileSync(resolve(filename));
// The package.json includes the hash, so we need to normalize it first
if (filename === "package.json") {
const info = JSON.parse(content.toString());
delete info.gitHead;
delete info.tarballHash;
content = Buffer.from(JSON.stringify(info, null, 2));
}
accum[filename] = keccak256(content);
return accum;
}, {});
return keccak256(Buffer.from("{" + files.map((filename) => {
return `${JSON.stringify(filename)}:"${hashes[filename]}"`;
}).join(",") + "}"));
}
(async function () {
// Local pkg
const pkgPath = resolve("package.json");
const pkgInfo = loadJson(pkgPath);
const tag = pkgInfo.publishConfig.tag;
// Get the remote version that matches our dist-tag
const remoteInfo = await getNpmPackage(pkgInfo.name);
const remoteVersion = remoteInfo["dist-tags"][tag];
// Remote pkg
const remotePkgInfo = remoteInfo.versions[remoteVersion];
// Compute the populated values
const tarballHash = computeTarballHash();
const gitHead = await getGitTag(resolve("."));
if (remotePkgInfo.tarballHash !== tarballHash) {
pkgInfo.tarballHash = tarballHash;
pkgInfo.gitHead = gitHead;
if (tag.indexOf("beta") >= 0) {
// Still a beta branch; advance the beta version
const prerelease = semver.prerelease(remoteVersion);
if (prerelease == null || prerelease.length !== 2) {
throw new Error("no prerelease found");
}
pkgInfo.version = semver.inc(remoteVersion, "prerelease", String(prerelease[0]));
}
else if (semver.minor(remoteVersion) == semver.minor(pkgInfo.version)) {
// If we want to bump the minor version, it was done explicitly in the pkg
pkgInfo.version = semver.inc(remoteVersion, "patch");
}
}
saveJson(pkgPath, pkgInfo, true);
})().catch((error) => {
console.log(error);
});
//# sourceMappingURL=update-publish-properties.js.map

@ -0,0 +1 @@
{"version":3,"file":"update-publish-properties.js","sourceRoot":"","sources":["../../src.ts/_admin/update-publish-properties.ts"],"names":[],"mappings":"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"}

@ -0,0 +1,18 @@
import { run } from "./run.js";
// Returns the most recent git commit hash for a given filename
export async function getGitTag(filename) {
const result = await run("git", ["log", "-n", "1", "--", filename]);
if (!result.ok) {
throw new Error(`git log error`);
}
let log = result.stdout.trim();
if (!log) {
return null;
}
const hashMatch = log.match(/^commit\s+([0-9a-f]{40})\n/i);
if (!hashMatch) {
return null;
}
return hashMatch[1];
}
//# sourceMappingURL=git.js.map

@ -0,0 +1 @@
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src.ts/_admin/utils/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB;IAC5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAE,CAAC,CAAC;IACtE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;KAAE;IAErD,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,IAAI,CAAC;KAAE;IAE1B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC3D,IAAI,CAAC,SAAS,EAAE;QAAE,OAAO,IAAI,CAAC;KAAE;IAChC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC"}

@ -0,0 +1,78 @@
"use strict";
/*
import semver from "semver";
import { FetchRequest } from "../../utils/index.js";
export type PackageInfo = {
dependencies: { [ name: string ]: string };
devDependencies: { [ name: string ]: string };
gitHead: string;
name: string;
version: string;
tarballHash: string;
location: "remote" | "local";
_ethers_nobuild: boolean;
};
export class Package {
readonly #info: PackageInfo;
constructor(info: PackageInfo) {
this.#info = info;
}
get name(): string { return this.#info.name; }
get version(): string { return this.#info.version; }
get dependencies(): Record<string, string> { return this.#info.dependencies; }
get devDependencies(): Record<string, string> { return this.#info.devDependencies; }
get gitHead(): string { return this.#info.gitHead; }
get tarballHash(): string { return this.#info.tarballHash; }
}
const cache: Record<string, any> = { };
async function getPackageInfo(name: string): Promise<any> {
if (!cache[name]) {
const resp = await (new FetchRequest("https:/\/registry.npmjs.org/" + name)).send();
resp.assertOk();
cache[name] = resp.bodyJson();
}
return cache[name] || null;
}
export async function getPackage(name: string, version?: string): Promise<null | Package> {
const infos = await getPackageInfo(name);
if (infos == null) { return null; }
if (version == null) {
const versions = Object.keys(infos.versions);
versions.sort(semver.compare);
// HACK: So v5 continues working while v6 is managed by reticulate
version = "6.0.0";
while (version.indexOf("beta") >= 0 || semver.gte(version, "6.0.0")) {
version = versions.pop();
}
}
const info = infos.versions[version];
return new Package({
dependencies: (info.dependencies || {}),
devDependencies: (info.devDependencies || {}),
gitHead: info.gitHead,
location: "remote",
name: info.name,
tarballHash: info.tarballHash,
version : info.version,
_ethers_nobuild: !!info._ethers_nobuild,
});
}
*/
//# sourceMappingURL=npm.js.map

@ -0,0 +1 @@
{"version":3,"file":"npm.js","sourceRoot":"","sources":["../../../src.ts/_admin/utils/npm.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2EE"}

@ -0,0 +1,54 @@
import { spawnSync } from "child_process";
export class RunResult {
#cmd;
#status;
#stdout;
#stderr;
constructor(progname, args, status, stdout, stderr) {
this.#cmd = `${progname} ${args.map((a) => JSON.stringify(a))}`;
this.#status = status;
this.#stdout = stdout;
this.#stderr = stderr;
}
get cmd() { return this.#cmd; }
get stderr() {
return this._stderr.toString() || null;
}
get _stderr() {
return this.#stderr;
}
get stdout() {
return this._stdout.toString();
}
get _stdout() {
return this.#stdout;
}
get status() { return this.#status; }
get ok() {
return (this.#stderr.length === 0 && this.#status === 0);
}
assertOk(message) {
if (!this.ok) {
throw new Error(message || `failed to run: ${this.#cmd}`);
}
}
}
;
export function run(progname, args, currentWorkingDirectory) {
if (args == null) {
args = [];
}
const options = {};
if (currentWorkingDirectory) {
options.cwd = currentWorkingDirectory;
}
const child = spawnSync(progname, args, options);
const result = new RunResult(progname, args, child.status, child.stdout, child.stderr);
if (child.error) {
const error = child.error;
error.result = result;
throw error;
}
return result;
}
//# sourceMappingURL=run.js.map

@ -0,0 +1 @@
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src.ts/_admin/utils/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,OAAO,SAAS;IACT,IAAI,CAAS;IACb,OAAO,CAAgB;IACvB,OAAO,CAAkB;IACzB,OAAO,CAAkB;IAElC,YAAY,QAAgB,EAAE,IAAmB,EAAE,MAAqB,EAAE,MAAuB,EAAE,MAAuB;QACtH,IAAI,CAAC,IAAI,GAAG,GAAI,QAAS,IAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IAC1B,CAAC;IAED,IAAI,GAAG,KAAa,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEvC,IAAI,MAAM;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;IAC3C,CAAC;IAED,IAAI,OAAO;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,IAAI,MAAM;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,OAAO;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,IAAI,MAAM,KAAoB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpD,IAAI,EAAE;QACF,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,QAAQ,CAAC,OAAgB;QACrB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE;YACV,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,kBAAmB,IAAI,CAAC,IAAK,EAAE,CAAC,CAAC;SAC/D;IACL,CAAC;CACJ;AAAA,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAE,IAAoB,EAAE,uBAAgC;IACxF,IAAI,IAAI,IAAI,IAAI,EAAE;QAAE,IAAI,GAAG,EAAG,CAAC;KAAE;IAEjC,MAAM,OAAO,GAAQ,EAAG,CAAC;IACzB,IAAI,uBAAuB,EAAE;QAAE,OAAO,CAAC,GAAG,GAAG,uBAAuB,CAAC;KAAE;IACvE,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAEjD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAEvF,IAAI,KAAK,CAAC,KAAK,EAAE;QACb,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QACpB,KAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QAC7B,MAAM,KAAK,CAAC;KACf;IAED,OAAO,MAAM,CAAC;AAClB,CAAC"}

@ -1,2 +1,2 @@
export const version = "6.0.0-beta-exports.1";
export const version = "6.0.0-beta-exports.2";
//# sourceMappingURL=_version.js.map

@ -634,7 +634,7 @@ export class Fragment {
case "function": return FunctionFragment.fromObject(obj);
case "struct": return StructFragment.fromObject(obj);
}
throw new Error("not implemented yet");
throw new Error(`not implemented yet: ${obj.type}`);
}
static fromString(text) {
try {
@ -721,6 +721,9 @@ export class ErrorFragment extends NamedFragment {
result.push(this.name + joinParams(format, this.inputs));
return result.join(" ");
}
static fromObject(obj) {
return new ErrorFragment(_guard, obj.name, obj.inputs ? obj.inputs.map(ParamType.fromObject) : []);
}
static fromString(text) {
return ErrorFragment.fromTokens(lex(text));
}
@ -759,6 +762,9 @@ export class EventFragment extends NamedFragment {
}
return result.join(" ");
}
static fromObject(obj) {
return new EventFragment(_guard, obj.name, obj.inputs ? obj.inputs.map(ParamType.fromObject) : [], !!obj.anonymous);
}
static fromString(text) {
return EventFragment.fromTokens(lex(text));
}
@ -799,12 +805,12 @@ export class ConstructorFragment extends Fragment {
}
return result.join(" ");
}
static fromObject(obj) {
return new ConstructorFragment(_guard, "constructor", obj.inputs ? obj.inputs.map(ParamType.fromObject) : [], !!obj.payable, (obj.gas != null) ? obj.gas : null);
}
static fromString(text) {
return ConstructorFragment.fromTokens(lex(text));
}
static fromObject(obj) {
throw new Error("TODO");
}
static fromTokens(tokens) {
consumeKeywords(tokens, setify(["constructor"]));
const inputs = consumeParams(tokens);
@ -862,6 +868,10 @@ export class FunctionFragment extends NamedFragment {
}
return result.join(" ");
}
static fromObject(obj) {
// @TODO: verifyState for stateMutability
return new FunctionFragment(_guard, obj.name, obj.stateMutability, obj.inputs ? obj.inputs.map(ParamType.fromObject) : [], obj.outputs ? obj.outputs.map(ParamType.fromObject) : [], (obj.gas != null) ? obj.gas : null);
}
static fromString(text) {
return FunctionFragment.fromTokens(lex(text));
}

File diff suppressed because one or more lines are too long

@ -117,8 +117,15 @@ export class Interface {
this.#errors = new Map();
this.#events = new Map();
// this.#structs = new Map();
const frags = [];
for (const a of abi) {
try {
frags.push(Fragment.from(a));
}
catch (error) { }
}
defineProperties(this, {
fragments: Object.freeze(abi.map((f) => Fragment.from(f)).filter((f) => (f != null))),
fragments: Object.freeze(frags)
});
this.#abiCoder = this.getAbiCoder();
// Add all fragments by their signature

File diff suppressed because one or more lines are too long

@ -165,6 +165,8 @@ class WrappedMethod extends _WrappedMethodBase() {
}
const tx = await runner.sendTransaction(await this.populateTransaction(...args));
const provider = getProvider(this._contract.runner);
// @TODO: the provider can be null; make a custom dummy provider that will throw a
// meaningful error
return new ContractTransactionResponse(this._contract.interface, provider, tx);
}
async estimateGas(...args) {
@ -382,6 +384,8 @@ export class BaseContract {
let deployTx = null;
if (_deployTx) {
const provider = getProvider(runner);
// @TODO: the provider can be null; make a custom dummy provider that will throw a
// meaningful error
deployTx = new ContractTransactionResponse(this.interface, provider, _deployTx);
}
let subs = new Map();

File diff suppressed because one or more lines are too long

@ -1 +1 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src.ts/contract/types.ts"],"names":[],"mappings":"AAeC,CAAC;AAiBqE,CAAC;AAkDvE,CAAC"}
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src.ts/contract/types.ts"],"names":[],"mappings":"AAeC,CAAC;AAiB4E,CAAC;AAkD9E,CAAC"}

@ -1 +1 @@
{"version":3,"file":"wrappers.js","sourceRoot":"","sources":["../../src.ts/contract/wrappers.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"wrappers.js","sourceRoot":"","sources":["../../src.ts/contract/wrappers.ts"],"names":[],"mappings":"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"}

@ -8,12 +8,16 @@
import { resolveAddress } from "../address/index.js";
import { concat, dataLength, dataSlice, hexlify, isHexString, getBigInt, getBytes, getNumber, isCallException, makeError, throwError, throwArgumentError, FetchRequest, toArray, toQuantity, defineProperties, EventPayload, resolveProperties, toUtf8String } from "../utils/index.js";
import { EnsResolver } from "./ens-resolver.js";
import { formatBlock, formatBlockWithTransactions, formatLog, formatTransactionReceipt, formatTransactionResponse } from "./format.js";
import { Network } from "./network.js";
import { FeeData } from "./provider.js";
import { copyRequest, Block, FeeData, Log, TransactionReceipt, TransactionResponse } from "./provider.js";
import { PollingBlockSubscriber, PollingEventSubscriber, PollingOrphanSubscriber, PollingTransactionSubscriber } from "./subscriber-polling.js";
// Constants
const BN_2 = BigInt(2);
const MAX_CCIP_REDIRECTS = 10;
function isPromise(value) {
return (value && typeof (value.then) === "function");
}
function getTag(prefix, value) {
return prefix + ":" + JSON.stringify(value, (k, v) => {
if (typeof (v) === "bigint") {
@ -50,10 +54,6 @@ function concisify(items) {
items.sort();
return items;
}
// Normalize a ProviderEvent into a Subscription
// @TODO: Make events sync if possible; like block
//function getSyncSubscription(_event: ProviderEvent): Subscription {
//}
async function getSubscription(_event, provider) {
if (_event == null) {
throw new Error("invalid event");
@ -123,10 +123,6 @@ async function getSubscription(_event, provider) {
return throwArgumentError("unknown ProviderEvent", "event", _event);
}
function getTime() { return (new Date()).getTime(); }
export function copyRequest(tx) {
// @TODO: copy the copy from contracts and use it from this
return tx;
}
export class AbstractProvider {
#subs;
#plugins;
@ -135,6 +131,8 @@ export class AbstractProvider {
#networkPromise;
#anyNetwork;
#performCache;
// The most recent block number if running an event or -1 if no "block" event
#lastBlockNumber;
#nextTimer;
#timers;
#disableCcipRead;
@ -155,6 +153,7 @@ export class AbstractProvider {
this.#anyNetwork = false;
this.#networkPromise = null;
}
this.#lastBlockNumber = -1;
this.#performCache = new Map();
this.#subs = new Map();
this.#plugins = new Map();
@ -243,8 +242,20 @@ export class AbstractProvider {
transaction: tx, info: { urls, errorMessages }
});
}
_wrapTransaction(tx, hash, blockNumber) {
return tx;
_wrapBlock(value, network) {
return new Block(formatBlock(value), this);
}
_wrapBlockWithTransactions(value, network) {
return new Block(formatBlock(value), this);
}
_wrapLog(value, network) {
return new Log(formatLog(value), this);
}
_wrapTransactionReceipt(value, network) {
return new TransactionReceipt(formatTransactionReceipt(value), this);
}
_wrapTransactionResponse(tx, network) {
return new TransactionResponse(tx, this);
}
_detectNetwork() {
return throwError("sub-classes must implement this", "UNSUPPORTED_OPERATION", {
@ -261,20 +272,14 @@ export class AbstractProvider {
}
// State
async getBlockNumber() {
return getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
const blockNumber = getNumber(await this.#perform({ method: "getBlockNumber" }), "%response");
if (this.#lastBlockNumber >= 0) {
this.#lastBlockNumber = blockNumber;
}
return blockNumber;
}
// @TODO: Make this string | Promsie<string> so no await needed if sync is possible
_getAddress(address) {
return resolveAddress(address, this);
/*
if (typeof(address) === "string") {
if (address.match(/^0x[0-9a-f]+$/i)) { return address; }
const resolved = await this.resolveName(address);
if (resolved == null) { throw new Error("not confiugred @TODO"); }
return resolved;
}
return address.getAddress();
*/
}
_getBlockTag(blockTag) {
if (blockTag == null) {
@ -299,236 +304,13 @@ export class AbstractProvider {
if (blockTag >= 0) {
return toQuantity(blockTag);
}
if (this.#lastBlockNumber >= 0) {
return toQuantity(this.#lastBlockNumber + blockTag);
}
return this.getBlockNumber().then((b) => toQuantity(b + blockTag));
}
return throwArgumentError("invalid blockTag", "blockTag", blockTag);
}
async getNetwork() {
// No explicit network was set and this is our first time
if (this.#networkPromise == null) {
// Detect the current network (shared with all calls)
const detectNetwork = this._detectNetwork().then((network) => {
this.emit("network", network, null);
return network;
}, (error) => {
// Reset the networkPromise on failure, so we will try again
if (this.#networkPromise === detectNetwork) {
this.#networkPromise = null;
}
throw error;
});
this.#networkPromise = detectNetwork;
return await detectNetwork;
}
const networkPromise = this.#networkPromise;
const [expected, actual] = await Promise.all([
networkPromise,
this._detectNetwork() // The actual connected network
]);
if (expected.chainId !== actual.chainId) {
if (this.#anyNetwork) {
// The "any" network can change, so notify listeners
this.emit("network", actual, expected);
// Update the network if something else hasn't already changed it
if (this.#networkPromise === networkPromise) {
this.#networkPromise = Promise.resolve(actual);
}
}
else {
// Otherwise, we do not allow changes to the underlying network
throwError(`network changed: ${expected.chainId} => ${actual.chainId} `, "NETWORK_ERROR", {
event: "changed"
});
}
}
return expected.clone().freeze();
}
async getFeeData() {
const { block, gasPrice } = await resolveProperties({
block: this.getBlock("latest"),
gasPrice: ((async () => {
try {
const gasPrice = await this.#perform({ method: "getGasPrice" });
return getBigInt(gasPrice, "%response");
}
catch (error) { }
return null;
})())
});
let maxFeePerGas = null, maxPriorityFeePerGas = null;
if (block && block.baseFeePerGas) {
// We may want to compute this more accurately in the future,
// using the formula "check if the base fee is correct".
// See: https://eips.ethereum.org/EIPS/eip-1559
maxPriorityFeePerGas = BigInt("1500000000");
// Allow a network to override their maximum priority fee per gas
//const priorityFeePlugin = (await this.getNetwork()).getPlugin<MaxPriorityFeePlugin>("org.ethers.plugins.max-priority-fee");
//if (priorityFeePlugin) {
// maxPriorityFeePerGas = await priorityFeePlugin.getPriorityFee(this);
//}
maxFeePerGas = (block.baseFeePerGas * BN_2) + maxPriorityFeePerGas;
}
return new FeeData(gasPrice, maxFeePerGas, maxPriorityFeePerGas);
}
async _getTransaction(_request) {
const network = await this.getNetwork();
// Fill in any addresses
const request = Object.assign({}, _request, await resolveProperties({
to: (_request.to ? resolveAddress(_request.to, this) : undefined),
from: (_request.from ? resolveAddress(_request.from, this) : undefined),
}));
return network.formatter.transactionRequest(request);
}
async estimateGas(_tx) {
const transaction = await this._getTransaction(_tx);
return getBigInt(await this.#perform({
method: "estimateGas", transaction
}), "%response");
}
async #call(tx, blockTag, attempt) {
if (attempt >= MAX_CCIP_REDIRECTS) {
throwError("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
reason: "TOO_MANY_REDIRECTS",
transaction: Object.assign({}, tx, { blockTag, enableCcipRead: true })
});
}
const transaction = copyRequest(tx);
try {
return hexlify(await this._perform({ method: "call", transaction, blockTag }));
}
catch (error) {
// CCIP Read OffchainLookup
if (!this.disableCcipRead && isCallException(error) && attempt >= 0 && blockTag === "latest" && transaction.to != null && dataSlice(error.data, 0, 4) === "0x556f1830") {
const data = error.data;
const txSender = await resolveAddress(transaction.to, this);
// Parse the CCIP Read Arguments
let ccipArgs;
try {
ccipArgs = parseOffchainLookup(dataSlice(error.data, 4));
}
catch (error) {
return throwError(error.message, "OFFCHAIN_FAULT", {
reason: "BAD_DATA",
transaction, info: { data }
});
}
// Check the sender of the OffchainLookup matches the transaction
if (ccipArgs.sender.toLowerCase() !== txSender.toLowerCase()) {
return throwError("CCIP Read sender mismatch", "CALL_EXCEPTION", {
data, transaction,
errorSignature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
errorName: "OffchainLookup",
errorArgs: ccipArgs.errorArgs
});
}
const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
if (ccipResult == null) {
return throwError("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
reason: "FETCH_FAILED",
transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
});
}
return this.#call({
to: txSender,
data: concat([
ccipArgs.selector, encodeBytes([ccipResult, ccipArgs.extraData])
]),
}, blockTag, attempt + 1);
}
throw error;
}
}
async call(_tx) {
const [tx, blockTag] = await Promise.all([
this._getTransaction(_tx), this._getBlockTag(_tx.blockTag)
]);
return this.#call(tx, blockTag, _tx.enableCcipRead ? 0 : -1);
}
// Account
async #getAccountValue(request, _address, _blockTag) {
let address = this._getAddress(_address);
let blockTag = this._getBlockTag(_blockTag);
if (typeof (address) !== "string" || typeof (blockTag) !== "string") {
[address, blockTag] = await Promise.all([address, blockTag]);
}
return await this.#perform(Object.assign(request, { address, blockTag }));
}
async getBalance(address, blockTag) {
return getBigInt(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
}
async getTransactionCount(address, blockTag) {
return getNumber(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
}
async getCode(address, blockTag) {
return hexlify(await this.#getAccountValue({ method: "getCode" }, address, blockTag));
}
async getStorageAt(address, _position, blockTag) {
const position = getBigInt(_position, "position");
return hexlify(await this.#getAccountValue({ method: "getStorageAt", position }, address, blockTag));
}
// Write
async broadcastTransaction(signedTx) {
throw new Error();
return {};
}
async #getBlock(block, includeTransactions) {
if (isHexString(block, 32)) {
return await this.#perform({
method: "getBlock", blockHash: block, includeTransactions
});
}
let blockTag = this._getBlockTag(block);
if (typeof (blockTag) !== "string") {
blockTag = await blockTag;
}
return await this.#perform({
method: "getBlock", blockTag, includeTransactions
});
}
// Queries
async getBlock(block) {
const [network, params] = await Promise.all([
this.getNetwork(), this.#getBlock(block, false)
]);
if (params == null) {
return null;
}
return network.formatter.block(params, this);
}
async getBlockWithTransactions(block) {
const format = (await this.getNetwork()).formatter;
const params = this.#getBlock(block, true);
if (params == null) {
return null;
}
return format.blockWithTransactions(params, this);
}
async getTransaction(hash) {
const format = (await this.getNetwork()).formatter;
const params = await this.#perform({ method: "getTransaction", hash });
return format.transactionResponse(params, this);
}
async getTransactionReceipt(hash) {
const format = (await this.getNetwork()).formatter;
const receipt = await this.#perform({ method: "getTransactionReceipt", hash });
if (receipt == null) {
return null;
}
// Some backends did not backfill the effectiveGasPrice into old transactions
// in the receipt, so we look it up manually and inject it.
if (receipt.gasPrice == null && receipt.effectiveGasPrice == null) {
const tx = await this.#perform({ method: "getTransaction", hash });
receipt.effectiveGasPrice = tx.gasPrice;
}
return format.receipt(receipt, this);
}
async getTransactionResult(hash) {
const result = await this.#perform({ method: "getTransactionResult", hash });
if (result == null) {
return null;
}
return hexlify(result);
}
_getFilter(filter) {
// Create a canonical representation of the topics
const topics = (filter.topics || []).map((t) => {
@ -604,15 +386,295 @@ export class AbstractProvider {
}
return resolve(address, fromBlock, toBlock);
}
_getTransactionRequest(_request) {
const request = copyRequest(_request);
const promises = [];
["to", "from"].forEach((key) => {
if (request[key] == null) {
return;
}
const addr = resolveAddress(request[key]);
if (isPromise(addr)) {
promises.push((async function () { request[key] = await addr; })());
}
else {
request[key] = addr;
}
});
if (request.blockTag != null) {
const blockTag = this._getBlockTag(request.blockTag);
if (isPromise(blockTag)) {
promises.push((async function () { request.blockTag = await blockTag; })());
}
else {
request.blockTag = blockTag;
}
}
if (promises.length) {
return (async function () {
await Promise.all(promises);
return request;
})();
}
return request;
}
async getNetwork() {
// No explicit network was set and this is our first time
if (this.#networkPromise == null) {
// Detect the current network (shared with all calls)
const detectNetwork = this._detectNetwork().then((network) => {
this.emit("network", network, null);
return network;
}, (error) => {
// Reset the networkPromise on failure, so we will try again
if (this.#networkPromise === detectNetwork) {
this.#networkPromise = null;
}
throw error;
});
this.#networkPromise = detectNetwork;
return (await detectNetwork).clone();
}
const networkPromise = this.#networkPromise;
const [expected, actual] = await Promise.all([
networkPromise,
this._detectNetwork() // The actual connected network
]);
if (expected.chainId !== actual.chainId) {
if (this.#anyNetwork) {
// The "any" network can change, so notify listeners
this.emit("network", actual, expected);
// Update the network if something else hasn't already changed it
if (this.#networkPromise === networkPromise) {
this.#networkPromise = Promise.resolve(actual);
}
}
else {
// Otherwise, we do not allow changes to the underlying network
throwError(`network changed: ${expected.chainId} => ${actual.chainId} `, "NETWORK_ERROR", {
event: "changed"
});
}
}
return expected.clone();
}
async getFeeData() {
const { block, gasPrice } = await resolveProperties({
block: this.getBlock("latest"),
gasPrice: ((async () => {
try {
const gasPrice = await this.#perform({ method: "getGasPrice" });
return getBigInt(gasPrice, "%response");
}
catch (error) { }
return null;
})())
});
let maxFeePerGas = null, maxPriorityFeePerGas = null;
if (block && block.baseFeePerGas) {
// We may want to compute this more accurately in the future,
// using the formula "check if the base fee is correct".
// See: https://eips.ethereum.org/EIPS/eip-1559
maxPriorityFeePerGas = BigInt("1500000000");
// Allow a network to override their maximum priority fee per gas
//const priorityFeePlugin = (await this.getNetwork()).getPlugin<MaxPriorityFeePlugin>("org.ethers.plugins.max-priority-fee");
//if (priorityFeePlugin) {
// maxPriorityFeePerGas = await priorityFeePlugin.getPriorityFee(this);
//}
maxFeePerGas = (block.baseFeePerGas * BN_2) + maxPriorityFeePerGas;
}
return new FeeData(gasPrice, maxFeePerGas, maxPriorityFeePerGas);
}
async estimateGas(_tx) {
let tx = this._getTransactionRequest(_tx);
if (isPromise(tx)) {
tx = await tx;
}
return getBigInt(await this.#perform({
method: "estimateGas", transaction: tx
}), "%response");
}
async #call(tx, blockTag, attempt) {
if (attempt >= MAX_CCIP_REDIRECTS) {
throwError("CCIP read exceeded maximum redirections", "OFFCHAIN_FAULT", {
reason: "TOO_MANY_REDIRECTS",
transaction: Object.assign({}, tx, { blockTag, enableCcipRead: true })
});
}
// This came in as a PerformActionTransaction, so to/from are safe; we can cast
const transaction = copyRequest(tx);
try {
return hexlify(await this._perform({ method: "call", transaction, blockTag }));
}
catch (error) {
// CCIP Read OffchainLookup
if (!this.disableCcipRead && isCallException(error) && attempt >= 0 && blockTag === "latest" && transaction.to != null && dataSlice(error.data, 0, 4) === "0x556f1830") {
const data = error.data;
const txSender = await resolveAddress(transaction.to, this);
// Parse the CCIP Read Arguments
let ccipArgs;
try {
ccipArgs = parseOffchainLookup(dataSlice(error.data, 4));
}
catch (error) {
return throwError(error.message, "OFFCHAIN_FAULT", {
reason: "BAD_DATA",
transaction, info: { data }
});
}
// Check the sender of the OffchainLookup matches the transaction
if (ccipArgs.sender.toLowerCase() !== txSender.toLowerCase()) {
return throwError("CCIP Read sender mismatch", "CALL_EXCEPTION", {
data, transaction,
errorSignature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",
errorName: "OffchainLookup",
errorArgs: ccipArgs.errorArgs
});
}
const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);
if (ccipResult == null) {
return throwError("CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {
reason: "FETCH_FAILED",
transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }
});
}
return this.#call({
to: txSender,
data: concat([
ccipArgs.selector, encodeBytes([ccipResult, ccipArgs.extraData])
]),
}, blockTag, attempt + 1);
}
throw error;
}
}
async #checkNetwork(promise) {
const { value } = await resolveProperties({
network: this.getNetwork(),
value: promise
});
return value;
}
async call(_tx) {
const { tx, blockTag } = await resolveProperties({
tx: this._getTransactionRequest(_tx),
blockTag: this._getBlockTag(_tx.blockTag)
});
return await this.#checkNetwork(this.#call(tx, blockTag, _tx.enableCcipRead ? 0 : -1));
}
// Account
async #getAccountValue(request, _address, _blockTag) {
let address = this._getAddress(_address);
let blockTag = this._getBlockTag(_blockTag);
if (typeof (address) !== "string" || typeof (blockTag) !== "string") {
[address, blockTag] = await Promise.all([address, blockTag]);
}
return await this.#checkNetwork(this.#perform(Object.assign(request, { address, blockTag })));
}
async getBalance(address, blockTag) {
return getBigInt(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");
}
async getTransactionCount(address, blockTag) {
return getNumber(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");
}
async getCode(address, blockTag) {
return hexlify(await this.#getAccountValue({ method: "getCode" }, address, blockTag));
}
async getStorageAt(address, _position, blockTag) {
const position = getBigInt(_position, "position");
return hexlify(await this.#getAccountValue({ method: "getStorageAt", position }, address, blockTag));
}
// Write
async broadcastTransaction(signedTx) {
throw new Error();
return {};
}
async #getBlock(block, includeTransactions) {
// @TODO: Add CustomBlockPlugin check
if (isHexString(block, 32)) {
return await this.#perform({
method: "getBlock", blockHash: block, includeTransactions
});
}
let blockTag = this._getBlockTag(block);
if (typeof (blockTag) !== "string") {
blockTag = await blockTag;
}
return await this.#perform({
method: "getBlock", blockTag, includeTransactions
});
}
// Queries
async getBlock(block) {
const { network, params } = await resolveProperties({
network: this.getNetwork(),
params: this.#getBlock(block, false)
});
if (params == null) {
return null;
}
return this._wrapBlock(formatBlock(params), network);
}
async getBlockWithTransactions(block) {
const { network, params } = await resolveProperties({
network: this.getNetwork(),
params: this.#getBlock(block, true)
});
if (params == null) {
return null;
}
return this._wrapBlockWithTransactions(formatBlockWithTransactions(params), network);
}
async getTransaction(hash) {
const { network, params } = await resolveProperties({
network: this.getNetwork(),
params: this.#perform({ method: "getTransaction", hash })
});
if (params == null) {
return null;
}
return this._wrapTransactionResponse(formatTransactionResponse(params), network);
}
async getTransactionReceipt(hash) {
const { network, params } = await resolveProperties({
network: this.getNetwork(),
params: this.#perform({ method: "getTransactionReceipt", hash })
});
if (params == null) {
return null;
}
// Some backends did not backfill the effectiveGasPrice into old transactions
// in the receipt, so we look it up manually and inject it.
if (params.gasPrice == null && params.effectiveGasPrice == null) {
const tx = await this.#perform({ method: "getTransaction", hash });
if (tx == null) {
throw new Error("report this; could not find tx or effectiveGasPrice");
}
params.effectiveGasPrice = tx.gasPrice;
}
return this._wrapTransactionReceipt(formatTransactionReceipt(params), network);
}
async getTransactionResult(hash) {
const { result } = await resolveProperties({
network: this.getNetwork(),
result: this.#perform({ method: "getTransactionResult", hash })
});
if (result == null) {
return null;
}
return hexlify(result);
}
// Bloom-filter Queries
async getLogs(_filter) {
const { network, filter } = await resolveProperties({
let filter = this._getFilter(_filter);
if (isPromise(filter)) {
filter = await filter;
}
const { network, params } = await resolveProperties({
network: this.getNetwork(),
filter: this._getFilter(_filter)
});
return (await this.#perform({ method: "getLogs", filter })).map((l) => {
return network.formatter.log(l, this);
params: this.#perform({ method: "getLogs", filter })
});
return params.map((p) => this._wrapLog(formatLog(p), network));
}
// ENS
_getProvider(chainId) {
@ -922,6 +984,7 @@ export class AbstractProvider {
}
}
pause(dropWhilePaused) {
this.#lastBlockNumber = -1;
if (this.#pausedState != null) {
if (this.#pausedState == !!dropWhilePaused) {
return;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -3,7 +3,7 @@
* networks injected registered.
*/
import { EnsPlugin, GasCostPlugin } from "./plugins-network.js";
import { EtherscanPlugin } from "./provider-etherscan.js";
import { EtherscanPlugin } from "./provider-etherscan-base.js";
import { Network } from "./network.js";
// See: https://chainlist.org
export function injectCommonNetworks() {

@ -1 +1 @@
{"version":3,"file":"common-networks.js","sourceRoot":"","sources":["../../src.ts/providers/common-networks.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"common-networks.js","sourceRoot":"","sources":["../../src.ts/providers/common-networks.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASvC,6BAA6B;AAC7B,MAAM,UAAU,oBAAoB;IAEhC,sCAAsC;IACtC,SAAS,WAAW,CAAC,IAAY,EAAE,OAAe,EAAE,OAAgB;QAChE,MAAM,IAAI,GAAG;YACT,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAE3C,0BAA0B;YAC1B,IAAI,OAAO,CAAC,UAAU,IAAI,IAAI,EAAE;gBAC5B,OAAO,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;aACjE;YAED,IAAI,OAAO,CAAC,WAAW,EAAE;gBACrC,sFAAsF;aACzE;YAED,IAAI,OAAO,CAAC,SAAS,EAAE;gBACnB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;gBAC1C,OAAO,CAAC,YAAY,CAAC,IAAI,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;aAC1D;YAED,OAAO,CAAC,YAAY,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;YAE1C,OAAO,OAAO,CAAC;QACnB,CAAC,CAAC;QAEF,4CAA4C;QAC5C,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAEhC,IAAI,OAAO,CAAC,QAAQ,EAAE;YAClB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;SACN;IACL,CAAC;IAED,WAAW,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAE,SAAS,CAAE,EAAE,CAAC,CAAC;IACxE,WAAW,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7C,WAAW,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7C,WAAW,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,WAAW,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;IAE7C,WAAW,CAAC,SAAS,EAAE,EAAE,EAAE,EAAG,CAAC,CAAC;IAChC,WAAW,CAAC,cAAc,EAAE,CAAC,EAAE,EAAG,CAAC,CAAC;IAEpC,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;IAE5C,mDAAmD;IACnD,WAAW,CAAC,OAAO,EAAE,GAAG,EAAE;QACtB,UAAU,EAAE,CAAC;QACrB,mCAAmC;QAC3B,SAAS,EAAE;YACP,MAAM,EAAE,oCAAoC;YAC5C,GAAG,EAAE,+BAA+B;SACvC;KACJ,CAAC,CAAC;IACH,WAAW,CAAC,aAAa,EAAE,KAAK,EAAE;QACtC,mCAAmC;QAC3B,SAAS,EAAE;YACP,MAAM,EAAE,oCAAoC;YAC5C,GAAG,EAAE,uCAAuC;SAC/C;KACJ,CAAC,CAAC;IAEH,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE;QACnB,UAAU,EAAE,CAAC;QACb,SAAS,EAAE;YACP,MAAM,EAAE,oCAAoC;YAC5C,GAAG,EAAE,yBAAyB;SACjC;KACJ,CAAC,CAAC;IACH,WAAW,CAAC,MAAM,EAAE,EAAE,EAAE;QACpB,SAAS,EAAE;YACP,MAAM,EAAE,oCAAoC;YAC5C,GAAG,EAAE,iCAAiC;SACzC;KACJ,CAAC,CAAC;AACP,CAAC;AAED,oBAAoB,EAAE,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,CAAC"}

@ -1,3 +1,4 @@
import { getAddress } from "../address/index.js";
import { ZeroHash } from "../constants/hashes.js";
import { dnsEncode, namehash } from "../hash/index.js";
import { concat, dataSlice, getBytes, hexlify, zeroPadValue, defineProperties, encodeBase58, getBigInt, toArray, toNumber, toUtf8Bytes, toUtf8String, throwArgumentError, throwError, FetchRequest } from "../utils/index.js";
@ -58,6 +59,12 @@ function encodeBytes(datas) {
}
return concat(result);
}
function callAddress(value) {
if (value.length !== 66 || dataSlice(value, 0, 12) !== "0x000000000000000000000000") {
throwArgumentError("invalid call address", "value", value);
}
return getAddress("0x" + value.substring(26));
}
// @TODO: This should use the fetch-data:ipfs gateway
// Trim off the ipfs:// prefix and return the default gateway URL
function getIpfsLink(link) {
@ -174,11 +181,10 @@ export class EnsResolver {
// keccak256("addr(bytes32)")
const result = await this._fetch("0x3b3b57de");
// No address
if (result === "0x" || result === ZeroHash) {
if (result == null || result === "0x" || result === ZeroHash) {
return null;
}
const network = await this.provider.getNetwork();
return network.formatter.callAddress(result);
return callAddress(result);
}
catch (error) {
if (error.code === "CALL_EXCEPTION") {
@ -301,13 +307,12 @@ export class EnsResolver {
linkage.push({ type: `!${scheme}caip`, value: (match[2] || "") });
throw new Error("!caip");
}
const formatter = (await this.provider.getNetwork()).formatter;
const addr = formatter.address(comps[0]);
const addr = getAddress(comps[0]);
const tokenId = numPad(comps[1]);
// Check that this account owns the token
if (scheme === "erc721") {
// ownerOf(uint256 tokenId)
const tokenOwner = formatter.callAddress(await this.provider.call({
const tokenOwner = callAddress(await this.provider.call({
to: addr, data: concat(["0x6352211e", tokenId])
}));
if (owner !== tokenOwner) {
@ -419,7 +424,7 @@ export class EnsResolver {
data: concat(["0x0178b8bf", namehash(name)]),
enableCcipRead: true
});
const addr = network.formatter.callAddress(addrData);
const addr = callAddress(addrData);
if (addr === dataSlice(ZeroHash, 0, 20)) {
return null;
}

File diff suppressed because one or more lines are too long

229
lib.esm/providers/format.js Normal file

@ -0,0 +1,229 @@
import { getAddress, getCreateAddress } from "../address/index.js";
import { accessListify } from "../transaction/index.js";
import { getBigInt, getNumber, hexlify, isHexString, zeroPadValue, throwArgumentError, throwError } from "../utils/index.js";
const BN_0 = BigInt(0);
export function allowNull(format, nullValue) {
return (function (value) {
if (value == null) {
return nullValue;
}
return format(value);
});
}
export function arrayOf(format) {
return ((array) => {
if (!Array.isArray(array)) {
throw new Error("not an array");
}
return array.map((i) => format(i));
});
}
// Requires an object which matches a fleet of other formatters
// Any FormatFunc may return `undefined` to have the value omitted
// from the result object. Calls preserve `this`.
export function object(format, altNames) {
return ((value) => {
const result = {};
for (const key in format) {
let srcKey = key;
if (altNames && key in altNames && !(srcKey in value)) {
for (const altKey of altNames[key]) {
if (altKey in value) {
srcKey = altKey;
break;
}
}
}
try {
const nv = format[key](value[srcKey]);
if (nv !== undefined) {
result[key] = nv;
}
}
catch (error) {
const message = (error instanceof Error) ? error.message : "not-an-error";
throwError(`invalid value for value.${key} (${message})`, "BAD_DATA", { value });
}
}
return result;
});
}
export function formatBoolean(value) {
switch (value) {
case true:
case "true":
return true;
case false:
case "false":
return false;
}
return throwArgumentError(`invalid boolean; ${JSON.stringify(value)}`, "value", value);
}
export function formatData(value) {
if (!isHexString(value, true)) {
throwArgumentError("", "value", value);
}
return value;
}
export function formatHash(value) {
if (!isHexString(value, 32)) {
throwArgumentError("", "value", value);
}
return value;
}
export function formatUint256(value) {
if (!isHexString(value)) {
throw new Error("invalid uint256");
}
return zeroPadValue(value, 32);
}
export const formatLog = object({
address: getAddress,
blockHash: formatHash,
blockNumber: getNumber,
data: formatData,
index: getNumber,
removed: formatBoolean,
topics: arrayOf(formatHash),
transactionHash: formatHash,
transactionIndex: getNumber,
}, {
index: ["logIndex"]
});
function _formatBlock(txFunc) {
return object({
hash: allowNull(formatHash),
parentHash: formatHash,
number: getNumber,
timestamp: getNumber,
nonce: allowNull(formatData),
difficulty: getBigInt,
gasLimit: getBigInt,
gasUsed: getBigInt,
miner: allowNull(getAddress),
extraData: formatData,
transactions: arrayOf(txFunc),
baseFeePerGas: allowNull(getBigInt)
});
}
export const formatBlock = _formatBlock(formatHash);
export const formatBlockWithTransactions = _formatBlock(formatTransactionResponse);
export const formatReceiptLog = object({
transactionIndex: getNumber,
blockNumber: getNumber,
transactionHash: formatHash,
address: getAddress,
topics: arrayOf(formatHash),
data: formatData,
logIndex: getNumber,
blockHash: formatHash,
});
export const formatTransactionReceipt = object({
to: allowNull(getAddress, null),
from: allowNull(getAddress, null),
contractAddress: allowNull(getAddress, null),
transactionIndex: getNumber,
// should be allowNull(hash), but broken-EIP-658 support is handled in receipt
root: allowNull(hexlify),
gasUsed: getBigInt,
logsBloom: allowNull(formatData),
blockHash: formatHash,
transactionHash: formatHash,
logs: arrayOf(formatReceiptLog),
blockNumber: getNumber,
confirmations: allowNull(getNumber, null),
cumulativeGasUsed: getBigInt,
effectiveGasPrice: allowNull(getBigInt),
status: allowNull(getNumber),
type: getNumber
}, {
effectiveGasPrice: ["gasPrice"]
});
export function formatTransactionResponse(value) {
// Some clients (TestRPC) do strange things like return 0x0 for the
// 0 address; correct this to be a real address
if (value.to && getBigInt(value.to) === BN_0) {
value.to = "0x0000000000000000000000000000000000000000";
}
const result = object({
hash: formatHash,
type: (value) => {
if (value === "0x" || value == null) {
return 0;
}
return getNumber(value);
},
accessList: allowNull(accessListify, null),
blockHash: allowNull(formatHash, null),
blockNumber: allowNull(getNumber, null),
transactionIndex: allowNull(getNumber, null),
confirmations: allowNull(getNumber, null),
from: getAddress,
// either (gasPrice) or (maxPriorityFeePerGas + maxFeePerGas) must be set
gasPrice: allowNull(getBigInt),
maxPriorityFeePerGas: allowNull(getBigInt),
maxFeePerGas: allowNull(getBigInt),
gasLimit: getBigInt,
to: allowNull(getAddress, null),
value: getBigInt,
nonce: getNumber,
data: formatData,
r: allowNull(formatUint256),
s: allowNull(formatUint256),
v: allowNull(getNumber),
creates: allowNull(getAddress, null),
chainId: allowNull(getBigInt, null)
}, {
data: ["input"],
gasLimit: ["gas"]
})(value);
// If to and creates are empty, populate the creates from the value
if (result.to == null && result.creates == null) {
result.creates = getCreateAddress(result);
}
// @TODO: Check fee data
// Add an access list to supported transaction types
if ((value.type === 1 || value.type === 2) && value.accessList == null) {
value.accessList = [];
}
// @TODO: check chainID
/*
if (value.chainId != null) {
let chainId = value.chainId;
if (isHexString(chainId)) {
chainId = BigNumber.from(chainId).toNumber();
}
result.chainId = chainId;
} else {
let chainId = value.networkId;
// geth-etc returns chainId
if (chainId == null && result.v == null) {
chainId = value.chainId;
}
if (isHexString(chainId)) {
chainId = BigNumber.from(chainId).toNumber();
}
if (typeof(chainId) !== "number" && result.v != null) {
chainId = (result.v - 35) / 2;
if (chainId < 0) { chainId = 0; }
chainId = parseInt(chainId);
}
if (typeof(chainId) !== "number") { chainId = 0; }
result.chainId = chainId;
}
*/
// 0x0000... should actually be null
if (result.blockHash && getBigInt(result.blockHash) === BN_0) {
result.blockHash = null;
}
return result;
}
//# sourceMappingURL=format.js.map

File diff suppressed because one or more lines are too long

@ -1,3 +1,4 @@
"use strict";
// Belongs to Networks; requires abstract-provider
// provider requires abstract-provider and network
/**
@ -13,26 +14,56 @@
* Network object this allows exotic (non-Ethereum) networks
* to be fairly simple to adapt to ethers.
*/
/*
import { getAddress, getCreateAddress } from "../address/index.js";
import { dataLength, dataSlice, getBigInt, getNumber, isHexString, toQuantity, throwArgumentError, throwError } from "../utils/index.js";
import {
dataLength, dataSlice, getBigInt, getNumber, isHexString, toQuantity,
throwArgumentError, throwError
} from "../utils/index.js";
import { Signature } from "../crypto/signature.js";
import { accessListify } from "../transaction/index.js";
import { Block, Log, TransactionReceipt, TransactionResponse } from "./provider.js";
import type { AccessList } from "../transaction/index.js";
import type { PerformActionTransaction } from "./abstract-provider.js";
import type { Filter, Provider } from "./provider.js";
const BN_MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
export type FormatFunc = (value: any) => any;
//export type AccessListSet = { address: string, storageKeys: Array<string> };
//export type AccessList = Array<AccessListSet>;
//export type AccessListish = AccessList |
// Array<[ string, Array<string> ]> |
// Record<string, Array<string>>;
function stringify(value) {
if (typeof (value) !== "string") {
throw new Error("invalid string");
}
function stringify(value: any): string {
if (typeof(value) !== "string") { throw new Error("invalid string"); }
return value;
}
export class Formatter {
#format;
#baseBlock;
#format: {
address: FormatFunc,
bigNumber: FormatFunc,
blockTag: FormatFunc,
data: FormatFunc,
filter: FormatFunc,
hash: FormatFunc,
number: FormatFunc,
topics: FormatFunc,
transactionRequest: FormatFunc,
transactionResponse: FormatFunc,
uint256: FormatFunc,
};
#baseBlock: FormatFunc;
constructor() {
const address = this.address.bind(this);
const bigNumber = this.bigNumber.bind(this);
@ -41,7 +72,9 @@ export class Formatter {
const hash = this.hash.bind(this);
const number = this.number.bind(this);
const uint256 = this.uint256.bind(this);
const topics = this.arrayOf(hash);
this.#format = {
address,
bigNumber,
@ -50,7 +83,9 @@ export class Formatter {
hash,
number,
uint256,
topics,
filter: this.object({
fromBlock: this.allowNull(blockTag, undefined),
toBlock: this.allowNull(blockTag, undefined),
@ -58,6 +93,7 @@ export class Formatter {
address: this.allowNull(address, undefined),
topics: this.allowNull(topics, undefined)
}),
transactionRequest: this.object({
from: this.allowNull(address),
type: this.allowNull(number),
@ -70,21 +106,29 @@ export class Formatter {
data: this.allowNull(data),
value: this.allowNull(uint256),
}),
transactionResponse: this.object({
hash: hash,
index: number,
type: this.allowNull(number, 0),
// These can be null for pending blocks
blockHash: this.allowNull(hash),
blockNumber: this.allowNull(number),
// For Legacy transactions, this comes from the v
chainId: this.allowNull(number),
from: address,
to: this.address,
gasLimit: bigNumber,
gasPrice: this.allowNull(bigNumber),
maxFeePerGas: this.allowNull(bigNumber),
maxPriorityFeePerGas: this.allowNull(bigNumber),
value: bigNumber,
data: data,
nonce: number,
@ -93,92 +137,102 @@ export class Formatter {
v: number,
accessList: this.allowNull(this.accessList)
}, {
index: ["transactionIndex"]
index: [ "transactionIndex" ]
}),
};
this.#baseBlock = this.object({
number: number,
hash: this.allowNull(hash, null),
timestamp: number,
parentHash: hash,
nonce: this.allowNull(stringify, "0x0000000000000000"),
difficulty: bigNumber,
gasLimit: bigNumber,
gasUsed: bigNumber,
miner: this.allowNull(address, "0x0000000000000000000000000000000000000000"),
extraData: stringify,
baseFeePerGas: this.allowNull(bigNumber),
});
}
// An address
address(value) {
address(value: any): string {
return getAddress(value);
}
// An address from a call result; may be zero-padded
callAddress(value) {
callAddress(value: any): string {
if (dataLength(value) !== 32 || dataSlice(value, 0, 12) !== "0x000000000000000000000000") {
throwArgumentError("invalid call address", "value", value);
}
return this.address(dataSlice(value, 12));
}
// An address from a transaction (e.g. { from: string, nonce: number })
contractAddress(value) {
contractAddress(value: any): string {
return getCreateAddress({
from: this.address(value.from),
nonce: getNumber(value.nonce, "value.nonce")
});
}
// Block Tag
blockTag(value) {
if (value == null) {
return "latest";
}
blockTag(value?: any): string {
if (value == null) { return "latest"; }
switch (value) {
case "earliest":
return "0x0";
case "latest":
case "pending":
case "safe":
case "finalized":
case "latest": case "pending": case "safe": case "finalized":
return value;
}
if (typeof (value) === "number" || (isHexString(value) && dataLength(value) < 32)) {
if (typeof(value) === "number" || (isHexString(value) && dataLength(value) < 32)) {
return toQuantity(value);
}
return throwArgumentError("invalid blockTag", "value", value);
}
// Block objects
block(value, provider) {
block(value: any, provider?: Provider): Block<string> {
const params = this.#baseBlock(value);
params.transactions = value.transactions.map((t) => this.hash(t));
params.transactions = value.transactions.map((t: any) => this.hash(t));
return new Block(params, provider);
}
blockWithTransactions(value, provider) {
blockWithTransactions(value: any, provider?: Provider): Block<TransactionResponse> {
throw new Error();
}
// Transactions
transactionRequest(value, provider) {
transactionRequest(value: any, provider?: Provider): PerformActionTransaction {
return this.#format.transactionRequest(value);
}
transactionResponse(value, provider) {
value = Object.assign({}, value);
transactionResponse(value: any, provider?: Provider): TransactionResponse {
value = Object.assign({ }, value);
// @TODO: Use the remap feature
if (value.data == null && value.input != null) {
value.data = value.input;
}
if (value.gasLimit == null && value.gas) {
value.gasLimit = value.gas;
}
if (value.data == null && value.input != null) { value.data = value.input; }
if (value.gasLimit == null && value.gas) { value.gasLimit = value.gas; }
value = this.#format.transactionResponse(value);
const sig = Signature.from({ r: value.r, s: value.s, v: value.v });
value.signature = sig;
if (value.chainId == null) {
value.chainId = sig.legacyChainId;
}
if (value.chainId == null) { value.chainId = sig.legacyChainId; }
return new TransactionResponse(value, provider);
}
// Receipts
log(value, provider) {
log(value: any, provider?: Provider): Log {
const log = this.object({
address: this.address,
blockHash: this.hash,
@ -190,11 +244,12 @@ export class Formatter {
transactionHash: this.hash,
transactionIndex: this.number,
}, {
index: ["logIndex"]
index: [ "logIndex" ]
})(value);
return new Log(log, provider);
}
receipt(value, provider) {
receipt(value: any, provider?: Provider): TransactionReceipt {
const receipt = this.object({
blockHash: this.hash,
blockNumber: this.number,
@ -202,7 +257,7 @@ export class Formatter {
cumulativeGasUsed: this.bigNumber,
from: this.address,
gasUsed: this.bigNumber,
logs: this.arrayOf((v) => (this.log(v, provider))),
logs: this.arrayOf((v: any) => (this.log(v, provider))),
logsBloom: this.data,
root: this.allowNull(this.data),
status: this.allowNull(this.number),
@ -212,10 +267,11 @@ export class Formatter {
index: this.number,
type: this.allowNull(this.number, 0),
}, {
hash: ["transactionHash"],
gasPrice: ["effectiveGasPrice"],
index: ["transactionIndex"]
hash: [ "transactionHash" ],
gasPrice: [ "effectiveGasPrice" ],
index: [ "transactionIndex" ]
})(value);
// RSK incorrectly implemented EIP-658, so we munge things a bit here for it
if (receipt.root != null) {
if (receipt.root.length <= 4) {
@ -230,131 +286,138 @@ export class Formatter {
}
receipt.status = value;
delete receipt.root;
}
else {
} else {
return throwError("invalid alt-root-status", "BAD_DATA", {
value: receipt.root
});
}
}
else if (!isHexString(receipt.root, 32)) {
} else if (!isHexString(receipt.root, 32)) {
// Must be a valid bytes32
return throwError("invalid receipt root hash", "BAD_DATA", {
value: receipt.root
});
}
}
//receipt.byzantium = (receipt.root == null);
return new TransactionReceipt(receipt, provider);
}
// Fitlers
topics(value) {
topics(value: any): Array<string> {
return this.#format.topics(value);
}
filter(value) {
filter(value: any): Filter {
return this.#format.filter(value);
}
filterLog(value) {
filterLog(value: any): any {
console.log("ME", value);
return null;
}
// Converts a serialized transaction to a TransactionResponse
transaction(value) {
transaction(value: any): TransactionResponse {
throw new Error();
}
// Useful utility formatters functions, which if need be use the
// methods within the formatter to ensure internal compatibility
// Access List; converts an AccessListish to an AccessList
accessList(value) {
accessList(value: any): AccessList {
return accessListify(value);
}
// Converts falsish values to a specific value, otherwise use the formatter. Calls preserve `this`.
allowFalsish(format, ifFalse) {
return ((value) => {
if (!value) {
return ifFalse;
}
allowFalsish(format: FormatFunc, ifFalse: any): FormatFunc {
return ((value: any) => {
if (!value) { return ifFalse; }
return format.call(this, value);
});
}
// Allows null, optionally replacing it with a default value. Calls preserve `this`.
allowNull(format, ifNull) {
return ((value) => {
if (value == null) {
return ifNull;
}
allowNull(format: FormatFunc, ifNull?: any): FormatFunc {
return ((value: any) => {
if (value == null) { return ifNull; }
return format.call(this, value);
});
}
// Requires an Array satisfying the formatter. Calls preserves `this`.
arrayOf(format) {
return ((array) => {
if (!Array.isArray(array)) {
throw new Error("not an array");
}
arrayOf(format: FormatFunc): FormatFunc {
return ((array: any) => {
if (!Array.isArray(array)) { throw new Error("not an array"); }
return array.map((i) => format.call(this, i));
});
}
// Requires a value which is a value BigNumber
bigNumber(value) {
bigNumber(value: any): bigint {
return getBigInt(value, "value");
}
uint256(value) {
uint256(value: any): bigint {
const result = this.bigNumber(value);
if (result < 0 || result > BN_MAX_UINT256) {
throwArgumentError("invalid uint256", "value", value);
}
return result;
}
// Requires a value which is a value boolean or string equivalent
boolean(value) {
boolean(value: any): boolean {
switch (value) {
case true:
case "true":
case true: case "true":
return true;
case false:
case "false":
case false: case "false":
return false;
}
return throwArgumentError(`invalid boolean; ${JSON.stringify(value)}`, "value", value);
return throwArgumentError(`invalid boolean; ${ JSON.stringify(value) }`, "value", value);
}
// Requires a value which is a valid hexstring. If dataOrLength is true,
// the length must be even (i.e. a datahexstring) or if it is a number,
// specifies teh number of bytes value must represent
_hexstring(dataOrLength) {
if (dataOrLength == null) {
dataOrLength = false;
}
return (function (value) {
_hexstring(dataOrLength?: boolean | number): FormatFunc {
if (dataOrLength == null) { dataOrLength = false; }
return (function(value: any) {
if (isHexString(value, dataOrLength)) {
return value.toLowerCase();
}
throw new Error("bad hexstring");
});
}
data(value) {
data(value: string): string {
if (dataLength(value) == null) {
throwArgumentError("", "value", value);
}
return value;
}
// Requires a network-native hash
hash(value) {
hash(value: any): string {
if (dataLength(value) !== 32) {
throwArgumentError("", "value", value);
}
return this.#format.data(value);
}
// Requires a valid number, within the IEEE 754 safe range
number(value) {
number(value: any): number {
return getNumber(value);
}
// Requires an object which matches a fleet of other formatters
// Any FormatFunc may return `undefined` to have the value omitted
// from the result object. Calls preserve `this`.
object(format, altNames) {
return ((value) => {
const result = {};
object(format: Record<string, FormatFunc>, altNames?: Record<string, Array<string>>): FormatFunc {
return ((value: any) => {
const result: any = { };
for (const key in format) {
let srcKey = key;
if (altNames && key in altNames && !(srcKey in value)) {
@ -365,19 +428,18 @@ export class Formatter {
}
}
}
try {
const nv = format[key].call(this, value[srcKey]);
if (nv !== undefined) {
result[key] = nv;
}
}
catch (error) {
const message = (error instanceof Error) ? error.message : "not-an-error";
throwError(`invalid value for value.${key} (${message})`, "BAD_DATA", { value });
if (nv !== undefined) { result[key] = nv; }
} catch (error) {
const message = (error instanceof Error) ? error.message: "not-an-error";
throwError(`invalid value for value.${ key } (${ message })`, "BAD_DATA", { value })
}
}
return result;
});
}
}
*/
//# sourceMappingURL=formatter.js.map

File diff suppressed because one or more lines are too long

@ -10,14 +10,13 @@ export { getDefaultProvider } from "./default-provider.js";
export { EnsResolver } from "./ens-resolver.js";
*/
export { Formatter } from "./formatter.js";
export { Network } from "./common-networks.js";
export { NetworkPlugin, GasCostPlugin, EnsPlugin,
//LayerOneConnectionPlugin,
//MaxPriorityFeePlugin,
//PriceOraclePlugin,
} from "./plugins-network.js";
export { Block, FeeData, Log, TransactionReceipt, TransactionResponse, dummyProvider, copyRequest,
export { Block, FeeData, Log, TransactionReceipt, TransactionResponse, copyRequest,
//resolveTransactionRequest,
} from "./provider.js";
export { FallbackProvider } from "./provider-fallback.js";
@ -25,6 +24,7 @@ export { JsonRpcApiProvider, JsonRpcProvider, JsonRpcSigner } from "./provider-j
export { AlchemyProvider } from "./provider-alchemy.js";
export { AnkrProvider } from "./provider-ankr.js";
export { CloudflareProvider } from "./provider-cloudflare.js";
export { BaseEtherscanProvider, EtherscanPlugin } from "./provider-etherscan-base.js";
export { EtherscanProvider } from "./provider-etherscan.js";
export { InfuraProvider } from "./provider-infura.js";
//export { PocketProvider } from "./provider-pocket.js";

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src.ts/providers/index.ts"],"names":[],"mappings":"AAGA,KAAK;AAEL,OAAO,EACH,gBAAgB,EAAE,mBAAmB,EACxC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACH,cAAc,EACd,UAAU,EACV,aAAa,EAChB,MAAM,sBAAsB,CAAC;AAC9B;;;;;;;;EAQE;AAEF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EACH,aAAa,EACb,aAAa,EACb,SAAS;AACT,2BAA2B;AAC3B,uBAAuB;AACvB,oBAAoB;EACvB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,KAAK,EACL,OAAO,EACP,GAAG,EACH,kBAAkB,EAClB,mBAAmB,EAEnB,aAAa,EAEb,WAAW;AACX,4BAA4B;EAC/B,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE1F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,wDAAwD;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC,CAAC,YAAY;AACzE,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EACH,gBAAgB,EAAE,qBAAqB,EAAE,uBAAuB,EAChE,qBAAqB,EACxB,MAAM,sBAAsB,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src.ts/providers/index.ts"],"names":[],"mappings":"AAGA,KAAK;AAEL,OAAO,EACH,gBAAgB,EAAE,mBAAmB,EACxC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACH,cAAc,EACd,UAAU,EACV,aAAa,EAChB,MAAM,sBAAsB,CAAC;AAC9B;;;;;;;;EAQE;AAEF,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,EACH,aAAa,EACb,aAAa,EACb,SAAS;AACT,2BAA2B;AAC3B,uBAAuB;AACvB,oBAAoB;EACvB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,KAAK,EACL,OAAO,EACP,GAAG,EACH,kBAAkB,EAClB,mBAAmB,EAEnB,WAAW;AACX,4BAA4B;EAC/B,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAE1F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,wDAAwD;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC,CAAC,YAAY;AACzE,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EACH,gBAAgB,EAAE,qBAAqB,EAAE,uBAAuB,EAChE,qBAAqB,EACxB,MAAM,sBAAsB,CAAC"}

@ -1,5 +1,5 @@
import { accessListify } from "../transaction/index.js";
import { getStore, getBigInt, setStore, throwArgumentError } from "../utils/index.js";
import { Formatter } from "./formatter.js";
import { EnsPlugin, GasCostPlugin } from "./plugins-network.js";
/* * * *
// Networks which operation against an L2 can use this plugin to
@ -52,16 +52,13 @@ export class CcipPreflightPlugin extends NetworkPlugin {
}
*/
const Networks = new Map();
const defaultFormatter = new Formatter();
// @TODO: Add a _ethersNetworkObj variable to better detect network ovjects
export class Network {
#props;
constructor(name, _chainId, formatter) {
constructor(name, _chainId) {
const chainId = getBigInt(_chainId);
if (formatter == null) {
formatter = defaultFormatter;
}
const plugins = new Map();
this.#props = { name, chainId, formatter, plugins };
this.#props = { name, chainId, plugins };
}
toJSON() {
return { name: this.name, chainId: this.chainId };
@ -70,19 +67,14 @@ export class Network {
set name(value) { setStore(this.#props, "name", value); }
get chainId() { return getStore(this.#props, "chainId"); }
set chainId(value) { setStore(this.#props, "chainId", getBigInt(value, "chainId")); }
get formatter() { return getStore(this.#props, "formatter"); }
set formatter(value) { setStore(this.#props, "formatter", value); }
get plugins() {
return Array.from(this.#props.plugins.values());
}
attachPlugin(plugin) {
if (this.isFrozen()) {
throw new Error("frozen");
}
if (this.#props.plugins.get(plugin.name)) {
throw new Error(`cannot replace existing plugin: ${plugin.name} `);
}
this.#props.plugins.set(plugin.name, plugin.validate(this));
this.#props.plugins.set(plugin.name, plugin.clone());
return this;
}
getPlugin(name) {
@ -93,19 +85,22 @@ export class Network {
return (this.plugins.filter((p) => (p.name.split("#")[0] === basename)));
}
clone() {
const clone = new Network(this.name, this.chainId, this.formatter);
const clone = new Network(this.name, this.chainId);
this.plugins.forEach((plugin) => {
clone.attachPlugin(plugin.clone());
});
return clone;
}
freeze() {
/*
freeze(): Frozen<Network> {
Object.freeze(this.#props);
return this;
}
isFrozen() {
isFrozen(): boolean {
return Object.isFrozen(this.#props);
}
*/
computeIntrinsicGas(tx) {
const costs = this.getPlugin("org.ethers.gas-cost") || (new GasCostPlugin());
let gas = costs.txBase;
@ -123,7 +118,7 @@ export class Network {
}
}
if (tx.accessList) {
const accessList = this.formatter.accessList(tx.accessList);
const accessList = accessListify(tx.accessList);
for (const addr in accessList) {
gas += costs.txAccessListAddress + costs.txAccessListStorageKey * accessList[addr].storageKeys.length;
}

File diff suppressed because one or more lines are too long

@ -9,9 +9,6 @@ export class NetworkPlugin {
clone() {
return new NetworkPlugin(this.name);
}
validate(network) {
return this;
}
}
export class GasCostPlugin extends NetworkPlugin {
effectiveBlock;
@ -63,10 +60,6 @@ export class EnsPlugin extends NetworkPlugin {
clone() {
return new EnsPlugin(this.address, this.targetNetwork);
}
validate(network) {
network.formatter.address(this.address);
return this;
}
}
/*
export class MaxPriorityFeePlugin extends NetworkPlugin {
@ -102,4 +95,22 @@ export class FeeDataNetworkPlugin extends NetworkPlugin {
return new FeeDataNetworkPlugin(this.#feeDataFunc);
}
}
export class CustomBlockNetworkPlugin extends NetworkPlugin {
#blockFunc;
#blockWithTxsFunc;
constructor(blockFunc, blockWithTxsFunc) {
super("org.ethers.network-plugins.custom-block");
this.#blockFunc = blockFunc;
this.#blockWithTxsFunc = blockWithTxsFunc;
}
async getBlock(provider, block) {
return await this.#blockFunc(provider, block);
}
async getBlockWithTransactions(provider, block) {
return await this.#blockWithTxsFunc(provider, block);
}
clone() {
return new CustomBlockNetworkPlugin(this.#blockFunc, this.#blockWithTxsFunc);
}
}
//# sourceMappingURL=plugins-network.js.map

@ -1 +1 @@
{"version":3,"file":"plugins-network.js","sourceRoot":"","sources":["../../src.ts/providers/plugins-network.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"plugins-network.js","sourceRoot":"","sources":["../../src.ts/providers/plugins-network.ts"],"names":[],"mappings":"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"}

@ -0,0 +1,427 @@
import { accessListify } from "../transaction/index.js";
import { defineProperties, hexlify, toQuantity, FetchRequest, throwArgumentError, throwError, toUtf8String } from "../utils/index.js";
import { AbstractProvider } from "./abstract-provider.js";
import { Network } from "./network.js";
import { NetworkPlugin } from "./plugins-network.js";
import { showThrottleMessage } from "./community.js";
const THROTTLE = 2000;
const EtherscanPluginId = "org.ethers.plugins.etherscan";
export class EtherscanPlugin extends NetworkPlugin {
baseUrl;
communityApiKey;
constructor(baseUrl, communityApiKey) {
super(EtherscanPluginId);
//if (communityApiKey == null) { communityApiKey = null; }
defineProperties(this, { baseUrl, communityApiKey });
}
clone() {
return new EtherscanPlugin(this.baseUrl, this.communityApiKey);
}
}
let nextId = 1;
export class BaseEtherscanProvider extends AbstractProvider {
network;
apiKey;
#plugin;
constructor(_network, apiKey) {
super();
const network = Network.from(_network);
this.#plugin = network.getPlugin(EtherscanPluginId);
if (apiKey == null && this.#plugin) {
apiKey = this.#plugin.communityApiKey;
}
defineProperties(this, { apiKey, network });
// Test that the network is supported by Etherscan
this.getBaseUrl();
}
getBaseUrl() {
if (this.#plugin) {
return this.#plugin.baseUrl;
}
switch (this.network.name) {
case "homestead":
return "https:/\/api.etherscan.io";
case "ropsten":
return "https:/\/api-ropsten.etherscan.io";
case "rinkeby":
return "https:/\/api-rinkeby.etherscan.io";
case "kovan":
return "https:/\/api-kovan.etherscan.io";
case "goerli":
return "https:/\/api-goerli.etherscan.io";
default:
}
return throwArgumentError("unsupported network", "network", this.network);
}
getUrl(module, params) {
const query = Object.keys(params).reduce((accum, key) => {
const value = params[key];
if (value != null) {
accum += `&${key}=${value}`;
}
return accum;
}, "");
const apiKey = ((this.apiKey) ? `&apikey=${this.apiKey}` : "");
return `${this.getBaseUrl()}/api?module=${module}${query}${apiKey}`;
}
getPostUrl() {
return `${this.getBaseUrl()}/api`;
}
getPostData(module, params) {
params.module = module;
params.apikey = this.apiKey;
return params;
}
async detectNetwork() {
return this.network;
}
async fetch(module, params, post) {
const id = nextId++;
const url = (post ? this.getPostUrl() : this.getUrl(module, params));
const payload = (post ? this.getPostData(module, params) : null);
this.emit("debug", { action: "sendRequest", id, url, payload: payload });
const request = new FetchRequest(url);
request.setThrottleParams({ slotInterval: 1000 });
request.retryFunc = (req, resp, attempt) => {
if (this.isCommunityResource()) {
showThrottleMessage("Etherscan");
}
return Promise.resolve(true);
};
request.processFunc = async (request, response) => {
const result = response.hasBody() ? JSON.parse(toUtf8String(response.body)) : {};
const throttle = ((typeof (result.result) === "string") ? result.result : "").toLowerCase().indexOf("rate limit") >= 0;
if (module === "proxy") {
// This JSON response indicates we are being throttled
if (result && result.status == 0 && result.message == "NOTOK" && throttle) {
this.emit("debug", { action: "receiveError", id, reason: "proxy-NOTOK", error: result });
response.throwThrottleError(result.result, THROTTLE);
}
}
else {
if (throttle) {
this.emit("debug", { action: "receiveError", id, reason: "null result", error: result.result });
response.throwThrottleError(result.result, THROTTLE);
}
}
return response;
};
if (payload) {
request.setHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
request.body = Object.keys(payload).map((k) => `${k}=${payload[k]}`).join("&");
}
const response = await request.send();
try {
response.assertOk();
}
catch (error) {
this.emit("debug", { action: "receiveError", id, error, reason: "assertOk" });
}
if (!response.hasBody()) {
this.emit("debug", { action: "receiveError", id, error: "missing body", reason: "null body" });
throw new Error();
}
const result = JSON.parse(toUtf8String(response.body));
if (module === "proxy") {
if (result.jsonrpc != "2.0") {
this.emit("debug", { action: "receiveError", id, result, reason: "invalid JSON-RPC" });
const error = new Error("invalid response");
error.result = JSON.stringify(result);
throw error;
}
if (result.error) {
this.emit("debug", { action: "receiveError", id, result, reason: "JSON-RPC error" });
const error = new Error(result.error.message || "unknown error");
if (result.error.code) {
error.code = result.error.code;
}
if (result.error.data) {
error.data = result.error.data;
}
throw error;
}
this.emit("debug", { action: "receiveRequest", id, result });
return result.result;
}
else {
// getLogs, getHistory have weird success responses
if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
this.emit("debug", { action: "receiveRequest", id, result });
return result.result;
}
if (result.status != 1 || (typeof (result.message) === "string" && !result.message.match(/^OK/))) {
this.emit("debug", { action: "receiveError", id, result });
const error = new Error("invalid response");
error.result = JSON.stringify(result);
// if ((result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
// error.throttleRetry = true;
// }
throw error;
}
this.emit("debug", { action: "receiveRequest", id, result });
return result.result;
}
}
// The transaction has already been sanitized by the calls in Provider
_getTransactionPostData(transaction) {
const result = {};
for (let key in transaction) {
if (transaction[key] == null) {
continue;
}
let value = transaction[key];
if (key === "type" && value === 0) {
continue;
}
// Quantity-types require no leading zero, unless 0
if ({ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true }[key]) {
value = toQuantity(hexlify(value));
}
else if (key === "accessList") {
value = "[" + accessListify(value).map((set) => {
return `{address:"${set.address}",storageKeys:["${set.storageKeys.join('","')}"]}`;
}).join(",") + "]";
}
else {
value = hexlify(value);
}
result[key] = value;
}
return result;
}
_checkError(req, error, transaction) {
/*
let body = "";
if (isError(error, Logger.Errors.SERVER_ERROR) && error.response && error.response.hasBody()) {
body = toUtf8String(error.response.body);
}
console.log(body);
// Undo the "convenience" some nodes are attempting to prevent backwards
// incompatibility; maybe for v6 consider forwarding reverts as errors
if (method === "call" && body) {
// Etherscan keeps changing their string
if (body.match(/reverted/i) || body.match(/VM execution error/i)) {
// Etherscan prefixes the data like "Reverted 0x1234"
let data = e.data;
if (data) { data = "0x" + data.replace(/^.*0x/i, ""); }
if (!isHexString(data)) { data = "0x"; }
logger.throwError("call exception", Logger.Errors.CALL_EXCEPTION, {
error, data
});
}
}
// Get the message from any nested error structure
let message = error.message;
if (isError(error, Logger.Errors.SERVER_ERROR)) {
if (error.error && typeof(error.error.message) === "string") {
message = error.error.message;
} else if (typeof(error.body) === "string") {
message = error.body;
} else if (typeof(error.responseText) === "string") {
message = error.responseText;
}
}
message = (message || "").toLowerCase();
// "Insufficient funds. The account you tried to send transaction from
// does not have enough funds. Required 21464000000000 and got: 0"
if (message.match(/insufficient funds/)) {
logger.throwError("insufficient funds for intrinsic transaction cost", Logger.Errors.INSUFFICIENT_FUNDS, {
error, transaction, info: { method }
});
}
// "Transaction with the same hash was already imported."
if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
logger.throwError("nonce has already been used", Logger.Errors.NONCE_EXPIRED, {
error, transaction, info: { method }
});
}
// "Transaction gas price is too low. There is another transaction with
// same nonce in the queue. Try increasing the gas price or incrementing the nonce."
if (message.match(/another transaction with same nonce/)) {
logger.throwError("replacement fee too low", Logger.Errors.REPLACEMENT_UNDERPRICED, {
error, transaction, info: { method }
});
}
if (message.match(/execution failed due to an exception|execution reverted/)) {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.Errors.UNPREDICTABLE_GAS_LIMIT, {
error, transaction, info: { method }
});
}
*/
throw error;
}
async _detectNetwork() {
return this.network;
}
async _perform(req) {
switch (req.method) {
case "chainId":
return this.network.chainId;
case "getBlockNumber":
return this.fetch("proxy", { action: "eth_blockNumber" });
case "getGasPrice":
return this.fetch("proxy", { action: "eth_gasPrice" });
case "getBalance":
// Returns base-10 result
return this.fetch("account", {
action: "balance",
address: req.address,
tag: req.blockTag
});
case "getTransactionCount":
return this.fetch("proxy", {
action: "eth_getTransactionCount",
address: req.address,
tag: req.blockTag
});
case "getCode":
return this.fetch("proxy", {
action: "eth_getCode",
address: req.address,
tag: req.blockTag
});
case "getStorageAt":
return this.fetch("proxy", {
action: "eth_getStorageAt",
address: req.address,
position: req.position,
tag: req.blockTag
});
case "broadcastTransaction":
return this.fetch("proxy", {
action: "eth_sendRawTransaction",
hex: req.signedTransaction
}, true).catch((error) => {
return this._checkError(req, error, req.signedTransaction);
});
case "getBlock":
if ("blockTag" in req) {
return this.fetch("proxy", {
action: "eth_getBlockByNumber",
tag: req.blockTag,
boolean: (req.includeTransactions ? "true" : "false")
});
}
return throwError("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
operation: "getBlock(blockHash)"
});
case "getTransaction":
return this.fetch("proxy", {
action: "eth_getTransactionByHash",
txhash: req.hash
});
case "getTransactionReceipt":
return this.fetch("proxy", {
action: "eth_getTransactionReceipt",
txhash: req.hash
});
case "call": {
if (req.blockTag !== "latest") {
throw new Error("EtherscanProvider does not support blockTag for call");
}
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_call";
try {
return await this.fetch("proxy", postData, true);
}
catch (error) {
return this._checkError(req, error, req.transaction);
}
}
case "estimateGas": {
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_estimateGas";
try {
return await this.fetch("proxy", postData, true);
}
catch (error) {
return this._checkError(req, error, req.transaction);
}
}
/*
case "getLogs": {
// Needs to complain if more than one address is passed in
const args: Record<string, any> = { action: "getLogs" }
if (params.filter.fromBlock) {
args.fromBlock = checkLogTag(params.filter.fromBlock);
}
if (params.filter.toBlock) {
args.toBlock = checkLogTag(params.filter.toBlock);
}
if (params.filter.address) {
args.address = params.filter.address;
}
// @TODO: We can handle slightly more complicated logs using the logs API
if (params.filter.topics && params.filter.topics.length > 0) {
if (params.filter.topics.length > 1) {
logger.throwError("unsupported topic count", Logger.Errors.UNSUPPORTED_OPERATION, { topics: params.filter.topics });
}
if (params.filter.topics.length === 1) {
const topic0 = params.filter.topics[0];
if (typeof(topic0) !== "string" || topic0.length !== 66) {
logger.throwError("unsupported topic format", Logger.Errors.UNSUPPORTED_OPERATION, { topic0: topic0 });
}
args.topic0 = topic0;
}
}
const logs: Array<any> = await this.fetch("logs", args);
// Cache txHash => blockHash
let blocks: { [tag: string]: string } = {};
// Add any missing blockHash to the logs
for (let i = 0; i < logs.length; i++) {
const log = logs[i];
if (log.blockHash != null) { continue; }
if (blocks[log.blockNumber] == null) {
const block = await this.getBlock(log.blockNumber);
if (block) {
blocks[log.blockNumber] = block.hash;
}
}
log.blockHash = blocks[log.blockNumber];
}
return logs;
}
*/
default:
break;
}
return super._perform(req);
}
async getNetwork() {
return this.network;
}
async getEtherPrice() {
if (this.network.name !== "homestead") {
return 0.0;
}
return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd);
}
isCommunityResource() {
const plugin = this.network.getPlugin(EtherscanPluginId);
if (plugin) {
return (plugin.communityApiKey === this.apiKey);
}
return (this.apiKey == null);
}
}
//# sourceMappingURL=provider-etherscan-base.js.map

File diff suppressed because one or more lines are too long

@ -1,454 +1,22 @@
import { defineProperties, hexlify, toQuantity, FetchRequest, throwArgumentError, throwError, toUtf8String } from "../utils/index.js";
import { AbstractProvider } from "./abstract-provider.js";
import { Network } from "./network.js";
import { NetworkPlugin } from "./plugins-network.js";
const defaultApiKey = "9D13ZE7XSBTJ94N9BNJ2MA33VMAY2YPIRB";
const EtherscanPluginId = "org.ethers.plugins.etherscan";
export class EtherscanPlugin extends NetworkPlugin {
baseUrl;
communityApiKey;
constructor(baseUrl, communityApiKey) {
super(EtherscanPluginId);
//if (communityApiKey == null) { communityApiKey = null; }
defineProperties(this, { baseUrl, communityApiKey });
}
clone() {
return new EtherscanPlugin(this.baseUrl, this.communityApiKey);
}
import { BaseEtherscanProvider } from "./provider-etherscan-base.js";
import { Contract } from "../contract/index.js";
function isPromise(value) {
return (value && typeof (value.then) === "function");
}
export class EtherscanProvider extends AbstractProvider {
network;
apiKey;
constructor(_network, apiKey) {
super();
const network = Network.from(_network);
if (apiKey == null) {
const plugin = network.getPlugin(EtherscanPluginId);
if (plugin) {
apiKey = plugin.communityApiKey;
export class EtherscanProvider extends BaseEtherscanProvider {
async getContract(_address) {
let address = this._getAddress(_address);
if (isPromise(address)) {
address = await address;
}
else {
apiKey = defaultApiKey;
}
}
defineProperties(this, { apiKey, network });
// Test that the network is supported by Etherscan
this.getBaseUrl();
}
getBaseUrl() {
const plugin = this.network.getPlugin(EtherscanPluginId);
if (plugin) {
return plugin.baseUrl;
}
switch (this.network.name) {
case "homestead":
return "https:/\/api.etherscan.io";
case "ropsten":
return "https:/\/api-ropsten.etherscan.io";
case "rinkeby":
return "https:/\/api-rinkeby.etherscan.io";
case "kovan":
return "https:/\/api-kovan.etherscan.io";
case "goerli":
return "https:/\/api-goerli.etherscan.io";
default:
}
return throwArgumentError("unsupported network", "network", this.network);
}
getUrl(module, params) {
const query = Object.keys(params).reduce((accum, key) => {
const value = params[key];
if (value != null) {
accum += `&${key}=${value}`;
}
return accum;
}, "");
const apiKey = ((this.apiKey) ? `&apikey=${this.apiKey}` : "");
return `${this.getBaseUrl()}/api?module=${module}${query}${apiKey}`;
}
getPostUrl() {
return `${this.getBaseUrl()}/api`;
}
getPostData(module, params) {
params.module = module;
params.apikey = this.apiKey;
return params;
}
async detectNetwork() {
return this.network;
}
async fetch(module, params, post) {
const url = (post ? this.getPostUrl() : this.getUrl(module, params));
const payload = (post ? this.getPostData(module, params) : null);
/*
this.emit("debug", {
action: "request",
request: url,
provider: this
});
*/
const request = new FetchRequest(url);
request.processFunc = async (request, response) => {
const result = response.hasBody() ? JSON.parse(toUtf8String(response.body)) : {};
const throttle = ((typeof (result.result) === "string") ? result.result : "").toLowerCase().indexOf("rate limit") >= 0;
if (module === "proxy") {
// This JSON response indicates we are being throttled
if (result && result.status == 0 && result.message == "NOTOK" && throttle) {
response.throwThrottleError(result.result);
}
}
else {
if (throttle) {
response.throwThrottleError(result.result);
}
}
return response;
};
// @TODO:
//throttleSlotInterval: 1000,
if (payload) {
request.setHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
request.body = Object.keys(payload).map((k) => `${k}=${payload[k]}`).join("&");
}
const response = await request.send();
response.assertOk();
if (!response.hasBody()) {
throw new Error();
}
/*
this.emit("debug", {
action: "response",
request: url,
response: deepCopy(result),
provider: this
});
*/
const result = JSON.parse(toUtf8String(response.body));
if (module === "proxy") {
if (result.jsonrpc != "2.0") {
// @TODO: not any
const error = new Error("invalid response");
error.result = JSON.stringify(result);
throw error;
}
if (result.error) {
// @TODO: not any
const error = new Error(result.error.message || "unknown error");
if (result.error.code) {
error.code = result.error.code;
}
if (result.error.data) {
error.data = result.error.data;
}
throw error;
}
return result.result;
}
else {
// getLogs, getHistory have weird success responses
if (result.status == 0 && (result.message === "No records found" || result.message === "No transactions found")) {
return result.result;
}
if (result.status != 1 || result.message != "OK") {
const error = new Error("invalid response");
error.result = JSON.stringify(result);
// if ((result.result || "").toLowerCase().indexOf("rate limit") >= 0) {
// error.throttleRetry = true;
// }
throw error;
}
return result.result;
}
}
// The transaction has already been sanitized by the calls in Provider
_getTransactionPostData(transaction) {
const result = {};
for (let key in transaction) {
if (transaction[key] == null) {
continue;
}
let value = transaction[key];
if (key === "type" && value === 0) {
continue;
}
// Quantity-types require no leading zero, unless 0
if ({ type: true, gasLimit: true, gasPrice: true, maxFeePerGs: true, maxPriorityFeePerGas: true, nonce: true, value: true }[key]) {
value = toQuantity(hexlify(value));
}
else if (key === "accessList") {
value = "[" + this.network.formatter.accessList(value).map((set) => {
return `{address:"${set.address}",storageKeys:["${set.storageKeys.join('","')}"]}`;
}).join(",") + "]";
}
else {
value = hexlify(value);
}
result[key] = value;
}
return result;
}
_checkError(req, error, transaction) {
/*
let body = "";
if (isError(error, Logger.Errors.SERVER_ERROR) && error.response && error.response.hasBody()) {
body = toUtf8String(error.response.body);
}
console.log(body);
// Undo the "convenience" some nodes are attempting to prevent backwards
// incompatibility; maybe for v6 consider forwarding reverts as errors
if (method === "call" && body) {
// Etherscan keeps changing their string
if (body.match(/reverted/i) || body.match(/VM execution error/i)) {
// Etherscan prefixes the data like "Reverted 0x1234"
let data = e.data;
if (data) { data = "0x" + data.replace(/^.*0x/i, ""); }
if (!isHexString(data)) { data = "0x"; }
logger.throwError("call exception", Logger.Errors.CALL_EXCEPTION, {
error, data
});
}
}
// Get the message from any nested error structure
let message = error.message;
if (isError(error, Logger.Errors.SERVER_ERROR)) {
if (error.error && typeof(error.error.message) === "string") {
message = error.error.message;
} else if (typeof(error.body) === "string") {
message = error.body;
} else if (typeof(error.responseText) === "string") {
message = error.responseText;
}
}
message = (message || "").toLowerCase();
// "Insufficient funds. The account you tried to send transaction from
// does not have enough funds. Required 21464000000000 and got: 0"
if (message.match(/insufficient funds/)) {
logger.throwError("insufficient funds for intrinsic transaction cost", Logger.Errors.INSUFFICIENT_FUNDS, {
error, transaction, info: { method }
});
}
// "Transaction with the same hash was already imported."
if (message.match(/same hash was already imported|transaction nonce is too low|nonce too low/)) {
logger.throwError("nonce has already been used", Logger.Errors.NONCE_EXPIRED, {
error, transaction, info: { method }
});
}
// "Transaction gas price is too low. There is another transaction with
// same nonce in the queue. Try increasing the gas price or incrementing the nonce."
if (message.match(/another transaction with same nonce/)) {
logger.throwError("replacement fee too low", Logger.Errors.REPLACEMENT_UNDERPRICED, {
error, transaction, info: { method }
});
}
if (message.match(/execution failed due to an exception|execution reverted/)) {
logger.throwError("cannot estimate gas; transaction may fail or may require manual gas limit", Logger.Errors.UNPREDICTABLE_GAS_LIMIT, {
error, transaction, info: { method }
});
}
*/
throw error;
}
async _detectNetwork() {
return this.network;
}
async _perform(req) {
switch (req.method) {
case "chainId":
return this.network.chainId;
case "getBlockNumber":
return this.fetch("proxy", { action: "eth_blockNumber" });
case "getGasPrice":
return this.fetch("proxy", { action: "eth_gasPrice" });
case "getBalance":
// Returns base-10 result
return this.fetch("account", {
action: "balance",
address: req.address,
tag: req.blockTag
});
case "getTransactionCount":
return this.fetch("proxy", {
action: "eth_getTransactionCount",
address: req.address,
tag: req.blockTag
});
case "getCode":
return this.fetch("proxy", {
action: "eth_getCode",
address: req.address,
tag: req.blockTag
});
case "getStorageAt":
return this.fetch("proxy", {
action: "eth_getStorageAt",
address: req.address,
position: req.position,
tag: req.blockTag
});
case "broadcastTransaction":
return this.fetch("proxy", {
action: "eth_sendRawTransaction",
hex: req.signedTransaction
}, true).catch((error) => {
return this._checkError(req, error, req.signedTransaction);
});
case "getBlock":
if ("blockTag" in req) {
return this.fetch("proxy", {
action: "eth_getBlockByNumber",
tag: req.blockTag,
boolean: (req.includeTransactions ? "true" : "false")
});
}
return throwError("getBlock by blockHash not supported by Etherscan", "UNSUPPORTED_OPERATION", {
operation: "getBlock(blockHash)"
});
case "getTransaction":
return this.fetch("proxy", {
action: "eth_getTransactionByHash",
txhash: req.hash
});
case "getTransactionReceipt":
return this.fetch("proxy", {
action: "eth_getTransactionReceipt",
txhash: req.hash
});
case "call": {
if (req.blockTag !== "latest") {
throw new Error("EtherscanProvider does not support blockTag for call");
}
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_call";
try {
return await this.fetch("proxy", postData, true);
const resp = await this.fetch("contract", { action: "getabi", address });
const abi = JSON.parse(resp);
return new Contract(address, abi, this);
}
catch (error) {
return this._checkError(req, error, req.transaction);
return null;
}
}
case "estimateGas": {
const postData = this._getTransactionPostData(req.transaction);
postData.module = "proxy";
postData.action = "eth_estimateGas";
try {
return await this.fetch("proxy", postData, true);
}
catch (error) {
return this._checkError(req, error, req.transaction);
}
}
/*
case "getLogs": {
// Needs to complain if more than one address is passed in
const args: Record<string, any> = { action: "getLogs" }
if (params.filter.fromBlock) {
args.fromBlock = checkLogTag(params.filter.fromBlock);
}
if (params.filter.toBlock) {
args.toBlock = checkLogTag(params.filter.toBlock);
}
if (params.filter.address) {
args.address = params.filter.address;
}
// @TODO: We can handle slightly more complicated logs using the logs API
if (params.filter.topics && params.filter.topics.length > 0) {
if (params.filter.topics.length > 1) {
logger.throwError("unsupported topic count", Logger.Errors.UNSUPPORTED_OPERATION, { topics: params.filter.topics });
}
if (params.filter.topics.length === 1) {
const topic0 = params.filter.topics[0];
if (typeof(topic0) !== "string" || topic0.length !== 66) {
logger.throwError("unsupported topic format", Logger.Errors.UNSUPPORTED_OPERATION, { topic0: topic0 });
}
args.topic0 = topic0;
}
}
const logs: Array<any> = await this.fetch("logs", args);
// Cache txHash => blockHash
let blocks: { [tag: string]: string } = {};
// Add any missing blockHash to the logs
for (let i = 0; i < logs.length; i++) {
const log = logs[i];
if (log.blockHash != null) { continue; }
if (blocks[log.blockNumber] == null) {
const block = await this.getBlock(log.blockNumber);
if (block) {
blocks[log.blockNumber] = block.hash;
}
}
log.blockHash = blocks[log.blockNumber];
}
return logs;
}
*/
default:
break;
}
return super._perform(req);
}
async getNetwork() {
return this.network;
}
async getEtherPrice() {
if (this.network.name !== "homestead") {
return 0.0;
}
return parseFloat((await this.fetch("stats", { action: "ethprice" })).ethusd);
}
isCommunityResource() {
const plugin = this.network.getPlugin(EtherscanPluginId);
if (plugin) {
return (plugin.communityApiKey === this.apiKey);
}
return (defaultApiKey === this.apiKey);
}
}
/*
(async function() {
const provider = new EtherscanProvider();
console.log(provider);
console.log(await provider.getBlockNumber());
/ *
provider.on("block", (b) => {
console.log("BB", b);
});
console.log(await provider.getTransactionReceipt("0xa5ded92f548e9f362192f9ab7e5b3fbc9b5a919a868e29247f177d49ce38de6e"));
provider.once("0xa5ded92f548e9f362192f9ab7e5b3fbc9b5a919a868e29247f177d49ce38de6e", (tx) => {
console.log("TT", tx);
});
* /
try {
console.log(await provider.getBlock(100));
} catch (error) {
console.log(error);
}
try {
console.log(await provider.getBlock(13821768));
} catch (error) {
console.log(error);
}
})();
*/
//# sourceMappingURL=provider-etherscan.js.map

File diff suppressed because one or more lines are too long

@ -1,5 +1,6 @@
import { getBigInt, getNumber, hexlify, throwError, throwArgumentError } from "../utils/index.js";
import { AbstractProvider } from "./abstract-provider.js";
import { formatBlock, formatBlockWithTransactions, formatLog, formatTransactionReceipt, formatTransactionResponse } from "./format.js";
import { Network } from "./network.js";
//const BN_0 = BigInt("0");
const BN_1 = BigInt("1");
@ -40,7 +41,7 @@ async function waitForSync(config, blockNumber) {
}
// Normalizes a result to a string that can be used to compare against
// other results using normal string equality
function normalize(network, value, req) {
function normalize(provider, value, req) {
switch (req.method) {
case "chainId":
return getBigInt(value).toString();
@ -58,19 +59,19 @@ function normalize(network, value, req) {
return hexlify(value);
case "getBlock":
if (req.includeTransactions) {
return JSON.stringify(network.formatter.blockWithTransactions(value));
return JSON.stringify(formatBlockWithTransactions(value));
}
return JSON.stringify(network.formatter.block(value));
return JSON.stringify(formatBlock(value));
case "getTransaction":
return JSON.stringify(network.formatter.transactionResponse(value));
return JSON.stringify(formatTransactionResponse(value));
case "getTransactionReceipt":
return JSON.stringify(network.formatter.receipt(value));
return JSON.stringify(formatTransactionReceipt(value));
case "call":
return hexlify(value);
case "estimateGas":
return getBigInt(value).toString();
case "getLogs":
return JSON.stringify(value.map((v) => network.formatter.log(v)));
return JSON.stringify(value.map((v) => formatLog(v)));
}
return throwError("unsupported method", "UNSUPPORTED_OPERATION", {
operation: `_perform(${JSON.stringify(req.method)})`
@ -174,7 +175,7 @@ export class FallbackProvider extends AbstractProvider {
return this.#configs.slice();
}
async _detectNetwork() {
return Network.from(getBigInt(await this._perform({ method: "chainId" }))).freeze();
return Network.from(getBigInt(await this._perform({ method: "chainId" })));
}
// @TODO: Add support to select providers to be the event subscriber
//_getSubscriber(sub: Subscription): Subscriber {
@ -269,7 +270,7 @@ export class FallbackProvider extends AbstractProvider {
const result = runner.result.result;
results.push({
result,
normal: normalize((runner.config._network), result, req),
normal: normalize(runner.config.provider, result, req),
weight: runner.config.weight
});
}

File diff suppressed because one or more lines are too long

@ -21,7 +21,15 @@ export class IpcSocketProvider extends SocketProvider {
constructor(path, network) {
super(network);
this.#socket = connect(path);
this.socket.on("ready", () => { this._start(); });
this.socket.on("ready", async () => {
try {
await this._start();
}
catch (error) {
console.log("failed to start IpcSocketProvider", error);
// @TODO: Now what? Restart?
}
});
let response = Buffer.alloc(0);
this.socket.on("data", (data) => {
response = Buffer.concat([response, data]);

@ -1 +1 @@
{"version":3,"file":"provider-ipcsocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-ipcsocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAMtD,yEAAyE;AACzE,0CAA0C;AAC1C,SAAS,WAAW,CAAC,IAAY;IAC7B,MAAM,QAAQ,GAAkB,EAAG,CAAC;IAEpC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,IAAI,EAAE;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE;YAAE,MAAM;SAAE;QACzB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC;KACtB;IAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,OAAO,iBAAkB,SAAQ,cAAc;IACjD,OAAO,CAAS;IAChB,IAAI,MAAM,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAE7C,YAAY,IAAY,EAAE,OAAoB;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAElD,IAAI,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5B,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAE,QAAQ,EAAE,IAAI,CAAE,CAAC,CAAC;YAC7C,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACtD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACzB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;YACH,QAAQ,GAAG,SAAS,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,IAAI;QACA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;CACJ;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCE"}
{"version":3,"file":"provider-ipcsocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-ipcsocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAMtD,yEAAyE;AACzE,0CAA0C;AAC1C,SAAS,WAAW,CAAC,IAAY;IAC7B,MAAM,QAAQ,GAAkB,EAAG,CAAC;IAEpC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,IAAI,EAAE;QACT,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE;YAAE,MAAM;SAAE;QACzB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9D,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC;KACtB;IAED,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,OAAO,iBAAkB,SAAQ,cAAc;IACjD,OAAO,CAAS;IAChB,IAAI,MAAM,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAE7C,YAAY,IAAY,EAAE,OAAoB;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;YAC/B,IAAI;gBACA,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;aACvB;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;gBACxD,4BAA4B;aAC/B;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5B,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAE,QAAQ,EAAE,IAAI,CAAE,CAAC,CAAC;YAC7C,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YACtD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBACzB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;YACH,QAAQ,GAAG,SAAS,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,IAAI;QACA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;CACJ;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoCE"}

@ -1,10 +1,10 @@
// @TODO:
// - Add the batching API
// https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
import { resolveAddress } from "../address/index.js";
import { getAddress, resolveAddress } from "../address/index.js";
import { TypedDataEncoder } from "../hash/index.js";
import { accessListify } from "../transaction/index.js";
import { defineProperties, getBigInt, hexlify, isHexString, toQuantity, toUtf8Bytes, makeError, throwArgumentError, throwError, FetchRequest } from "../utils/index.js";
import { defineProperties, getBigInt, hexlify, isHexString, toQuantity, toUtf8Bytes, makeError, throwArgumentError, throwError, FetchRequest, resolveProperties } from "../utils/index.js";
import { AbstractProvider, UnmanagedSubscriber } from "./abstract-provider.js";
import { AbstractSigner } from "./abstract-signer.js";
import { Network } from "./network.js";
@ -30,6 +30,9 @@ function deepCopy(value) {
}
throw new Error(`should not happen: ${value} (${typeof (value)})`);
}
function stall(duration) {
return new Promise((resolve) => { setTimeout(resolve, duration); });
}
function getLowerCase(value) {
if (value) {
return value.toLowerCase();
@ -120,7 +123,7 @@ export class JsonRpcSigner extends AbstractSigner {
// Try getting the transaction
const tx = await this.provider.getTransaction(hash);
if (tx != null) {
resolve(this.provider._wrapTransaction(tx, hash, blockNumber));
resolve(tx.replaceableTransaction(blockNumber));
return;
}
// Wait another 4 seconds
@ -184,23 +187,36 @@ export class JsonRpcSigner extends AbstractSigner {
* sub-classed.
*
* It provides the base for all JSON-RPC-based Provider interaction.
*
* Sub-classing Notes:
* - a sub-class MUST override _send
* - a sub-class MUST call the `_start()` method once connected
*/
export class JsonRpcApiProvider extends AbstractProvider {
#options;
#nextId;
#payloads;
#ready;
#starting;
#drainTimer;
#network;
constructor(network, options) {
super(network);
this.#ready = false;
this.#starting = null;
this.#nextId = 1;
this.#options = Object.assign({}, defaultOptions, options || {});
this.#payloads = [];
this.#drainTimer = null;
this.#network = null;
// This could be relaxed in the future to just check equivalent networks
const staticNetwork = this._getOption("staticNetwork");
if (staticNetwork && staticNetwork !== network) {
if (staticNetwork) {
if (staticNetwork !== network) {
throwArgumentError("staticNetwork MUST match network object", "options", options);
}
this.#network = staticNetwork;
}
}
/**
* Returns the value associated with the option %%key%%.
@ -210,8 +226,40 @@ export class JsonRpcApiProvider extends AbstractProvider {
_getOption(key) {
return this.#options[key];
}
get _network() {
if (!this.#network) {
throwError("network is not available yet", "NETWORK_ERROR");
}
return this.#network;
}
get ready() { return this.#ready; }
async _start() {
if (this.#ready) {
return;
}
if (this.#starting) {
return this.#starting;
}
this.#starting = (async () => {
// Bootstrap the network
if (this.#network == null) {
try {
this.#network = await this._detectNetwork();
}
catch (error) {
console.log("JsonRpcProvider failed to startup; retry in 1s");
await stall(1000);
this.#starting = null;
}
}
this.#ready = true;
this.#starting = null;
// Start dispatching requests
this.#scheduleDrain();
})();
}
#scheduleDrain() {
if (this.#drainTimer) {
if (this.#drainTimer || !this.ready) {
return;
}
// If we aren't using batching, no hard in sending it immeidately
@ -268,7 +316,6 @@ export class JsonRpcApiProvider extends AbstractProvider {
}
}, stallTime);
}
// Sub-classes should **NOT** override this
/**
* Requests the %%method%% with %%params%% via the JSON-RPC protocol
* over the underlying channel. This can be used to call methods
@ -327,25 +374,44 @@ export class JsonRpcApiProvider extends AbstractProvider {
}
return new JsonRpcSigner(this, accounts[address]);
}
const [network, accounts] = await Promise.all([this.getNetwork(), accountsPromise]);
const { accounts } = await resolveProperties({
network: this.getNetwork(),
accounts: accountsPromise
});
// Account address
address = network.formatter.address(address);
address = getAddress(address);
for (const account of accounts) {
if (network.formatter.address(account) === account) {
if (getAddress(account) === account) {
return new JsonRpcSigner(this, account);
}
}
throw new Error("invalid account");
}
// Sub-classes can override this; it detects the *actual* network we
// are connected to
/** Sub-classes can override this; it detects the *actual* network that
* we are **currently** connected to.
*
* Keep in mind that [[send]] may only be used once [[ready]].
*/
async _detectNetwork() {
// We have a static network (like INFURA)
const network = this._getOption("staticNetwork");
if (network) {
return network;
}
return Network.from(getBigInt(await this._perform({ method: "chainId" })));
// If we are ready, use ``send``, which enabled requests to be batched
if (this.ready) {
return Network.from(getBigInt(await this.send("eth_chainId", [])));
}
// We are not ready yet; use the primitive _send
const payload = {
id: this.#nextId++, method: "eth_chainId", params: [], jsonrpc: "2.0"
};
this.emit("debug", { action: "sendRpcPayload", payload });
const result = (await this._send(payload))[0];
this.emit("debug", { action: "receiveRpcResult", result });
if ("result" in result) {
return Network.from(getBigInt(result.result));
}
throw this.getRpcError(payload, result);
}
/**
* Return a Subscriber that will manage the %%sub%%.
@ -597,6 +663,13 @@ export class JsonRpcProvider extends JsonRpcApiProvider {
}
this.#pollingInterval = 4000;
}
async send(method, params) {
// All requests are over HTTP, so we can just start handling requests
// We do this here rather than the constructor so that we don't send any
// requests to the network until we absolutely have to.
await this._start();
return await super.send(method, params);
}
async _send(payload) {
// Configure a POST connection for the requested method
const request = this.#connect.clone();

File diff suppressed because one or more lines are too long

@ -95,20 +95,16 @@ export class SocketPendingSubscriber extends SocketSubscriber {
export class SocketEventSubscriber extends SocketSubscriber {
#logFilter;
get logFilter() { return JSON.parse(this.#logFilter); }
#formatter;
constructor(provider, filter) {
super(provider, ["logs", filter]);
this.#logFilter = JSON.stringify(filter);
this.#formatter = provider.getNetwork().then((network) => network.formatter);
}
async _emit(provider, message) {
const formatter = await this.#formatter;
provider.emit(this.#logFilter, formatter.log(message, provider));
provider.emit(this.#logFilter, provider._wrapLog(message, provider._network));
}
}
export class SocketProvider extends JsonRpcApiProvider {
#callbacks;
#ready;
// Maps each filterId to its subscriber
#subs;
// If any events come in before a subscriber has finished
@ -117,10 +113,18 @@ export class SocketProvider extends JsonRpcApiProvider {
constructor(network) {
super(network, { batchMaxCount: 1 });
this.#callbacks = new Map();
this.#ready = false;
this.#subs = new Map();
this.#pending = new Map();
}
// This value is only valid after _start has been called
/*
get _network(): Network {
if (this.#network == null) {
throw new Error("this shouldn't happen");
}
return this.#network.clone();
}
*/
_getSubscriber(sub) {
switch (sub.type) {
case "close":
@ -157,21 +161,23 @@ export class SocketProvider extends JsonRpcApiProvider {
const promise = new Promise((resolve, reject) => {
this.#callbacks.set(payload.id, { payload, resolve, reject });
});
if (this.#ready) {
await this._write(JSON.stringify(payload));
}
return [await promise];
}
// Sub-classes must call this once they are connected
async _start() {
if (this.#ready) {
return;
}
this.#ready = true;
/*
async _start(): Promise<void> {
if (this.#ready) { return; }
for (const { payload } of this.#callbacks.values()) {
await this._write(JSON.stringify(payload));
}
this.#ready = (async function() {
await super._start();
})();
}
*/
// Sub-classes must call this for each message
async _processMessage(message) {
const result = (JSON.parse(message));

File diff suppressed because one or more lines are too long

@ -12,8 +12,14 @@ export class WebSocketProvider extends SocketProvider {
else {
this.#websocket = url;
}
this.websocket.onopen = () => {
this._start();
this.websocket.onopen = async () => {
try {
await this._start();
}
catch (error) {
console.log("failed to start WebsocketProvider", error);
// @TODO: now what? Attempt reconnect?
}
};
this.websocket.onmessage = (message) => {
this._processMessage(message.data);

@ -1 +1 @@
{"version":3,"file":"provider-websocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-websocket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC,CAAC,YAAY;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAetD,MAAM,OAAO,iBAAkB,SAAQ,cAAc;IACjD,GAAG,CAAU;IAEb,UAAU,CAAgB;IAC1B,IAAI,SAAS,KAAoB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAE1D,YAAY,GAA2B,EAAE,OAAoB;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,OAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE;YAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;SACzC;aAAM;YACH,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;SACzB;QAED,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG,EAAE;YACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QAClB,CAAC,CAAC;QAEF,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,OAAyB,EAAE,EAAE;YACrD,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACJ"}
{"version":3,"file":"provider-websocket.js","sourceRoot":"","sources":["../../src.ts/providers/provider-websocket.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC,CAAC,YAAY;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAetD,MAAM,OAAO,iBAAkB,SAAQ,cAAc;IACjD,GAAG,CAAU;IAEb,UAAU,CAAgB;IAC1B,IAAI,SAAS,KAAoB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAE1D,YAAY,GAA2B,EAAE,OAAoB;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,OAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE;YAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;SACzC;aAAM;YACH,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC;SACzB;QAED,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,KAAK,IAAI,EAAE;YAC/B,IAAI;gBACA,MAAM,IAAI,CAAC,MAAM,EAAE,CAAA;aACtB;YAAC,OAAO,KAAK,EAAE;gBACZ,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;gBACxD,sCAAsC;aACzC;QACL,CAAC,CAAC;QAEF,IAAI,CAAC,SAAS,CAAC,SAAS,GAAG,CAAC,OAAyB,EAAE,EAAE;YACrD,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACJ"}

Some files were not shown because too many files have changed in this diff Show More