Moved ABI check for unique names to coding time and only if ambiguous (#816).
This commit is contained in:
parent
82a93263fa
commit
fa87417e94
@ -4,26 +4,46 @@ import { Logger } from "@ethersproject/logger";
|
||||
import { version } from "../_version";
|
||||
const logger = new Logger(version);
|
||||
|
||||
import { Coder, Reader, Writer } from "./abstract-coder";
|
||||
import { Coder, Reader, Result, Writer } from "./abstract-coder";
|
||||
import { AnonymousCoder } from "./anonymous";
|
||||
|
||||
export function pack(writer: Writer, coders: Array<Coder>, values: Array<any>): number {
|
||||
export function pack(writer: Writer, coders: ReadonlyArray<Coder>, values: Array<any> | { [ name: string ]: any }): number {
|
||||
let arrayValues: Array<any> = null;
|
||||
|
||||
if (Array.isArray(values)) {
|
||||
// do nothing
|
||||
arrayValues = values;
|
||||
|
||||
} else if (values && typeof(values) === "object") {
|
||||
let arrayValues: Array<any> = [];
|
||||
coders.forEach(function(coder) {
|
||||
arrayValues.push((<any>values)[coder.localName]);
|
||||
let unique: { [ name: string ]: boolean } = { };
|
||||
|
||||
arrayValues = coders.map((coder) => {
|
||||
const name = coder.localName;
|
||||
if (!name) {
|
||||
logger.throwError("cannot encode object for signature with missing names", Logger.errors.INVALID_ARGUMENT, {
|
||||
argument: "values",
|
||||
coder: coder,
|
||||
value: values
|
||||
});
|
||||
}
|
||||
|
||||
if (unique[name]) {
|
||||
logger.throwError("cannot encode object for signature with duplicate names", Logger.errors.INVALID_ARGUMENT, {
|
||||
argument: "values",
|
||||
coder: coder,
|
||||
value: values
|
||||
});
|
||||
}
|
||||
|
||||
unique[name] = true;
|
||||
|
||||
return values[name];
|
||||
});
|
||||
values = arrayValues;
|
||||
|
||||
} else {
|
||||
logger.throwArgumentError("invalid tuple value", "tuple", values);
|
||||
}
|
||||
|
||||
if (coders.length !== values.length) {
|
||||
if (coders.length !== arrayValues.length) {
|
||||
logger.throwArgumentError("types/value length mismatch", "tuple", values);
|
||||
}
|
||||
|
||||
@ -32,7 +52,7 @@ export function pack(writer: Writer, coders: Array<Coder>, values: Array<any>):
|
||||
|
||||
let updateFuncs: Array<(baseOffset: number) => void> = [];
|
||||
coders.forEach((coder, index) => {
|
||||
let value = values[index];
|
||||
let value = arrayValues[index];
|
||||
|
||||
if (coder.dynamic) {
|
||||
// Get current dynamic offset (for the future pointer)
|
||||
@ -60,7 +80,7 @@ export function pack(writer: Writer, coders: Array<Coder>, values: Array<any>):
|
||||
return length;
|
||||
}
|
||||
|
||||
export function unpack(reader: Reader, coders: Array<Coder>): Array<any> {
|
||||
export function unpack(reader: Reader, coders: Array<Coder>): Result {
|
||||
let values: any = [];
|
||||
|
||||
// A reader anchored to this base
|
||||
@ -109,10 +129,20 @@ export function unpack(reader: Reader, coders: Array<Coder>): Array<any> {
|
||||
// Consume the dynamic components in the main reader
|
||||
reader.readBytes(dynamicLength);
|
||||
|
||||
// We only output named properties for uniquely named coders
|
||||
const uniqueNames = coders.reduce((accum, coder) => {
|
||||
const name = coder.localName;
|
||||
if (name) {
|
||||
if (!accum[name]) { accum[name] = 0; }
|
||||
accum[name]++;
|
||||
}
|
||||
return accum;
|
||||
}, <{ [ name: string ]: number }>{ });
|
||||
|
||||
// Add any named parameters (i.e. tuples)
|
||||
coders.forEach((coder: Coder, index: number) => {
|
||||
let name: string = coder.localName;
|
||||
if (!name) { return; }
|
||||
let name = coder.localName;
|
||||
if (!name || uniqueNames[name] !== 1) { return; }
|
||||
|
||||
if (name === "length") { name = "_length"; }
|
||||
|
||||
|
@ -19,7 +19,7 @@ export class TupleCoder extends Coder {
|
||||
this.coders = coders;
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: Array<any>): number {
|
||||
encode(writer: Writer, value: Array<any> | { [ name: string ]: any }): number {
|
||||
return pack(writer, this.coders, value);
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ function wrapAccessError(property: string, error: Error): Error {
|
||||
return wrap;
|
||||
}
|
||||
|
||||
/*
|
||||
function checkNames(fragment: Fragment, type: "input" | "output", params: Array<ParamType>): void {
|
||||
params.reduce((accum, param) => {
|
||||
if (param.name) {
|
||||
@ -60,7 +61,7 @@ function checkNames(fragment: Fragment, type: "input" | "output", params: Array<
|
||||
return accum;
|
||||
}, <{ [ name: string ]: boolean }>{ });
|
||||
}
|
||||
|
||||
*/
|
||||
export class Interface {
|
||||
readonly fragments: Array<Fragment>;
|
||||
|
||||
@ -105,16 +106,16 @@ export class Interface {
|
||||
logger.warn("duplicate definition - constructor");
|
||||
return;
|
||||
}
|
||||
checkNames(fragment, "input", fragment.inputs);
|
||||
//checkNames(fragment, "input", fragment.inputs);
|
||||
defineReadOnly(this, "deploy", <ConstructorFragment>fragment);
|
||||
return;
|
||||
case "function":
|
||||
checkNames(fragment, "input", fragment.inputs);
|
||||
checkNames(fragment, "output", (<FunctionFragment>fragment).outputs);
|
||||
//checkNames(fragment, "input", fragment.inputs);
|
||||
//checkNames(fragment, "output", (<FunctionFragment>fragment).outputs);
|
||||
bucket = this.functions;
|
||||
break;
|
||||
case "event":
|
||||
checkNames(fragment, "input", fragment.inputs);
|
||||
//checkNames(fragment, "input", fragment.inputs);
|
||||
bucket = this.events;
|
||||
break;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user