diff options
-rw-r--r-- | packages/utils/src/abi_encoder/calldata.ts | 33 | ||||
-rw-r--r-- | packages/utils/src/abi_encoder/constants.ts | 2 | ||||
-rw-r--r-- | packages/utils/src/abi_encoder/data_type.ts | 19 | ||||
-rw-r--r-- | packages/utils/src/abi_encoder/evm_data_types.ts | 4 | ||||
-rw-r--r-- | packages/utils/test/abi_encoder_test.ts | 4 | ||||
-rw-r--r-- | packages/utils/test/optimizer_abis.ts | 339 | ||||
-rw-r--r-- | packages/utils/test/return_value_abis.ts | 98 |
7 files changed, 463 insertions, 36 deletions
diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts index 9f91f8495..0c45d6198 100644 --- a/packages/utils/src/abi_encoder/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata.ts @@ -90,12 +90,7 @@ export abstract class CalldataBlock { export class PayloadCalldataBlock extends CalldataBlock { private readonly _payload: Buffer; - constructor( - name: string, - signature: string, - parentName: string, - payload: Buffer, - ) { + constructor(name: string, signature: string, parentName: string, payload: Buffer) { const headerSizeInBytes = 0; const bodySizeInBytes = payload.byteLength; super(name, signature, parentName, headerSizeInBytes, bodySizeInBytes); @@ -120,13 +115,7 @@ export class DependentCalldataBlock extends CalldataBlock { private readonly _dependency: CalldataBlock; private _aliasFor: CalldataBlock | undefined; - constructor( - name: string, - signature: string, - parentName: string, - dependency: CalldataBlock, - parent: CalldataBlock, - ) { + 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); @@ -408,7 +397,13 @@ export class Calldata { line = `\n${offsetStr}${value}${nameStr}`; } else { offsetStr = `0x${offset.toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); - value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES))).padEnd(valuePadding); + value = ethUtil + .stripHexPrefix( + ethUtil.bufferToHex( + block.toBuffer().slice(evmWordStartIndex, Constants.EVM_WORD_WIDTH_IN_BYTES), + ), + ) + .padEnd(valuePadding); if (block instanceof MemberCalldataBlock) { nameStr = `### ${prettyName.padEnd(namePadding)}`; line = `\n${offsetStr}${value}${nameStr}`; @@ -420,7 +415,11 @@ export class Calldata { for (let j = Constants.EVM_WORD_WIDTH_IN_BYTES; j < size; j += Constants.EVM_WORD_WIDTH_IN_BYTES) { offsetStr = `0x${(offset + j).toString(Constants.HEX_BASE)}`.padEnd(offsetPadding); - value = ethUtil.stripHexPrefix(ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES))).padEnd(valuePadding); + value = ethUtil + .stripHexPrefix( + ethUtil.bufferToHex(block.toBuffer().slice(j, j + Constants.EVM_WORD_WIDTH_IN_BYTES)), + ) + .padEnd(valuePadding); nameStr = ' '.repeat(namePadding); line = `${line}\n${offsetStr}${value}${nameStr}`; } @@ -465,7 +464,9 @@ export class RawCalldata { } 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._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'; diff --git a/packages/utils/src/abi_encoder/constants.ts b/packages/utils/src/abi_encoder/constants.ts index b52630d74..bc5b985e0 100644 --- a/packages/utils/src/abi_encoder/constants.ts +++ b/packages/utils/src/abi_encoder/constants.ts @@ -3,4 +3,4 @@ export const HEX_BASE = 16; export const BIN_BASE = 2; export const HEX_SELECTOR_LENGTH_IN_CHARS = 10; export const HEX_SELECTOR_LENGTH_IN_BYTES = 4; -export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0;
\ No newline at end of file +export const HEX_SELECTOR_BYTE_OFFSET_IN_CALLDATA = 0; diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts index 926023468..4370cb253 100644 --- a/packages/utils/src/abi_encoder/data_type.ts +++ b/packages/utils/src/abi_encoder/data_type.ts @@ -74,12 +74,7 @@ export abstract class PayloadDataType extends DataType { const signature = this.getSignature(); const parentName = parentBlock === undefined ? '' : parentBlock.getName(); const relocatable = false; - const block = new PayloadCalldataBlock( - name, - signature, - parentName, - encodedValue, - ); + const block = new PayloadCalldataBlock(name, signature, parentName, encodedValue); return block; } @@ -115,13 +110,7 @@ export abstract class DependentDataType extends DataType { const name = this.getDataItem().name; const signature = this.getSignature(); const parentName = parentBlock === undefined ? '' : parentBlock.getName(); - const block = new DependentCalldataBlock( - name, - signature, - parentName, - dependencyBlock, - parentBlock, - ); + const block = new DependentCalldataBlock(name, signature, parentName, dependencyBlock, parentBlock); return block; } @@ -232,7 +221,7 @@ export abstract class MemberDataType extends DataType { const methodBlock: MemberCalldataBlock = new MemberCalldataBlock( this.getDataItem().name, this.getSignature(), - parentName + parentName, ); let members = this.members; @@ -257,7 +246,7 @@ export abstract class MemberDataType extends DataType { const methodBlock: MemberCalldataBlock = new MemberCalldataBlock( this.getDataItem().name, this.getSignature(), - parentName + parentName, ); const memberBlocks: CalldataBlock[] = []; let childMap = _.cloneDeep(this.memberMap); diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts index b862e9396..76837361e 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) { @@ -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) { diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts index 0220984b0..c7986fa00 100644 --- a/packages/utils/test/abi_encoder_test.ts +++ b/packages/utils/test/abi_encoder_test.ts @@ -102,7 +102,7 @@ describe.only('ABI Encoder', () => { it('Duplicate Dynamic Arrays with Dynamic Elements', async () => { // Generate calldata const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithDynamicElements); - const array1 = ["Hello", "World"]; + const array1 = ['Hello', 'World']; const array2 = array1; const args = [array1, array2]; // Validata calldata @@ -138,7 +138,7 @@ describe.only('ABI Encoder', () => { it('Duplicate Static Arrays with Dynamic Elements', async () => { // Generate calldata const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithDynamicElements); - const array1 = ["Hello", "World"]; + const array1 = ['Hello', 'World']; const array2 = array1; const args = [array1, array2]; // Validata calldata diff --git a/packages/utils/test/optimizer_abis.ts b/packages/utils/test/optimizer_abis.ts new file mode 100644 index 000000000..ea562e5b5 --- /dev/null +++ b/packages/utils/test/optimizer_abis.ts @@ -0,0 +1,339 @@ +import { MethodAbi } from 'ethereum-types'; + +export const duplicateDynamicArraysWithStaticElements = { + constant: false, + inputs: [ + { + name: 'array1', + type: 'uint[]', + }, + { + name: 'array2', + type: 'uint[]', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateDynamicArraysWithDynamicElements = { + constant: false, + inputs: [ + { + name: 'array1', + type: 'string[]', + }, + { + name: 'array2', + type: 'string[]', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateStaticArraysWithStaticElements = { + constant: false, + inputs: [ + { + name: 'array1', + type: 'uint[2]', + }, + { + name: 'array2', + type: 'uint[2]', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateStaticArraysWithDynamicElements = { + constant: false, + inputs: [ + { + name: 'array1', + type: 'string[2]', + }, + { + name: 'array2', + type: 'string[2]', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateArrayElements = { + constant: false, + inputs: [ + { + name: 'array', + type: 'string[]', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateTupleFields = { + constant: false, + inputs: [ + { + components: [ + { + name: 'field1', + type: 'string', + }, + { + name: 'field2', + type: 'string', + }, + ], + name: 'Tuple', + type: 'tuple', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateStrings = { + constant: false, + inputs: [ + { + name: 'string1', + type: 'string', + }, + { + name: 'string2', + type: 'string', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateBytes = { + constant: false, + inputs: [ + { + name: 'bytes1', + type: 'bytes', + }, + { + name: 'bytes2', + type: 'bytes', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateTuples = { + constant: false, + inputs: [ + { + components: [ + { + name: 'field1', + type: 'string', + }, + { + name: 'field2', + type: 'uint', + }, + ], + name: 'Tuple', + type: 'tuple', + }, + { + components: [ + { + name: 'field1', + type: 'string', + }, + { + name: 'field2', + type: 'uint', + }, + ], + name: 'Tuple', + type: 'tuple', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateArraysNestedInTuples = { + constant: false, + inputs: [ + { + components: [ + { + name: 'field', + type: 'uint[]', + }, + ], + name: 'Tuple1', + type: 'tuple', + }, + { + components: [ + { + name: 'field', + type: 'uint[]', + }, + { + name: 'extraField', + type: 'string', + }, + ], + name: 'Tuple2', + type: 'tuple', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateTuplesNestedInTuples = { + constant: false, + inputs: [ + { + components: [ + { + components: [ + { + name: 'nestedField', + type: 'string', + }, + ], + name: 'field', + type: 'tuple', + }, + ], + name: 'Tuple1', + type: 'tuple', + }, + { + components: [ + { + components: [ + { + name: 'nestedField', + type: 'string', + }, + ], + name: 'field', + type: 'tuple', + }, + { + name: 'extraField', + type: 'string', + }, + ], + name: 'Tuple1', + type: 'tuple', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const duplicateTwoDimensionalArrays = { + constant: false, + inputs: [ + { + name: 'array1', + type: 'string[][]', + }, + { + name: 'array2', + type: 'string[][]', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const arrayElementsDuplicatedAsSeparateParameter = { + constant: false, + inputs: [ + { + name: 'stringArray', + type: 'string[]', + }, + { + name: 'string', + type: 'string', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const arrayElementsDuplicatedAsTupleFields = { + constant: false, + inputs: [ + { + name: 'uint8Array', + type: 'uint8[]', + }, + { + components: [ + { + name: 'uint', + type: 'uint', + }, + ], + name: 'uintTuple', + type: 'tuple[]', + }, + ], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; diff --git a/packages/utils/test/return_value_abis.ts b/packages/utils/test/return_value_abis.ts new file mode 100644 index 000000000..847559dac --- /dev/null +++ b/packages/utils/test/return_value_abis.ts @@ -0,0 +1,98 @@ +import { MethodAbi } from 'ethereum-types'; + +export const noReturnValues = { + constant: false, + inputs: [], + name: 'simpleFunction', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const singleStaticReturnValue = { + constant: false, + inputs: [], + name: 'simpleFunction', + outputs: [ + { + name: 'Bytes4', + type: 'bytes4', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const multipleStaticReturnValues = { + constant: false, + inputs: [], + name: 'simpleFunction', + outputs: [ + { + name: 'val1', + type: 'bytes4', + }, + { + name: 'val2', + type: 'bytes4', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const singleDynamicReturnValue = { + constant: false, + inputs: [], + name: 'simpleFunction', + outputs: [ + { + name: 'val', + type: 'bytes', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const multipleDynamicReturnValues = { + constant: false, + inputs: [], + name: 'simpleFunction', + outputs: [ + { + name: 'val1', + type: 'bytes', + }, + { + name: 'val2', + type: 'bytes', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; + +export const mixedStaticAndDynamicReturnValues = { + constant: false, + inputs: [], + name: 'simpleFunction', + outputs: [ + { + name: 'val1', + type: 'bytes4', + }, + { + name: 'val2', + type: 'bytes', + }, + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function', +} as MethodAbi; |