"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); var bignumber_1 = require("@ethersproject/bignumber"); var errors = __importStar(require("@ethersproject/errors")); var properties_1 = require("@ethersproject/properties"); ; var _constructorGuard = {}; var ModifiersBytes = { calldata: true, memory: true, storage: true }; function checkModifier(type, name) { if (type === "bytes" || type === "string") { if (ModifiersBytes[name]) { return true; } } else if (type === "address") { if (name === "payable") { return true; } } if (ModifiersBytes[name] || name === "payable") { errors.throwArgumentError("invalid modifier", "name", name); } return false; } // @TODO: Make sure that children of an indexed tuple are marked with a null indexed function parseParamType(param, allowIndexed) { var originalParam = param; function throwError(i) { throw new Error("unexpected character '" + originalParam[i] + "' at position " + i + " in '" + originalParam + "'"); } param = param.replace(/\s/g, " "); function newNode(parent) { var node = { type: "", name: "", parent: parent, state: { allowType: true } }; if (allowIndexed) { node.indexed = false; } return node; } var parent = { type: "", name: "", state: { allowType: true } }; var node = parent; for (var i = 0; i < param.length; i++) { var c = param[i]; switch (c) { case "(": if (!node.state.allowParams) { throwError(i); } node.state.allowType = false; node.type = verifyType(node.type); node.components = [newNode(node)]; node = node.components[0]; break; case ")": delete node.state; if (node.name === "indexed") { if (!allowIndexed) { throwError(i); } node.indexed = true; node.name = ""; } if (checkModifier(node.type, node.name)) { node.name = ""; } node.type = verifyType(node.type); var child = node; node = node.parent; if (!node) { throwError(i); } delete child.parent; node.state.allowParams = false; node.state.allowName = true; node.state.allowArray = true; break; case ",": delete node.state; if (node.name === "indexed") { if (!allowIndexed) { throwError(i); } node.indexed = true; node.name = ""; } if (checkModifier(node.type, node.name)) { node.name = ""; } node.type = verifyType(node.type); var sibling = newNode(node.parent); //{ type: "", name: "", parent: node.parent, state: { allowType: true } }; node.parent.components.push(sibling); delete node.parent; node = sibling; break; // Hit a space... case " ": // If reading type, the type is done and may read a param or name if (node.state.allowType) { if (node.type !== "") { node.type = verifyType(node.type); delete node.state.allowType; node.state.allowName = true; node.state.allowParams = true; } } // If reading name, the name is done if (node.state.allowName) { if (node.name !== "") { if (node.name === "indexed") { if (!allowIndexed) { throwError(i); } if (node.indexed) { throwError(i); } node.indexed = true; node.name = ""; } else if (checkModifier(node.type, node.name)) { node.name = ""; } else { node.state.allowName = false; } } } break; case "[": if (!node.state.allowArray) { throwError(i); } node.type += c; node.state.allowArray = false; node.state.allowName = false; node.state.readArray = true; break; case "]": if (!node.state.readArray) { throwError(i); } node.type += c; node.state.readArray = false; node.state.allowArray = true; node.state.allowName = true; break; default: if (node.state.allowType) { node.type += c; node.state.allowParams = true; node.state.allowArray = true; } else if (node.state.allowName) { node.name += c; delete node.state.allowArray; } else if (node.state.readArray) { node.type += c; } else { throwError(i); } } } if (node.parent) { throw new Error("unexpected eof"); } delete parent.state; if (node.name === "indexed") { if (!allowIndexed) { throwError(originalParam.length - 7); } if (node.indexed) { throwError(originalParam.length - 7); } node.indexed = true; node.name = ""; } else if (checkModifier(node.type, node.name)) { node.name = ""; } parent.type = verifyType(parent.type); return parent; } function populate(object, params) { for (var key in params) { properties_1.defineReadOnly(object, key, params[key]); } } exports.FormatTypes = Object.freeze({ // Bare formatting, as is needed for computing a sighash of an event or function sighash: "sighash", // Human-Readable with Minimal spacing and without names (compact human-readable) minimal: "minimal", // Human-Readble with nice spacing, including all names full: "full", // JSON-format a la Solidity json: "json" }); var paramTypeArray = new RegExp(/^(.*)\[([0-9]*)\]$/); var ParamType = /** @class */ (function () { function ParamType(constructorGuard, params) { if (constructorGuard !== _constructorGuard) { throw new Error("use fromString"); } populate(this, params); var match = this.type.match(paramTypeArray); if (match) { populate(this, { arrayLength: parseInt(match[2] || "-1"), arrayChildren: ParamType.fromObject({ type: match[1], components: this.components }), baseType: "array" }); } else { populate(this, { arrayLength: null, arrayChildren: null, baseType: ((this.components != null) ? "tuple" : this.type) }); } this._isParamType = true; Object.freeze(this); } // Format the parameter fragment // - sighash: "(uint256,address)" // - minimal: "tuple(uint256,address) indexed" // - full: "tuple(uint256 foo, addres bar) indexed baz" ParamType.prototype.format = function (format) { if (!format) { format = exports.FormatTypes.sighash; } if (!exports.FormatTypes[format]) { errors.throwArgumentError("invalid format type", "format", format); } if (format === exports.FormatTypes.json) { var result_1 = { type: ((this.baseType === "tuple") ? "tuple" : this.type), name: (this.name || undefined) }; if (typeof (this.indexed) === "boolean") { result_1.indexed = this.indexed; } if (this.components) { result_1.components = this.components.map(function (comp) { return JSON.parse(comp.format(format)); }); } return JSON.stringify(result_1); } var result = ""; // Array if (this.baseType === "array") { result += this.arrayChildren.format(format); result += "[" + (this.arrayLength < 0 ? "" : String(this.arrayLength)) + "]"; } else { if (this.baseType === "tuple") { if (format !== exports.FormatTypes.sighash) { result += this.type; } result += "(" + this.components.map(function (comp) { return comp.format(format); }).join((format === exports.FormatTypes.full) ? ", " : ",") + ")"; } else { result += this.type; } } if (format !== exports.FormatTypes.sighash) { if (this.indexed === true) { result += " indexed"; } if (format === exports.FormatTypes.full && this.name) { result += " " + this.name; } } return result; }; ParamType.from = function (value, allowIndexed) { if (typeof (value) === "string") { return ParamType.fromString(value, allowIndexed); } return ParamType.fromObject(value); }; ParamType.fromObject = function (value) { if (ParamType.isParamType(value)) { return value; } return new ParamType(_constructorGuard, { name: (value.name || null), type: verifyType(value.type), indexed: ((value.indexed == null) ? null : !!value.indexed), components: (value.components ? value.components.map(ParamType.fromObject) : null) }); }; ParamType.fromString = function (value, allowIndexed) { function ParamTypify(node) { return ParamType.fromObject({ name: node.name, type: node.type, indexed: node.indexed, components: node.components }); } return ParamTypify(parseParamType(value, !!allowIndexed)); }; ParamType.isParamType = function (value) { return !!(value != null && value._isParamType); }; return ParamType; }()); exports.ParamType = ParamType; ; function parseParams(value, allowIndex) { return splitNesting(value).map(function (param) { return ParamType.fromString(param, allowIndex); }); } var Fragment = /** @class */ (function () { function Fragment(constructorGuard, params) { if (constructorGuard !== _constructorGuard) { throw new Error("use a static from method"); } populate(this, params); this._isFragment = true; Object.freeze(this); } Fragment.from = function (value) { if (Fragment.isFragment(value)) { return value; } if (typeof (value) === "string") { return Fragment.fromString(value); } return Fragment.fromObject(value); }; Fragment.fromObject = function (value) { if (Fragment.isFragment(value)) { return value; } if (value.type === "function") { return FunctionFragment.fromObject(value); } else if (value.type === "event") { return EventFragment.fromObject(value); } else if (value.type === "constructor") { return ConstructorFragment.fromObject(value); } else if (value.type === "fallback") { // @TODO: return null; } return errors.throwArgumentError("invalid fragment object", "value", value); }; Fragment.fromString = function (value) { // Make sure the "returns" is surrounded by a space and all whitespace is exactly one space value = value.replace(/\s/g, " "); value = value.replace(/\(/g, " (").replace(/\)/g, ") ").replace(/\s+/g, " "); value = value.trim(); if (value.split(" ")[0] === "event") { return EventFragment.fromString(value.substring(5).trim()); } else if (value.split(" ")[0] === "function") { return FunctionFragment.fromString(value.substring(8).trim()); } else if (value.split("(")[0].trim() === "constructor") { return ConstructorFragment.fromString(value.trim()); } throw new Error("unknown fragment"); }; Fragment.isFragment = function (value) { return !!(value && value._isFragment); }; return Fragment; }()); exports.Fragment = Fragment; var EventFragment = /** @class */ (function (_super) { __extends(EventFragment, _super); function EventFragment() { return _super !== null && _super.apply(this, arguments) || this; } EventFragment.prototype.format = function (format) { if (!format) { format = exports.FormatTypes.sighash; } if (!exports.FormatTypes[format]) { errors.throwArgumentError("invalid format type", "format", format); } if (format === exports.FormatTypes.json) { return JSON.stringify({ type: "event", anonymous: this.anonymous, name: this.name, inputs: this.inputs.map(function (input) { return JSON.parse(input.format(format)); }) }); } var result = ""; if (format !== exports.FormatTypes.sighash) { result += "event "; } result += this.name + "(" + this.inputs.map(function (input) { return input.format(format); }).join((format === exports.FormatTypes.full) ? ", " : ",") + ") "; if (format !== exports.FormatTypes.sighash) { if (this.anonymous) { result += "anonymous "; } } return result.trim(); }; EventFragment.from = function (value) { if (typeof (value) === "string") { return EventFragment.fromString(value); } return EventFragment.fromObject(value); }; EventFragment.fromObject = function (value) { if (EventFragment.isEventFragment(value)) { return value; } if (value.type !== "event") { throw new Error("invalid event object - " + value.type); } return new EventFragment(_constructorGuard, { name: verifyIdentifier(value.name), anonymous: value.anonymous, inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), type: "event" }); }; EventFragment.fromString = function (value) { var match = value.match(regexParen); if (!match) { throw new Error("invalid event: " + value); } var anonymous = false; match[3].split(" ").forEach(function (modifier) { switch (modifier.trim()) { case "anonymous": anonymous = true; break; case "": break; default: errors.warn("unknown modifier: " + modifier); } }); return EventFragment.fromObject({ name: match[1].trim(), anonymous: anonymous, inputs: parseParams(match[2], true), type: "event" }); }; EventFragment.isEventFragment = function (value) { return (value && value._isFragment && value.type === "event"); }; return EventFragment; }(Fragment)); exports.EventFragment = EventFragment; function parseGas(value, params) { params.gas = null; var comps = value.split("@"); if (comps.length !== 1) { if (comps.length > 2) { throw new Error("invalid signature"); } if (!comps[1].match(/^[0-9]+$/)) { throw new Error("invalid signature gas"); } params.gas = bignumber_1.BigNumber.from(comps[1]); return comps[0]; } return value; } function parseModifiers(value, params) { params.constant = false; params.payable = false; params.stateMutability = "nonpayable"; value.split(" ").forEach(function (modifier) { switch (modifier.trim()) { case "constant": params.constant = true; break; case "payable": params.payable = true; params.stateMutability = "payable"; break; case "pure": params.constant = true; params.stateMutability = "pure"; break; case "view": params.constant = true; params.stateMutability = "view"; break; case "external": case "public": case "": break; default: console.log("unknown modifier: " + modifier); } }); } function verifyState(value) { var result = { constant: false, payable: true, stateMutability: "payable" }; if (value.stateMutability != null) { result.stateMutability = value.stateMutability; result.constant = (result.stateMutability === "view" || result.stateMutability === "pure"); if (value.constant != null) { if ((!!value.constant) !== result.constant) { throw new Error("cannot have constant function with mutability " + result.stateMutability); } } result.payable = (result.stateMutability === "payable"); if (value.payable != null) { if ((!!value.payable) !== result.payable) { throw new Error("cannot have payable function with mutability " + result.stateMutability); } } } else if (value.payable != null) { result.payable = !!value.payable; result.stateMutability = (result.payable ? "payable" : "nonpayable"); result.constant = !result.payable; if (value.constant != null && (value.constant !== result.constant)) { throw new Error("cannot have constant payable function"); } } else if (value.constant != null) { result.constant = !!value.constant; result.payable = !result.constant; result.stateMutability = (result.constant ? "view" : "payable"); } return result; } var ConstructorFragment = /** @class */ (function (_super) { __extends(ConstructorFragment, _super); function ConstructorFragment() { return _super !== null && _super.apply(this, arguments) || this; } ConstructorFragment.prototype.format = function (format) { if (!format) { format = exports.FormatTypes.sighash; } if (!exports.FormatTypes[format]) { errors.throwArgumentError("invalid format type", "format", format); } if (format === exports.FormatTypes.json) { return JSON.stringify({ type: "constructor", stateMutability: ((this.stateMutability !== "nonpayable") ? this.stateMutability : undefined), payble: this.payable, gas: (this.gas ? this.gas.toNumber() : undefined), inputs: this.inputs.map(function (input) { return JSON.parse(input.format(format)); }) }); } if (format === exports.FormatTypes.sighash) { errors.throwError("cannot format a constructor for sighash", errors.UNSUPPORTED_OPERATION, { operation: "format(sighash)" }); } var result = "constructor(" + this.inputs.map(function (input) { return input.format(format); }).join((format === exports.FormatTypes.full) ? ", " : ",") + ") "; if (this.stateMutability && this.stateMutability !== "nonpayable") { result += this.stateMutability + " "; } return result.trim(); }; ConstructorFragment.from = function (value) { if (typeof (value) === "string") { return ConstructorFragment.fromString(value); } return ConstructorFragment.fromObject(value); }; ConstructorFragment.fromObject = function (value) { if (ConstructorFragment.isConstructorFragment(value)) { return value; } if (value.type !== "constructor") { throw new Error("invalid constructor object - " + value.type); } var state = verifyState(value); if (state.constant) { throw new Error("constructor cannot be constant"); } return new ConstructorFragment(_constructorGuard, { type: value.type, inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), payable: state.payable, gas: (value.gas ? bignumber_1.BigNumber.from(value.gas) : null) }); }; ConstructorFragment.fromString = function (value) { var params = { type: "constructor" }; value = parseGas(value, params); var parens = value.match(regexParen); if (!parens) { throw new Error("invalid constructor: " + value); } if (parens[1].trim() !== "constructor") { throw new Error("invalid constructor"); } params.inputs = parseParams(parens[2].trim(), false); parseModifiers(parens[3].trim(), params); return ConstructorFragment.fromObject(params); }; ConstructorFragment.isConstructorFragment = function (value) { return (value && value._isFragment && value.type === "constructor"); }; return ConstructorFragment; }(Fragment)); exports.ConstructorFragment = ConstructorFragment; var FunctionFragment = /** @class */ (function (_super) { __extends(FunctionFragment, _super); function FunctionFragment() { return _super !== null && _super.apply(this, arguments) || this; } FunctionFragment.prototype.format = function (format) { if (!format) { format = exports.FormatTypes.sighash; } if (!exports.FormatTypes[format]) { errors.throwArgumentError("invalid format type", "format", format); } if (format === exports.FormatTypes.json) { return JSON.stringify({ type: "function", name: this.name, constant: this.constant, stateMutability: ((this.stateMutability !== "nonpayable") ? this.stateMutability : undefined), payble: this.payable, gas: (this.gas ? this.gas.toNumber() : undefined), inputs: this.inputs.map(function (input) { return JSON.parse(input.format(format)); }), ouputs: this.outputs.map(function (output) { return JSON.parse(output.format(format)); }), }); } var result = ""; if (format !== exports.FormatTypes.sighash) { result += "function "; } result += this.name + "(" + this.inputs.map(function (input) { return input.format(format); }).join((format === exports.FormatTypes.full) ? ", " : ",") + ") "; if (format !== exports.FormatTypes.sighash) { if (this.stateMutability) { if (this.stateMutability !== "nonpayable") { result += (this.stateMutability + " "); } } else if (this.constant) { result += "view "; } if (this.outputs && this.outputs.length) { result += "returns (" + this.outputs.map(function (output) { return output.format(format); }).join(", ") + ") "; } if (this.gas != null) { result += "@" + this.gas.toString() + " "; } } return result.trim(); }; FunctionFragment.from = function (value) { if (typeof (value) === "string") { return FunctionFragment.fromString(value); } return FunctionFragment.fromObject(value); }; FunctionFragment.fromObject = function (value) { if (FunctionFragment.isFunctionFragment(value)) { return value; } if (value.type !== "function") { throw new Error("invalid function object - " + value.type); } var state = verifyState(value); return new FunctionFragment(_constructorGuard, { type: value.type, name: verifyIdentifier(value.name), constant: state.constant, inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []), outputs: (value.outputs ? value.outputs.map(ParamType.fromObject) : []), payable: state.payable, stateMutability: state.stateMutability, gas: (value.gas ? bignumber_1.BigNumber.from(value.gas) : null) }); }; FunctionFragment.fromString = function (value) { var params = { type: "function" }; value = parseGas(value, params); var comps = value.split(" returns "); if (comps.length > 2) { throw new Error("invalid function"); } var parens = comps[0].match(regexParen); if (!parens) { throw new Error("invalid signature"); } params.name = parens[1].trim(); if (!params.name.match(regexIdentifier)) { throw new Error("invalid identifier: '" + params.name + "'"); } params.inputs = parseParams(parens[2], false); parseModifiers(parens[3].trim(), params); // We have outputs if (comps.length > 1) { var returns = comps[1].match(regexParen); if (returns[1].trim() != "" || returns[3].trim() != "") { throw new Error("unexpected tokens"); } params.outputs = parseParams(returns[2], false); } else { params.outputs = []; } return FunctionFragment.fromObject(params); }; FunctionFragment.isFunctionFragment = function (value) { return (value && value._isFragment && value.type === "function"); }; return FunctionFragment; }(ConstructorFragment)); exports.FunctionFragment = FunctionFragment; //export class ErrorFragment extends Fragment { //} //export class StructFragment extends Fragment { //} function verifyType(type) { // These need to be transformed to their full description if (type.match(/^uint($|[^1-9])/)) { type = "uint256" + type.substring(4); } else if (type.match(/^int($|[^1-9])/)) { type = "int256" + type.substring(3); } // @TODO: more verification return type; } var regexIdentifier = new RegExp("^[A-Za-z_][A-Za-z0-9_]*$"); function verifyIdentifier(value) { if (!value || !value.match(regexIdentifier)) { throw new Error("invalid identifier: '" + value + "'"); } return value; } var regexParen = new RegExp("^([^)(]*)\\((.*)\\)([^)(]*)$"); function splitNesting(value) { value = value.trim(); var result = []; var accum = ""; var depth = 0; for (var offset = 0; offset < value.length; offset++) { var c = value[offset]; if (c === "," && depth === 0) { result.push(accum); accum = ""; } else { accum += c; if (c === "(") { depth++; } else if (c === ")") { depth--; if (depth === -1) { throw new Error("unbalanced parenthsis"); } } } } if (accum) { result.push(accum); } return result; }