From 9a51af46ee4a35b3d1ce2fcdc6f561aa68307cf0 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Sun, 25 Nov 2018 18:24:46 -0800 Subject: Payload -> Blob, Dependent -> Pointer, Member -> Set --- .../abstract_data_types/dependent_data_type.ts | 51 ----- .../src/abi_encoder/abstract_data_types/index.ts | 5 +- .../abstract_data_types/member_data_type.ts | 226 -------------------- .../abstract_data_types/payload_data_type.ts | 38 ---- .../abi_encoder/abstract_data_types/types/blob.ts | 38 ++++ .../abi_encoder/abstract_data_types/types/index.ts | 3 + .../abstract_data_types/types/pointer.ts | 51 +++++ .../abi_encoder/abstract_data_types/types/set.ts | 227 +++++++++++++++++++++ .../utils/src/abi_encoder/calldata/blocks/blob.ts | 20 ++ .../utils/src/abi_encoder/calldata/blocks/index.ts | 3 + .../src/abi_encoder/calldata/blocks/pointer.ts | 59 ++++++ .../utils/src/abi_encoder/calldata/blocks/set.ts | 47 +++++ .../utils/src/abi_encoder/calldata/calldata.ts | 14 +- .../src/abi_encoder/calldata/calldata_blocks.ts | 3 - .../calldata/dependent_calldata_block.ts | 59 ------ packages/utils/src/abi_encoder/calldata/index.ts | 7 +- .../abi_encoder/calldata/member_calldata_block.ts | 48 ----- .../abi_encoder/calldata/payload_calldata_block.ts | 20 -- .../utils/src/abi_encoder/calldata/raw_calldata.ts | 25 ++- .../src/abi_encoder/evm_data_types/address.ts | 4 +- .../utils/src/abi_encoder/evm_data_types/array.ts | 4 +- .../utils/src/abi_encoder/evm_data_types/bool.ts | 4 +- .../abi_encoder/evm_data_types/dynamic_bytes.ts | 4 +- .../utils/src/abi_encoder/evm_data_types/int.ts | 10 +- .../utils/src/abi_encoder/evm_data_types/method.ts | 4 +- .../src/abi_encoder/evm_data_types/pointer.ts | 4 +- .../src/abi_encoder/evm_data_types/static_bytes.ts | 4 +- .../utils/src/abi_encoder/evm_data_types/string.ts | 4 +- .../utils/src/abi_encoder/evm_data_types/tuple.ts | 4 +- .../utils/src/abi_encoder/evm_data_types/uint.ts | 16 +- 30 files changed, 502 insertions(+), 504 deletions(-) delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts delete mode 100644 packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/index.ts create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts create mode 100644 packages/utils/src/abi_encoder/abstract_data_types/types/set.ts create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/blob.ts create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/index.ts create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/pointer.ts create mode 100644 packages/utils/src/abi_encoder/calldata/blocks/set.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/calldata_blocks.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/member_calldata_block.ts delete mode 100644 packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts (limited to 'packages') diff --git a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts deleted file mode 100644 index 7649b1836..000000000 --- a/packages/utils/src/abi_encoder/abstract_data_types/dependent_data_type.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { DataItem } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { CalldataBlock, DependentCalldataBlock, RawCalldata } from '../calldata'; -import * as Constants from '../utils/constants'; -import { DecodingRules } from '../utils/rules'; - -import { DataType } from './data_type'; -import { DataTypeFactory } from './interfaces'; - -export abstract class DependentDataType extends 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._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 name = this.getDataItem().name; - const signature = this.getSignature(); - const parentName = parentBlock ? parentBlock.getName() : ''; - const block = new DependentCalldataBlock(name, signature, parentName, dependencyBlock, parentBlock); - return block; - } - - public generateValue(calldata: RawCalldata, rules: DecodingRules): any { - const destinationOffsetBuf = calldata.popWord(); - const destinationOffsetHex = ethUtil.bufferToHex(destinationOffsetBuf); - const destinationOffsetRelative = parseInt(destinationOffsetHex, Constants.HEX_BASE); - const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative); - const currentOffset = calldata.getOffset(); - calldata.setOffset(destinationOffsetAbsolute); - const value = this._dependency.generateValue(calldata, rules); - calldata.setOffset(currentOffset); - return value; - } - - public isStatic(): boolean { - return this._isStatic; - } -} diff --git a/packages/utils/src/abi_encoder/abstract_data_types/index.ts b/packages/utils/src/abi_encoder/abstract_data_types/index.ts index 9ad568134..d1c7d93e4 100644 --- a/packages/utils/src/abi_encoder/abstract_data_types/index.ts +++ b/packages/utils/src/abi_encoder/abstract_data_types/index.ts @@ -1,5 +1,4 @@ export * from './interfaces'; export * from './data_type'; -export * from './dependent_data_type'; -export * from './member_data_type'; -export * from './payload_data_type'; +import * as AbstractDataTypes from './types'; +export { AbstractDataTypes }; diff --git a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts deleted file mode 100644 index dacdbf8af..000000000 --- a/packages/utils/src/abi_encoder/abstract_data_types/member_data_type.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { DataItem } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; -import * as _ from 'lodash'; - -import { BigNumber } from '../../configured_bignumber'; -import { CalldataBlock, MemberCalldataBlock, RawCalldata } from '../calldata'; -import * as Constants from '../utils/constants'; -import { DecodingRules } from '../utils/rules'; - -import { DataType } from './data_type'; -import { DependentDataType } from './dependent_data_type'; -import { DataTypeFactory, MemberIndexByName } from './interfaces'; - -export abstract class MemberDataType extends DataType { - protected readonly _arrayLength: number | undefined; - protected readonly _arrayElementType: string | undefined; - private readonly _memberIndexByName: MemberIndexByName; - private readonly _members: DataType[]; - private readonly _isArray: boolean; - - public constructor( - dataItem: DataItem, - factory: DataTypeFactory, - isArray: boolean = false, - arrayLength?: number, - arrayElementType?: string, - ) { - super(dataItem, factory); - this._memberIndexByName = {}; - this._members = []; - this._isArray = isArray; - this._arrayLength = arrayLength; - this._arrayElementType = arrayElementType; - if (isArray && arrayLength !== undefined) { - [this._members, this._memberIndexByName] = this._createMembersWithLength(dataItem, arrayLength); - } else if (!isArray) { - [this._members, this._memberIndexByName] = this._createMembersWithKeys(dataItem); - } - } - - 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._memberIndexByName, (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; - } - - 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 - - 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 { - // Sanity check length - if (this._arrayLength !== undefined && value.length !== this._arrayLength) { - throw new Error( - `Expected array of ${JSON.stringify( - this._arrayLength, - )} elements, but got array of length ${JSON.stringify(value.length)}`, - ); - } - - const parentName = parentBlock === undefined ? '' : parentBlock.getName(); - const methodBlock: MemberCalldataBlock = new MemberCalldataBlock( - this.getDataItem().name, - this.getSignature(), - parentName, - ); - - 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(Constants.HEX_BASE)}`), - Constants.EVM_WORD_WIDTH_IN_BYTES, - ); - methodBlock.setHeader(lenBuf); - } - - const memberBlocks: CalldataBlock[] = []; - _.each(members, (member: DataType, idx: number) => { - const block = member.generateCalldataBlock(value[idx], methodBlock); - memberBlocks.push(block); - }); - methodBlock.setMembers(memberBlocks); - return methodBlock; - } - - protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): MemberCalldataBlock { - const parentName = parentBlock === undefined ? '' : parentBlock.getName(); - const methodBlock: MemberCalldataBlock = new MemberCalldataBlock( - this.getDataItem().name, - this.getSignature(), - parentName, - ); - const memberBlocks: CalldataBlock[] = []; - const childMap = _.cloneDeep(this._memberIndexByName); - _.forOwn(obj, (value: any, key: string) => { - 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._memberIndexByName[key]].generateCalldataBlock(value, methodBlock); - memberBlocks.push(block); - delete childMap[key]; - }); - - if (Object.keys(childMap).length !== 0) { - throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`); - } - - methodBlock.setMembers(memberBlocks); - return methodBlock; - } - - protected _computeSignatureOfMembers(): string { - // Compute signature of members - let signature = `(`; - _.each(this._members, (member: DataType, i: number) => { - signature += member.getSignature(); - if (i < this._members.length - 1) { - signature += ','; - } - }); - signature += ')'; - return signature; - } - - private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] { - // Sanity check - if (dataItem.components === undefined) { - throw new Error(`Expected components`); - } - - const members: DataType[] = []; - const memberIndexByName: MemberIndexByName = {}; - _.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); - memberIndexByName[memberItem.name] = members.length; - members.push(child); - }); - - return [members, memberIndexByName]; - } - - private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberIndexByName] { - const members: DataType[] = []; - const memberIndexByName: MemberIndexByName = {}; - 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); - memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length; - members.push(child); - }); - - return [members, memberIndexByName]; - } -} diff --git a/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts deleted file mode 100644 index fa420bc74..000000000 --- a/packages/utils/src/abi_encoder/abstract_data_types/payload_data_type.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { DataItem } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { CalldataBlock, PayloadCalldataBlock, RawCalldata } from '../calldata'; -import { DecodingRules } from '../utils/rules'; - -import { DataType } from './data_type'; -import { DataTypeFactory } from './interfaces'; - -export abstract class PayloadDataType extends DataType { - protected _hasConstantSize: boolean; - - public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) { - super(dataItem, factory); - this._hasConstantSize = hasConstantSize; - } - - public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): PayloadCalldataBlock { - const encodedValue = this.encodeValue(value); - const name = this.getDataItem().name; - const signature = this.getSignature(); - const parentName = parentBlock ? parentBlock.getName() : ''; - const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue); - return block; - } - - public generateValue(calldata: RawCalldata, rules: DecodingRules): any { - const value = this.decodeValue(calldata); - return value; - } - - public isStatic(): boolean { - return this._hasConstantSize; - } - - public abstract encodeValue(value: any): Buffer; - public abstract decodeValue(calldata: RawCalldata): any; -} diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts new file mode 100644 index 000000000..f4246c893 --- /dev/null +++ b/packages/utils/src/abi_encoder/abstract_data_types/types/blob.ts @@ -0,0 +1,38 @@ +import { DataItem } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata'; +import { DecodingRules } from '../../utils/rules'; + +import { DataType } from '../data_type'; +import { DataTypeFactory } from '../interfaces'; + +export abstract class Blob extends DataType { + protected _hasConstantSize: boolean; + + public constructor(dataItem: DataItem, factory: DataTypeFactory, hasConstantSize: boolean) { + super(dataItem, factory); + this._hasConstantSize = hasConstantSize; + } + + public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Blob { + const encodedValue = this.encodeValue(value); + const name = this.getDataItem().name; + const signature = this.getSignature(); + const parentName = parentBlock ? parentBlock.getName() : ''; + const block = new CalldataBlocks.Blob(name, signature, parentName, encodedValue); + return block; + } + + public generateValue(calldata: RawCalldata, rules: DecodingRules): any { + const value = this.decodeValue(calldata); + return value; + } + + public isStatic(): boolean { + return this._hasConstantSize; + } + + public abstract encodeValue(value: any): Buffer; + public abstract decodeValue(calldata: RawCalldata): any; +} diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts new file mode 100644 index 000000000..958582dae --- /dev/null +++ b/packages/utils/src/abi_encoder/abstract_data_types/types/index.ts @@ -0,0 +1,3 @@ +export * from './blob'; +export * from './pointer'; +export * from './set'; diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts new file mode 100644 index 000000000..47efac521 --- /dev/null +++ b/packages/utils/src/abi_encoder/abstract_data_types/types/pointer.ts @@ -0,0 +1,51 @@ +import { DataItem } from 'ethereum-types'; +import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; + +import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata'; +import * as Constants from '../../utils/constants'; +import { DecodingRules } from '../../utils/rules'; + +import { DataType } from '../data_type'; +import { DataTypeFactory } from '../interfaces'; + +export abstract class Pointer extends 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._isStatic = true; + } + + public generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlocks.Pointer { + if (parentBlock === undefined) { + throw new Error(`DependentDataType requires a parent block to generate its block`); + } + const dependencyBlock = this._dependency.generateCalldataBlock(value, parentBlock); + const name = this.getDataItem().name; + const signature = this.getSignature(); + const parentName = parentBlock ? parentBlock.getName() : ''; + const block = new CalldataBlocks.Pointer(name, signature, parentName, dependencyBlock, parentBlock); + return block; + } + + public generateValue(calldata: RawCalldata, rules: DecodingRules): any { + const destinationOffsetBuf = calldata.popWord(); + const destinationOffsetHex = ethUtil.bufferToHex(destinationOffsetBuf); + const destinationOffsetRelative = parseInt(destinationOffsetHex, Constants.HEX_BASE); + const destinationOffsetAbsolute = calldata.toAbsoluteOffset(destinationOffsetRelative); + const currentOffset = calldata.getOffset(); + calldata.setOffset(destinationOffsetAbsolute); + const value = this._dependency.generateValue(calldata, rules); + calldata.setOffset(currentOffset); + return value; + } + + public isStatic(): boolean { + return this._isStatic; + } +} diff --git a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts new file mode 100644 index 000000000..77fd7b3ea --- /dev/null +++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts @@ -0,0 +1,227 @@ +import { DataItem } from 'ethereum-types'; +import * as ethUtil from 'ethereumjs-util'; +import * as _ from 'lodash'; + +import { BigNumber } from '../../../configured_bignumber'; +import { CalldataBlock, CalldataBlocks, RawCalldata } from '../../calldata'; +import * as Constants from '../../utils/constants'; +import { DecodingRules } from '../../utils/rules'; + +import { DataType } from '../data_type'; +import { DataTypeFactory, MemberIndexByName } from '../interfaces'; + +import { Pointer } from './pointer'; + +export abstract class Set extends DataType { + protected readonly _arrayLength: number | undefined; + protected readonly _arrayElementType: string | undefined; + private readonly _memberIndexByName: MemberIndexByName; + private readonly _members: DataType[]; + private readonly _isArray: boolean; + + public constructor( + dataItem: DataItem, + factory: DataTypeFactory, + isArray: boolean = false, + arrayLength?: number, + arrayElementType?: string, + ) { + super(dataItem, factory); + this._memberIndexByName = {}; + this._members = []; + this._isArray = isArray; + this._arrayLength = arrayLength; + this._arrayElementType = arrayElementType; + if (isArray && arrayLength !== undefined) { + [this._members, this._memberIndexByName] = this._createMembersWithLength(dataItem, arrayLength); + } else if (!isArray) { + [this._members, this._memberIndexByName] = this._createMembersWithKeys(dataItem); + } + } + + public generateCalldataBlock(value: any[] | object, parentBlock?: CalldataBlock): CalldataBlocks.Set { + 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._memberIndexByName, (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; + } + + 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 + + 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 Pointer; + }); + const isStatic = dependentMember === undefined; // static if we couldn't find a dependent member + return isStatic; + } + + protected _generateCalldataBlockFromArray(value: any[], parentBlock?: CalldataBlock): CalldataBlocks.Set { + // Sanity check length + if (this._arrayLength !== undefined && value.length !== this._arrayLength) { + throw new Error( + `Expected array of ${JSON.stringify( + this._arrayLength, + )} elements, but got array of length ${JSON.stringify(value.length)}`, + ); + } + + const parentName = parentBlock === undefined ? '' : parentBlock.getName(); + const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set( + this.getDataItem().name, + this.getSignature(), + parentName, + ); + + 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(Constants.HEX_BASE)}`), + Constants.EVM_WORD_WIDTH_IN_BYTES, + ); + methodBlock.setHeader(lenBuf); + } + + const memberCalldataBlocks: CalldataBlock[] = []; + _.each(members, (member: DataType, idx: number) => { + const block = member.generateCalldataBlock(value[idx], methodBlock); + memberCalldataBlocks.push(block); + }); + methodBlock.setMembers(memberCalldataBlocks); + return methodBlock; + } + + protected _generateCalldataBlockFromObject(obj: object, parentBlock?: CalldataBlock): CalldataBlocks.Set { + const parentName = parentBlock === undefined ? '' : parentBlock.getName(); + const methodBlock: CalldataBlocks.Set = new CalldataBlocks.Set( + this.getDataItem().name, + this.getSignature(), + parentName, + ); + const memberCalldataBlocks: CalldataBlock[] = []; + const childMap = _.cloneDeep(this._memberIndexByName); + _.forOwn(obj, (value: any, key: string) => { + 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._memberIndexByName[key]].generateCalldataBlock(value, methodBlock); + memberCalldataBlocks.push(block); + delete childMap[key]; + }); + + if (Object.keys(childMap).length !== 0) { + throw new Error(`Could not assign tuple to object: missing keys ${Object.keys(childMap)}`); + } + + methodBlock.setMembers(memberCalldataBlocks); + return methodBlock; + } + + protected _computeSignatureOfMembers(): string { + // Compute signature of members + let signature = `(`; + _.each(this._members, (member: DataType, i: number) => { + signature += member.getSignature(); + if (i < this._members.length - 1) { + signature += ','; + } + }); + signature += ')'; + return signature; + } + + private _createMembersWithKeys(dataItem: DataItem): [DataType[], MemberIndexByName] { + // Sanity check + if (dataItem.components === undefined) { + throw new Error(`Expected components`); + } + + const members: DataType[] = []; + const memberIndexByName: MemberIndexByName = {}; + _.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); + memberIndexByName[memberItem.name] = members.length; + members.push(child); + }); + + return [members, memberIndexByName]; + } + + private _createMembersWithLength(dataItem: DataItem, length: number): [DataType[], MemberIndexByName] { + const members: DataType[] = []; + const memberIndexByName: MemberIndexByName = {}; + 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); + memberIndexByName[idx.toString(Constants.DEC_BASE)] = members.length; + members.push(child); + }); + + return [members, memberIndexByName]; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/blocks/blob.ts b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts new file mode 100644 index 000000000..210ef6420 --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/blob.ts @@ -0,0 +1,20 @@ +import { CalldataBlock } from '../calldata_block'; + +export class Blob extends CalldataBlock { + private readonly _blob: Buffer; + + constructor(name: string, signature: string, parentName: string, blob: Buffer) { + const headerSizeInBytes = 0; + const bodySizeInBytes = blob.byteLength; + super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); + this._blob = blob; + } + + public toBuffer(): Buffer { + return this._blob; + } + + public getRawData(): Buffer { + return this._blob; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/blocks/index.ts b/packages/utils/src/abi_encoder/calldata/blocks/index.ts new file mode 100644 index 000000000..958582dae --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/index.ts @@ -0,0 +1,3 @@ +export * from './blob'; +export * from './pointer'; +export * from './set'; diff --git a/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts new file mode 100644 index 000000000..1c49a8c6c --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/pointer.ts @@ -0,0 +1,59 @@ +import * as ethUtil from 'ethereumjs-util'; + +import * as Constants from '../../utils/constants'; + +import { CalldataBlock } from '../calldata_block'; + +export class Pointer extends CalldataBlock { + public static readonly RAW_DATA_START = new Buffer('<'); + public static readonly RAW_DATA_END = new Buffer('>'); + private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32; + private static readonly _EMPTY_HEADER_SIZE = 0; + private readonly _parent: CalldataBlock; + private readonly _dependency: CalldataBlock; + private _aliasFor: CalldataBlock | undefined; + + constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) { + const headerSizeInBytes = Pointer._EMPTY_HEADER_SIZE; + const bodySizeInBytes = Pointer._DEPENDENT_PAYLOAD_SIZE_IN_BYTES; + super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); + this._parent = parent; + this._dependency = dependency; + this._aliasFor = undefined; + } + + public toBuffer(): Buffer { + const destinationOffset = + this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); + const parentOffset = this._parent.getOffsetInBytes(); + const parentHeaderSize = this._parent.getHeaderSizeInBytes(); + const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); + const pointerHex = `0x${pointer.toString(Constants.HEX_BASE)}`; + const pointerBuf = ethUtil.toBuffer(pointerHex); + const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, Constants.EVM_WORD_WIDTH_IN_BYTES); + return pointerBufPadded; + } + + public getDependency(): CalldataBlock { + return this._dependency; + } + + public setAlias(block: CalldataBlock): void { + this._aliasFor = block; + this._setName(`${this.getName()} (alias for ${block.getName()})`); + } + + public getAlias(): CalldataBlock | undefined { + return this._aliasFor; + } + + public getRawData(): Buffer { + const dependencyRawData = this._dependency.getRawData(); + const rawDataComponents: Buffer[] = []; + rawDataComponents.push(Pointer.RAW_DATA_START); + rawDataComponents.push(dependencyRawData); + rawDataComponents.push(Pointer.RAW_DATA_END); + const rawData = Buffer.concat(rawDataComponents); + return rawData; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/blocks/set.ts b/packages/utils/src/abi_encoder/calldata/blocks/set.ts new file mode 100644 index 000000000..e4de22c5c --- /dev/null +++ b/packages/utils/src/abi_encoder/calldata/blocks/set.ts @@ -0,0 +1,47 @@ +import * as _ from 'lodash'; + +import { CalldataBlock } from '../calldata_block'; + +export class Set extends CalldataBlock { + private _header: Buffer | undefined; + private _members: CalldataBlock[]; + + constructor(name: string, signature: string, parentName: string) { + super(name, signature, parentName, 0, 0); + this._members = []; + this._header = undefined; + } + + public getRawData(): Buffer { + const rawDataComponents: Buffer[] = []; + if (this._header) { + rawDataComponents.push(this._header); + } + _.each(this._members, (member: CalldataBlock) => { + const memberBuffer = member.getRawData(); + rawDataComponents.push(memberBuffer); + }); + const rawData = Buffer.concat(rawDataComponents); + return rawData; + } + + public setMembers(members: CalldataBlock[]): void { + this._members = members; + } + + public setHeader(header: Buffer): void { + this._setHeaderSize(header.byteLength); + this._header = header; + } + + public toBuffer(): Buffer { + if (this._header) { + return this._header; + } + return new Buffer(''); + } + + public getMembers(): CalldataBlock[] { + return this._members; + } +} diff --git a/packages/utils/src/abi_encoder/calldata/calldata.ts b/packages/utils/src/abi_encoder/calldata/calldata.ts index 3b85f821b..b2396ee8f 100644 --- a/packages/utils/src/abi_encoder/calldata/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/calldata.ts @@ -5,8 +5,8 @@ import * as Constants from '../utils/constants'; import { Queue } from '../utils/queue'; import { EncodingRules } from '../utils/rules'; +import * as CalldataBlocks from './blocks'; import { CalldataBlock } from './calldata_block'; -import * as CalldataBlocks from './calldata_blocks'; export class Calldata { private readonly _rules: EncodingRules; @@ -18,7 +18,7 @@ export class Calldata { const blockQueue = new Queue(); // Base Case - if (!(block instanceof CalldataBlocks.MemberCalldataBlock)) { + if (!(block instanceof CalldataBlocks.Set)) { blockQueue.pushBack(block); return blockQueue; } @@ -26,7 +26,7 @@ export class Calldata { // This is a Member Block const memberBlock = block; _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => { - if (member instanceof CalldataBlocks.MemberCalldataBlock) { + if (member instanceof CalldataBlocks.Set) { blockQueue.mergeFront(Calldata._createQueue(member)); } else { blockQueue.pushFront(member); @@ -35,9 +35,9 @@ export class Calldata { // Children _.each(memberBlock.getMembers(), (member: CalldataBlock) => { - if (member instanceof CalldataBlocks.DependentCalldataBlock && member.getAlias() === undefined) { + if (member instanceof CalldataBlocks.Pointer && member.getAlias() === undefined) { const dependency = member.getDependency(); - if (dependency instanceof CalldataBlocks.MemberCalldataBlock) { + if (dependency instanceof CalldataBlocks.Set) { blockQueue.mergeBack(Calldata._createQueue(dependency)); } else { blockQueue.pushBack(dependency); @@ -68,7 +68,7 @@ export class Calldata { const subtreeQueue = Calldata._createQueue(this._root); let block: CalldataBlock | undefined; for (block = subtreeQueue.popBack(); block !== undefined; block = subtreeQueue.popBack()) { - if (block instanceof CalldataBlocks.DependentCalldataBlock) { + if (block instanceof CalldataBlocks.Pointer) { const dependencyBlockHashBuf = block.getDependency().computeHash(); const dependencyBlockHash = ethUtil.bufferToHex(dependencyBlockHashBuf); if (dependencyBlockHash in blocksByHash) { @@ -175,7 +175,7 @@ export class Calldata { ), ) .padEnd(valuePadding); - if (block instanceof CalldataBlocks.MemberCalldataBlock) { + if (block instanceof CalldataBlocks.Set) { nameStr = `### ${prettyName.padEnd(namePadding)}`; line = `\n${offsetStr}${value}${nameStr}`; } else { diff --git a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts b/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts deleted file mode 100644 index 8d4e7d7ca..000000000 --- a/packages/utils/src/abi_encoder/calldata/calldata_blocks.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './dependent_calldata_block'; -export * from './member_calldata_block'; -export * from './payload_calldata_block'; diff --git a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts deleted file mode 100644 index 16b9a6fe6..000000000 --- a/packages/utils/src/abi_encoder/calldata/dependent_calldata_block.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as ethUtil from 'ethereumjs-util'; - -import * as Constants from '../utils/constants'; - -import { CalldataBlock } from './calldata_block'; - -export class DependentCalldataBlock extends CalldataBlock { - public static readonly RAW_DATA_START = new Buffer('<'); - public static readonly RAW_DATA_END = new Buffer('>'); - private static readonly _DEPENDENT_PAYLOAD_SIZE_IN_BYTES = 32; - private static readonly _EMPTY_HEADER_SIZE = 0; - private readonly _parent: CalldataBlock; - private readonly _dependency: CalldataBlock; - private _aliasFor: CalldataBlock | undefined; - - constructor(name: string, signature: string, parentName: string, dependency: CalldataBlock, parent: CalldataBlock) { - const headerSizeInBytes = DependentCalldataBlock._EMPTY_HEADER_SIZE; - const bodySizeInBytes = DependentCalldataBlock._DEPENDENT_PAYLOAD_SIZE_IN_BYTES; - super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); - this._parent = parent; - this._dependency = dependency; - this._aliasFor = undefined; - } - - public toBuffer(): Buffer { - const destinationOffset = - this._aliasFor !== undefined ? this._aliasFor.getOffsetInBytes() : this._dependency.getOffsetInBytes(); - const parentOffset = this._parent.getOffsetInBytes(); - const parentHeaderSize = this._parent.getHeaderSizeInBytes(); - const pointer: number = destinationOffset - (parentOffset + parentHeaderSize); - const pointerBuf = ethUtil.toBuffer(`0x${pointer.toString(Constants.HEX_BASE)}`); - const evmWordWidthInBytes = 32; - const pointerBufPadded = ethUtil.setLengthLeft(pointerBuf, evmWordWidthInBytes); - return pointerBufPadded; - } - - public getDependency(): CalldataBlock { - return this._dependency; - } - - public setAlias(block: CalldataBlock): void { - this._aliasFor = block; - this._setName(`${this.getName()} (alias for ${block.getName()})`); - } - - public getAlias(): CalldataBlock | undefined { - return this._aliasFor; - } - - public getRawData(): Buffer { - const dependencyRawData = this._dependency.getRawData(); - const rawDataComponents: Buffer[] = []; - rawDataComponents.push(DependentCalldataBlock.RAW_DATA_START); - rawDataComponents.push(dependencyRawData); - rawDataComponents.push(DependentCalldataBlock.RAW_DATA_END); - const rawData = Buffer.concat(rawDataComponents); - return rawData; - } -} diff --git a/packages/utils/src/abi_encoder/calldata/index.ts b/packages/utils/src/abi_encoder/calldata/index.ts index 2c786cd8d..2ef75e8d0 100644 --- a/packages/utils/src/abi_encoder/calldata/index.ts +++ b/packages/utils/src/abi_encoder/calldata/index.ts @@ -1,6 +1,5 @@ -export * from './calldata_block'; -export * from './dependent_calldata_block'; -export * from './payload_calldata_block'; -export * from './member_calldata_block'; export * from './calldata'; +export * from './calldata_block'; export * from './raw_calldata'; +import * as CalldataBlocks from './blocks'; +export { CalldataBlocks }; diff --git a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts deleted file mode 100644 index c35beb8de..000000000 --- a/packages/utils/src/abi_encoder/calldata/member_calldata_block.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as _ from 'lodash'; - -import { CalldataBlock } from './calldata_block'; - -export class MemberCalldataBlock extends CalldataBlock { - private _header: Buffer | undefined; - private _members: CalldataBlock[]; - - constructor(name: string, signature: string, parentName: string) { - super(name, signature, parentName, 0, 0); - this._members = []; - this._header = undefined; - } - - public getRawData(): Buffer { - const rawDataComponents: Buffer[] = []; - if (this._header !== undefined) { - rawDataComponents.push(this._header); - } - _.each(this._members, (member: CalldataBlock) => { - const memberBuffer = member.getRawData(); - rawDataComponents.push(memberBuffer); - }); - - const rawData = Buffer.concat(rawDataComponents); - return rawData; - } - - public setMembers(members: CalldataBlock[]): void { - this._members = members; - } - - public setHeader(header: Buffer): void { - this._setHeaderSize(header.byteLength); - this._header = header; - } - - public toBuffer(): Buffer { - if (this._header !== undefined) { - return this._header; - } - return new Buffer(''); - } - - public getMembers(): CalldataBlock[] { - return this._members; - } -} diff --git a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts b/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts deleted file mode 100644 index 0420b01d8..000000000 --- a/packages/utils/src/abi_encoder/calldata/payload_calldata_block.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CalldataBlock } from './calldata_block'; - -export class PayloadCalldataBlock extends CalldataBlock { - private readonly _payload: Buffer; - - constructor(name: string, signature: string, parentName: string, payload: Buffer) { - const headerSizeInBytes = 0; - const bodySizeInBytes = payload.byteLength; - super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); - this._payload = payload; - } - - public toBuffer(): Buffer { - return this._payload; - } - - public getRawData(): Buffer { - return this._payload; - } -} diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index 9e72bbd62..b13cbdfd9 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -8,26 +8,25 @@ export class RawCalldata { private readonly _value: Buffer; private readonly _selector: string; private readonly _scopes: Queue; - private _offset: number; // tracks current offset into raw calldata; used for parsing + private _offset: number; - constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) { + public constructor(value: string | Buffer, hasSelector: boolean = true) { + // Sanity check if (typeof value === 'string' && !value.startsWith('0x')) { throw new Error(`Expected raw calldata to start with '0x'`); } - const valueBuf = ethUtil.toBuffer(value); - if (hasSelectorPrefix) { - this._selector = ethUtil.bufferToHex( - valueBuf.slice(Constants.HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA, Constants.HEX_SELECTOR_LENGTH_IN_BYTES), - ); - this._value = valueBuf.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); // disregard selector - } else { - this._selector = '0x'; - this._value = valueBuf; - } - + // Construct initial values + this._value = ethUtil.toBuffer(value); + this._selector = '0x'; this._scopes = new Queue(); this._scopes.pushBack(RawCalldata._INITIAL_OFFSET); this._offset = RawCalldata._INITIAL_OFFSET; + // If there's a selector then slice it + if (hasSelector) { + const selectorBuf = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); + this._value = this._value.slice(Constants.HEX_SELECTOR_LENGTH_IN_BYTES); + this._selector = ethUtil.bufferToHex(selectorBuf); + } } public popBytes(lengthInBytes: number): Buffer { diff --git a/packages/utils/src/abi_encoder/evm_data_types/address.ts b/packages/utils/src/abi_encoder/evm_data_types/address.ts index 84f6665cb..71aa293b5 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/address.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts @@ -3,11 +3,11 @@ import { DataItem } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; -export class Address extends PayloadDataType { +export class Address extends AbstractDataTypes.Blob { public static ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X = "Address must start with '0x'"; public static ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES = 'Address must be 20 bytes'; private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; diff --git a/packages/utils/src/abi_encoder/evm_data_types/array.ts b/packages/utils/src/abi_encoder/evm_data_types/array.ts index 77e38ebd7..54f7ba9fa 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/array.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts @@ -1,9 +1,9 @@ import { DataItem } from 'ethereum-types'; -import { DataTypeFactory, MemberDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import * as Constants from '../utils/constants'; -export class Array extends MemberDataType { +export class Array extends AbstractDataTypes.Set { private static readonly _MATCHER = RegExp('^(.+)\\[([0-9]*)\\]$'); private readonly _arraySignature: string; private readonly _elementType: string; diff --git a/packages/utils/src/abi_encoder/evm_data_types/bool.ts b/packages/utils/src/abi_encoder/evm_data_types/bool.ts index 82a519aae..031acc88a 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts @@ -4,11 +4,11 @@ import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; import { BigNumber } from '../../configured_bignumber'; -import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; -export class Bool extends PayloadDataType { +export class Bool extends AbstractDataTypes.Blob { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; public static matchType(type: string): boolean { diff --git a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts index ce6ace627..01d83d11a 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/dynamic_bytes.ts @@ -3,11 +3,11 @@ import { DataItem } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; -export class DynamicBytes extends PayloadDataType { +export class DynamicBytes extends AbstractDataTypes.Blob { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false; public static matchType(type: string): boolean { diff --git a/packages/utils/src/abi_encoder/evm_data_types/int.ts b/packages/utils/src/abi_encoder/evm_data_types/int.ts index 83aeacd66..8a82ed4cc 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/int.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts @@ -2,21 +2,21 @@ import { DataItem } from 'ethereum-types'; import { BigNumber } from '../../configured_bignumber'; -import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; import * as EncoderMath from '../utils/math'; -export class Int extends PayloadDataType { +export class Int extends AbstractDataTypes.Blob { private static readonly _MATCHER = RegExp( '^int(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$', ); private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; private static readonly _MAX_WIDTH: number = 256; private static readonly _DEFAULT_WIDTH: number = Int._MAX_WIDTH; - private _width: number; - private _minValue: BigNumber; - private _maxValue: BigNumber; + private readonly _width: number; + private readonly _minValue: BigNumber; + private readonly _maxValue: BigNumber; public static matchType(type: string): boolean { return Int._MATCHER.test(type); diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts index f2e417485..bd4732097 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/method.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts @@ -2,13 +2,13 @@ import { DataItem, MethodAbi } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import { DataType, DataTypeFactory, MemberDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types'; import * as Constants from '../utils/constants'; import { DecodingRules, EncodingRules } from '../utils/rules'; import { Tuple } from './tuple'; -export class Method extends MemberDataType { +export class Method extends AbstractDataTypes.Set { private readonly _methodSignature: string; private readonly _methodSelector: string; private readonly _returnDataType: DataType; diff --git a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts index d4411df9b..00c743d2b 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts @@ -1,8 +1,8 @@ import { DataItem } from 'ethereum-types'; -import { DataType, DataTypeFactory, DependentDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataType, DataTypeFactory } from '../abstract_data_types'; -export class Pointer extends DependentDataType { +export class Pointer extends AbstractDataTypes.Pointer { constructor(destDataType: DataType, parentDataType: DataType, dataTypeFactory: DataTypeFactory) { const destDataItem = destDataType.getDataItem(); const dataItem: DataItem = { name: `ptr<${destDataItem.name}>`, type: `ptr<${destDataItem.type}>` }; diff --git a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts index 0d01e6105..d0b41194e 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/static_bytes.ts @@ -2,11 +2,11 @@ import { DataItem } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; -export class StaticBytes extends PayloadDataType { +export class StaticBytes extends AbstractDataTypes.Blob { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; private static readonly _MATCHER = RegExp( '^(byte|bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32))$', diff --git a/packages/utils/src/abi_encoder/evm_data_types/string.ts b/packages/utils/src/abi_encoder/evm_data_types/string.ts index 2bb6541a3..6ab3513c9 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/string.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts @@ -3,11 +3,11 @@ import { DataItem } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; -export class String extends PayloadDataType { +export class String extends AbstractDataTypes.Blob { private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = false; public static matchType(type: string): boolean { diff --git a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts index 63d9dfa9e..3802f96c0 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts @@ -1,8 +1,8 @@ import { DataItem } from 'ethereum-types'; -import { DataTypeFactory, MemberDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; -export class Tuple extends MemberDataType { +export class Tuple extends AbstractDataTypes.Set { private readonly _signature: string; public static matchType(type: string): boolean { diff --git a/packages/utils/src/abi_encoder/evm_data_types/uint.ts b/packages/utils/src/abi_encoder/evm_data_types/uint.ts index 832ab075c..b1bc690d8 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts @@ -2,21 +2,21 @@ import { DataItem } from 'ethereum-types'; import { BigNumber } from '../../configured_bignumber'; -import { DataTypeFactory, PayloadDataType } from '../abstract_data_types'; +import { AbstractDataTypes, DataTypeFactory } from '../abstract_data_types'; import { RawCalldata } from '../calldata'; import * as Constants from '../utils/constants'; import * as EncoderMath from '../utils/math'; -export class UInt extends PayloadDataType { +export class UInt extends AbstractDataTypes.Blob { private static readonly _MATCHER = RegExp( '^uint(8|16|24|32|40|48|56|64|72|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256){0,1}$', ); private static readonly _SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; private static readonly _MAX_WIDTH: number = 256; private static readonly _DEFAULT_WIDTH: number = UInt._MAX_WIDTH; - private _width: number; - private _minValue: BigNumber; - private _maxValue: BigNumber; + private static readonly _MIN_VALUE = new BigNumber(0); + private readonly _width: number; + private readonly _maxValue: BigNumber; public static matchType(type: string): boolean { return UInt._MATCHER.test(type); @@ -36,18 +36,17 @@ export class UInt extends PayloadDataType { throw new Error(`Tried to instantiate UInt with bad input: ${dataItem}`); } this._width = UInt._decodeWidthFromType(dataItem.type); - this._minValue = new BigNumber(0); this._maxValue = new BigNumber(2).toPower(this._width).sub(1); } public encodeValue(value: BigNumber | string | number): Buffer { - const encodedValue = EncoderMath.safeEncodeNumericValue(value, this._minValue, this._maxValue); + const encodedValue = EncoderMath.safeEncodeNumericValue(value, UInt._MIN_VALUE, this._maxValue); return encodedValue; } public decodeValue(calldata: RawCalldata): BigNumber { const valueBuf = calldata.popWord(); - const value = EncoderMath.safeDecodeNumericValue(valueBuf, this._minValue, this._maxValue); + const value = EncoderMath.safeDecodeNumericValue(valueBuf, UInt._MIN_VALUE, this._maxValue); return value; } @@ -55,4 +54,3 @@ export class UInt extends PayloadDataType { return `uint${this._width}`; } } - -- cgit v1.2.3