| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409 | "use strict";/** *  The available providers should suffice for most developers purposes, *  but the [[AbstractProvider]] class has many features which enable *  sub-classing it for specific purposes. * *  @_section: api/providers/abstract-provider: Subclassing Provider  [abstract-provider] */Object.defineProperty(exports, "__esModule", { value: true });exports.AbstractProvider = exports.UnmanagedSubscriber = void 0;// @TODO// Event coalescence//   When we register an event with an async value (e.g. address is a Signer//   or ENS name), we need to add it immeidately for the Event API, but also//   need time to resolve the address. Upon resolving the address, we need to//   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.const index_js_1 = require("../address/index.js");const index_js_2 = require("../constants/index.js");const index_js_3 = require("../contract/index.js");const index_js_4 = require("../hash/index.js");const index_js_5 = require("../transaction/index.js");const index_js_6 = 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");// Constantsconst 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 (v == null) {            return "null";        }        if (typeof (v) === "bigint") {            return `bigint:${v.toString()}`;        }        if (typeof (v) === "string") {            return v.toLowerCase();        }        // Sort object keys        if (typeof (v) === "object" && !Array.isArray(v)) {            const keys = Object.keys(v);            keys.sort();            return keys.reduce((accum, key) => {                accum[key] = v[key];                return accum;            }, {});        }        return v;    });}/** *  An **UnmanagedSubscriber** is useful for events which do not require *  any additional management, such as ``"debug"`` which only requires *  emit in synchronous event loop triggered calls. */class UnmanagedSubscriber {    /**     *  The name fof the event.     */    name;    /**     *  Create a new UnmanagedSubscriber with %%name%%.     */    constructor(name) { (0, index_js_6.defineProperties)(this, { name }); }    start() { }    stop() { }    pause(dropWhilePaused) { }    resume() { }}exports.UnmanagedSubscriber = UnmanagedSubscriber;function copy(value) {    return JSON.parse(JSON.stringify(value));}function concisify(items) {    items = Array.from((new Set(items)).values());    items.sort();    return items;}async function getSubscription(_event, provider) {    if (_event == null) {        throw new Error("invalid event");    }    // Normalize topic array info an EventFilter    if (Array.isArray(_event)) {        _event = { topics: _event };    }    if (typeof (_event) === "string") {        switch (_event) {            case "block":            case "debug":            case "error":            case "finalized":            case "network":            case "pending":            case "safe": {                return { type: _event, tag: _event };            }        }    }    if ((0, index_js_6.isHexString)(_event, 32)) {        const hash = _event.toLowerCase();        return { type: "transaction", tag: getTag("tx", { hash }), hash };    }    if (_event.orphan) {        const event = _event;        // @TODO: Should lowercase and whatnot things here instead of copy...        return { type: "orphan", tag: getTag("orphan", event), filter: copy(event) };    }    if ((_event.address || _event.topics)) {        const event = _event;        const filter = {            topics: ((event.topics || []).map((t) => {                if (t == null) {                    return null;                }                if (Array.isArray(t)) {                    return concisify(t.map((t) => t.toLowerCase()));                }                return t.toLowerCase();            }))        };        if (event.address) {            const addresses = [];            const promises = [];            const addAddress = (addr) => {                if ((0, index_js_6.isHexString)(addr)) {                    addresses.push(addr);                }                else {                    promises.push((async () => {                        addresses.push(await (0, index_js_1.resolveAddress)(addr, provider));                    })());                }            };            if (Array.isArray(event.address)) {                event.address.forEach(addAddress);            }            else {                addAddress(event.address);            }            if (promises.length) {                await Promise.all(promises);            }            filter.address = concisify(addresses.map((a) => a.toLowerCase()));        }        return { filter, tag: getTag("event", filter), type: "event" };    }    (0, index_js_6.assertArgument)(false, "unknown ProviderEvent", "event", _event);}function getTime() { return (new Date()).getTime(); }const defaultOptions = {    cacheTimeout: 250,    pollingInterval: 4000};/** *  An **AbstractProvider** provides a base class for other sub-classes to *  implement the [[Provider]] API by normalizing input arguments and *  formatting output results as well as tracking events for consistent *  behaviour on an eventually-consistent network. */class AbstractProvider {    #subs;    #plugins;    // null=unpaused, true=paused+dropWhilePaused, false=paused    #pausedState;    #destroyed;    #networkPromise;    #anyNetwork;    #performCache;    // The most recent block number if running an event or -1 if no "block" event    #lastBlockNumber;    #nextTimer;    #timers;    #disableCcipRead;    #options;    /**     *  Create a new **AbstractProvider** connected to %%network%%, or     *  use the various network detection capabilities to discover the     *  [[Network]] if necessary.     */    constructor(_network, options) {        this.#options = Object.assign({}, defaultOptions, options || {});        if (_network === "any") {            this.#anyNetwork = true;            this.#networkPromise = null;        }        else if (_network) {            const network = network_js_1.Network.from(_network);            this.#anyNetwork = false;            this.#networkPromise = Promise.resolve(network);            setTimeout(() => { this.emit("network", network, null); }, 0);        }        else {            this.#anyNetwork = false;            this.#networkPromise = null;        }        this.#lastBlockNumber = -1;        this.#performCache = new Map();        this.#subs = new Map();        this.#plugins = new Map();        this.#pausedState = null;        this.#destroyed = false;        this.#nextTimer = 1;        this.#timers = new Map();        this.#disableCcipRead = false;    }    get pollingInterval() { return this.#options.pollingInterval; }    /**     *  Returns ``this``, to allow an **AbstractProvider** to implement     *  the [[ContractRunner]] interface.     */    get provider() { return this; }    /**     *  Returns all the registered plug-ins.     */    get plugins() {        return Array.from(this.#plugins.values());    }    /**     *  Attach a new plug-in.     */    attachPlugin(plugin) {        if (this.#plugins.get(plugin.name)) {            throw new Error(`cannot replace existing plugin: ${plugin.name} `);        }        this.#plugins.set(plugin.name, plugin.connect(this));        return this;    }    /**     *  Get a plugin by name.     */    getPlugin(name) {        return (this.#plugins.get(name)) || null;    }    /**     *  Prevent any CCIP-read operation, regardless of whether requested     *  in a [[call]] using ``enableCcipRead``.     */    get disableCcipRead() { return this.#disableCcipRead; }    set disableCcipRead(value) { this.#disableCcipRead = !!value; }    // Shares multiple identical requests made during the same 250ms    async #perform(req) {        const timeout = this.#options.cacheTimeout;        // Caching disabled        if (timeout < 0) {            return await this._perform(req);        }        // Create a tag        const tag = getTag(req.method, req);        let perform = this.#performCache.get(tag);        if (!perform) {            perform = this._perform(req);            this.#performCache.set(tag, perform);            setTimeout(() => {                if (this.#performCache.get(tag) === perform) {                    this.#performCache.delete(tag);                }            }, timeout);        }        return await perform;    }    /**     *  Resolves to the data for executing the CCIP-read operations.     */    async ccipReadFetch(tx, calldata, urls) {        if (this.disableCcipRead || urls.length === 0 || tx.to == null) {            return null;        }        const sender = tx.to.toLowerCase();        const data = calldata.toLowerCase();        const errorMessages = [];        for (let i = 0; i < urls.length; i++) {            const url = urls[i];            // URL expansion            const href = url.replace("{sender}", sender).replace("{data}", data);            // If no {data} is present, use POST; otherwise GET            //const json: string | null = (url.indexOf("{data}") >= 0) ? null: JSON.stringify({ data, sender });            //const result = await fetchJson({ url: href, errorPassThrough: true }, json, (value, response) => {            //    value.status = response.statusCode;            //    return value;            //});            const request = new index_js_6.FetchRequest(href);            if (url.indexOf("{data}") === -1) {                request.body = { data, sender };            }            this.emit("debug", { action: "sendCcipReadFetchRequest", request, index: i, urls });            let errorMessage = "unknown error";            // Fetch the resource...            let resp;            try {                resp = await request.send();            }            catch (error) {                // ...low-level fetch error (missing host, bad SSL, etc.),                // so try next URL                errorMessages.push(error.message);                this.emit("debug", { action: "receiveCcipReadFetchError", request, result: { error } });                continue;            }            try {                const result = resp.bodyJson;                if (result.data) {                    this.emit("debug", { action: "receiveCcipReadFetchResult", request, result });                    return result.data;                }                if (result.message) {                    errorMessage = result.message;                }                this.emit("debug", { action: "receiveCcipReadFetchError", request, result });            }            catch (error) { }            // 4xx indicates the result is not present; stop            (0, index_js_6.assert)(resp.statusCode < 400 || resp.statusCode >= 500, `response not found during CCIP fetch: ${errorMessage}`, "OFFCHAIN_FAULT", { reason: "404_MISSING_RESOURCE", transaction: tx, info: { url, errorMessage } });            // 5xx indicates server issue; try the next url            errorMessages.push(errorMessage);        }        (0, index_js_6.assert)(false, `error encountered during CCIP fetch: ${errorMessages.map((m) => JSON.stringify(m)).join(", ")}`, "OFFCHAIN_FAULT", {            reason: "500_SERVER_ERROR",            transaction: tx, info: { urls, errorMessages }        });    }    /**     *  Provides the opportunity for a sub-class to wrap a block before     *  returning it, to add additional properties or an alternate     *  sub-class of [[Block]].     */    _wrapBlock(value, network) {        return new provider_js_1.Block((0, format_js_1.formatBlock)(value), this);    }    /**     *  Provides the opportunity for a sub-class to wrap a log before     *  returning it, to add additional properties or an alternate     *  sub-class of [[Log]].     */    _wrapLog(value, network) {        return new provider_js_1.Log((0, format_js_1.formatLog)(value), this);    }    /**     *  Provides the opportunity for a sub-class to wrap a transaction     *  receipt before returning it, to add additional properties or an     *  alternate sub-class of [[TransactionReceipt]].     */    _wrapTransactionReceipt(value, network) {        return new provider_js_1.TransactionReceipt((0, format_js_1.formatTransactionReceipt)(value), this);    }    /**     *  Provides the opportunity for a sub-class to wrap a transaction     *  response before returning it, to add additional properties or an     *  alternate sub-class of [[TransactionResponse]].     */    _wrapTransactionResponse(tx, network) {        return new provider_js_1.TransactionResponse((0, format_js_1.formatTransactionResponse)(tx), this);    }    /**     *  Resolves to the Network, forcing a network detection using whatever     *  technique the sub-class requires.     *     *  Sub-classes **must** override this.     */    _detectNetwork() {        (0, index_js_6.assert)(false, "sub-classes must implement this", "UNSUPPORTED_OPERATION", {            operation: "_detectNetwork"        });    }    /**     *  Sub-classes should use this to perform all built-in operations. All     *  methods sanitizes and normalizes the values passed into this.     *     *  Sub-classes **must** override this.     */    async _perform(req) {        (0, index_js_6.assert)(false, `unsupported method: ${req.method}`, "UNSUPPORTED_OPERATION", {            operation: req.method,            info: req        });    }    // State    async getBlockNumber() {        const blockNumber = (0, index_js_6.getNumber)(await this.#perform({ method: "getBlockNumber" }), "%response");        if (this.#lastBlockNumber >= 0) {            this.#lastBlockNumber = blockNumber;        }        return blockNumber;    }    /**     *  Returns or resolves to the address for %%address%%, resolving ENS     *  names and [[Addressable]] objects and returning if already an     *  address.     */    _getAddress(address) {        return (0, index_js_1.resolveAddress)(address, this);    }    /**     *  Returns or resolves to a valid block tag for %%blockTag%%, resolving     *  negative values and returning if already a valid block tag.     */    _getBlockTag(blockTag) {        if (blockTag == null) {            return "latest";        }        switch (blockTag) {            case "earliest":                return "0x0";            case "finalized":            case "latest":            case "pending":            case "safe":                return blockTag;        }        if ((0, index_js_6.isHexString)(blockTag)) {            if ((0, index_js_6.isHexString)(blockTag, 32)) {                return blockTag;            }            return (0, index_js_6.toQuantity)(blockTag);        }        if (typeof (blockTag) === "bigint") {            blockTag = (0, index_js_6.getNumber)(blockTag, "blockTag");        }        if (typeof (blockTag) === "number") {            if (blockTag >= 0) {                return (0, index_js_6.toQuantity)(blockTag);            }            if (this.#lastBlockNumber >= 0) {                return (0, index_js_6.toQuantity)(this.#lastBlockNumber + blockTag);            }            return this.getBlockNumber().then((b) => (0, index_js_6.toQuantity)(b + blockTag));        }        (0, index_js_6.assertArgument)(false, "invalid blockTag", "blockTag", blockTag);    }    /**     *  Returns or resolves to a filter for %%filter%%, resolving any ENS     *  names or [[Addressable]] object and returning if already a valid     *  filter.     */    _getFilter(filter) {        // Create a canonical representation of the topics        const topics = (filter.topics || []).map((t) => {            if (t == null) {                return null;            }            if (Array.isArray(t)) {                return concisify(t.map((t) => t.toLowerCase()));            }            return t.toLowerCase();        });        const blockHash = ("blockHash" in filter) ? filter.blockHash : undefined;        const resolve = (_address, fromBlock, toBlock) => {            let address = undefined;            switch (_address.length) {                case 0: break;                case 1:                    address = _address[0];                    break;                default:                    _address.sort();                    address = _address;            }            if (blockHash) {                if (fromBlock != null || toBlock != null) {                    throw new Error("invalid filter");                }            }            const filter = {};            if (address) {                filter.address = address;            }            if (topics.length) {                filter.topics = topics;            }            if (fromBlock) {                filter.fromBlock = fromBlock;            }            if (toBlock) {                filter.toBlock = toBlock;            }            if (blockHash) {                filter.blockHash = blockHash;            }            return filter;        };        // Addresses could be async (ENS names or Addressables)        let address = [];        if (filter.address) {            if (Array.isArray(filter.address)) {                for (const addr of filter.address) {                    address.push(this._getAddress(addr));                }            }            else {                address.push(this._getAddress(filter.address));            }        }        let fromBlock = undefined;        if ("fromBlock" in filter) {            fromBlock = this._getBlockTag(filter.fromBlock);        }        let toBlock = undefined;        if ("toBlock" in filter) {            toBlock = this._getBlockTag(filter.toBlock);        }        if (address.filter((a) => (typeof (a) !== "string")).length ||            (fromBlock != null && typeof (fromBlock) !== "string") ||            (toBlock != null && typeof (toBlock) !== "string")) {            return Promise.all([Promise.all(address), fromBlock, toBlock]).then((result) => {                return resolve(result[0], result[1], result[2]);            });        }        return resolve(address, fromBlock, toBlock);    }    /**     *  Returns or resolves to a transaction for %%request%%, resolving     *  any ENS names or [[Addressable]] and returning if already a valid     *  transaction.     */    _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], this);            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 = (async () => {                try {                    const network = await this._detectNetwork();                    this.emit("network", network, null);                    return network;                }                catch (error) {                    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_6.assert)(false, `network changed: ${expected.chainId} => ${actual.chainId} `, "NETWORK_ERROR", {                    event: "changed"                });            }        }        return expected.clone();    }    async getFeeData() {        const network = await this.getNetwork();        const getFeeDataFunc = async () => {            const { _block, gasPrice, priorityFee } = await (0, index_js_6.resolveProperties)({                _block: this.#getBlock("latest", false),                gasPrice: ((async () => {                    try {                        const value = await this.#perform({ method: "getGasPrice" });                        return (0, index_js_6.getBigInt)(value, "%response");                    }                    catch (error) { }                    return null;                })()),                priorityFee: ((async () => {                    try {                        const value = await this.#perform({ method: "getPriorityFee" });                        return (0, index_js_6.getBigInt)(value, "%response");                    }                    catch (error) { }                    return null;                })())            });            let maxFeePerGas = null;            let maxPriorityFeePerGas = null;            // These are the recommended EIP-1559 heuristics for fee data            const block = this._wrapBlock(_block, network);            if (block && block.baseFeePerGas) {                maxPriorityFeePerGas = (priorityFee != null) ? priorityFee : BigInt("1000000000");                maxFeePerGas = (block.baseFeePerGas * BN_2) + maxPriorityFeePerGas;            }            return new provider_js_1.FeeData(gasPrice, maxFeePerGas, maxPriorityFeePerGas);        };        // Check for a FeeDataNetWorkPlugin        const plugin = network.getPlugin("org.ethers.plugins.network.FetchUrlFeeDataPlugin");        if (plugin) {            const req = new index_js_6.FetchRequest(plugin.url);            const feeData = await plugin.processFunc(getFeeDataFunc, this, req);            return new provider_js_1.FeeData(feeData.gasPrice, feeData.maxFeePerGas, feeData.maxPriorityFeePerGas);        }        return await getFeeDataFunc();    }    async estimateGas(_tx) {        let tx = this._getTransactionRequest(_tx);        if (isPromise(tx)) {            tx = await tx;        }        return (0, index_js_6.getBigInt)(await this.#perform({            method: "estimateGas", transaction: tx        }), "%response");    }    async #call(tx, blockTag, attempt) {        (0, index_js_6.assert)(attempt < MAX_CCIP_REDIRECTS, "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_6.hexlify)(await this._perform({ method: "call", transaction, blockTag }));        }        catch (error) {            // CCIP Read OffchainLookup            if (!this.disableCcipRead && (0, index_js_6.isCallException)(error) && error.data && attempt >= 0 && blockTag === "latest" && transaction.to != null && (0, index_js_6.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_6.dataSlice)(error.data, 4));                }                catch (error) {                    (0, index_js_6.assert)(false, error.message, "OFFCHAIN_FAULT", {                        reason: "BAD_DATA", transaction, info: { data }                    });                }                // Check the sender of the OffchainLookup matches the transaction                (0, index_js_6.assert)(ccipArgs.sender.toLowerCase() === txSender.toLowerCase(), "CCIP Read sender mismatch", "CALL_EXCEPTION", {                    action: "call",                    data,                    reason: "OffchainLookup",                    transaction: transaction,                    invocation: null,                    revert: {                        signature: "OffchainLookup(address,string[],bytes,bytes4,bytes)",                        name: "OffchainLookup",                        args: ccipArgs.errorArgs                    }                });                const ccipResult = await this.ccipReadFetch(transaction, ccipArgs.calldata, ccipArgs.urls);                (0, index_js_6.assert)(ccipResult != null, "CCIP Read failed to fetch data", "OFFCHAIN_FAULT", {                    reason: "FETCH_FAILED", transaction, info: { data: error.data, errorArgs: ccipArgs.errorArgs }                });                const tx = {                    to: txSender,                    data: (0, index_js_6.concat)([ccipArgs.selector, encodeBytes([ccipResult, ccipArgs.extraData])])                };                this.emit("debug", { action: "sendCcipReadCall", transaction: tx });                try {                    const result = await this.#call(tx, blockTag, attempt + 1);                    this.emit("debug", { action: "receiveCcipReadCallResult", transaction: Object.assign({}, tx), result });                    return result;                }                catch (error) {                    this.emit("debug", { action: "receiveCcipReadCallError", transaction: Object.assign({}, tx), error });                    throw error;                }            }            throw error;        }    }    async #checkNetwork(promise) {        const { value } = await (0, index_js_6.resolveProperties)({            network: this.getNetwork(),            value: promise        });        return value;    }    async call(_tx) {        const { tx, blockTag } = await (0, index_js_6.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_6.getBigInt)(await this.#getAccountValue({ method: "getBalance" }, address, blockTag), "%response");    }    async getTransactionCount(address, blockTag) {        return (0, index_js_6.getNumber)(await this.#getAccountValue({ method: "getTransactionCount" }, address, blockTag), "%response");    }    async getCode(address, blockTag) {        return (0, index_js_6.hexlify)(await this.#getAccountValue({ method: "getCode" }, address, blockTag));    }    async getStorage(address, _position, blockTag) {        const position = (0, index_js_6.getBigInt)(_position, "position");        return (0, index_js_6.hexlify)(await this.#getAccountValue({ method: "getStorage", position }, address, blockTag));    }    // Write    async broadcastTransaction(signedTx) {        const { blockNumber, hash, network } = await (0, index_js_6.resolveProperties)({            blockNumber: this.getBlockNumber(),            hash: this._perform({                method: "broadcastTransaction",                signedTransaction: signedTx            }),            network: this.getNetwork()        });        const tx = index_js_5.Transaction.from(signedTx);        if (tx.hash !== hash) {            throw new Error("@TODO: the returned hash did not match");        }        return this._wrapTransactionResponse(tx, network).replaceableTransaction(blockNumber);    }    async #getBlock(block, includeTransactions) {        // @TODO: Add CustomBlockPlugin check        if ((0, index_js_6.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, prefetchTxs) {        const { network, params } = await (0, index_js_6.resolveProperties)({            network: this.getNetwork(),            params: this.#getBlock(block, !!prefetchTxs)        });        if (params == null) {            return null;        }        return this._wrapBlock(params, network);    }    async getTransaction(hash) {        const { network, params } = await (0, index_js_6.resolveProperties)({            network: this.getNetwork(),            params: this.#perform({ method: "getTransaction", hash })        });        if (params == null) {            return null;        }        return this._wrapTransactionResponse(params, network);    }    async getTransactionReceipt(hash) {        const { network, params } = await (0, index_js_6.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(params, network);    }    async getTransactionResult(hash) {        const { result } = await (0, index_js_6.resolveProperties)({            network: this.getNetwork(),            result: this.#perform({ method: "getTransactionResult", hash })        });        if (result == null) {            return null;        }        return (0, index_js_6.hexlify)(result);    }    // Bloom-filter Queries    async getLogs(_filter) {        let filter = this._getFilter(_filter);        if (isPromise(filter)) {            filter = await filter;        }        const { network, params } = await (0, index_js_6.resolveProperties)({            network: this.getNetwork(),            params: this.#perform({ method: "getLogs", filter })        });        return params.map((p) => this._wrapLog(p, network));    }    // ENS    _getProvider(chainId) {        (0, index_js_6.assert)(false, "provider cannot connect to target network", "UNSUPPORTED_OPERATION", {            operation: "_getProvider()"        });    }    async getResolver(name) {        return await ens_resolver_js_1.EnsResolver.fromName(this, name);    }    async getAvatar(name) {        const resolver = await this.getResolver(name);        if (resolver) {            return await resolver.getAvatar();        }        return null;    }    async resolveName(name) {        const resolver = await this.getResolver(name);        if (resolver) {            return await resolver.getAddress();        }        return null;    }    async lookupAddress(address) {        address = (0, index_js_1.getAddress)(address);        const node = (0, index_js_4.namehash)(address.substring(2).toLowerCase() + ".addr.reverse");        try {            const ensAddr = await ens_resolver_js_1.EnsResolver.getEnsAddress(this);            const ensContract = new index_js_3.Contract(ensAddr, [                "function resolver(bytes32) view returns (address)"            ], this);            const resolver = await ensContract.resolver(node);            if (resolver == null || resolver === index_js_2.ZeroAddress) {                return null;            }            const resolverContract = new index_js_3.Contract(resolver, [                "function name(bytes32) view returns (string)"            ], this);            const name = await resolverContract.name(node);            // Failed forward resolution            const check = await this.resolveName(name);            if (check !== address) {                return null;            }            return name;        }        catch (error) {            // No data was returned from the resolver            if ((0, index_js_6.isError)(error, "BAD_DATA") && error.value === "0x") {                return null;            }            // Something reerted            if ((0, index_js_6.isError)(error, "CALL_EXCEPTION")) {                return null;            }            throw error;        }        return null;    }    async waitForTransaction(hash, _confirms, timeout) {        const confirms = (_confirms != null) ? _confirms : 1;        if (confirms === 0) {            return this.getTransactionReceipt(hash);        }        return new Promise(async (resolve, reject) => {            let timer = null;            const listener = (async (blockNumber) => {                try {                    const receipt = await this.getTransactionReceipt(hash);                    if (receipt != null) {                        if (blockNumber - receipt.blockNumber + 1 >= confirms) {                            resolve(receipt);                            //this.off("block", listener);                            if (timer) {                                clearTimeout(timer);                                timer = null;                            }                            return;                        }                    }                }                catch (error) {                    console.log("EEE", error);                }                this.once("block", listener);            });            if (timeout != null) {                timer = setTimeout(() => {                    if (timer == null) {                        return;                    }                    timer = null;                    this.off("block", listener);                    reject((0, index_js_6.makeError)("timeout", "TIMEOUT", { reason: "timeout" }));                }, timeout);            }            listener(await this.getBlockNumber());        });    }    async waitForBlock(blockTag) {        (0, index_js_6.assert)(false, "not implemented yet", "NOT_IMPLEMENTED", {            operation: "waitForBlock"        });    }    /**     *  Clear a timer created using the [[_setTimeout]] method.     */    _clearTimeout(timerId) {        const timer = this.#timers.get(timerId);        if (!timer) {            return;        }        if (timer.timer) {            clearTimeout(timer.timer);        }        this.#timers.delete(timerId);    }    /**     *  Create a timer that will execute %%func%% after at least %%timeout%%     *  (in ms). If %%timeout%% is unspecified, then %%func%% will execute     *  in the next event loop.     *     *  [Pausing](AbstractProvider-paused) the provider will pause any     *  associated timers.     */    _setTimeout(_func, timeout) {        if (timeout == null) {            timeout = 0;        }        const timerId = this.#nextTimer++;        const func = () => {            this.#timers.delete(timerId);            _func();        };        if (this.paused) {            this.#timers.set(timerId, { timer: null, func, time: timeout });        }        else {            const timer = setTimeout(func, timeout);            this.#timers.set(timerId, { timer, func, time: getTime() });        }        return timerId;    }    /**     *  Perform %%func%% on each subscriber.     */    _forEachSubscriber(func) {        for (const sub of this.#subs.values()) {            func(sub.subscriber);        }    }    /**     *  Sub-classes may override this to customize subscription     *  implementations.     */    _getSubscriber(sub) {        switch (sub.type) {            case "debug":            case "error":            case "network":                return new UnmanagedSubscriber(sub.type);            case "block": {                const subscriber = new subscriber_polling_js_1.PollingBlockSubscriber(this);                subscriber.pollingInterval = this.pollingInterval;                return subscriber;            }            case "safe":            case "finalized":                return new subscriber_polling_js_1.PollingBlockTagSubscriber(this, sub.type);            case "event":                return new subscriber_polling_js_1.PollingEventSubscriber(this, sub.filter);            case "transaction":                return new subscriber_polling_js_1.PollingTransactionSubscriber(this, sub.hash);            case "orphan":                return new subscriber_polling_js_1.PollingOrphanSubscriber(this, sub.filter);        }        throw new Error(`unsupported event: ${sub.type}`);    }    /**     *  If a [[Subscriber]] fails and needs to replace itself, this     *  method may be used.     *     *  For example, this is used for providers when using the     *  ``eth_getFilterChanges`` method, which can return null if state     *  filters are not supported by the backend, allowing the Subscriber     *  to swap in a [[PollingEventSubscriber]].     */    _recoverSubscriber(oldSub, newSub) {        for (const sub of this.#subs.values()) {            if (sub.subscriber === oldSub) {                if (sub.started) {                    sub.subscriber.stop();                }                sub.subscriber = newSub;                if (sub.started) {                    newSub.start();                }                if (this.#pausedState != null) {                    newSub.pause(this.#pausedState);                }                break;            }        }    }    async #hasSub(event, emitArgs) {        let sub = await getSubscription(event, this);        // This is a log that is removing an existing log; we actually want        // to emit an orphan event for the removed log        if (sub.type === "event" && emitArgs && emitArgs.length > 0 && emitArgs[0].removed === true) {            sub = await getSubscription({ orphan: "drop-log", log: emitArgs[0] }, this);        }        return this.#subs.get(sub.tag) || null;    }    async #getSub(event) {        const subscription = await getSubscription(event, this);        // Prevent tampering with our tag in any subclass' _getSubscriber        const tag = subscription.tag;        let sub = this.#subs.get(tag);        if (!sub) {            const subscriber = this._getSubscriber(subscription);            const addressableMap = new WeakMap();            const nameMap = new Map();            sub = { subscriber, tag, addressableMap, nameMap, started: false, listeners: [] };            this.#subs.set(tag, sub);        }        return sub;    }    async on(event, listener) {        const sub = await this.#getSub(event);        sub.listeners.push({ listener, once: false });        if (!sub.started) {            sub.subscriber.start();            sub.started = true;            if (this.#pausedState != null) {                sub.subscriber.pause(this.#pausedState);            }        }        return this;    }    async once(event, listener) {        const sub = await this.#getSub(event);        sub.listeners.push({ listener, once: true });        if (!sub.started) {            sub.subscriber.start();            sub.started = true;            if (this.#pausedState != null) {                sub.subscriber.pause(this.#pausedState);            }        }        return this;    }    async emit(event, ...args) {        const sub = await this.#hasSub(event, args);        // If there is not subscription or if a recent emit removed        // the last of them (which also deleted the sub) do nothing        if (!sub || sub.listeners.length === 0) {            return false;        }        ;        const count = sub.listeners.length;        sub.listeners = sub.listeners.filter(({ listener, once }) => {            const payload = new index_js_6.EventPayload(this, (once ? null : listener), event);            try {                listener.call(this, ...args, payload);            }            catch (error) { }            return !once;        });        if (sub.listeners.length === 0) {            if (sub.started) {                sub.subscriber.stop();            }            this.#subs.delete(sub.tag);        }        return (count > 0);    }    async listenerCount(event) {        if (event) {            const sub = await this.#hasSub(event);            if (!sub) {                return 0;            }            return sub.listeners.length;        }        let total = 0;        for (const { listeners } of this.#subs.values()) {            total += listeners.length;        }        return total;    }    async listeners(event) {        if (event) {            const sub = await this.#hasSub(event);            if (!sub) {                return [];            }            return sub.listeners.map(({ listener }) => listener);        }        let result = [];        for (const { listeners } of this.#subs.values()) {            result = result.concat(listeners.map(({ listener }) => listener));        }        return result;    }    async off(event, listener) {        const sub = await this.#hasSub(event);        if (!sub) {            return this;        }        if (listener) {            const index = sub.listeners.map(({ listener }) => listener).indexOf(listener);            if (index >= 0) {                sub.listeners.splice(index, 1);            }        }        if (!listener || sub.listeners.length === 0) {            if (sub.started) {                sub.subscriber.stop();            }            this.#subs.delete(sub.tag);        }        return this;    }    async removeAllListeners(event) {        if (event) {            const { tag, started, subscriber } = await this.#getSub(event);            if (started) {                subscriber.stop();            }            this.#subs.delete(tag);        }        else {            for (const [tag, { started, subscriber }] of this.#subs) {                if (started) {                    subscriber.stop();                }                this.#subs.delete(tag);            }        }        return this;    }    // Alias for "on"    async addListener(event, listener) {        return await this.on(event, listener);    }    // Alias for "off"    async removeListener(event, listener) {        return this.off(event, listener);    }    /**     *  If this provider has been destroyed using the [[destroy]] method.     *     *  Once destroyed, all resources are reclaimed, internal event loops     *  and timers are cleaned up and no further requests may be sent to     *  the provider.     */    get destroyed() {        return this.#destroyed;    }    /**     *  Sub-classes may use this to shutdown any sockets or release their     *  resources and reject any pending requests.     *     *  Sub-classes **must** call ``super.destroy()``.     */    destroy() {        // Stop all listeners        this.removeAllListeners();        // Shut down all tiemrs        for (const timerId of this.#timers.keys()) {            this._clearTimeout(timerId);        }        this.#destroyed = true;    }    /**     *  Whether the provider is currently paused.     *     *  A paused provider will not emit any events, and generally should     *  not make any requests to the network, but that is up to sub-classes     *  to manage.     *     *  Setting ``paused = true`` is identical to calling ``.pause(false)``,     *  which will buffer any events that occur while paused until the     *  provider is unpaused.     */    get paused() { return (this.#pausedState != null); }    set paused(pause) {        if (!!pause === this.paused) {            return;        }        if (this.paused) {            this.resume();        }        else {            this.pause(false);        }    }    /**     *  Pause the provider. If %%dropWhilePaused%%, any events that occur     *  while paused are dropped, otherwise all events will be emitted once     *  the provider is unpaused.     */    pause(dropWhilePaused) {        this.#lastBlockNumber = -1;        if (this.#pausedState != null) {            if (this.#pausedState == !!dropWhilePaused) {                return;            }            (0, index_js_6.assert)(false, "cannot change pause type; resume first", "UNSUPPORTED_OPERATION", {                operation: "pause"            });        }        this._forEachSubscriber((s) => s.pause(dropWhilePaused));        this.#pausedState = !!dropWhilePaused;        for (const timer of this.#timers.values()) {            // Clear the timer            if (timer.timer) {                clearTimeout(timer.timer);            }            // Remaining time needed for when we become unpaused            timer.time = getTime() - timer.time;        }    }    /**     *  Resume the provider.     */    resume() {        if (this.#pausedState == null) {            return;        }        this._forEachSubscriber((s) => s.resume());        this.#pausedState = null;        for (const timer of this.#timers.values()) {            // Remaining time when we were paused            let timeout = timer.time;            if (timeout < 0) {                timeout = 0;            }            // Start time (in cause paused, so we con compute remaininf time)            timer.time = getTime();            // Start the timer            setTimeout(timer.func, timeout);        }    }}exports.AbstractProvider = AbstractProvider;function _parseString(result, start) {    try {        const bytes = _parseBytes(result, start);        if (bytes) {            return (0, index_js_6.toUtf8String)(bytes);        }    }    catch (error) { }    return null;}function _parseBytes(result, start) {    if (result === "0x") {        return null;    }    try {        const offset = (0, index_js_6.getNumber)((0, index_js_6.dataSlice)(result, start, start + 32));        const length = (0, index_js_6.getNumber)((0, index_js_6.dataSlice)(result, offset, offset + 32));        return (0, index_js_6.dataSlice)(result, offset + 32, offset + 32 + length);    }    catch (error) { }    return null;}function numPad(value) {    const result = (0, index_js_6.toBeArray)(value);    if (result.length > 32) {        throw new Error("internal; should not happen");    }    const padded = new Uint8Array(32);    padded.set(result, 32 - result.length);    return padded;}function bytesPad(value) {    if ((value.length % 32) === 0) {        return value;    }    const result = new Uint8Array(Math.ceil(value.length / 32) * 32);    result.set(value);    return result;}const empty = new Uint8Array([]);// ABI Encodes a series of (bytes, bytes, ...)function encodeBytes(datas) {    const result = [];    let byteCount = 0;    // Add place-holders for pointers as we add items    for (let i = 0; i < datas.length; i++) {        result.push(empty);        byteCount += 32;    }    for (let i = 0; i < datas.length; i++) {        const data = (0, index_js_6.getBytes)(datas[i]);        // Update the bytes offset        result[i] = numPad(byteCount);        // The length and padded value of data        result.push(numPad(data.length));        result.push(bytesPad(data));        byteCount += 32 + Math.ceil(data.length / 32) * 32;    }    return (0, index_js_6.concat)(result);}const zeros = "0x0000000000000000000000000000000000000000000000000000000000000000";function parseOffchainLookup(data) {    const result = {        sender: "", urls: [], calldata: "", selector: "", extraData: "", errorArgs: []    };    (0, index_js_6.assert)((0, index_js_6.dataLength)(data) >= 5 * 32, "insufficient OffchainLookup data", "OFFCHAIN_FAULT", {        reason: "insufficient OffchainLookup data"    });    const sender = (0, index_js_6.dataSlice)(data, 0, 32);    (0, index_js_6.assert)((0, index_js_6.dataSlice)(sender, 0, 12) === (0, index_js_6.dataSlice)(zeros, 0, 12), "corrupt OffchainLookup sender", "OFFCHAIN_FAULT", {        reason: "corrupt OffchainLookup sender"    });    result.sender = (0, index_js_6.dataSlice)(sender, 12);    // Read the URLs from the response    try {        const urls = [];        const urlsOffset = (0, index_js_6.getNumber)((0, index_js_6.dataSlice)(data, 32, 64));        const urlsLength = (0, index_js_6.getNumber)((0, index_js_6.dataSlice)(data, urlsOffset, urlsOffset + 32));        const urlsData = (0, index_js_6.dataSlice)(data, urlsOffset + 32);        for (let u = 0; u < urlsLength; u++) {            const url = _parseString(urlsData, u * 32);            if (url == null) {                throw new Error("abort");            }            urls.push(url);        }        result.urls = urls;    }    catch (error) {        (0, index_js_6.assert)(false, "corrupt OffchainLookup urls", "OFFCHAIN_FAULT", {            reason: "corrupt OffchainLookup urls"        });    }    // Get the CCIP calldata to forward    try {        const calldata = _parseBytes(data, 64);        if (calldata == null) {            throw new Error("abort");        }        result.calldata = calldata;    }    catch (error) {        (0, index_js_6.assert)(false, "corrupt OffchainLookup calldata", "OFFCHAIN_FAULT", {            reason: "corrupt OffchainLookup calldata"        });    }    // Get the callbackSelector (bytes4)    (0, index_js_6.assert)((0, index_js_6.dataSlice)(data, 100, 128) === (0, index_js_6.dataSlice)(zeros, 0, 28), "corrupt OffchainLookup callbaackSelector", "OFFCHAIN_FAULT", {        reason: "corrupt OffchainLookup callbaackSelector"    });    result.selector = (0, index_js_6.dataSlice)(data, 96, 100);    // Get the extra data to send back to the contract as context    try {        const extraData = _parseBytes(data, 128);        if (extraData == null) {            throw new Error("abort");        }        result.extraData = extraData;    }    catch (error) {        (0, index_js_6.assert)(false, "corrupt OffchainLookup extraData", "OFFCHAIN_FAULT", {            reason: "corrupt OffchainLookup extraData"        });    }    result.errorArgs = "sender,urls,calldata,selector,extraData".split(/,/).map((k) => result[k]);    return result;}//# sourceMappingURL=abstract-provider.js.map
 |