diff options
author | Greg Hysen <greg.hysen@gmail.com> | 2018-12-20 05:01:22 +0800 |
---|---|---|
committer | Greg Hysen <greg.hysen@gmail.com> | 2019-01-15 02:49:44 +0800 |
commit | e9a82905e35041d36c4c9be75e11c0399ee96b89 (patch) | |
tree | bd49ab279ae96fb0248b252e55399f3ce50c4793 /packages/utils/src | |
parent | f8684d6a776724d0172c30126a7277885ed4e966 (diff) | |
download | dexon-0x-contracts-e9a82905e35041d36c4c9be75e11c0399ee96b89.tar dexon-0x-contracts-e9a82905e35041d36c4c9be75e11c0399ee96b89.tar.gz dexon-0x-contracts-e9a82905e35041d36c4c9be75e11c0399ee96b89.tar.bz2 dexon-0x-contracts-e9a82905e35041d36c4c9be75e11c0399ee96b89.tar.lz dexon-0x-contracts-e9a82905e35041d36c4c9be75e11c0399ee96b89.tar.xz dexon-0x-contracts-e9a82905e35041d36c4c9be75e11c0399ee96b89.tar.zst dexon-0x-contracts-e9a82905e35041d36c4c9be75e11c0399ee96b89.zip |
Abi Encoder tests fixed + added a signature parser for cases where MethodAbi/DataItems are not readily available
Diffstat (limited to 'packages/utils/src')
15 files changed, 206 insertions, 22 deletions
diff --git a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts index 13cc87e2a..5bd6aae03 100644 --- a/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts +++ b/packages/utils/src/abi_encoder/abstract_data_types/data_type.ts @@ -51,8 +51,16 @@ export abstract class DataType { return value; } + public getSignature(detailed?: boolean): string { + if (_.isEmpty(this._dataItem.name) || !detailed) return this.getSignatureType(); + const name = this.getDataItem().name; + const shortName = name.indexOf('.') > 0 ? name.substr(name.lastIndexOf('.') + 1) : name; + const detailedSignature = `${shortName} ${this.getSignatureType()}`; + return detailedSignature; + } + public abstract generateCalldataBlock(value: any, parentBlock?: CalldataBlock): CalldataBlock; public abstract generateValue(calldata: RawCalldata, rules: DecodingRules): any; - public abstract getSignature(): string; + public abstract getSignatureType(): string; public abstract isStatic(): boolean; } 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 index 73e9cf778..d7105ff5f 100644 --- a/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts +++ b/packages/utils/src/abi_encoder/abstract_data_types/types/set.ts @@ -155,11 +155,11 @@ export abstract class AbstractSetDataType extends DataType { return block; } - protected _computeSignatureOfMembers(): string { + protected _computeSignatureOfMembers(detailed?: boolean): string { // Compute signature of members let signature = `(`; _.each(this._members, (member: DataType, i: number) => { - signature += member.getSignature(); + signature += member.getSignature(detailed); if (i < this._members.length - 1) { signature += ','; } 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 3ab823019..2278830eb 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/address.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/address.ts @@ -43,7 +43,7 @@ export class AddressDataType extends AbstractBlobDataType { return valueLowercase; } - public getSignature(): string { + public getSignatureType(): string { return SolidityTypes.Address; } /* tslint:enable prefer-function-over-method */ 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 7595cb667..8b71dc913 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/array.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/array.ts @@ -38,22 +38,30 @@ export class ArrayDataType extends AbstractSetDataType { this._arraySignature = this._computeSignature(); } - public getSignature(): string { - return this._arraySignature; + public getSignatureType(): string { + return this._computeSignature(false); } - private _computeSignature(): string { + public getSignature(detailed?: boolean): string { + if (_.isEmpty(this.getDataItem().name) || !detailed) return this.getSignatureType(); + const name = this.getDataItem().name; + const shortName = name.indexOf('.') > 0 ? name.substr(name.lastIndexOf('.') + 1) : name; + const detailedSignature = `${shortName} ${this._computeSignature(detailed)}`; + return detailedSignature; + } + + private _computeSignature(detailed?: boolean): string { // Compute signature for a single array element const elementDataItem: DataItem = { type: this._elementType, - name: 'N/A', + name: '', }; const elementComponents = this.getDataItem().components; if (!_.isUndefined(elementComponents)) { elementDataItem.components = elementComponents; } const elementDataType = this.getFactory().create(elementDataItem); - const elementSignature = elementDataType.getSignature(); + const elementSignature = elementDataType.getSignature(detailed); // Construct signature for array of type `element` if (_.isUndefined(this._arrayLength)) { return `${elementSignature}[]`; 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 d713d5a94..7f91f34e6 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/bool.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/bool.ts @@ -46,7 +46,7 @@ export class BoolDataType extends AbstractBlobDataType { return value; } - public getSignature(): string { + public getSignatureType(): string { return SolidityTypes.Bool; } /* tslint:enable prefer-function-over-method */ 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 5277efd6c..fa38b63c0 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 @@ -65,7 +65,7 @@ export class DynamicBytesDataType extends AbstractBlobDataType { return value; } - public getSignature(): string { + public getSignatureType(): string { return SolidityTypes.Bytes; } /* tslint:enable prefer-function-over-method */ 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 c9f734799..865a76545 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/int.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/int.ts @@ -56,7 +56,7 @@ export class IntDataType extends AbstractBlobDataType { return value; } - public getSignature(): string { + public getSignatureType(): string { return `${SolidityTypes.Int}${this._width}`; } } 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 bae0fdb5d..44456cd0a 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/method.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts @@ -57,7 +57,7 @@ export class MethodDataType extends AbstractSetDataType { return returnValue; } - public getSignature(): string { + public getSignatureType(): string { return this._methodSignature; } 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 389e75927..8c3afe0c3 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/pointer.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/pointer.ts @@ -11,7 +11,11 @@ export class PointerDataType extends AbstractPointerDataType { super(dataItem, dataTypeFactory, destDataType, parentDataType); } - public getSignature(): string { - return this._destination.getSignature(); + public getSignatureType(): string { + return this._destination.getSignature(false); + } + + public getSignature(detailed?: boolean): string { + return this._destination.getSignature(detailed); } } 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 2e371c505..cbf1957d7 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 @@ -36,7 +36,7 @@ export class StaticBytesDataType extends AbstractBlobDataType { this._width = StaticBytesDataType._decodeWidthFromType(dataItem.type); } - public getSignature(): string { + public getSignatureType(): string { // Note that `byte` reduces to `bytes1` return `${SolidityTypes.Bytes}${this._width}`; } 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 91a72ad3f..97ac46442 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/string.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/string.ts @@ -52,7 +52,7 @@ export class StringDataType extends AbstractBlobDataType { return value; } - public getSignature(): string { + public getSignatureType(): string { return SolidityTypes.String; } /* tslint:enable prefer-function-over-method */ 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 31593c882..587653f49 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/tuple.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/tuple.ts @@ -1,10 +1,11 @@ import { DataItem, SolidityTypes } from 'ethereum-types'; +import * as _ from 'lodash'; import { DataTypeFactory } from '../abstract_data_types/interfaces'; import { AbstractSetDataType } from '../abstract_data_types/types/set'; export class TupleDataType extends AbstractSetDataType { - private readonly _signature: string; + //private readonly _signature: string; public static matchType(type: string): boolean { return type === SolidityTypes.Tuple; @@ -15,10 +16,18 @@ export class TupleDataType extends AbstractSetDataType { if (!TupleDataType.matchType(dataItem.type)) { throw new Error(`Tried to instantiate Tuple with bad input: ${dataItem}`); } - this._signature = this._computeSignatureOfMembers(); + //this._signature = } - public getSignature(): string { - return this._signature; + public getSignatureType(): string { + return this._computeSignatureOfMembers(false); + } + + public getSignature(detailed?: boolean): string { + if (_.isEmpty(this.getDataItem().name) || !detailed) return this.getSignatureType(); + const name = this.getDataItem().name; + const shortName = name.indexOf('.') > 0 ? name.substr(name.lastIndexOf('.') + 1) : name; + const detailedSignature = `${shortName} ${this._computeSignatureOfMembers(detailed)}`; + return detailedSignature; } } 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 06cde4eea..86d2705f0 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/uint.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/uint.ts @@ -55,7 +55,7 @@ export class UIntDataType extends AbstractBlobDataType { return value; } - public getSignature(): string { + public getSignatureType(): string { return `${SolidityTypes.Uint}${this._width}`; } } diff --git a/packages/utils/src/abi_encoder/index.ts b/packages/utils/src/abi_encoder/index.ts index baf844ac6..23422dd8b 100644 --- a/packages/utils/src/abi_encoder/index.ts +++ b/packages/utils/src/abi_encoder/index.ts @@ -12,3 +12,4 @@ export { Tuple, UInt, } from './evm_data_type_factory'; +export { fromSignature } from './utils/signatureParser'; diff --git a/packages/utils/src/abi_encoder/utils/signatureParser.ts b/packages/utils/src/abi_encoder/utils/signatureParser.ts new file mode 100644 index 000000000..fe5127032 --- /dev/null +++ b/packages/utils/src/abi_encoder/utils/signatureParser.ts @@ -0,0 +1,154 @@ +import * as _ from 'lodash'; + +import { DataType } from '../abstract_data_types/data_type'; +import { DataItem } from 'ethereum-protocol'; +import { MethodAbi } from 'ethereum-types'; +import * as EvmDataTypes from '../evm_data_type_factory'; + +// Valid signatures: +// functionName(param1, param2, ...): (output1, output2, ...) +// functionName(param1, param2, ...) +// (param1, param2, ...) +/* +export function fromSignature(signature: string): DataType { + const maxSignatureIndex = signature.length - 1; + // Function name + const isFunction = signature.startsWith('function '); + // Output components + const outputComponentsBeginIndex = signature.indexOf(':'); + const outputComponentsEndIndex = outputComponentsBeginIndex >= 0 ? maxSignatureIndex : 0; + const hasOutputComponents = outputComponentsBeginIndex >= 0; + const outputComponentsSignature = hasOutputComponents ? signature.substring(outputComponentsBeginIndex, outputComponentsEndIndex + 1) : ""; + // Input components + const inputComponentsBeginIndex = signature.indexOf('('); + const inputComponentsEndIndex = hasOutputComponents ? outputComponentsBeginIndex : maxSignatureIndex; + const inputComponentsSignature = signature.substring(inputComponentsBeginIndex, inputComponentsEndIndex + 1); + // Function anme + const functionName = signature.substr(0, inputComponentsBeginIndex); + const isFunction = !_.isEmpty(functionName); + + console.log(`sig - ` + inputComponentsSignature); + // Create data type + let dataType: DataType; + if (isFunction) { + const methodAbi = { + type: 'function', + name: functionName, + inputs: generateDataItems(inputComponentsSignature), + outputs: !_.isEmpty(outputComponentsSignature) ? generateDataItems(outputComponentsSignature) : [], + } as MethodAbi; + dataType = new EvmDataTypes.Method(methodAbi); + } else if(hasOutputComponents) { + throw new Error(`Invalid signature: Contains outputs but no function name.`); + } else { + const inputDataItem = generateDataItem(inputComponentsSignature); + console.log(JSON.stringify(inputDataItem)); + dataType = EvmDataTypes.EvmDataTypeFactory.getInstance().create(inputDataItem); + } + return dataType; +}*/ + +export function fromSignature(signature: string): DataType { + const dataItems = generateDataItems(signature); + if (dataItems.length === 1) { + return EvmDataTypes.EvmDataTypeFactory.getInstance().create(dataItems[0]); + } + // this is a tuple + return EvmDataTypes.EvmDataTypeFactory.getInstance().create({ + name: '', + type: 'tuple', + components: dataItems + }); +} + +function generateDataItems(signature: string): DataItem[] { + let trimmedSignature = signature; + if (signature.startsWith('(')) { + if(!signature.endsWith(')')) { + throw new Error(`Failed to generate data item. Must end with ')'`); + } + trimmedSignature = signature.substr(1, signature.length - 2); + } + trimmedSignature += ','; + let currTokenIsArray = false; + let currTokenArrayModifier = ""; + let isParsingArrayModifier = false; + let currToken = ''; + let parenCount = 0; + let currTokenName = ''; + const dataItems: DataItem[] = []; + for(const char of trimmedSignature) { + // Tokenize the type string while keeping track of parentheses. + switch (char) { + case '(': + parenCount += 1; + currToken += char; + break; + case ')': + parenCount -= 1; + currToken += char; + break; + case '[': + if (parenCount === 0) { + isParsingArrayModifier = true; + currTokenIsArray = true; + currTokenArrayModifier += "["; + } else { + currToken += char; + } + break; + case ']': + if (parenCount === 0) { + isParsingArrayModifier = false; + currTokenArrayModifier += ']'; + } else { + currToken += char; + } + break; + case ' ': + if (parenCount === 0) { + currTokenName = currToken; + currToken = ""; + } else { + currToken += char; + } + break; + case ',': + if (parenCount === 0) { + //throw new Error(`Generating Data Items`); + const components = currToken.startsWith('(') ? generateDataItems(currToken) : []; + const isTuple = !_.isEmpty(components); + const isArray = currTokenIsArray; + let dataItem: DataItem = {name: currTokenName, type: ''}; + if (isTuple) { + dataItem.type = 'tuple'; + dataItem.components = components; + } else { + dataItem.type = currToken; + } + if (isArray) { + dataItem.type += currTokenArrayModifier; + } + + dataItems.push(dataItem); + + currTokenName = ''; + currToken = ''; + currTokenIsArray = false; + currTokenArrayModifier = ""; + break; + } else { + currToken += char; + break; + } + default: + if (isParsingArrayModifier) { + currTokenArrayModifier += char; + } else { + currToken += char; + } + break; + } + } + return dataItems; +}
\ No newline at end of file |