diff options
-rw-r--r-- | packages/utils/src/abi_encoder/calldata.ts | 12 | ||||
-rw-r--r-- | packages/utils/src/abi_encoder/data_type.ts | 2 | ||||
-rw-r--r-- | packages/utils/src/abi_encoder/evm_data_types.ts | 32 | ||||
-rw-r--r-- | packages/utils/test/abi_encoder_test.ts | 29 | ||||
-rw-r--r-- | packages/utils/test/abi_samples.ts | 34 |
5 files changed, 102 insertions, 7 deletions
diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts index 32278e5c5..078767c22 100644 --- a/packages/utils/src/abi_encoder/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata.ts @@ -456,13 +456,19 @@ export class RawCalldata { private selector: string; private scopes: Queue<number>; - constructor(value: string | Buffer) { + constructor(value: string | Buffer, hasSelectorPrefix: boolean = true) { if (typeof value === 'string' && !value.startsWith('0x')) { throw new Error(`Expected raw calldata to start with '0x'`); } const valueBuf = ethUtil.toBuffer(value); - this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4)); - this.value = valueBuf.slice(4); // disregard selector + if (hasSelectorPrefix) { + this.selector = ethUtil.bufferToHex(valueBuf.slice(0, 4)); + this.value = valueBuf.slice(4); // disregard selector + } else { + this.selector = '0x'; + this.value = valueBuf; + } + this.offset = 0; this.scopes = new Queue<number>(); this.scopes.push(0); diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts index 3b4028abd..f5a8087ea 100644 --- a/packages/utils/src/abi_encoder/data_type.ts +++ b/packages/utils/src/abi_encoder/data_type.ts @@ -6,7 +6,7 @@ import ethUtil = require('ethereumjs-util'); var _ = require('lodash'); export interface DataTypeFactory { - create: (dataItem: DataItem, parentDataType: DataType) => DataType; + create: (dataItem: DataItem, parentDataType?: DataType) => DataType; mapDataItemToDataType: (dataItem: DataItem) => DataType; } diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts index 2973596fe..d024a9bfa 100644 --- a/packages/utils/src/abi_encoder/evm_data_types.ts +++ b/packages/utils/src/abi_encoder/evm_data_types.ts @@ -106,7 +106,8 @@ abstract class Number extends PayloadDataType { } } - public encodeValue(value: BigNumber): Buffer { + public encodeValue(value_: BigNumber | string | number): Buffer { + const value = new BigNumber(value_, 10); if (value.greaterThan(this.getMaxValue())) { throw `tried to assign value of ${value}, which exceeds max value of ${this.getMaxValue()}`; } else if (value.lessThan(this.getMinValue())) { @@ -465,6 +466,7 @@ export class SolArray extends MemberDataType { export class Method extends MemberDataType { private methodSignature: string; private methodSelector: string; + private returnDataTypes: DataType[]; // TMP public selector: string; @@ -473,7 +475,11 @@ export class Method extends MemberDataType { super({ type: 'method', name: abi.name, components: abi.inputs }, EvmDataTypeFactory.getInstance()); this.methodSignature = this.computeSignature(); this.selector = this.methodSelector = this.computeSelector(); - + this.returnDataTypes = []; + const dummy = new Byte({ type: 'byte', name: 'DUMMY' }); // @TODO TMP + _.each(abi.outputs, (dataItem: DataItem) => { + this.returnDataTypes.push(this.getFactory().create(dataItem, dummy)); + }); } private computeSignature(): string { @@ -501,6 +507,23 @@ export class Method extends MemberDataType { return value; } + public decodeReturnValues(returndata: string, rules?: DecodingRules): any { + //console.log('O'.repeat(100), '\n', returndata, '\n', this.returnDataTypes, 'P'.repeat(100)); + + const returnValues: any[] = []; + const rules_ = rules ? rules : { structsAsObjects: false } as DecodingRules; + const rawReturnData = new RawCalldata(returndata, false); + _.each(this.returnDataTypes, (dataType: DataType) => { + returnValues.push(dataType.generateValue(rawReturnData, rules_)); + }); + + //console.log('*'.repeat(40), '\n', JSON.stringify(returnValues), '\n', '*'.repeat(100)); + /*if (returnValues.length === 1) { + return returnValues[0]; + }*/ + return returnValues; + } + public getSignature(): string { return this.methodSignature; } @@ -538,12 +561,15 @@ export class EvmDataTypeFactory implements DataTypeFactory { throw new Error(`Unrecognized data type: '${dataItem.type}'`); } - public create(dataItem: DataItem, parentDataType: DataType): DataType { + public create(dataItem: DataItem, parentDataType?: DataType): DataType { const dataType = this.mapDataItemToDataType(dataItem); if (dataType.isStatic()) { return dataType; } + if (parentDataType === undefined) { // @Todo -- will this work for return values? + throw new Error(`Trying to create a pointer`); + } const pointer = new Pointer(dataType, parentDataType); return pointer; } diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts index 8d78b61b5..8add41af6 100644 --- a/packages/utils/test/abi_encoder_test.ts +++ b/packages/utils/test/abi_encoder_test.ts @@ -15,6 +15,35 @@ describe.only('ABI Encoder', () => { describe.only('ABI Tests at Method Level', () => { + it.only('Should reuse duplicated strings in string array', async () => { + const method = new AbiEncoder.Method(AbiSamples.GAbi); + + const args = [ + { + a: new BigNumber(5), + e: '0x616161', + b: 'aaa', + f: '0xe41d2489571d322189246dafa5ebde1f4699f498' + } + ] + + // Verify optimized calldata is expected + const optimizedCalldata = method.encode(args, { optimize: true }); + //const expectedOptimizedCalldata = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000'; + //expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + + // Verify args decode properly + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + //expect(decodedArgsJson).to.be.equal(argsJson); + + console.log(method.getSignature()); + console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true, annotate: true }), '\n', '*'.repeat(100)); + console.log('*'.repeat(100), '\n', method.encode(args, { optimize: true }), '\n', '*'.repeat(100)); + + }); + it('Should reuse duplicated strings in string array', async () => { const method = new AbiEncoder.Method(AbiSamples.stringAbi); const strings = [ diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts index 5e8268f1a..aa38711cd 100644 --- a/packages/utils/test/abi_samples.ts +++ b/packages/utils/test/abi_samples.ts @@ -34,6 +34,40 @@ export const stringAbi = { type: 'function', } as MethodAbi; + +export const GAbi = { + constant: false, + inputs: [ + { + components: [{ + name: 'a', + type: 'uint256', + }, + { + name: 'b', + type: 'string', + }, + { + name: 'e', + type: 'bytes', + }, + { + name: 'f', + type: 'address', + }], + + name: 'f', + type: 'tuple', + + } + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + export const optimizerAbi2 = { constant: false, inputs: [ |