2019-08-25 02:39:20 -04:00
|
|
|
"use strict";
|
|
|
|
// See: https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
|
|
|
import { arrayify } from "@ethersproject/bytes";
|
|
|
|
import { defineReadOnly } from "@ethersproject/properties";
|
|
|
|
import { Logger } from "@ethersproject/logger";
|
|
|
|
import { version } from "./_version";
|
|
|
|
const logger = new Logger(version);
|
|
|
|
import { Reader, Writer } from "./coders/abstract-coder";
|
|
|
|
import { AddressCoder } from "./coders/address";
|
|
|
|
import { ArrayCoder } from "./coders/array";
|
|
|
|
import { BooleanCoder } from "./coders/boolean";
|
|
|
|
import { BytesCoder } from "./coders/bytes";
|
|
|
|
import { FixedBytesCoder } from "./coders/fixed-bytes";
|
|
|
|
import { NullCoder } from "./coders/null";
|
|
|
|
import { NumberCoder } from "./coders/number";
|
|
|
|
import { StringCoder } from "./coders/string";
|
|
|
|
import { TupleCoder } from "./coders/tuple";
|
|
|
|
import { ParamType } from "./fragments";
|
|
|
|
const paramTypeBytes = new RegExp(/^bytes([0-9]*)$/);
|
|
|
|
const paramTypeNumber = new RegExp(/^(u?int)([0-9]*)$/);
|
|
|
|
export class AbiCoder {
|
|
|
|
constructor(coerceFunc) {
|
|
|
|
logger.checkNew(new.target, AbiCoder);
|
|
|
|
defineReadOnly(this, "coerceFunc", coerceFunc || null);
|
|
|
|
}
|
|
|
|
_getCoder(param) {
|
|
|
|
switch (param.baseType) {
|
|
|
|
case "address":
|
|
|
|
return new AddressCoder(param.name);
|
|
|
|
case "bool":
|
|
|
|
return new BooleanCoder(param.name);
|
|
|
|
case "string":
|
|
|
|
return new StringCoder(param.name);
|
|
|
|
case "bytes":
|
|
|
|
return new BytesCoder(param.name);
|
|
|
|
case "array":
|
|
|
|
return new ArrayCoder(this._getCoder(param.arrayChildren), param.arrayLength, param.name);
|
|
|
|
case "tuple":
|
|
|
|
return new TupleCoder((param.components || []).map((component) => {
|
|
|
|
return this._getCoder(component);
|
|
|
|
}), param.name);
|
|
|
|
case "":
|
|
|
|
return new NullCoder(param.name);
|
|
|
|
}
|
|
|
|
// u?int[0-9]*
|
|
|
|
let match = param.type.match(paramTypeNumber);
|
|
|
|
if (match) {
|
|
|
|
let size = parseInt(match[2] || "256");
|
|
|
|
if (size === 0 || size > 256 || (size % 8) !== 0) {
|
|
|
|
logger.throwArgumentError("invalid " + match[1] + " bit length", "param", param);
|
|
|
|
}
|
|
|
|
return new NumberCoder(size / 8, (match[1] === "int"), param.name);
|
|
|
|
}
|
|
|
|
// bytes[0-9]+
|
|
|
|
match = param.type.match(paramTypeBytes);
|
|
|
|
if (match) {
|
|
|
|
let size = parseInt(match[1]);
|
|
|
|
if (size === 0 || size > 32) {
|
|
|
|
logger.throwArgumentError("invalid bytes length", "param", param);
|
|
|
|
}
|
|
|
|
return new FixedBytesCoder(size, param.name);
|
|
|
|
}
|
2020-04-25 03:54:54 -04:00
|
|
|
return logger.throwArgumentError("invalid type", "type", param.type);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
_getWordSize() { return 32; }
|
2020-09-07 19:55:52 -04:00
|
|
|
_getReader(data, allowLoose) {
|
|
|
|
return new Reader(data, this._getWordSize(), this.coerceFunc, allowLoose);
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
_getWriter() {
|
|
|
|
return new Writer(this._getWordSize());
|
|
|
|
}
|
2020-11-23 03:43:28 -05:00
|
|
|
getDefaultValue(types) {
|
|
|
|
const coders = types.map((type) => this._getCoder(ParamType.from(type)));
|
|
|
|
const coder = new TupleCoder(coders, "_");
|
|
|
|
return coder.defaultValue();
|
|
|
|
}
|
2019-08-25 02:39:20 -04:00
|
|
|
encode(types, values) {
|
|
|
|
if (types.length !== values.length) {
|
|
|
|
logger.throwError("types/values length mismatch", Logger.errors.INVALID_ARGUMENT, {
|
|
|
|
count: { types: types.length, values: values.length },
|
|
|
|
value: { types: types, values: values }
|
|
|
|
});
|
|
|
|
}
|
2020-01-07 19:58:04 -05:00
|
|
|
const coders = types.map((type) => this._getCoder(ParamType.from(type)));
|
|
|
|
const coder = (new TupleCoder(coders, "_"));
|
|
|
|
const writer = this._getWriter();
|
2019-08-25 02:39:20 -04:00
|
|
|
coder.encode(writer, values);
|
|
|
|
return writer.data;
|
|
|
|
}
|
2020-09-07 19:55:52 -04:00
|
|
|
decode(types, data, loose) {
|
2020-01-07 19:58:04 -05:00
|
|
|
const coders = types.map((type) => this._getCoder(ParamType.from(type)));
|
|
|
|
const coder = new TupleCoder(coders, "_");
|
2020-09-07 19:55:52 -04:00
|
|
|
return coder.decode(this._getReader(arrayify(data), loose));
|
2019-08-25 02:39:20 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
export const defaultAbiCoder = new AbiCoder();
|
2020-07-13 08:03:56 -04:00
|
|
|
//# sourceMappingURL=abi-coder.js.map
|