2019-05-14 18:48:48 -04:00
|
|
|
"use strict";
|
2019-08-25 02:39:20 -04:00
|
|
|
import { BigNumber } from "@ethersproject/bignumber";
|
|
|
|
import { defineReadOnly } from "@ethersproject/properties";
|
|
|
|
import { Logger } from "@ethersproject/logger";
|
|
|
|
import { version } from "./_version";
|
|
|
|
const logger = new Logger(version);
|
2019-05-14 18:48:48 -04:00
|
|
|
;
|
2019-08-25 02:39:20 -04:00
|
|
|
const _constructorGuard = {};
|
|
|
|
let ModifiersBytes = { calldata: true, memory: true, storage: true };
|
2020-05-01 17:00:44 -04:00
|
|
|
let ModifiersNest = { calldata: true, memory: true };
|
2019-07-20 20:13:00 -03:00
|
|
|
function checkModifier(type, name) {
|
|
|
|
if (type === "bytes" || type === "string") {
|
|
|
|
if (ModifiersBytes[name]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type === "address") {
|
|
|
|
if (name === "payable") {
|
|
|
|
return true;
|
2020-05-01 17:00:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type.indexOf("[") >= 0 || type === "tuple") {
|
|
|
|
if (ModifiersNest[name]) {
|
|
|
|
return true;
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ModifiersBytes[name] || name === "payable") {
|
2019-08-02 02:10:58 -04:00
|
|
|
logger.throwArgumentError("invalid modifier", "name", name);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2019-05-14 18:48:48 -04:00
|
|
|
// @TODO: Make sure that children of an indexed tuple are marked with a null indexed
|
|
|
|
function parseParamType(param, allowIndexed) {
|
2019-08-25 02:39:20 -04:00
|
|
|
let originalParam = param;
|
2019-05-14 18:48:48 -04:00
|
|
|
function throwError(i) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError(`unexpected character at position ${i}`, "param", param);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
param = param.replace(/\s/g, " ");
|
|
|
|
function newNode(parent) {
|
2019-08-25 02:39:20 -04:00
|
|
|
let node = { type: "", name: "", parent: parent, state: { allowType: true } };
|
2019-05-14 18:48:48 -04:00
|
|
|
if (allowIndexed) {
|
|
|
|
node.indexed = false;
|
|
|
|
}
|
|
|
|
return node;
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let parent = { type: "", name: "", state: { allowType: true } };
|
|
|
|
let node = parent;
|
|
|
|
for (let i = 0; i < param.length; i++) {
|
|
|
|
let c = param[i];
|
2019-05-14 18:48:48 -04:00
|
|
|
switch (c) {
|
|
|
|
case "(":
|
2019-11-20 18:57:38 +09:00
|
|
|
if (node.state.allowType && node.type === "") {
|
|
|
|
node.type = "tuple";
|
|
|
|
}
|
|
|
|
else if (!node.state.allowParams) {
|
2019-05-14 18:48:48 -04:00
|
|
|
throwError(i);
|
|
|
|
}
|
|
|
|
node.state.allowType = false;
|
|
|
|
node.type = verifyType(node.type);
|
|
|
|
node.components = [newNode(node)];
|
|
|
|
node = node.components[0];
|
|
|
|
break;
|
|
|
|
case ")":
|
|
|
|
delete node.state;
|
2019-05-24 18:15:42 -04:00
|
|
|
if (node.name === "indexed") {
|
|
|
|
if (!allowIndexed) {
|
|
|
|
throwError(i);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-05-24 18:15:42 -04:00
|
|
|
node.indexed = true;
|
|
|
|
node.name = "";
|
|
|
|
}
|
2019-07-20 20:13:00 -03:00
|
|
|
if (checkModifier(node.type, node.name)) {
|
2019-05-24 18:15:42 -04:00
|
|
|
node.name = "";
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
node.type = verifyType(node.type);
|
2019-08-25 02:39:20 -04:00
|
|
|
let child = node;
|
2019-05-14 18:48:48 -04:00
|
|
|
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;
|
2019-05-24 18:15:42 -04:00
|
|
|
if (node.name === "indexed") {
|
|
|
|
if (!allowIndexed) {
|
|
|
|
throwError(i);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-05-24 18:15:42 -04:00
|
|
|
node.indexed = true;
|
|
|
|
node.name = "";
|
|
|
|
}
|
2019-07-20 20:13:00 -03:00
|
|
|
if (checkModifier(node.type, node.name)) {
|
2019-05-24 18:15:42 -04:00
|
|
|
node.name = "";
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
node.type = verifyType(node.type);
|
2019-08-25 02:39:20 -04:00
|
|
|
let sibling = newNode(node.parent);
|
2019-05-14 18:48:48 -04:00
|
|
|
//{ 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 !== "") {
|
2019-05-24 18:15:42 -04:00
|
|
|
if (node.name === "indexed") {
|
|
|
|
if (!allowIndexed) {
|
|
|
|
throwError(i);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-05-24 18:15:42 -04:00
|
|
|
if (node.indexed) {
|
|
|
|
throwError(i);
|
|
|
|
}
|
|
|
|
node.indexed = true;
|
|
|
|
node.name = "";
|
|
|
|
}
|
2019-07-20 20:13:00 -03:00
|
|
|
else if (checkModifier(node.type, node.name)) {
|
2019-05-24 18:15:42 -04:00
|
|
|
node.name = "";
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
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) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("unexpected eof", "param", param);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
delete parent.state;
|
2019-05-24 18:15:42 -04:00
|
|
|
if (node.name === "indexed") {
|
|
|
|
if (!allowIndexed) {
|
|
|
|
throwError(originalParam.length - 7);
|
|
|
|
}
|
|
|
|
if (node.indexed) {
|
|
|
|
throwError(originalParam.length - 7);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-05-24 18:15:42 -04:00
|
|
|
node.indexed = true;
|
|
|
|
node.name = "";
|
|
|
|
}
|
2019-07-20 20:13:00 -03:00
|
|
|
else if (checkModifier(node.type, node.name)) {
|
2019-05-24 18:15:42 -04:00
|
|
|
node.name = "";
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
parent.type = verifyType(parent.type);
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
function populate(object, params) {
|
2019-08-25 02:39:20 -04:00
|
|
|
for (let key in params) {
|
|
|
|
defineReadOnly(object, key, params[key]);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
export const FormatTypes = Object.freeze({
|
2019-07-20 20:13:00 -03:00
|
|
|
// 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"
|
|
|
|
});
|
2019-08-25 02:39:20 -04:00
|
|
|
const paramTypeArray = new RegExp(/^(.*)\[([0-9]*)\]$/);
|
|
|
|
export class ParamType {
|
|
|
|
constructor(constructorGuard, params) {
|
2019-05-14 18:48:48 -04:00
|
|
|
if (constructorGuard !== _constructorGuard) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwError("use fromString", Logger.errors.UNSUPPORTED_OPERATION, {
|
|
|
|
operation: "new ParamType()"
|
|
|
|
});
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
populate(this, params);
|
2019-08-25 02:39:20 -04:00
|
|
|
let match = this.type.match(paramTypeArray);
|
2019-05-14 18:48:48 -04:00
|
|
|
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)
|
|
|
|
});
|
|
|
|
}
|
2019-06-11 17:57:04 -04:00
|
|
|
this._isParamType = true;
|
|
|
|
Object.freeze(this);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
// Format the parameter fragment
|
2019-07-20 20:13:00 -03:00
|
|
|
// - sighash: "(uint256,address)"
|
|
|
|
// - minimal: "tuple(uint256,address) indexed"
|
|
|
|
// - full: "tuple(uint256 foo, addres bar) indexed baz"
|
2019-08-25 02:39:20 -04:00
|
|
|
format(format) {
|
2019-07-20 20:13:00 -03:00
|
|
|
if (!format) {
|
2019-08-25 02:39:20 -04:00
|
|
|
format = FormatTypes.sighash;
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (!FormatTypes[format]) {
|
2019-08-02 02:10:58 -04:00
|
|
|
logger.throwArgumentError("invalid format type", "format", format);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format === FormatTypes.json) {
|
|
|
|
let result = {
|
2019-07-20 20:13:00 -03:00
|
|
|
type: ((this.baseType === "tuple") ? "tuple" : this.type),
|
|
|
|
name: (this.name || undefined)
|
|
|
|
};
|
|
|
|
if (typeof (this.indexed) === "boolean") {
|
2019-08-25 02:39:20 -04:00
|
|
|
result.indexed = this.indexed;
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
|
|
|
if (this.components) {
|
2019-08-25 02:39:20 -04:00
|
|
|
result.components = this.components.map((comp) => JSON.parse(comp.format(format)));
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
return JSON.stringify(result);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let result = "";
|
2019-05-14 18:48:48 -04:00
|
|
|
// Array
|
|
|
|
if (this.baseType === "array") {
|
2019-07-20 20:13:00 -03:00
|
|
|
result += this.arrayChildren.format(format);
|
2019-05-14 18:48:48 -04:00
|
|
|
result += "[" + (this.arrayLength < 0 ? "" : String(this.arrayLength)) + "]";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (this.baseType === "tuple") {
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format !== FormatTypes.sighash) {
|
2019-05-14 18:48:48 -04:00
|
|
|
result += this.type;
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
result += "(" + this.components.map((comp) => comp.format(format)).join((format === FormatTypes.full) ? ", " : ",") + ")";
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
result += this.type;
|
|
|
|
}
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format !== FormatTypes.sighash) {
|
2019-05-14 18:48:48 -04:00
|
|
|
if (this.indexed === true) {
|
|
|
|
result += " indexed";
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format === FormatTypes.full && this.name) {
|
2019-05-14 18:48:48 -04:00
|
|
|
result += " " + this.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static from(value, allowIndexed) {
|
2019-05-14 18:48:48 -04:00
|
|
|
if (typeof (value) === "string") {
|
|
|
|
return ParamType.fromString(value, allowIndexed);
|
|
|
|
}
|
|
|
|
return ParamType.fromObject(value);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromObject(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
if (ParamType.isParamType(value)) {
|
2019-05-14 18:48:48 -04:00
|
|
|
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)
|
|
|
|
});
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromString(value, allowIndexed) {
|
2019-05-14 18:48:48 -04:00
|
|
|
function ParamTypify(node) {
|
|
|
|
return ParamType.fromObject({
|
|
|
|
name: node.name,
|
|
|
|
type: node.type,
|
|
|
|
indexed: node.indexed,
|
|
|
|
components: node.components
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return ParamTypify(parseParamType(value, !!allowIndexed));
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static isParamType(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
return !!(value != null && value._isParamType);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
}
|
2019-05-14 18:48:48 -04:00
|
|
|
;
|
|
|
|
function parseParams(value, allowIndex) {
|
2019-08-25 02:39:20 -04:00
|
|
|
return splitNesting(value).map((param) => ParamType.fromString(param, allowIndex));
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
export class Fragment {
|
|
|
|
constructor(constructorGuard, params) {
|
2019-05-14 18:48:48 -04:00
|
|
|
if (constructorGuard !== _constructorGuard) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwError("use a static from method", Logger.errors.UNSUPPORTED_OPERATION, {
|
|
|
|
operation: "new Fragment()"
|
|
|
|
});
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
populate(this, params);
|
2019-06-11 17:57:04 -04:00
|
|
|
this._isFragment = true;
|
|
|
|
Object.freeze(this);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
static from(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
if (Fragment.isFragment(value)) {
|
|
|
|
return value;
|
|
|
|
}
|
2019-05-14 18:48:48 -04:00
|
|
|
if (typeof (value) === "string") {
|
|
|
|
return Fragment.fromString(value);
|
|
|
|
}
|
|
|
|
return Fragment.fromObject(value);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromObject(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
if (Fragment.isFragment(value)) {
|
2019-05-14 18:48:48 -04:00
|
|
|
return value;
|
|
|
|
}
|
2020-03-21 12:48:22 -04:00
|
|
|
switch (value.type) {
|
|
|
|
case "function":
|
|
|
|
return FunctionFragment.fromObject(value);
|
|
|
|
case "event":
|
|
|
|
return EventFragment.fromObject(value);
|
|
|
|
case "constructor":
|
|
|
|
return ConstructorFragment.fromObject(value);
|
2021-04-22 06:34:02 -04:00
|
|
|
case "error":
|
2021-05-17 16:19:36 -04:00
|
|
|
return ErrorFragment.fromObject(value);
|
2020-03-21 12:48:22 -04:00
|
|
|
case "fallback":
|
|
|
|
case "receive":
|
|
|
|
// @TODO: Something? Maybe return a FunctionFragment? A custom DefaultFunctionFragment?
|
|
|
|
return null;
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-02 02:10:58 -04:00
|
|
|
return logger.throwArgumentError("invalid fragment object", "value", value);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromString(value) {
|
2019-05-14 18:48:48 -04:00
|
|
|
// 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());
|
|
|
|
}
|
2021-05-17 16:19:36 -04:00
|
|
|
else if (value.split(" ")[0] === "error") {
|
|
|
|
return ErrorFragment.fromString(value.substring(5).trim());
|
|
|
|
}
|
2020-04-15 18:28:04 -04:00
|
|
|
return logger.throwArgumentError("unsupported fragment", "value", value);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static isFragment(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
return !!(value && value._isFragment);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
export class EventFragment extends Fragment {
|
|
|
|
format(format) {
|
2019-07-20 20:13:00 -03:00
|
|
|
if (!format) {
|
2019-08-25 02:39:20 -04:00
|
|
|
format = FormatTypes.sighash;
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (!FormatTypes[format]) {
|
2019-08-02 02:10:58 -04:00
|
|
|
logger.throwArgumentError("invalid format type", "format", format);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format === FormatTypes.json) {
|
2019-07-20 20:13:00 -03:00
|
|
|
return JSON.stringify({
|
|
|
|
type: "event",
|
|
|
|
anonymous: this.anonymous,
|
|
|
|
name: this.name,
|
2019-08-25 02:39:20 -04:00
|
|
|
inputs: this.inputs.map((input) => JSON.parse(input.format(format)))
|
2019-07-20 20:13:00 -03:00
|
|
|
});
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let result = "";
|
|
|
|
if (format !== FormatTypes.sighash) {
|
2019-07-20 20:13:00 -03:00
|
|
|
result += "event ";
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
result += this.name + "(" + this.inputs.map((input) => input.format(format)).join((format === FormatTypes.full) ? ", " : ",") + ") ";
|
|
|
|
if (format !== FormatTypes.sighash) {
|
2019-07-20 20:13:00 -03:00
|
|
|
if (this.anonymous) {
|
|
|
|
result += "anonymous ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result.trim();
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static from(value) {
|
2019-05-14 18:48:48 -04:00
|
|
|
if (typeof (value) === "string") {
|
|
|
|
return EventFragment.fromString(value);
|
|
|
|
}
|
|
|
|
return EventFragment.fromObject(value);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromObject(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
if (EventFragment.isEventFragment(value)) {
|
2019-05-14 18:48:48 -04:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
if (value.type !== "event") {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("invalid event object", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2020-04-25 03:54:54 -04:00
|
|
|
const params = {
|
2019-05-14 18:48:48 -04:00
|
|
|
name: verifyIdentifier(value.name),
|
|
|
|
anonymous: value.anonymous,
|
|
|
|
inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []),
|
|
|
|
type: "event"
|
2020-04-25 03:54:54 -04:00
|
|
|
};
|
|
|
|
return new EventFragment(_constructorGuard, params);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromString(value) {
|
|
|
|
let match = value.match(regexParen);
|
2019-05-14 18:48:48 -04:00
|
|
|
if (!match) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("invalid event string", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let anonymous = false;
|
|
|
|
match[3].split(" ").forEach((modifier) => {
|
2019-05-14 18:48:48 -04:00
|
|
|
switch (modifier.trim()) {
|
|
|
|
case "anonymous":
|
|
|
|
anonymous = true;
|
|
|
|
break;
|
|
|
|
case "":
|
|
|
|
break;
|
|
|
|
default:
|
2019-08-02 02:10:58 -04:00
|
|
|
logger.warn("unknown modifier: " + modifier);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return EventFragment.fromObject({
|
|
|
|
name: match[1].trim(),
|
|
|
|
anonymous: anonymous,
|
|
|
|
inputs: parseParams(match[2], true),
|
|
|
|
type: "event"
|
|
|
|
});
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static isEventFragment(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
return (value && value._isFragment && value.type === "event");
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
}
|
2019-05-14 18:48:48 -04:00
|
|
|
function parseGas(value, params) {
|
|
|
|
params.gas = null;
|
2019-08-25 02:39:20 -04:00
|
|
|
let comps = value.split("@");
|
2019-05-14 18:48:48 -04:00
|
|
|
if (comps.length !== 1) {
|
|
|
|
if (comps.length > 2) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("invalid human-readable ABI signature", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
if (!comps[1].match(/^[0-9]+$/)) {
|
2020-04-23 23:35:39 -04:00
|
|
|
logger.throwArgumentError("invalid human-readable ABI signature gas", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
params.gas = BigNumber.from(comps[1]);
|
2019-05-14 18:48:48 -04:00
|
|
|
return comps[0];
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
function parseModifiers(value, params) {
|
|
|
|
params.constant = false;
|
|
|
|
params.payable = false;
|
2019-05-24 18:15:42 -04:00
|
|
|
params.stateMutability = "nonpayable";
|
2019-08-25 02:39:20 -04:00
|
|
|
value.split(" ").forEach((modifier) => {
|
2019-05-14 18:48:48 -04:00
|
|
|
switch (modifier.trim()) {
|
|
|
|
case "constant":
|
|
|
|
params.constant = true;
|
|
|
|
break;
|
|
|
|
case "payable":
|
|
|
|
params.payable = true;
|
|
|
|
params.stateMutability = "payable";
|
|
|
|
break;
|
2020-06-12 04:57:38 -04:00
|
|
|
case "nonpayable":
|
|
|
|
params.payable = false;
|
|
|
|
params.stateMutability = "nonpayable";
|
|
|
|
break;
|
2019-05-14 18:48:48 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2019-07-20 20:13:00 -03:00
|
|
|
function verifyState(value) {
|
2019-08-25 02:39:20 -04:00
|
|
|
let result = {
|
2019-07-20 20:13:00 -03:00
|
|
|
constant: false,
|
|
|
|
payable: true,
|
|
|
|
stateMutability: "payable"
|
|
|
|
};
|
|
|
|
if (value.stateMutability != null) {
|
|
|
|
result.stateMutability = value.stateMutability;
|
2020-04-03 22:13:06 -04:00
|
|
|
// Set (and check things are consistent) the constant property
|
2019-07-20 20:13:00 -03:00
|
|
|
result.constant = (result.stateMutability === "view" || result.stateMutability === "pure");
|
|
|
|
if (value.constant != null) {
|
|
|
|
if ((!!value.constant) !== result.constant) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("cannot have constant function with mutability " + result.stateMutability, "value", value);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:13:06 -04:00
|
|
|
// Set (and check things are consistent) the payable property
|
2019-07-20 20:13:00 -03:00
|
|
|
result.payable = (result.stateMutability === "payable");
|
|
|
|
if (value.payable != null) {
|
|
|
|
if ((!!value.payable) !== result.payable) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("cannot have payable function with mutability " + result.stateMutability, "value", value);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (value.payable != null) {
|
|
|
|
result.payable = !!value.payable;
|
2020-04-03 22:13:06 -04:00
|
|
|
// If payable we can assume non-constant; otherwise we can't assume
|
|
|
|
if (value.constant == null && !result.payable && value.type !== "constructor") {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("unable to determine stateMutability", "value", value);
|
2020-04-03 22:13:06 -04:00
|
|
|
}
|
|
|
|
result.constant = !!value.constant;
|
|
|
|
if (result.constant) {
|
|
|
|
result.stateMutability = "view";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result.stateMutability = (result.payable ? "payable" : "nonpayable");
|
|
|
|
}
|
|
|
|
if (result.payable && result.constant) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("cannot have constant payable function", "value", value);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (value.constant != null) {
|
|
|
|
result.constant = !!value.constant;
|
|
|
|
result.payable = !result.constant;
|
|
|
|
result.stateMutability = (result.constant ? "view" : "payable");
|
|
|
|
}
|
2020-04-03 22:13:06 -04:00
|
|
|
else if (value.type !== "constructor") {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("unable to determine stateMutability", "value", value);
|
2020-04-03 22:13:06 -04:00
|
|
|
}
|
2019-07-20 20:13:00 -03:00
|
|
|
return result;
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
export class ConstructorFragment extends Fragment {
|
|
|
|
format(format) {
|
2019-07-20 20:13:00 -03:00
|
|
|
if (!format) {
|
2019-08-25 02:39:20 -04:00
|
|
|
format = FormatTypes.sighash;
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (!FormatTypes[format]) {
|
2019-08-02 02:10:58 -04:00
|
|
|
logger.throwArgumentError("invalid format type", "format", format);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format === FormatTypes.json) {
|
2019-07-20 20:13:00 -03:00
|
|
|
return JSON.stringify({
|
|
|
|
type: "constructor",
|
|
|
|
stateMutability: ((this.stateMutability !== "nonpayable") ? this.stateMutability : undefined),
|
2021-02-03 14:44:48 -05:00
|
|
|
payable: this.payable,
|
2019-07-20 20:13:00 -03:00
|
|
|
gas: (this.gas ? this.gas.toNumber() : undefined),
|
2019-08-25 02:39:20 -04:00
|
|
|
inputs: this.inputs.map((input) => JSON.parse(input.format(format)))
|
2019-07-20 20:13:00 -03:00
|
|
|
});
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format === FormatTypes.sighash) {
|
|
|
|
logger.throwError("cannot format a constructor for sighash", Logger.errors.UNSUPPORTED_OPERATION, {
|
2019-07-20 20:13:00 -03:00
|
|
|
operation: "format(sighash)"
|
|
|
|
});
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let result = "constructor(" + this.inputs.map((input) => input.format(format)).join((format === FormatTypes.full) ? ", " : ",") + ") ";
|
2019-07-20 20:13:00 -03:00
|
|
|
if (this.stateMutability && this.stateMutability !== "nonpayable") {
|
|
|
|
result += this.stateMutability + " ";
|
|
|
|
}
|
|
|
|
return result.trim();
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static from(value) {
|
2019-05-14 18:48:48 -04:00
|
|
|
if (typeof (value) === "string") {
|
|
|
|
return ConstructorFragment.fromString(value);
|
|
|
|
}
|
|
|
|
return ConstructorFragment.fromObject(value);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromObject(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
if (ConstructorFragment.isConstructorFragment(value)) {
|
2019-05-14 18:48:48 -04:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
if (value.type !== "constructor") {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("invalid constructor object", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let state = verifyState(value);
|
2019-07-20 20:13:00 -03:00
|
|
|
if (state.constant) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("constructor cannot be constant", "value", value);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2020-04-25 03:54:54 -04:00
|
|
|
const params = {
|
2020-01-06 19:00:55 -05:00
|
|
|
name: null,
|
2019-05-14 18:48:48 -04:00
|
|
|
type: value.type,
|
|
|
|
inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []),
|
2019-07-20 20:13:00 -03:00
|
|
|
payable: state.payable,
|
2020-04-25 03:54:54 -04:00
|
|
|
stateMutability: state.stateMutability,
|
2019-08-25 02:39:20 -04:00
|
|
|
gas: (value.gas ? BigNumber.from(value.gas) : null)
|
2020-04-25 03:54:54 -04:00
|
|
|
};
|
|
|
|
return new ConstructorFragment(_constructorGuard, params);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromString(value) {
|
|
|
|
let params = { type: "constructor" };
|
2019-05-14 18:48:48 -04:00
|
|
|
value = parseGas(value, params);
|
2019-08-25 02:39:20 -04:00
|
|
|
let parens = value.match(regexParen);
|
2020-04-15 18:28:04 -04:00
|
|
|
if (!parens || parens[1].trim() !== "constructor") {
|
|
|
|
logger.throwArgumentError("invalid constructor string", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
params.inputs = parseParams(parens[2].trim(), false);
|
|
|
|
parseModifiers(parens[3].trim(), params);
|
|
|
|
return ConstructorFragment.fromObject(params);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static isConstructorFragment(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
return (value && value._isFragment && value.type === "constructor");
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
export class FunctionFragment extends ConstructorFragment {
|
|
|
|
format(format) {
|
2019-07-20 20:13:00 -03:00
|
|
|
if (!format) {
|
2019-08-25 02:39:20 -04:00
|
|
|
format = FormatTypes.sighash;
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (!FormatTypes[format]) {
|
2019-08-02 02:10:58 -04:00
|
|
|
logger.throwArgumentError("invalid format type", "format", format);
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
if (format === FormatTypes.json) {
|
2019-07-20 20:13:00 -03:00
|
|
|
return JSON.stringify({
|
|
|
|
type: "function",
|
|
|
|
name: this.name,
|
|
|
|
constant: this.constant,
|
|
|
|
stateMutability: ((this.stateMutability !== "nonpayable") ? this.stateMutability : undefined),
|
2021-02-03 14:44:48 -05:00
|
|
|
payable: this.payable,
|
2019-07-20 20:13:00 -03:00
|
|
|
gas: (this.gas ? this.gas.toNumber() : undefined),
|
2019-08-25 02:39:20 -04:00
|
|
|
inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
|
2021-02-03 14:44:48 -05:00
|
|
|
outputs: this.outputs.map((output) => JSON.parse(output.format(format))),
|
2019-07-20 20:13:00 -03:00
|
|
|
});
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let result = "";
|
|
|
|
if (format !== FormatTypes.sighash) {
|
2019-07-20 20:13:00 -03:00
|
|
|
result += "function ";
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
result += this.name + "(" + this.inputs.map((input) => input.format(format)).join((format === FormatTypes.full) ? ", " : ",") + ") ";
|
|
|
|
if (format !== FormatTypes.sighash) {
|
2019-07-20 20:13:00 -03:00
|
|
|
if (this.stateMutability) {
|
|
|
|
if (this.stateMutability !== "nonpayable") {
|
|
|
|
result += (this.stateMutability + " ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (this.constant) {
|
|
|
|
result += "view ";
|
|
|
|
}
|
|
|
|
if (this.outputs && this.outputs.length) {
|
2019-08-25 02:39:20 -04:00
|
|
|
result += "returns (" + this.outputs.map((output) => output.format(format)).join(", ") + ") ";
|
2019-07-20 20:13:00 -03:00
|
|
|
}
|
|
|
|
if (this.gas != null) {
|
|
|
|
result += "@" + this.gas.toString() + " ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result.trim();
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static from(value) {
|
2019-05-14 18:48:48 -04:00
|
|
|
if (typeof (value) === "string") {
|
|
|
|
return FunctionFragment.fromString(value);
|
|
|
|
}
|
|
|
|
return FunctionFragment.fromObject(value);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromObject(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
if (FunctionFragment.isFunctionFragment(value)) {
|
2019-05-14 18:48:48 -04:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
if (value.type !== "function") {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("invalid function object", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let state = verifyState(value);
|
2020-04-25 03:54:54 -04:00
|
|
|
const params = {
|
2019-05-14 18:48:48 -04:00
|
|
|
type: value.type,
|
|
|
|
name: verifyIdentifier(value.name),
|
2019-07-20 20:13:00 -03:00
|
|
|
constant: state.constant,
|
2019-05-14 18:48:48 -04:00
|
|
|
inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : []),
|
|
|
|
outputs: (value.outputs ? value.outputs.map(ParamType.fromObject) : []),
|
2019-07-20 20:13:00 -03:00
|
|
|
payable: state.payable,
|
|
|
|
stateMutability: state.stateMutability,
|
2019-08-25 02:39:20 -04:00
|
|
|
gas: (value.gas ? BigNumber.from(value.gas) : null)
|
2020-04-25 03:54:54 -04:00
|
|
|
};
|
|
|
|
return new FunctionFragment(_constructorGuard, params);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static fromString(value) {
|
|
|
|
let params = { type: "function" };
|
2019-05-14 18:48:48 -04:00
|
|
|
value = parseGas(value, params);
|
2019-08-25 02:39:20 -04:00
|
|
|
let comps = value.split(" returns ");
|
2019-05-14 18:48:48 -04:00
|
|
|
if (comps.length > 2) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("invalid function string", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
let parens = comps[0].match(regexParen);
|
2019-05-14 18:48:48 -04:00
|
|
|
if (!parens) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("invalid function signature", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
params.name = parens[1].trim();
|
2020-04-15 18:28:04 -04:00
|
|
|
if (params.name) {
|
|
|
|
verifyIdentifier(params.name);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
params.inputs = parseParams(parens[2], false);
|
|
|
|
parseModifiers(parens[3].trim(), params);
|
|
|
|
// We have outputs
|
|
|
|
if (comps.length > 1) {
|
2019-08-25 02:39:20 -04:00
|
|
|
let returns = comps[1].match(regexParen);
|
2019-05-14 18:48:48 -04:00
|
|
|
if (returns[1].trim() != "" || returns[3].trim() != "") {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError("unexpected tokens", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
params.outputs = parseParams(returns[2], false);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
params.outputs = [];
|
|
|
|
}
|
|
|
|
return FunctionFragment.fromObject(params);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
static isFunctionFragment(value) {
|
2019-06-11 17:57:04 -04:00
|
|
|
return (value && value._isFragment && value.type === "function");
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
}
|
2019-05-14 18:48:48 -04:00
|
|
|
//export class StructFragment extends Fragment {
|
|
|
|
//}
|
2021-05-17 16:19:36 -04:00
|
|
|
function checkForbidden(fragment) {
|
|
|
|
const sig = fragment.format();
|
|
|
|
if (sig === "Error(string)" || sig === "Panic(uint256)") {
|
|
|
|
logger.throwArgumentError(`cannot specify user defined ${sig} error`, "fragment", fragment);
|
|
|
|
}
|
|
|
|
return fragment;
|
|
|
|
}
|
|
|
|
export class ErrorFragment extends Fragment {
|
|
|
|
format(format) {
|
|
|
|
if (!format) {
|
|
|
|
format = FormatTypes.sighash;
|
|
|
|
}
|
|
|
|
if (!FormatTypes[format]) {
|
|
|
|
logger.throwArgumentError("invalid format type", "format", format);
|
|
|
|
}
|
|
|
|
if (format === FormatTypes.json) {
|
|
|
|
return JSON.stringify({
|
|
|
|
type: "error",
|
|
|
|
name: this.name,
|
|
|
|
inputs: this.inputs.map((input) => JSON.parse(input.format(format))),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
let result = "";
|
|
|
|
if (format !== FormatTypes.sighash) {
|
|
|
|
result += "error ";
|
|
|
|
}
|
|
|
|
result += this.name + "(" + this.inputs.map((input) => input.format(format)).join((format === FormatTypes.full) ? ", " : ",") + ") ";
|
|
|
|
return result.trim();
|
|
|
|
}
|
|
|
|
static from(value) {
|
|
|
|
if (typeof (value) === "string") {
|
|
|
|
return ErrorFragment.fromString(value);
|
|
|
|
}
|
|
|
|
return ErrorFragment.fromObject(value);
|
|
|
|
}
|
|
|
|
static fromObject(value) {
|
|
|
|
if (ErrorFragment.isErrorFragment(value)) {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
if (value.type !== "error") {
|
|
|
|
logger.throwArgumentError("invalid error object", "value", value);
|
|
|
|
}
|
|
|
|
const params = {
|
|
|
|
type: value.type,
|
|
|
|
name: verifyIdentifier(value.name),
|
|
|
|
inputs: (value.inputs ? value.inputs.map(ParamType.fromObject) : [])
|
|
|
|
};
|
|
|
|
return checkForbidden(new ErrorFragment(_constructorGuard, params));
|
|
|
|
}
|
|
|
|
static fromString(value) {
|
|
|
|
let params = { type: "error" };
|
|
|
|
let parens = value.match(regexParen);
|
|
|
|
if (!parens) {
|
|
|
|
logger.throwArgumentError("invalid error signature", "value", value);
|
|
|
|
}
|
|
|
|
params.name = parens[1].trim();
|
|
|
|
if (params.name) {
|
|
|
|
verifyIdentifier(params.name);
|
|
|
|
}
|
|
|
|
params.inputs = parseParams(parens[2], false);
|
|
|
|
return checkForbidden(ErrorFragment.fromObject(params));
|
|
|
|
}
|
|
|
|
static isErrorFragment(value) {
|
|
|
|
return (value && value._isFragment && value.type === "error");
|
|
|
|
}
|
|
|
|
}
|
2019-05-14 18:48:48 -04:00
|
|
|
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;
|
|
|
|
}
|
2021-06-10 18:29:05 -04:00
|
|
|
// See: https://github.com/ethereum/solidity/blob/1f8f1a3db93a548d0555e3e14cfc55a10e25b60e/docs/grammar/SolidityLexer.g4#L234
|
|
|
|
const regexIdentifier = new RegExp("^[a-zA-Z$_][a-zA-Z0-9$_]*$");
|
2019-05-14 18:48:48 -04:00
|
|
|
function verifyIdentifier(value) {
|
|
|
|
if (!value || !value.match(regexIdentifier)) {
|
2020-04-15 18:28:04 -04:00
|
|
|
logger.throwArgumentError(`invalid identifier "${value}"`, "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
const regexParen = new RegExp("^([^)(]*)\\((.*)\\)([^)(]*)$");
|
2019-05-14 18:48:48 -04:00
|
|
|
function splitNesting(value) {
|
|
|
|
value = value.trim();
|
2019-08-25 02:39:20 -04:00
|
|
|
let result = [];
|
|
|
|
let accum = "";
|
|
|
|
let depth = 0;
|
|
|
|
for (let offset = 0; offset < value.length; offset++) {
|
|
|
|
let c = value[offset];
|
2019-05-14 18:48:48 -04:00
|
|
|
if (c === "," && depth === 0) {
|
|
|
|
result.push(accum);
|
|
|
|
accum = "";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
accum += c;
|
|
|
|
if (c === "(") {
|
|
|
|
depth++;
|
|
|
|
}
|
|
|
|
else if (c === ")") {
|
|
|
|
depth--;
|
|
|
|
if (depth === -1) {
|
2020-04-23 23:35:39 -04:00
|
|
|
logger.throwArgumentError("unbalanced parenthesis", "value", value);
|
2019-05-14 18:48:48 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (accum) {
|
|
|
|
result.push(accum);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2020-07-13 08:03:56 -04:00
|
|
|
//# sourceMappingURL=fragments.js.map
|