| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 | "use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.Reader = exports.Writer = exports.Coder = exports.checkResultErrors = exports.Result = exports.WordSize = void 0;const index_js_1 = require("../../utils/index.js");/** * @_ignore: */exports.WordSize = 32;const Padding = new Uint8Array(exports.WordSize);// Properties used to immediate pass through to the underlying object// - `then` is used to detect if an object is a Promise for awaitconst passProperties = ["then"];const _guard = {};const resultNames = new WeakMap();function getNames(result) {    return resultNames.get(result);}function setNames(result, names) {    resultNames.set(result, names);}function throwError(name, error) {    const wrapped = new Error(`deferred error during ABI decoding triggered accessing ${name}`);    wrapped.error = error;    throw wrapped;}function toObject(names, items, deep) {    if (names.indexOf(null) >= 0) {        return items.map((item, index) => {            if (item instanceof Result) {                return toObject(getNames(item), item, deep);            }            return item;        });    }    return names.reduce((accum, name, index) => {        let item = items.getValue(name);        if (!(name in accum)) {            if (deep && item instanceof Result) {                item = toObject(getNames(item), item, deep);            }            accum[name] = item;        }        return accum;    }, {});}/** *  A [[Result]] is a sub-class of Array, which allows accessing any *  of its values either positionally by its index or, if keys are *  provided by its name. * *  @_docloc: api/abi */class Result extends Array {    // No longer used; but cannot be removed as it will remove the    // #private field from the .d.ts which may break backwards    // compatibility    #names;    /**     *  @private     */    constructor(...args) {        // To properly sub-class Array so the other built-in        // functions work, the constructor has to behave fairly        // well. So, in the event we are created via fromItems()        // we build the read-only Result object we want, but on        // any other input, we use the default constructor        // constructor(guard: any, items: Array<any>, keys?: Array<null | string>);        const guard = args[0];        let items = args[1];        let names = (args[2] || []).slice();        let wrap = true;        if (guard !== _guard) {            items = args;            names = [];            wrap = false;        }        // Can't just pass in ...items since an array of length 1        // is a special case in the super.        super(items.length);        items.forEach((item, index) => { this[index] = item; });        // Find all unique keys        const nameCounts = names.reduce((accum, name) => {            if (typeof (name) === "string") {                accum.set(name, (accum.get(name) || 0) + 1);            }            return accum;        }, (new Map()));        // Remove any key thats not unique        setNames(this, Object.freeze(items.map((item, index) => {            const name = names[index];            if (name != null && nameCounts.get(name) === 1) {                return name;            }            return null;        })));        // Dummy operations to prevent TypeScript from complaining        this.#names = [];        if (this.#names == null) {            void (this.#names);        }        if (!wrap) {            return;        }        // A wrapped Result is immutable        Object.freeze(this);        // Proxy indices and names so we can trap deferred errors        const proxy = new Proxy(this, {            get: (target, prop, receiver) => {                if (typeof (prop) === "string") {                    // Index accessor                    if (prop.match(/^[0-9]+$/)) {                        const index = (0, index_js_1.getNumber)(prop, "%index");                        if (index < 0 || index >= this.length) {                            throw new RangeError("out of result range");                        }                        const item = target[index];                        if (item instanceof Error) {                            throwError(`index ${index}`, item);                        }                        return item;                    }                    // Pass important checks (like `then` for Promise) through                    if (passProperties.indexOf(prop) >= 0) {                        return Reflect.get(target, prop, receiver);                    }                    const value = target[prop];                    if (value instanceof Function) {                        // Make sure functions work with private variables                        // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#no_private_property_forwarding                        return function (...args) {                            return value.apply((this === receiver) ? target : this, args);                        };                    }                    else if (!(prop in target)) {                        // Possible name accessor                        return target.getValue.apply((this === receiver) ? target : this, [prop]);                    }                }                return Reflect.get(target, prop, receiver);            }        });        setNames(proxy, getNames(this));        return proxy;    }    /**     *  Returns the Result as a normal Array. If %%deep%%, any children     *  which are Result objects are also converted to a normal Array.     *     *  This will throw if there are any outstanding deferred     *  errors.     */    toArray(deep) {        const result = [];        this.forEach((item, index) => {            if (item instanceof Error) {                throwError(`index ${index}`, item);            }            if (deep && item instanceof Result) {                item = item.toArray(deep);            }            result.push(item);        });        return result;    }    /**     *  Returns the Result as an Object with each name-value pair. If     *  %%deep%%, any children which are Result objects are also     *  converted to an Object.     *     *  This will throw if any value is unnamed, or if there are     *  any outstanding deferred errors.     */    toObject(deep) {        const names = getNames(this);        return names.reduce((accum, name, index) => {            (0, index_js_1.assert)(name != null, `value at index ${index} unnamed`, "UNSUPPORTED_OPERATION", {                operation: "toObject()"            });            return toObject(names, this, deep);        }, {});    }    /**     *  @_ignore     */    slice(start, end) {        if (start == null) {            start = 0;        }        if (start < 0) {            start += this.length;            if (start < 0) {                start = 0;            }        }        if (end == null) {            end = this.length;        }        if (end < 0) {            end += this.length;            if (end < 0) {                end = 0;            }        }        if (end > this.length) {            end = this.length;        }        const _names = getNames(this);        const result = [], names = [];        for (let i = start; i < end; i++) {            result.push(this[i]);            names.push(_names[i]);        }        return new Result(_guard, result, names);    }    /**     *  @_ignore     */    filter(callback, thisArg) {        const _names = getNames(this);        const result = [], names = [];        for (let i = 0; i < this.length; i++) {            const item = this[i];            if (item instanceof Error) {                throwError(`index ${i}`, item);            }            if (callback.call(thisArg, item, i, this)) {                result.push(item);                names.push(_names[i]);            }        }        return new Result(_guard, result, names);    }    /**     *  @_ignore     */    map(callback, thisArg) {        const result = [];        for (let i = 0; i < this.length; i++) {            const item = this[i];            if (item instanceof Error) {                throwError(`index ${i}`, item);            }            result.push(callback.call(thisArg, item, i, this));        }        return result;    }    /**     *  Returns the value for %%name%%.     *     *  Since it is possible to have a key whose name conflicts with     *  a method on a [[Result]] or its superclass Array, or any     *  JavaScript keyword, this ensures all named values are still     *  accessible by name.     */    getValue(name) {        const index = getNames(this).indexOf(name);        if (index === -1) {            return undefined;        }        const value = this[index];        if (value instanceof Error) {            throwError(`property ${JSON.stringify(name)}`, value.error);        }        return value;    }    /**     *  Creates a new [[Result]] for %%items%% with each entry     *  also accessible by its corresponding name in %%keys%%.     */    static fromItems(items, keys) {        return new Result(_guard, items, keys);    }}exports.Result = Result;/** *  Returns all errors found in a [[Result]]. * *  Since certain errors encountered when creating a [[Result]] do *  not impact the ability to continue parsing data, they are *  deferred until they are actually accessed. Hence a faulty string *  in an Event that is never used does not impact the program flow. * *  However, sometimes it may be useful to access, identify or *  validate correctness of a [[Result]]. * *  @_docloc api/abi */function checkResultErrors(result) {    // Find the first error (if any)    const errors = [];    const checkErrors = function (path, object) {        if (!Array.isArray(object)) {            return;        }        for (let key in object) {            const childPath = path.slice();            childPath.push(key);            try {                checkErrors(childPath, object[key]);            }            catch (error) {                errors.push({ path: childPath, error: error });            }        }    };    checkErrors([], result);    return errors;}exports.checkResultErrors = checkResultErrors;function getValue(value) {    let bytes = (0, index_js_1.toBeArray)(value);    (0, index_js_1.assert)(bytes.length <= exports.WordSize, "value out-of-bounds", "BUFFER_OVERRUN", { buffer: bytes, length: exports.WordSize, offset: bytes.length });    if (bytes.length !== exports.WordSize) {        bytes = (0, index_js_1.getBytesCopy)((0, index_js_1.concat)([Padding.slice(bytes.length % exports.WordSize), bytes]));    }    return bytes;}/** *  @_ignore */class Coder {    // The coder name:    //   - address, uint256, tuple, array, etc.    name;    // The fully expanded type, including composite types:    //   - address, uint256, tuple(address,bytes), uint256[3][4][],  etc.    type;    // The localName bound in the signature, in this example it is "baz":    //   - tuple(address foo, uint bar) baz    localName;    // Whether this type is dynamic:    //  - Dynamic: bytes, string, address[], tuple(boolean[]), etc.    //  - Not Dynamic: address, uint256, boolean[3], tuple(address, uint8)    dynamic;    constructor(name, type, localName, dynamic) {        (0, index_js_1.defineProperties)(this, { name, type, localName, dynamic }, {            name: "string", type: "string", localName: "string", dynamic: "boolean"        });    }    _throwError(message, value) {        (0, index_js_1.assertArgument)(false, message, this.localName, value);    }}exports.Coder = Coder;/** *  @_ignore */class Writer {    // An array of WordSize lengthed objects to concatenation    #data;    #dataLength;    constructor() {        this.#data = [];        this.#dataLength = 0;    }    get data() {        return (0, index_js_1.concat)(this.#data);    }    get length() { return this.#dataLength; }    #writeData(data) {        this.#data.push(data);        this.#dataLength += data.length;        return data.length;    }    appendWriter(writer) {        return this.#writeData((0, index_js_1.getBytesCopy)(writer.data));    }    // Arrayish item; pad on the right to *nearest* WordSize    writeBytes(value) {        let bytes = (0, index_js_1.getBytesCopy)(value);        const paddingOffset = bytes.length % exports.WordSize;        if (paddingOffset) {            bytes = (0, index_js_1.getBytesCopy)((0, index_js_1.concat)([bytes, Padding.slice(paddingOffset)]));        }        return this.#writeData(bytes);    }    // Numeric item; pad on the left *to* WordSize    writeValue(value) {        return this.#writeData(getValue(value));    }    // Inserts a numeric place-holder, returning a callback that can    // be used to asjust the value later    writeUpdatableValue() {        const offset = this.#data.length;        this.#data.push(Padding);        this.#dataLength += exports.WordSize;        return (value) => {            this.#data[offset] = getValue(value);        };    }}exports.Writer = Writer;/** *  @_ignore */class Reader {    // Allows incomplete unpadded data to be read; otherwise an error    // is raised if attempting to overrun the buffer. This is required    // to deal with an old Solidity bug, in which event data for    // external (not public thoguh) was tightly packed.    allowLoose;    #data;    #offset;    #bytesRead;    #parent;    #maxInflation;    constructor(data, allowLoose, maxInflation) {        (0, index_js_1.defineProperties)(this, { allowLoose: !!allowLoose });        this.#data = (0, index_js_1.getBytesCopy)(data);        this.#bytesRead = 0;        this.#parent = null;        this.#maxInflation = (maxInflation != null) ? maxInflation : 1024;        this.#offset = 0;    }    get data() { return (0, index_js_1.hexlify)(this.#data); }    get dataLength() { return this.#data.length; }    get consumed() { return this.#offset; }    get bytes() { return new Uint8Array(this.#data); }    #incrementBytesRead(count) {        if (this.#parent) {            return this.#parent.#incrementBytesRead(count);        }        this.#bytesRead += count;        // Check for excessive inflation (see: #4537)        (0, index_js_1.assert)(this.#maxInflation < 1 || this.#bytesRead <= this.#maxInflation * this.dataLength, `compressed ABI data exceeds inflation ratio of ${this.#maxInflation} ( see: https:/\/github.com/ethers-io/ethers.js/issues/4537 )`, "BUFFER_OVERRUN", {            buffer: (0, index_js_1.getBytesCopy)(this.#data), offset: this.#offset,            length: count, info: {                bytesRead: this.#bytesRead,                dataLength: this.dataLength            }        });    }    #peekBytes(offset, length, loose) {        let alignedLength = Math.ceil(length / exports.WordSize) * exports.WordSize;        if (this.#offset + alignedLength > this.#data.length) {            if (this.allowLoose && loose && this.#offset + length <= this.#data.length) {                alignedLength = length;            }            else {                (0, index_js_1.assert)(false, "data out-of-bounds", "BUFFER_OVERRUN", {                    buffer: (0, index_js_1.getBytesCopy)(this.#data),                    length: this.#data.length,                    offset: this.#offset + alignedLength                });            }        }        return this.#data.slice(this.#offset, this.#offset + alignedLength);    }    // Create a sub-reader with the same underlying data, but offset    subReader(offset) {        const reader = new Reader(this.#data.slice(this.#offset + offset), this.allowLoose, this.#maxInflation);        reader.#parent = this;        return reader;    }    // Read bytes    readBytes(length, loose) {        let bytes = this.#peekBytes(0, length, !!loose);        this.#incrementBytesRead(length);        this.#offset += bytes.length;        // @TODO: Make sure the length..end bytes are all 0?        return bytes.slice(0, length);    }    // Read a numeric values    readValue() {        return (0, index_js_1.toBigInt)(this.readBytes(exports.WordSize));    }    readIndex() {        return (0, index_js_1.toNumber)(this.readBytes(exports.WordSize));    }}exports.Reader = Reader;//# sourceMappingURL=abstract-coder.js.map
 |