Skip to content

Commit 215f9f2

Browse files
feat: ensure that undecodable logs no longer throw (#3933)
1 parent c9e0c5a commit 215f9f2

File tree

5 files changed

+101
-8
lines changed

5 files changed

+101
-8
lines changed

.changeset/shiny-laws-agree.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@fuel-ts/account": patch
3+
---
4+
5+
feat: ensure that undecodable logs no longer throw

packages/account/src/providers/transaction-response/getAllDecodedLogs.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,17 @@ export function getAllDecodedLogs<T = unknown>(opts: {
6565
? new BigNumberCoder('u64').encode(receipt.ra)
6666
: receipt.data;
6767

68-
const [decodedLog] = interfaceToUse.decodeLog(data, receipt.rb.toString());
69-
logs.push(decodedLog);
68+
let logEntry: unknown;
69+
70+
try {
71+
[logEntry] = interfaceToUse.decodeLog(data, receipt.rb.toString());
72+
} catch (error) {
73+
logEntry = { __decoded: false, data, logId: receipt.rb.toString() };
74+
}
75+
76+
logs.push(logEntry as T);
7077
// eslint-disable-next-line no-param-reassign
71-
groupedLogs[receipt.id] = [...(groupedLogs[receipt.id] || []), decodedLog];
78+
groupedLogs[receipt.id] = [...(groupedLogs[receipt.id] || []), logEntry as T];
7279
}
7380
}
7481

packages/account/src/providers/transaction-response/getDecodedLogs.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,15 @@ export function getDecodedLogs<T = unknown>(
5757
? new BigNumberCoder('u64').encode(receipt.ra)
5858
: receipt.data;
5959

60-
const [decodedLog] = interfaceToUse.decodeLog(data, receipt.rb.toString());
61-
logs.push(decodedLog);
60+
let logEntry: unknown;
61+
62+
try {
63+
[logEntry] = interfaceToUse.decodeLog(data, receipt.rb.toString());
64+
} catch (error) {
65+
logEntry = { __decoded: false, data, logId: receipt.rb.toString() };
66+
}
67+
68+
logs.push(logEntry as T);
6269
}
6370
}
6471

packages/account/src/providers/utils/extract-tx-error.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,14 @@ export const extractTxError = (params: IExtractTxError): FuelError => {
222222
if (isPanic) {
223223
return assemblePanicError(statusReason, metadata);
224224
}
225-
return assembleRevertError(receipts, logs, metadata, statusReason, abis);
225+
const decodedLogs = logs.filter((l: unknown) => {
226+
const log = l as unknown;
227+
return !(
228+
log !== null &&
229+
typeof log === 'object' &&
230+
'__decoded' in log &&
231+
(log as { __decoded: boolean }).__decoded === false
232+
);
233+
});
234+
return assembleRevertError(receipts, decodedLogs, metadata, statusReason, abis);
226235
};

packages/fuel-gauge/src/advanced-logging.test.ts

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type { FuelError } from '@fuel-ts/errors';
2-
import { bn, ZeroBytes32 } from 'fuels';
3-
import { launchTestNode } from 'fuels/test-utils';
2+
import { bn, Contract, ErrorCode, type JsonAbi, ZeroBytes32 } from 'fuels';
3+
import { expectToThrowFuelError, launchTestNode } from 'fuels/test-utils';
44

55
import {
66
AdvancedLoggingOtherContractFactory,
77
AdvancedLoggingFactory,
88
CallTestContractFactory,
99
ConfigurableContractFactory,
1010
CoverageContractFactory,
11+
AbiContractFactory,
1112
} from '../test/typegen/contracts';
1213
import { ScriptCallContract, ScriptCallLoggingContracts } from '../test/typegen/scripts';
1314

@@ -505,5 +506,69 @@ describe('Advanced Logging', () => {
505506
],
506507
});
507508
});
509+
510+
it('should not throw when unable to decode a log with a missing JSON ABI', async () => {
511+
using launched = await launchTestNode({
512+
contractsConfigs: [{ factory: AbiContractFactory }],
513+
});
514+
const {
515+
wallets: [wallet],
516+
contracts: [originalContract],
517+
} = launched;
518+
const abiWithoutLogs: JsonAbi = {
519+
...originalContract.interface.jsonAbi,
520+
loggedTypes: [],
521+
};
522+
const contract = new Contract(originalContract.id, abiWithoutLogs, wallet);
523+
524+
const { waitForResult } = await contract.functions.types_u8(8).call();
525+
const { logs, groupedLogs } = await waitForResult();
526+
527+
const expectedLogEntry = {
528+
__decoded: false,
529+
data: '0xff',
530+
logId: '14454674236531057292',
531+
};
532+
expect(logs).toStrictEqual([expectedLogEntry]);
533+
expect(groupedLogs).toStrictEqual({
534+
[originalContract.id.toB256()]: [expectedLogEntry],
535+
});
536+
});
537+
538+
it('should not display undecoded logs in the error message', async () => {
539+
using launched = await launchTestNode({
540+
contractsConfigs: [{ factory: AbiContractFactory }],
541+
});
542+
const {
543+
wallets: [wallet],
544+
contracts: [originalContract],
545+
} = launched;
546+
const abiWithoutLogs: JsonAbi = {
547+
...originalContract.interface.jsonAbi,
548+
loggedTypes: [],
549+
};
550+
const contract = new Contract(originalContract.id, abiWithoutLogs, wallet);
551+
552+
const call = () => contract.functions.types_u8(255).call();
553+
554+
await expectToThrowFuelError(call, {
555+
code: ErrorCode.SCRIPT_REVERTED,
556+
message: 'The transaction reverted because of an "assert_eq" statement.',
557+
metadata: {
558+
logs: [
559+
{
560+
__decoded: false,
561+
data: '0xff',
562+
logId: '14454674236531057292',
563+
},
564+
{
565+
__decoded: false,
566+
data: '0x08',
567+
logId: '14454674236531057292',
568+
},
569+
],
570+
},
571+
});
572+
});
508573
});
509574
});

0 commit comments

Comments
 (0)