Skip to content

Commit

Permalink
Better error reporting for Fragments.
Browse files Browse the repository at this point in the history
  • Loading branch information
ricmoo committed Apr 15, 2020
1 parent 2eb3823 commit 7dcefcb
Showing 1 changed file with 58 additions and 29 deletions.
87 changes: 58 additions & 29 deletions packages/abi/src.ts/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function parseParamType(param: string, allowIndexed: boolean): ParseNode {

let originalParam = param;
function throwError(i: number) {
throw new Error("unexpected character '" + originalParam[i] + "' at position " + i + " in '" + originalParam + "'");
logger.throwArgumentError(`unexpected character at position ${ i }`, "param", param);
}
param = param.replace(/\s/g, " ");

Expand Down Expand Up @@ -207,7 +207,7 @@ function parseParamType(param: string, allowIndexed: boolean): ParseNode {
}
}

if (node.parent) { throw new Error("unexpected eof"); }
if (node.parent) { logger.throwArgumentError("unexpected eof", "param", param); }

delete parent.state;

Expand Down Expand Up @@ -272,7 +272,9 @@ export class ParamType {
readonly _isParamType: boolean;

constructor(constructorGuard: any, params: any) {
if (constructorGuard !== _constructorGuard) { throw new Error("use fromString"); }
if (constructorGuard !== _constructorGuard) { logger.throwError("use fromString", Logger.errors.UNSUPPORTED_OPERATION, {
operation: "new ParamType()"
}); }
populate(this, params);

let match = this.type.match(paramTypeArray);
Expand Down Expand Up @@ -398,7 +400,11 @@ export abstract class Fragment {
readonly _isFragment: boolean;

constructor(constructorGuard: any, params: any) {
if (constructorGuard !== _constructorGuard) { throw new Error("use a static from method"); }
if (constructorGuard !== _constructorGuard) {
logger.throwError("use a static from method", Logger.errors.UNSUPPORTED_OPERATION, {
operation: "new Fragment()"
});
}
populate(this, params);

this._isFragment = true;
Expand Down Expand Up @@ -451,7 +457,7 @@ export abstract class Fragment {
return ConstructorFragment.fromString(value.trim());
}

throw new Error("unknown fragment");
return logger.throwArgumentError("unsupported fragment", "value", value);
}

static isFragment(value: any): value is Fragment {
Expand Down Expand Up @@ -506,7 +512,9 @@ export class EventFragment extends Fragment {
static fromObject(value: JsonFragment | EventFragment): EventFragment {
if (EventFragment.isEventFragment(value)) { return value; }

if (value.type !== "event") { throw new Error("invalid event object - " + value.type); }
if (value.type !== "event") {
logger.throwArgumentError("invalid event object", "value", value);
}

return new EventFragment(_constructorGuard, {
name: verifyIdentifier(value.name),
Expand All @@ -519,7 +527,9 @@ export class EventFragment extends Fragment {
static fromString(value: string): EventFragment {

let match = value.match(regexParen);
if (!match) { throw new Error("invalid event: " + value); }
if (!match) {
logger.throwArgumentError("invalid event string", "value", value);
}

let anonymous = false;
match[3].split(" ").forEach((modifier) => {
Expand Down Expand Up @@ -553,10 +563,10 @@ function parseGas(value: string, params: any): string {
let comps = value.split("@");
if (comps.length !== 1) {
if (comps.length > 2) {
throw new Error("invalid signature");
logger.throwArgumentError("invalid human-readable ABI signature", "value", value);
}
if (!comps[1].match(/^[0-9]+$/)) {
throw new Error("invalid signature gas");
logger.throwArgumentError("invalid human-readable aBI signature gas", "value", value);
}
params.gas = BigNumber.from(comps[1]);
return comps[0];
Expand Down Expand Up @@ -597,7 +607,20 @@ function parseModifiers(value: string, params: any): void {
});
}

function verifyState(value: any): { constant: boolean, payable: boolean, stateMutability: string } {
type StateInputValue = {
constant?: boolean;
payable?: boolean;
stateMutability?: string;
type?: string;
};

type StateOutputValue = {
constant: boolean;
payable: boolean;
stateMutability: string;
};

function verifyState(value: StateInputValue): StateOutputValue {
let result: any = {
constant: false,
payable: true,
Expand All @@ -611,15 +634,15 @@ function verifyState(value: any): { constant: boolean, payable: boolean, stateMu
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);
logger.throwArgumentError("cannot have constant function with mutability " + result.stateMutability, "value", value);
}
}

// Set (and check things are consistent) the payable property
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);
logger.throwArgumentError("cannot have payable function with mutability " + result.stateMutability, "value", value);
}
}

Expand All @@ -628,7 +651,7 @@ function verifyState(value: any): { constant: boolean, payable: boolean, stateMu

// If payable we can assume non-constant; otherwise we can't assume
if (value.constant == null && !result.payable && value.type !== "constructor") {
throw new Error("unable to determine stateMutability");
logger.throwArgumentError("unable to determine stateMutability", "value", value);
}

result.constant = !!value.constant;
Expand All @@ -640,7 +663,7 @@ function verifyState(value: any): { constant: boolean, payable: boolean, stateMu
}

if (result.payable && result.constant) {
throw new Error("cannot have constant payable function");
logger.throwArgumentError("cannot have constant payable function", "value", value);
}

} else if (value.constant != null) {
Expand All @@ -649,7 +672,7 @@ function verifyState(value: any): { constant: boolean, payable: boolean, stateMu
result.stateMutability = (result.constant ? "view": "payable");

} else if (value.type !== "constructor") {
throw new Error("unable to determine stateMutability");
logger.throwArgumentError("unable to determine stateMutability", "value", value);
}

return result;
Expand Down Expand Up @@ -703,11 +726,13 @@ export class ConstructorFragment extends Fragment {
static fromObject(value: ConstructorFragment | JsonFragment): ConstructorFragment {
if (ConstructorFragment.isConstructorFragment(value)) { return value; }

if (value.type !== "constructor") { throw new Error("invalid constructor object - " + value.type); }
if (value.type !== "constructor") {
logger.throwArgumentError("invalid constructor object", "value", value);
}

let state = verifyState(value);
if (state.constant) {
throw new Error("constructor cannot be constant");
logger.throwArgumentError("constructor cannot be constant", "value", value);
}

return new ConstructorFragment(_constructorGuard, {
Expand All @@ -725,9 +750,9 @@ export class ConstructorFragment extends Fragment {
value = parseGas(value, params);

let parens = value.match(regexParen);
if (!parens) { throw new Error("invalid constructor: " + value); }

if (parens[1].trim() !== "constructor") { throw new Error("invalid constructor"); }
if (!parens || parens[1].trim() !== "constructor") {
logger.throwArgumentError("invalid constructor string", "value", value);
}

params.inputs = parseParams(parens[2].trim(), false);

Expand Down Expand Up @@ -807,7 +832,9 @@ export class FunctionFragment extends ConstructorFragment {
static fromObject(value: FunctionFragment | JsonFragment): FunctionFragment {
if (FunctionFragment.isFunctionFragment(value)) { return value; }

if (value.type !== "function") { throw new Error("invalid function object - " + value.type); }
if (value.type !== "function") {
logger.throwArgumentError("invalid function object", "value", value);
}

let state = verifyState(value);

Expand All @@ -828,15 +855,17 @@ export class FunctionFragment extends ConstructorFragment {
value = parseGas(value, params);

let comps = value.split(" returns ");
if (comps.length > 2) { throw new Error("invalid function"); }
if (comps.length > 2) {
logger.throwArgumentError("invalid function string", "value", value);
}

let parens = comps[0].match(regexParen);
if (!parens) { throw new Error("invalid signature"); }
if (!parens) {
logger.throwArgumentError("invalid function signature", "value", value);
}

params.name = parens[1].trim();
if (!params.name.match(regexIdentifier)) {
throw new Error("invalid identifier: '" + params.name + "'");
}
if (params.name) { verifyIdentifier(params.name); }

params.inputs = parseParams(parens[2], false);

Expand All @@ -846,7 +875,7 @@ export class FunctionFragment extends ConstructorFragment {
if (comps.length > 1) {
let returns = comps[1].match(regexParen);
if (returns[1].trim() != "" || returns[3].trim() != "") {
throw new Error("unexpected tokens");
logger.throwArgumentError("unexpected tokens", "value", value);
}
params.outputs = parseParams(returns[2], false);
} else {
Expand Down Expand Up @@ -884,7 +913,7 @@ function verifyType(type: string): string {
const regexIdentifier = new RegExp("^[A-Za-z_][A-Za-z0-9_]*$");
function verifyIdentifier(value: string): string {
if (!value || !value.match(regexIdentifier)) {
throw new Error("invalid identifier: '" + value + "'");
logger.throwArgumentError(`invalid identifier "${ value }"`, "value", value);
}
return value;
}
Expand All @@ -909,7 +938,7 @@ function splitNesting(value: string): Array<any> {
} else if (c === ")") {
depth--;
if (depth === -1) {
throw new Error("unbalanced parenthsis");
logger.throwArgumentError("unbalanced parenthsis", "value", value);
}
}
}
Expand Down

0 comments on commit 7dcefcb

Please sign in to comment.