aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils/src/abi_encoder
diff options
context:
space:
mode:
Diffstat (limited to 'packages/utils/src/abi_encoder')
-rw-r--r--packages/utils/src/abi_encoder/calldata.ts6
-rw-r--r--packages/utils/src/abi_encoder/constants.ts1
-rw-r--r--packages/utils/src/abi_encoder/data_type.ts312
-rw-r--r--packages/utils/src/abi_encoder/evm_data_types.ts14
4 files changed, 171 insertions, 162 deletions
diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts
index 0c45d6198..994b0fb81 100644
--- a/packages/utils/src/abi_encoder/calldata.ts
+++ b/packages/utils/src/abi_encoder/calldata.ts
@@ -1,5 +1,7 @@
-import ethUtil = require('ethereumjs-util');
-const _ = require('lodash');
+
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
import * as Constants from './constants';
export interface DecodingRules {
diff --git a/packages/utils/src/abi_encoder/constants.ts b/packages/utils/src/abi_encoder/constants.ts
index bc5b985e0..52029695f 100644
--- a/packages/utils/src/abi_encoder/constants.ts
+++ b/packages/utils/src/abi_encoder/constants.ts
@@ -1,5 +1,6 @@
export const EVM_WORD_WIDTH_IN_BYTES = 32;
export const HEX_BASE = 16;
+export const DEC_BASE = 10;
export const BIN_BASE = 2;
export const HEX_SELECTOR_LENGTH_IN_CHARS = 10;
export const HEX_SELECTOR_LENGTH_IN_BYTES = 4;
diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts
index 4370cb253..ce7b11ef6 100644
--- a/packages/utils/src/abi_encoder/data_type.ts
+++ b/packages/utils/src/abi_encoder/data_type.ts
@@ -1,16 +1,21 @@
+import { DataItem } from 'ethereum-types';
+import * as ethUtil from 'ethereumjs-util';
+import * as _ from 'lodash';
+
+import { BigNumber } from '../configured_bignumber';
+
+import * as Constants from './constants';
+
import {
- RawCalldata,
Calldata,
CalldataBlock,
- PayloadCalldataBlock,
+ DecodingRules,
DependentCalldataBlock,
+ EncodingRules,
MemberCalldataBlock,
+ PayloadCalldataBlock,
+ RawCalldata,
} from './calldata';
-import { MethodAbi, DataItem } from 'ethereum-types';
-import { DecodingRules, EncodingRules } from './calldata';
-import { BigNumber } from '../configured_bignumber';
-import ethUtil = require('ethereumjs-util');
-var _ = require('lodash');
export interface DataTypeFactory {
create: (dataItem: DataItem, parentDataType?: DataType) => DataType;
@@ -18,29 +23,30 @@ export interface DataTypeFactory {
}
export abstract class DataType {
- private static DEFAULT_ENCODING_RULES = { optimize: false, annotate: false } as EncodingRules;
- private static DEFAULT_DECODING_RULES = { structsAsObjects: false } as DecodingRules;
-
- private dataItem: DataItem;
- private factory: DataTypeFactory;
+ private static readonly _DEFAULT_ENCODING_RULES: EncodingRules = { optimize: false, annotate: false };
+ private static readonly _DEFAULT_DECODING_RULES: DecodingRules = { structsAsObjects: false };
+ private readonly _dataItem: DataItem;
+ private readonly _factory: DataTypeFactory;
constructor(dataItem: DataItem, factory: DataTypeFactory) {
- this.dataItem = dataItem;
- this.factory = factory;
+ this._dataItem = dataItem;
+ this._factory = factory;
}
public getDataItem(): DataItem {
- return this.dataItem;
+ return this._dataItem;
}
public getFactory(): DataTypeFactory {
- return this.factory;
+ return this._factory;
}
public encode(value: any, rules?: EncodingRules, selector?: string): string {
- const rules_ = rules ? rules : DataType.DEFAULT_ENCODING_RULES;
+ const rules_ = rules ? rules : DataType._DEFAULT_ENCODING_RULES;
const calldata = new Calldata(rules_);
- if (selector) calldata.setSelector(selector);
+ if (selector) {
+ calldata.setSelector(selector);
+ }
const block = this.generateCalldataBlock(value);
calldata.setRoot(block); // @TODO CHANGE
const calldataHex = calldata.toHexString();
@@ -49,7 +55,7 @@ export abstract class DataType {
public decode(calldata: string, rules?: DecodingRules, hasSelector: boolean = false): any {
const rawCalldata = new RawCalldata(calldata, hasSelector);
- const rules_ = rules ? rules : DataType.DEFAULT_DECODING_RULES;
+ const rules_ = rules ? rules : DataType._DEFAULT_DECODING_RULES;
const value = this.generateValue(rawCalldata, rules_);
return value;
}
@@ -61,11 +67,11 @@ export abstract class DataType {
}
export abstract class PayloadDataType extends DataType {
- protected hasConstantSize: boolean;
+ protected _hasConstantSize: boolean;
public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) {
super(dataItem, factory);
- this.hasConstantSize = hasConstantSize;
+ this._hasConstantSize = hasConstantSize;
}
public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock {
@@ -73,7 +79,6 @@ export abstract class PayloadDataType extends DataType {
const name = this.getDataItem().name;
const signature = this.getSignature();
const parentName = parentBlock === undefined ? '' : parentBlock.getName();
- const relocatable = false;
const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue);
return block;
}
@@ -84,8 +89,7 @@ export abstract class PayloadDataType extends DataType {
}
public isStatic(): boolean {
- // If a payload has a constant size then it's static
- return this.hasConstantSize;
+ return this._hasConstantSize;
}
public abstract encodeValue(value: any): Buffer;
@@ -93,20 +97,22 @@ export abstract class PayloadDataType extends DataType {
}
export abstract class DependentDataType extends DataType {
- protected dependency: DataType;
- protected parent: DataType;
+ protected _dependency: DataType;
+ protected _parent: DataType;
+ private readonly _isStatic: boolean;
public constructor(dataItem: DataItem, factory: DataTypeFactory, dependency: DataType, parent: DataType) {
super(dataItem, factory);
- this.dependency = dependency;
- this.parent = parent;
+ this._dependency = dependency;
+ this._parent = parent;
+ this._isStatic = true;
}
public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): DependentCalldataBlock {
if (parentBlock === undefined) {
throw new Error(`DependentDataType requires a parent block to generate its block`);
}
- const dependencyBlock = this.dependency.generateCalldataBlock(value, parentBlock);
+ const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock);
const name = this.getDataItem().name;
const signature = this.getSignature();
const parentName = parentBlock === undefined ? '' : parentBlock.getName();
@@ -117,16 +123,16 @@ export abstract class DependentDataType extends DataType {
public generateValue(calldata: RawCalldata, rules: DecodingRules): any {
const destinationOffsetBuf = calldata.popWord();
const currentOffset = calldata.getOffset();
- const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), 16);
+ const destinationOffsetRelative = parseInt(ethUtil.bufferToHex(destinationOffsetBuf), Constants.HEX_BASE);
const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative);
calldata.setOffset(destinationOffsetAbsolute);
- const value = this.dependency.generateValue(calldata, rules);
+ const value = this._dependency.generateValue(calldata, rules);
calldata.setOffset(currentOffset);
return value;
}
public isStatic(): boolean {
- return true;
+ return this._isStatic;
}
}
@@ -135,11 +141,11 @@ export interface MemberMap {
}
export abstract class MemberDataType extends DataType {
- private memberMap: MemberMap;
- private members: DataType[];
- private isArray: boolean;
- protected arrayLength: number | undefined;
- protected arrayElementType: string | undefined;
+ protected readonly _arrayLength: number | undefined;
+ protected readonly _arrayElementType: string | undefined;
+ private readonly _memberMap: MemberMap;
+ private readonly _members: DataType[];
+ private readonly _isArray: boolean;
public constructor(
dataItem: DataItem,
@@ -149,70 +155,86 @@ export abstract class MemberDataType extends DataType {
arrayElementType?: string,
) {
super(dataItem, factory);
- this.memberMap = {};
- this.members = [];
- this.isArray = isArray;
- this.arrayLength = arrayLength;
- this.arrayElementType = arrayElementType;
+ this._memberMap = {};
+ this._members = [];
+ this._isArray = isArray;
+ this._arrayLength = arrayLength;
+ this._arrayElementType = arrayElementType;
if (isArray && arrayLength !== undefined) {
- [this.members, this.memberMap] = this.createMembersWithLength(dataItem, arrayLength);
+ [this._members, this._memberMap] = this._createMembersWithLength(dataItem, arrayLength);
} else if (!isArray) {
- [this.members, this.memberMap] = this.createMembersWithKeys(dataItem);
+ [this._members, this._memberMap] = this._createMembersWithKeys(dataItem);
}
}
- private createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
- // Sanity check
- if (dataItem.components === undefined) {
- throw new Error(`Expected components`);
- }
+ public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+ const block =
+ value instanceof Array
+ ? this._generateCalldataBlockFromArray(value, parentBlock)
+ : this._generateCalldataBlockFromObject(value, parentBlock);
+ return block;
+ }
- let members: DataType[] = [];
- let memberMap: MemberMap = {};
- _.each(dataItem.components, (memberItem: DataItem) => {
- const childDataItem = {
- type: memberItem.type,
- name: `${dataItem.name}.${memberItem.name}`,
- } as DataItem;
- const components = memberItem.components;
- if (components !== undefined) {
- childDataItem.components = components;
- }
- const child = this.getFactory().create(childDataItem, this);
- memberMap[memberItem.name] = members.length;
- members.push(child);
- });
+ public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
+ let members = this._members;
+ if (this._isArray && this._arrayLength === undefined) {
+ const arrayLengthBuf = calldata.popWord();
+ const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
+ const hexBase = 16;
+ const arrayLength = new BigNumber(arrayLengthHex, hexBase);
- return [members, memberMap];
+ [members] = this._createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
+ }
+
+ calldata.startScope();
+ let value: any[] | object;
+ if (rules.structsAsObjects && !this._isArray) {
+ value = {};
+ _.each(this._memberMap, (idx: number, key: string) => {
+ const member = this._members[idx];
+ const memberValue = member.generateValue(calldata, rules);
+ (value as { [key: string]: any })[key] = memberValue;
+ });
+ } else {
+ value = [];
+ _.each(members, (member: DataType, idx: number) => {
+ const memberValue = member.generateValue(calldata, rules);
+ (value as any[]).push(memberValue);
+ });
+ }
+ calldata.endScope();
+ return value;
}
- private createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
- let members: DataType[] = [];
- let memberMap: MemberMap = {};
- const range = _.range(length);
- _.each(range, (idx: number) => {
- const childDataItem = {
- type: this.arrayElementType,
- name: `${dataItem.name}[${idx.toString(10)}]`,
- } as DataItem;
- const components = dataItem.components;
- if (components !== undefined) {
- childDataItem.components = components;
- }
- const child = this.getFactory().create(childDataItem, this);
- memberMap[idx.toString(10)] = members.length;
- members.push(child);
- });
+ public isStatic(): boolean {
+ /* For Tuple:
+ const isStaticTuple = this.children.length === 0;
+ return isStaticTuple; // @TODO: True in every case or only when dynamic data?
- return [members, memberMap];
+ For Array:
+ if isLengthDefined = false then this is false
+
+ Otherwise if the first element is a Pointer then false
+ */
+
+ if (this._isArray && this._arrayLength === undefined) {
+ return false;
+ }
+
+ // Search for dependent members
+ const dependentMember = _.find(this._members, (member: DataType) => {
+ return member instanceof DependentDataType;
+ });
+ const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
+ return isStatic;
}
- protected generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
+ protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): MemberCalldataBlock {
// Sanity check length
- if (this.arrayLength !== undefined && value.length !== this.arrayLength) {
+ if (this._arrayLength !== undefined && value.length !== this._arrayLength) {
throw new Error(
`Expected array of ${JSON.stringify(
- this.arrayLength,
+ this._arrayLength,
)} elements, but got array of length ${JSON.stringify(value.length)}`,
);
}
@@ -224,11 +246,11 @@ export abstract class MemberDataType extends DataType {
parentName,
);
- let members = this.members;
- if (this.isArray && this.arrayLength === undefined) {
- [members] = this.createMembersWithLength(this.getDataItem(), value.length);
+ let members = this._members;
+ if (this._isArray && this._arrayLength === undefined) {
+ [members] = this._createMembersWithLength(this.getDataItem(), value.length);
- const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(16)}`), 32);
+ const lenBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(`0x${value.length.toString(Constants.HEX_BASE)}`), Constants.EVM_WORD_WIDTH_IN_BYTES);
methodBlock.setHeader(lenBuf);
}
@@ -241,7 +263,7 @@ export abstract class MemberDataType extends DataType {
return methodBlock;
}
- protected generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
+ protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock {
const parentName = parentBlock === undefined ? '' : parentBlock.getName();
const methodBlock: MemberCalldataBlock = new MemberCalldataBlock(
this.getDataItem().name,
@@ -249,14 +271,14 @@ export abstract class MemberDataType extends DataType {
parentName,
);
const memberBlocks: CalldataBlock[] = [];
- let childMap = _.cloneDeep(this.memberMap);
+ const childMap = _.cloneDeep(this._memberMap);
_.forOwn(obj, (value: any, key: string) => {
- if (key in childMap === false) {
+ if (!(key in childMap)) {
throw new Error(
`Could not assign tuple to object: unrecognized key '${key}' in object ${this.getDataItem().name}`,
);
}
- const block = this.members[this.memberMap[key]].generateCalldataBlock(value, methodBlock);
+ const block = this._members[this._memberMap[key]].generateCalldataBlock(value, methodBlock);
memberBlocks.push(block);
delete childMap[key];
});
@@ -269,51 +291,12 @@ export abstract class MemberDataType extends DataType {
return methodBlock;
}
- public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): MemberCalldataBlock {
- const block =
- value instanceof Array
- ? this.generateCalldataBlockFromArray(value, parentBlock)
- : this.generateCalldataBlockFromObject(value, parentBlock);
- return block;
- }
-
- public generateValue(calldata: RawCalldata, rules: DecodingRules): any[] | object {
- let members = this.members;
- if (this.isArray && this.arrayLength === undefined) {
- const arrayLengthBuf = calldata.popWord();
- const arrayLengthHex = ethUtil.bufferToHex(arrayLengthBuf);
- const hexBase = 16;
- const arrayLength = new BigNumber(arrayLengthHex, hexBase);
-
- [members] = this.createMembersWithLength(this.getDataItem(), arrayLength.toNumber());
- }
-
- calldata.startScope();
- let value: any[] | object;
- if (rules.structsAsObjects && !this.isArray) {
- value = {};
- _.each(this.memberMap, (idx: number, key: string) => {
- const member = this.members[idx];
- let memberValue = member.generateValue(calldata, rules);
- (value as { [key: string]: any })[key] = memberValue;
- });
- } else {
- value = [];
- _.each(members, (member: DataType, idx: number) => {
- let memberValue = member.generateValue(calldata, rules);
- (value as any[]).push(memberValue);
- });
- }
- calldata.endScope();
- return value;
- }
-
- protected computeSignatureOfMembers(): string {
+ protected _computeSignatureOfMembers(): string {
// Compute signature of members
let signature = `(`;
- _.each(this.members, (member: DataType, i: number) => {
+ _.each(this._members, (member: DataType, i: number) => {
signature += member.getSignature();
- if (i < this.members.length - 1) {
+ if (i < this._members.length - 1) {
signature += ',';
}
});
@@ -321,26 +304,49 @@ export abstract class MemberDataType extends DataType {
return signature;
}
- public isStatic(): boolean {
- /* For Tuple:
- const isStaticTuple = this.children.length === 0;
- return isStaticTuple; // @TODO: True in every case or only when dynamic data?
-
- For Array:
- if isLengthDefined = false then this is false
+ private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberMap] {
+ // Sanity check
+ if (dataItem.components === undefined) {
+ throw new Error(`Expected components`);
+ }
- Otherwise if the first element is a Pointer then false
- */
+ const members: DataType[] = [];
+ const memberMap: MemberMap = {};
+ _.each(dataItem.components, (memberItem: DataItem) => {
+ const childDataItem: DataItem = {
+ type: memberItem.type,
+ name: `${dataItem.name}.${memberItem.name}`,
+ };
+ const components = memberItem.components;
+ if (components !== undefined) {
+ childDataItem.components = components;
+ }
+ const child = this.getFactory().create(childDataItem, this);
+ memberMap[memberItem.name] = members.length;
+ members.push(child);
+ });
- if (this.isArray && this.arrayLength === undefined) {
- return false;
- }
+ return [members, memberMap];
+ }
- // Search for dependent members
- const dependentMember = _.find(this.members, (member: DataType) => {
- return member instanceof DependentDataType;
+ private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberMap] {
+ const members: DataType[] = [];
+ const memberMap: MemberMap = {};
+ const range = _.range(length);
+ _.each(range, (idx: number) => {
+ const childDataItem: DataItem = {
+ type: this._arrayElementType ? this._arrayElementType : '',
+ name: `${dataItem.name}[${idx.toString(Constants.DEC_BASE)}]`,
+ };
+ const components = dataItem.components;
+ if (components !== undefined) {
+ childDataItem.components = components;
+ }
+ const child = this.getFactory().create(childDataItem, this);
+ memberMap[idx.toString(Constants.DEC_BASE)] = members.length;
+ members.push(child);
});
- const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member
- return isStatic;
+
+ return [members, memberMap];
}
}
diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts
index 76837361e..1f5dff56f 100644
--- a/packages/utils/src/abi_encoder/evm_data_types.ts
+++ b/packages/utils/src/abi_encoder/evm_data_types.ts
@@ -276,7 +276,7 @@ export class Byte extends PayloadDataType {
if (valueBuf.byteLength > this.width) {
throw new Error(
`Tried to assign ${value} (${
- valueBuf.byteLength
+ valueBuf.byteLength
} bytes), which exceeds max bytes that can be stored in a ${this.getSignature()}`,
);
} else if (value.length % 2 !== 0) {
@@ -396,7 +396,7 @@ export class Pointer extends DependentDataType {
}
public getSignature(): string {
- return this.dependency.getSignature();
+ return this._dependency.getSignature();
}
}
@@ -408,7 +408,7 @@ export class Tuple extends MemberDataType {
if (!Tuple.matchGrammar(dataItem.type)) {
throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`);
}
- this.tupleSignature = this.computeSignatureOfMembers();
+ this.tupleSignature = this._computeSignatureOfMembers();
}
public getSignature(): string {
@@ -455,10 +455,10 @@ export class SolArray extends MemberDataType {
}
const elementDataType = this.getFactory().mapDataItemToDataType(dataItem);
const type = elementDataType.getSignature();
- if (this.arrayLength === undefined) {
+ if (this._arrayLength === undefined) {
return `${type}[]`;
} else {
- return `${type}[${this.arrayLength}]`;
+ return `${type}[${this._arrayLength}]`;
}
}
@@ -493,7 +493,7 @@ export class Method extends MemberDataType {
}
private computeSignature(): string {
- const memberSignature = this.computeSignatureOfMembers();
+ const memberSignature = this._computeSignatureOfMembers();
const methodSignature = `${this.getDataItem().name}${memberSignature}`;
return methodSignature;
}
@@ -548,7 +548,7 @@ export class Method extends MemberDataType {
export class EvmDataTypeFactory implements DataTypeFactory {
private static instance: DataTypeFactory;
- private constructor() {}
+ private constructor() { }
public static getInstance(): DataTypeFactory {
if (!EvmDataTypeFactory.instance) {