From 32aac233197ceb289553268d54719cdb5df8ad89 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Wed, 23 Jul 2025 09:06:47 +0100 Subject: [PATCH 1/3] Ensure that undecodable logs no longer throw --- .../transaction-response/getAllDecodedLogs.ts | 13 +++- .../transaction-response/getDecodedLogs.ts | 11 ++- .../src/providers/utils/extract-tx-error.ts | 6 +- .../fuel-gauge/src/advanced-logging.test.ts | 69 ++++++++++++++++++- 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts b/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts index c8728c10a9d..64c274e769a 100644 --- a/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts +++ b/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts @@ -65,10 +65,17 @@ export function getAllDecodedLogs(opts: { ? new BigNumberCoder('u64').encode(receipt.ra) : receipt.data; - const [decodedLog] = interfaceToUse.decodeLog(data, receipt.rb.toString()); - logs.push(decodedLog); + let logEntry: unknown; + + try { + [logEntry] = interfaceToUse.decodeLog(data, receipt.rb.toString()); + } catch (error) { + logEntry = { __decoded: false, data, logId: receipt.rb.toString() } + } + + logs.push(logEntry as T); // eslint-disable-next-line no-param-reassign - groupedLogs[receipt.id] = [...(groupedLogs[receipt.id] || []), decodedLog]; + groupedLogs[receipt.id] = [...(groupedLogs[receipt.id] || []), logEntry as T]; } } diff --git a/packages/account/src/providers/transaction-response/getDecodedLogs.ts b/packages/account/src/providers/transaction-response/getDecodedLogs.ts index 8f710a71e47..2acb0c55015 100644 --- a/packages/account/src/providers/transaction-response/getDecodedLogs.ts +++ b/packages/account/src/providers/transaction-response/getDecodedLogs.ts @@ -57,8 +57,15 @@ export function getDecodedLogs( ? new BigNumberCoder('u64').encode(receipt.ra) : receipt.data; - const [decodedLog] = interfaceToUse.decodeLog(data, receipt.rb.toString()); - logs.push(decodedLog); + let logEntry: unknown; + + try { + [logEntry] = interfaceToUse.decodeLog(data, receipt.rb.toString()); + } catch (error) { + logEntry = { __decoded: false, data, logId: receipt.rb.toString() } + } + + logs.push(logEntry as T); } } diff --git a/packages/account/src/providers/utils/extract-tx-error.ts b/packages/account/src/providers/utils/extract-tx-error.ts index a6cb5723e63..e6131bc9221 100644 --- a/packages/account/src/providers/utils/extract-tx-error.ts +++ b/packages/account/src/providers/utils/extract-tx-error.ts @@ -222,5 +222,9 @@ export const extractTxError = (params: IExtractTxError): FuelError => { if (isPanic) { return assemblePanicError(statusReason, metadata); } - return assembleRevertError(receipts, logs, metadata, statusReason, abis); + const decodedLogs = logs.filter((l: unknown) => { + const log = l as unknown as { __decoded: boolean }; + return !(typeof log === 'object' && '__decoded' in log && log.__decoded === false); + }); + return assembleRevertError(receipts, decodedLogs, metadata, statusReason, abis); }; diff --git a/packages/fuel-gauge/src/advanced-logging.test.ts b/packages/fuel-gauge/src/advanced-logging.test.ts index c5390bbf67e..5f81842d3bd 100644 --- a/packages/fuel-gauge/src/advanced-logging.test.ts +++ b/packages/fuel-gauge/src/advanced-logging.test.ts @@ -1,6 +1,6 @@ import type { FuelError } from '@fuel-ts/errors'; -import { bn, ZeroBytes32 } from 'fuels'; -import { launchTestNode } from 'fuels/test-utils'; +import { bn, Contract, ErrorCode, type JsonAbi, ZeroBytes32 } from 'fuels'; +import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils'; import { AdvancedLoggingOtherContractFactory, @@ -8,6 +8,7 @@ import { CallTestContractFactory, ConfigurableContractFactory, CoverageContractFactory, + AbiContractFactory, } from '../test/typegen/contracts'; import { ScriptCallContract, ScriptCallLoggingContracts } from '../test/typegen/scripts'; @@ -505,5 +506,69 @@ describe('Advanced Logging', () => { ], }); }); + + it('should not throw when unable to decode a log with a missing JSON ABI', async () => { + using launched = await launchTestNode({ + contractsConfigs: [{ factory: AbiContractFactory }], + }); + const { + wallets: [wallet], + contracts: [originalContract], + } = launched; + const abiWithoutLogs: JsonAbi = { + ...originalContract.interface.jsonAbi, + loggedTypes: [], + }; + const contract = new Contract(originalContract.id, abiWithoutLogs, wallet); + + const { waitForResult } = await contract.functions.types_u8(8).call(); + const { logs, groupedLogs } = await waitForResult(); + + const expectedLogEntry = { + __decoded: false, + data: '0xff', + logId: '14454674236531057292', + }; + expect(logs).toStrictEqual([expectedLogEntry]); + expect(groupedLogs).toStrictEqual({ + [originalContract.id.toB256()]: [expectedLogEntry], + }); + }); + + it('should not display undecoded logs in the error message', async () => { + using launched = await launchTestNode({ + contractsConfigs: [{ factory: AbiContractFactory }], + }); + const { + wallets: [wallet], + contracts: [originalContract], + } = launched; + const abiWithoutLogs: JsonAbi = { + ...originalContract.interface.jsonAbi, + loggedTypes: [], + }; + const contract = new Contract(originalContract.id, abiWithoutLogs, wallet); + + const call = () => contract.functions.types_u8(255).call(); + + await expectToThrowFuelError(call, { + code: ErrorCode.SCRIPT_REVERTED, + message: 'The transaction reverted because of an "assert_eq" statement.', + metadata: { + logs: [ + { + __decoded: false, + data: '0xff', + logId: '14454674236531057292', + }, + { + __decoded: false, + data: '0x08', + logId: '14454674236531057292', + }, + ], + }, + }); + }); }); }); From 2b7dcaf8eb4696974538dc001454c8748a0400a1 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Wed, 23 Jul 2025 09:14:00 +0100 Subject: [PATCH 2/3] Changeset --- .changeset/shiny-laws-agree.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/shiny-laws-agree.md diff --git a/.changeset/shiny-laws-agree.md b/.changeset/shiny-laws-agree.md new file mode 100644 index 00000000000..30fd48f33f7 --- /dev/null +++ b/.changeset/shiny-laws-agree.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": patch +--- + +feat: ensure that undecodable logs no longer throw From 955c17594849d8b72cda7e2a26b07517654ecd24 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Wed, 23 Jul 2025 09:18:12 +0100 Subject: [PATCH 3/3] Lintfix --- .../src/providers/transaction-response/getAllDecodedLogs.ts | 2 +- .../src/providers/transaction-response/getDecodedLogs.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts b/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts index 64c274e769a..8a55a260613 100644 --- a/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts +++ b/packages/account/src/providers/transaction-response/getAllDecodedLogs.ts @@ -70,7 +70,7 @@ export function getAllDecodedLogs(opts: { try { [logEntry] = interfaceToUse.decodeLog(data, receipt.rb.toString()); } catch (error) { - logEntry = { __decoded: false, data, logId: receipt.rb.toString() } + logEntry = { __decoded: false, data, logId: receipt.rb.toString() }; } logs.push(logEntry as T); diff --git a/packages/account/src/providers/transaction-response/getDecodedLogs.ts b/packages/account/src/providers/transaction-response/getDecodedLogs.ts index 2acb0c55015..031fe0cae19 100644 --- a/packages/account/src/providers/transaction-response/getDecodedLogs.ts +++ b/packages/account/src/providers/transaction-response/getDecodedLogs.ts @@ -62,7 +62,7 @@ export function getDecodedLogs( try { [logEntry] = interfaceToUse.decodeLog(data, receipt.rb.toString()); } catch (error) { - logEntry = { __decoded: false, data, logId: receipt.rb.toString() } + logEntry = { __decoded: false, data, logId: receipt.rb.toString() }; } logs.push(logEntry as T);