From 34236f9e3ba4e79c0fab0265cf31e4365852ba2f Mon Sep 17 00:00:00 2001 From: Louis Aussedat Date: Mon, 16 Dec 2024 11:16:38 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20(context-module):=20Iterate=20on?= =?UTF-8?q?=20transaction=20calldata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/HttpTransactionDataSource.test.ts | 66 +++++++++-- .../data/HttpTransactionDataSource.ts | 111 +++++++++--------- 2 files changed, 109 insertions(+), 68 deletions(-) diff --git a/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.test.ts b/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.test.ts index 20acdf5bb..83fc5bd68 100644 --- a/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.test.ts +++ b/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.test.ts @@ -302,7 +302,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: No generic descriptor for contract 0x0abc", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x0abc and selector 0x01ff", ), ), ); @@ -471,6 +471,50 @@ describe("HttpTransactionDataSource", () => { ]); }); + it("Calldata on third array element", async () => { + // GIVEN + const calldataDTO = createCalldata( + transactionInfo, + [], + [fieldAmount, fieldDatetime, fieldUnit, fieldDuration], + ); + jest + .spyOn(axios, "request") + .mockResolvedValue({ data: [{}, {}, calldataDTO] }); + + // WHEN + const result = await datasource.getTransactionDescriptors({ + chainId: 1, + address: "0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9", + selector: "0x69328dec", + }); + + // THEN + expect(result.extract()).toEqual([ + { + payload: + "0001000108000000000000000102147d2768de32b0b80b7a3454c06bdac94a69ddc7a9030469328dec04207d5e9ed0004b8035b164edd9d78c37415ad6b1d123be4943d0abd5a50035cae3050857697468647261770604416176650708416176652044414f081068747470733a2f2f616176652e636f6d0a045fc4ba9c81ff473045022100eb67599abfd9c7360b07599a2a2cb769c6e3f0f74e1e52444d788c8f577a16d20220402e92b0adbf97d890fa2f9654bc30c7bd70dacabe870f160e6842d9eb73d36f", + type: "transactionInfo", + }, + { + type: "transactionFieldDescription", + payload: fieldAmount.descriptor, + }, + { + type: "transactionFieldDescription", + payload: fieldDatetime.descriptor, + }, + { + type: "transactionFieldDescription", + payload: fieldUnit.descriptor, + }, + { + type: "transactionFieldDescription", + payload: fieldDuration.descriptor, + }, + ]); + }); + it("Calldata without fields references and transaction info signature length % 2 different from 0", async () => { // GIVEN const newTransactionInfo: CalldataTransactionInfoV1 = { @@ -549,7 +593,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -582,7 +626,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -608,7 +652,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -634,7 +678,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -669,7 +713,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -695,7 +739,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -728,7 +772,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -761,7 +805,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -800,7 +844,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); @@ -833,7 +877,7 @@ describe("HttpTransactionDataSource", () => { expect(result).toEqual( Left( new Error( - "[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", + "[ContextModule] HttpTransactionDataSource: Invalid response for contract 0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9 and selector 0x69328dec", ), ), ); diff --git a/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.ts b/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.ts index 290e9047f..de2c6dbcb 100644 --- a/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.ts +++ b/packages/signer/context-module/src/transaction/data/HttpTransactionDataSource.ts @@ -47,7 +47,7 @@ export class HttpTransactionDataSource implements TransactionDataSource { }: GetTransactionDescriptorsParams): Promise< Either > { - let calldata: CalldataDto | undefined; + let dto: CalldataDto[] | undefined; try { const response = await axios.request({ method: "GET", @@ -62,7 +62,7 @@ export class HttpTransactionDataSource implements TransactionDataSource { "X-Ledger-Client-Version": `context-module/${PACKAGE.version}`, }, }); - calldata = response.data?.[0]; + dto = response.data; } catch (error) { return Left( new Error( @@ -71,21 +71,7 @@ export class HttpTransactionDataSource implements TransactionDataSource { ); } - if (!calldata) { - return Left( - new Error( - `[ContextModule] HttpTransactionDataSource: No generic descriptor for contract ${address}`, - ), - ); - } - - // Normalize the address and selector - address = address.toLowerCase(); - selector = `0x${selector.slice(2).toLowerCase()}`; - - const calldataDescriptor = - calldata.descriptors_calldata?.[address]?.[selector]; - if (!calldataDescriptor) { + if (!Array.isArray(dto)) { return Left( new Error( `[ContextModule] HttpTransactionDataSource: Invalid response for contract ${address} and selector ${selector}`, @@ -93,51 +79,62 @@ export class HttpTransactionDataSource implements TransactionDataSource { ); } - if ( - !this.isCalldataDescriptorV1(calldataDescriptor, this.config.cal.mode) - ) { - return Left( - new Error( - `[ContextModule] HttpTransactionDataSource: Failed to decode transaction descriptor for contract ${address} and selector ${selector}`, - ), - ); - } + for (const calldata of dto) { + // Normalize the address and selector + address = address.toLowerCase(); + selector = `0x${selector.slice(2).toLowerCase()}`; + const calldataDescriptor = + calldata.descriptors_calldata?.[address]?.[selector]; - const infoData = calldataDescriptor.transaction_info.descriptor.data; - const infoSignature = - calldataDescriptor.transaction_info.descriptor.signatures[ - this.config.cal.mode - ]; - const info: ClearSignContextSuccess = { - type: ClearSignContextType.TRANSACTION_INFO, - payload: this.formatTransactionInfo(infoData, infoSignature), - }; - const enums: ClearSignContextSuccess[] = []; - for (const [id, values] of Object.entries(calldataDescriptor.enums)) { - for (const [ - value, - { data, signatures }, - ] of Object.entries(values)) { - enums.push({ - type: ClearSignContextType.ENUM, - id: Number(id), - value: Number(value), - payload: this.formatTransactionInfo( - data, - signatures[this.config.cal.mode]!, // the enum is validated by isCalldataDescriptorV1 - ), - }); + if ( + !calldataDescriptor || + !this.isCalldataDescriptorV1(calldataDescriptor, this.config.cal.mode) + ) { + continue; } + + const infoData = calldataDescriptor.transaction_info.descriptor.data; + const infoSignature = + calldataDescriptor.transaction_info.descriptor.signatures[ + this.config.cal.mode + ]; + const info: ClearSignContextSuccess = { + type: ClearSignContextType.TRANSACTION_INFO, + payload: this.formatTransactionInfo(infoData, infoSignature), + }; + const enums: ClearSignContextSuccess[] = []; + for (const [id, values] of Object.entries(calldataDescriptor.enums)) { + for (const [ + value, + { data, signatures }, + ] of Object.entries(values)) { + enums.push({ + type: ClearSignContextType.ENUM, + id: Number(id), + value: Number(value), + payload: this.formatTransactionInfo( + data, + signatures[this.config.cal.mode]!, // the enum is validated by isCalldataDescriptorV1 + ), + }); + } + } + + const fields: ClearSignContextSuccess[] = calldataDescriptor.fields.map( + (field) => ({ + type: ClearSignContextType.TRANSACTION_FIELD_DESCRIPTION, + payload: field.descriptor, + reference: this.getReference(field.param), + }), + ); + return Right([info, ...enums, ...fields]); } - const fields: ClearSignContextSuccess[] = calldataDescriptor.fields.map( - (field) => ({ - type: ClearSignContextType.TRANSACTION_FIELD_DESCRIPTION, - payload: field.descriptor, - reference: this.getReference(field.param), - }), + return Left( + new Error( + `[ContextModule] HttpTransactionDataSource: Invalid response for contract ${address} and selector ${selector}`, + ), ); - return Right([info, ...enums, ...fields]); } private formatTransactionInfo(