diff options
-rw-r--r-- | packages/utils/src/abi_encoder/calldata.ts | 15 | ||||
-rw-r--r-- | packages/utils/src/abi_encoder/data_type.ts | 2 | ||||
-rw-r--r-- | packages/utils/src/abi_encoder/evm_data_types.ts | 13 | ||||
-rw-r--r-- | packages/utils/test/abi_encoder_test.ts | 52 |
4 files changed, 66 insertions, 16 deletions
diff --git a/packages/utils/src/abi_encoder/calldata.ts b/packages/utils/src/abi_encoder/calldata.ts index 078767c22..11288064e 100644 --- a/packages/utils/src/abi_encoder/calldata.ts +++ b/packages/utils/src/abi_encoder/calldata.ts @@ -248,7 +248,7 @@ export class Calldata { private selector: string; private rules: EncodingRules; private sizeInBytes: number; - private root: MemberCalldataBlock | undefined; + private root: CalldataBlock | undefined; constructor(rules: EncodingRules) { this.selector = ''; @@ -257,8 +257,17 @@ export class Calldata { this.root = undefined; } - private createQueue(memberBlock: MemberCalldataBlock): Queue<CalldataBlock> { + private createQueue(block: CalldataBlock): Queue<CalldataBlock> { const blockQueue = new Queue<CalldataBlock>(); + + // Base Case + if (block instanceof MemberCalldataBlock === false) { + blockQueue.push(block); + return blockQueue; + } + + // This is a Member Block + const memberBlock = block as MemberCalldataBlock; _.eachRight(memberBlock.getMembers(), (member: CalldataBlock) => { if (member instanceof MemberCalldataBlock) { blockQueue.mergeFront(this.createQueue(member)); @@ -429,7 +438,7 @@ export class Calldata { return ""; } - public setRoot(block: MemberCalldataBlock) { + public setRoot(block: CalldataBlock) { this.root = block; this.sizeInBytes += block.getSizeInBytes(); } diff --git a/packages/utils/src/abi_encoder/data_type.ts b/packages/utils/src/abi_encoder/data_type.ts index 022f5621f..0f3cecac5 100644 --- a/packages/utils/src/abi_encoder/data_type.ts +++ b/packages/utils/src/abi_encoder/data_type.ts @@ -35,7 +35,7 @@ export abstract class DataType { const calldata = new Calldata(rules_); if (selector) calldata.setSelector(selector); const block = this.generateCalldataBlock(value); - calldata.setRoot(block as MemberCalldataBlock); // @TODO CHANGE + calldata.setRoot(block); // @TODO CHANGE const calldataHex = calldata.toHexString(); return calldataHex; } diff --git a/packages/utils/src/abi_encoder/evm_data_types.ts b/packages/utils/src/abi_encoder/evm_data_types.ts index bfb2808da..1ee95863b 100644 --- a/packages/utils/src/abi_encoder/evm_data_types.ts +++ b/packages/utils/src/abi_encoder/evm_data_types.ts @@ -20,6 +20,8 @@ export interface DataTypeStaticInterface { export class Address extends PayloadDataType { private static SIZE_KNOWN_AT_COMPILE_TIME: boolean = true; + 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"; constructor(dataItem: DataItem) { super(dataItem, EvmDataTypeFactory.getInstance(), Address.SIZE_KNOWN_AT_COMPILE_TIME); @@ -36,9 +38,16 @@ export class Address extends PayloadDataType { return type === 'address'; } - public encodeValue(value: boolean): Buffer { + public encodeValue(value: string): Buffer { + if (value.startsWith('0x') === false) { + throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X); + } + const valueAsBuffer = ethUtil.toBuffer(value); + if (valueAsBuffer.byteLength !== 20) { + throw new Error(Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES); + } const evmWordWidth = 32; - const encodedValueBuf = ethUtil.setLengthLeft(ethUtil.toBuffer(value), evmWordWidth); + const encodedValueBuf = ethUtil.setLengthLeft(valueAsBuffer, evmWordWidth); return encodedValueBuf; } diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts index cf1f0327a..5b341545e 100644 --- a/packages/utils/test/abi_encoder_test.ts +++ b/packages/utils/test/abi_encoder_test.ts @@ -725,7 +725,7 @@ describe.only('ABI Encoder', () => { }); }); - describe('Array', () => { + describe.only('Array', () => { it('Fixed size; Static elements', async () => { // Create DataType object const testDataItem = { name: 'testArray', type: 'int[2]' }; @@ -793,6 +793,9 @@ describe.only('ABI Encoder', () => { const argsAsJson = JSON.stringify(args); expect(decodedArgsAsJson).to.be.equal(argsAsJson); }); + + // @TODO: Add test that fails if we pass in the wrong number of elements + // @TODO: Add test that fails if we pass in an element of incorrecrt type }); describe.only('Tuple', () => { @@ -849,22 +852,51 @@ describe.only('ABI Encoder', () => { const argsAsJson = JSON.stringify(args); expect(decodedArgsAsJson).to.be.equal(argsAsJson); }); + + // @TODO: Add test that fails if we pass in the wrong number of elements + // @TODO: Add test that fails if we pass in arguments in wrong order }); - /* - describe('Address', () => { - const testAddressDataItem = { name: 'testAddress', type: 'address' }; + describe.only('Address', () => { it('Valid Address', async () => { - const addressDataType = new AbiEncoder.Address(testAddressDataItem); - addressDataType.assignValue('0xe41d2489571d322189246dafa5ebde1f4699f498'); - const expectedAbiEncodedAddress = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498'; + // Create DataType object + const testDataItem = { name: 'Address', type: 'address' }; + const dataType = new AbiEncoder.Address(testDataItem); + // Construct args to be encoded + const args = '0xe41d2489571d322189246dafa5ebde1f4699f498'; + // Encode Args and validate result + const encodedArgs = dataType.encode(args); + const expectedEncodedArgs = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498'; + expect(encodedArgs).to.be.equal(expectedEncodedArgs); + // Decode Encoded Args and validate result + const decodedArgs = dataType.decode(encodedArgs); + const decodedArgsAsJson = JSON.stringify(decodedArgs); + const argsAsJson = JSON.stringify(args); + expect(decodedArgsAsJson).to.be.equal(argsAsJson); + }); - console.log(addressDataType.getHexValue()); - console.log(expectedAbiEncodedAddress); - expect(addressDataType.getHexValue()).to.be.equal(expectedAbiEncodedAddress); + it('Invalid Address - input is not valid hex', async () => { + // Create DataType object + const testDataItem = { name: 'Address', type: 'address' }; + const dataType = new AbiEncoder.Address(testDataItem); + // Construct args to be encoded + const args = 'e4'; + // Encode Args and validate result + expect(() => { dataType.encode(args) }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_START_WITH_0X); + }); + + it('Invalid Address - input is not 20 bytes', async () => { + // Create DataType object + const testDataItem = { name: 'Address', type: 'address' }; + const dataType = new AbiEncoder.Address(testDataItem); + // Construct args to be encoded + const args = '0xe4'; + // Encode Args and validate result + expect(() => { dataType.encode(args) }).to.throw(AbiEncoder.Address.ERROR_MESSAGE_ADDRESS_MUST_BE_20_BYTES); }); }); + /* describe('Bool', () => { const testBoolDataItem = { name: 'testBool', type: 'bool' }; it('True', async () => { |