Add ABI coder function to compute default values (#1101).
This commit is contained in:
parent
7f775f7ad6
commit
a8e3380ed5
@ -91,6 +91,12 @@ export class AbiCoder {
|
||||
return new Writer(this._getWordSize());
|
||||
}
|
||||
|
||||
getDefaultValue(types: Array<string | ParamType>): Result {
|
||||
const coders: Array<Coder> = types.map((type) => this._getCoder(ParamType.from(type)));
|
||||
const coder = new TupleCoder(coders, "_");
|
||||
return coder.defaultValue();
|
||||
}
|
||||
|
||||
encode(types: Array<string | ParamType>, values: Array<any>): string {
|
||||
if (types.length !== values.length) {
|
||||
logger.throwError("types/values length mismatch", Logger.errors.INVALID_ARGUMENT, {
|
||||
|
@ -70,6 +70,8 @@ export abstract class Coder {
|
||||
|
||||
abstract encode(writer: Writer, value: any): number;
|
||||
abstract decode(reader: Reader): any;
|
||||
|
||||
abstract defaultValue(): any;
|
||||
}
|
||||
|
||||
export class Writer {
|
||||
|
@ -11,6 +11,10 @@ export class AddressCoder extends Coder {
|
||||
super("address", "address", localName, false);
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return "0x0000000000000000000000000000000000000000";
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: string): number {
|
||||
try {
|
||||
getAddress(value);
|
||||
|
@ -11,6 +11,10 @@ export class AnonymousCoder extends Coder {
|
||||
this.coder = coder;
|
||||
}
|
||||
|
||||
defaultValue(): any {
|
||||
return this.coder.defaultValue();
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
return this.coder.encode(writer, value);
|
||||
}
|
||||
|
@ -177,6 +177,17 @@ export class ArrayCoder extends Coder {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
defaultValue(): Array<any> {
|
||||
// Verifies the child coder is valid (even if the array is dynamic or 0-length)
|
||||
const defaultChild = this.coder.defaultValue();
|
||||
|
||||
const result: Array<any> = [];
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
result.push(defaultChild);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: Array<any>): number {
|
||||
if (!Array.isArray(value)) {
|
||||
this._throwError("expected array value", value);
|
||||
|
@ -8,6 +8,10 @@ export class BooleanCoder extends Coder {
|
||||
super("bool", "bool", localName, false);
|
||||
}
|
||||
|
||||
defaultValue(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: boolean): number {
|
||||
return writer.writeValue(value ? 1: 0);
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ export class DynamicBytesCoder extends Coder {
|
||||
super(type, type, localName, true);
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return "0x";
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
value = arrayify(value);
|
||||
let length = writer.writeValue(value.length);
|
||||
|
@ -14,6 +14,10 @@ export class FixedBytesCoder extends Coder {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return ("0x0000000000000000000000000000000000000000000000000000000000000000").substring(0, 2 + this.size * 2);
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: BytesLike): number {
|
||||
let data = arrayify(value);
|
||||
if (data.length !== this.size) { this._throwError("incorrect data length", value); }
|
||||
|
@ -8,6 +8,10 @@ export class NullCoder extends Coder {
|
||||
super("null", "", localName, false);
|
||||
}
|
||||
|
||||
defaultValue(): null {
|
||||
return null;
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
if (value != null) { this._throwError("not null", value); }
|
||||
return writer.writeBytes([ ]);
|
||||
|
@ -17,6 +17,10 @@ export class NumberCoder extends Coder {
|
||||
this.signed = signed;
|
||||
}
|
||||
|
||||
defaultValue(): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: BigNumberish): number {
|
||||
let v = BigNumber.from(value);
|
||||
|
||||
|
@ -11,6 +11,10 @@ export class StringCoder extends DynamicBytesCoder {
|
||||
super("string", localName);
|
||||
}
|
||||
|
||||
defaultValue(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: any): number {
|
||||
return super.encode(writer, toUtf8Bytes(value));
|
||||
}
|
||||
|
@ -19,6 +19,37 @@ export class TupleCoder extends Coder {
|
||||
this.coders = coders;
|
||||
}
|
||||
|
||||
defaultValue(): any {
|
||||
const values: any = [ ];
|
||||
this.coders.forEach((coder) => {
|
||||
values.push(coder.defaultValue());
|
||||
});
|
||||
|
||||
// We only output named properties for uniquely named coders
|
||||
const uniqueNames = this.coders.reduce((accum, coder) => {
|
||||
const name = coder.localName;
|
||||
if (name) {
|
||||
if (!accum[name]) { accum[name] = 0; }
|
||||
accum[name]++;
|
||||
}
|
||||
return accum;
|
||||
}, <{ [ name: string ]: number }>{ });
|
||||
|
||||
// Add named values
|
||||
this.coders.forEach((coder: Coder, index: number) => {
|
||||
let name = coder.localName;
|
||||
if (!name || uniqueNames[name] !== 1) { return; }
|
||||
|
||||
if (name === "length") { name = "_length"; }
|
||||
|
||||
if (values[name] != null) { return; }
|
||||
|
||||
values[name] = values[index];
|
||||
});
|
||||
|
||||
return Object.freeze(values);
|
||||
}
|
||||
|
||||
encode(writer: Writer, value: Array<any> | { [ name: string ]: any }): number {
|
||||
return pack(writer, this.coders, value);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user