Skip to content

Commit 3e9e44c

Browse files
fix: Mark multiple transactions as failed if a batch smart transaction fails (#551)
* Fail multiple transactions * fix: Mark multiple transactions as failed if a batch smart transaction fails Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com> * Renaming Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com> --------- Signed-off-by: dan437 <80175477+dan437@users.noreply.github.com> Co-authored-by: Matthew Walsh <matthew.walsh@consensys.net>
1 parent bfe8e9c commit 3e9e44c

3 files changed

Lines changed: 92 additions & 35 deletions

File tree

src/SmartTransactionsController.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ import {
5959
getTxHash,
6060
getSmartTransactionMetricsProperties,
6161
getSmartTransactionMetricsSensitiveProperties,
62-
shouldMarkRegularTransactionAsFailed,
63-
markRegularTransactionAsFailed,
62+
shouldMarkRegularTransactionsAsFailed,
63+
markRegularTransactionsAsFailed,
6464
} from './utils';
6565

6666
const SECOND = 1000;
@@ -561,13 +561,13 @@ export class SmartTransactionsController extends StaticIntervalPollingController
561561
);
562562

563563
if (
564-
shouldMarkRegularTransactionAsFailed({
564+
shouldMarkRegularTransactionsAsFailed({
565565
smartTransaction: nextSmartTransaction,
566566
clientId: this.#clientId,
567567
getFeatureFlags: this.#getFeatureFlags,
568568
})
569569
) {
570-
markRegularTransactionAsFailed({
570+
markRegularTransactionsAsFailed({
571571
smartTransaction: nextSmartTransaction,
572572
getRegularTransactions: () =>
573573
this.messenger.call('TransactionController:getTransactions'),

src/utils.test.ts

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ describe('src/utils.js', () => {
403403
});
404404
});
405405

406-
describe('shouldMarkRegularTransactionAsFailed', () => {
406+
describe('shouldMarkRegularTransactionsAsFailed', () => {
407407
const createSmartTransaction = (status: SmartTransactionStatuses) => ({
408408
uuid: 'test-uuid',
409409
status,
@@ -428,7 +428,7 @@ describe('src/utils.js', () => {
428428
});
429429

430430
it('returns true for "cancelled" status when feature flag is enabled', () => {
431-
const result = utils.shouldMarkRegularTransactionAsFailed({
431+
const result = utils.shouldMarkRegularTransactionsAsFailed({
432432
smartTransaction: createSmartTransaction(
433433
SmartTransactionStatuses.CANCELLED,
434434
),
@@ -439,7 +439,7 @@ describe('src/utils.js', () => {
439439
});
440440

441441
it('returns true for "cancelled_user_cancelled" status when feature flag is enabled', () => {
442-
const result = utils.shouldMarkRegularTransactionAsFailed({
442+
const result = utils.shouldMarkRegularTransactionsAsFailed({
443443
smartTransaction: createSmartTransaction(
444444
SmartTransactionStatuses.CANCELLED_USER_CANCELLED,
445445
),
@@ -450,7 +450,7 @@ describe('src/utils.js', () => {
450450
});
451451

452452
it('returns true for "unknown" status when feature flag is enabled', () => {
453-
const result = utils.shouldMarkRegularTransactionAsFailed({
453+
const result = utils.shouldMarkRegularTransactionsAsFailed({
454454
smartTransaction: createSmartTransaction(
455455
SmartTransactionStatuses.UNKNOWN,
456456
),
@@ -461,7 +461,7 @@ describe('src/utils.js', () => {
461461
});
462462

463463
it('returns true for "resolved" status when feature flag is enabled', () => {
464-
const result = utils.shouldMarkRegularTransactionAsFailed({
464+
const result = utils.shouldMarkRegularTransactionsAsFailed({
465465
smartTransaction: createSmartTransaction(
466466
SmartTransactionStatuses.RESOLVED,
467467
),
@@ -472,7 +472,7 @@ describe('src/utils.js', () => {
472472
});
473473

474474
it('returns false for "pending" status when feature flag is enabled', () => {
475-
const result = utils.shouldMarkRegularTransactionAsFailed({
475+
const result = utils.shouldMarkRegularTransactionsAsFailed({
476476
smartTransaction: createSmartTransaction(
477477
SmartTransactionStatuses.PENDING,
478478
),
@@ -483,7 +483,7 @@ describe('src/utils.js', () => {
483483
});
484484

485485
it('returns false for "success" status when feature flag is enabled', () => {
486-
const result = utils.shouldMarkRegularTransactionAsFailed({
486+
const result = utils.shouldMarkRegularTransactionsAsFailed({
487487
smartTransaction: createSmartTransaction(
488488
SmartTransactionStatuses.SUCCESS,
489489
),
@@ -494,7 +494,7 @@ describe('src/utils.js', () => {
494494
});
495495

496496
it('returns false when feature flag is disabled regardless of status', () => {
497-
const result = utils.shouldMarkRegularTransactionAsFailed({
497+
const result = utils.shouldMarkRegularTransactionsAsFailed({
498498
smartTransaction: createSmartTransaction(
499499
SmartTransactionStatuses.CANCELLED,
500500
),
@@ -509,7 +509,7 @@ describe('src/utils.js', () => {
509509
...createSmartTransaction(SmartTransactionStatuses.CANCELLED),
510510
transactionId: undefined,
511511
};
512-
const result = utils.shouldMarkRegularTransactionAsFailed({
512+
const result = utils.shouldMarkRegularTransactionsAsFailed({
513513
smartTransaction,
514514
clientId: ClientId.Extension,
515515
getFeatureFlags: mockGetFeatureFlags(true),
@@ -518,7 +518,7 @@ describe('src/utils.js', () => {
518518
});
519519

520520
it('returns true for mobile client when mobile feature flag is enabled', () => {
521-
const result = utils.shouldMarkRegularTransactionAsFailed({
521+
const result = utils.shouldMarkRegularTransactionsAsFailed({
522522
smartTransaction: createSmartTransaction(
523523
SmartTransactionStatuses.CANCELLED,
524524
),
@@ -529,7 +529,7 @@ describe('src/utils.js', () => {
529529
});
530530
});
531531

532-
describe('markRegularTransactionAsFailed', () => {
532+
describe('markRegularTransactionsAsFailed', () => {
533533
const createSmartTransaction = (status: SmartTransactionStatuses) => ({
534534
uuid: 'test-uuid',
535535
status,
@@ -561,7 +561,7 @@ describe('src/utils.js', () => {
561561
it('updates transaction with failed status and error message', () => {
562562
const updateTransactionMock = jest.fn();
563563

564-
utils.markRegularTransactionAsFailed({
564+
utils.markRegularTransactionsAsFailed({
565565
smartTransaction: createSmartTransaction(
566566
SmartTransactionStatuses.CANCELLED,
567567
),
@@ -587,7 +587,7 @@ describe('src/utils.js', () => {
587587
const getRegularTransactionsMock = jest.fn(() => []);
588588

589589
expect(() =>
590-
utils.markRegularTransactionAsFailed({
590+
utils.markRegularTransactionsAsFailed({
591591
smartTransaction: createSmartTransaction(
592592
SmartTransactionStatuses.CANCELLED,
593593
),
@@ -610,7 +610,7 @@ describe('src/utils.js', () => {
610610
},
611611
};
612612

613-
utils.markRegularTransactionAsFailed({
613+
utils.markRegularTransactionsAsFailed({
614614
smartTransaction: createSmartTransaction(
615615
SmartTransactionStatuses.CANCELLED,
616616
),
@@ -620,5 +620,53 @@ describe('src/utils.js', () => {
620620

621621
expect(updateTransactionMock).not.toHaveBeenCalled();
622622
});
623+
624+
it('marks multiple transactions as failed when txHashes match', () => {
625+
const updateTransactionMock = jest.fn();
626+
const transaction1: TransactionMeta = {
627+
...mockTransaction,
628+
id: '456',
629+
hash: '0xhash1',
630+
};
631+
const transaction2: TransactionMeta = {
632+
...mockTransaction,
633+
id: '789',
634+
hash: '0xhash2',
635+
};
636+
const smartTransaction = {
637+
...createSmartTransaction(SmartTransactionStatuses.CANCELLED),
638+
txHashes: ['0xhash1', '0xhash2'],
639+
};
640+
641+
utils.markRegularTransactionsAsFailed({
642+
smartTransaction,
643+
getRegularTransactions: () => [transaction1, transaction2],
644+
updateTransaction: updateTransactionMock,
645+
});
646+
647+
expect(updateTransactionMock).toHaveBeenCalledTimes(2);
648+
expect(updateTransactionMock).toHaveBeenCalledWith(
649+
{
650+
...transaction1,
651+
status: TransactionStatus.failed,
652+
error: {
653+
name: 'SmartTransactionFailed',
654+
message: 'Smart transaction failed with status: cancelled',
655+
},
656+
},
657+
'Smart transaction status: cancelled',
658+
);
659+
expect(updateTransactionMock).toHaveBeenCalledWith(
660+
{
661+
...transaction2,
662+
status: TransactionStatus.failed,
663+
error: {
664+
name: 'SmartTransactionFailed',
665+
message: 'Smart transaction failed with status: cancelled',
666+
},
667+
},
668+
'Smart transaction status: cancelled',
669+
);
670+
});
623671
});
624672
});

src/utils.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ export const getReturnTxHashAsap = (
240240
: smartTransactionsFeatureFlags?.mobileReturnTxHashAsap;
241241
};
242242

243-
export const shouldMarkRegularTransactionAsFailed = ({
243+
export const shouldMarkRegularTransactionsAsFailed = ({
244244
smartTransaction,
245245
clientId,
246246
getFeatureFlags,
@@ -271,7 +271,7 @@ export const shouldMarkRegularTransactionAsFailed = ({
271271
return Boolean(returnTxHashAsapEnabled && transactionId);
272272
};
273273

274-
export const markRegularTransactionAsFailed = ({
274+
export const markRegularTransactionsAsFailed = ({
275275
smartTransaction,
276276
getRegularTransactions,
277277
updateTransaction,
@@ -280,23 +280,32 @@ export const markRegularTransactionAsFailed = ({
280280
getRegularTransactions: TransactionControllerGetTransactionsAction['handler'];
281281
updateTransaction: TransactionControllerUpdateTransactionAction['handler'];
282282
}) => {
283-
const { transactionId, status } = smartTransaction;
284-
const originalTransaction = getRegularTransactions().find(
285-
(transaction) => transaction.id === transactionId,
283+
const { transactionId, status, txHashes } = smartTransaction;
284+
285+
const transactionsToFail = getRegularTransactions().filter(
286+
(tx) => (tx.hash && txHashes?.includes(tx.hash)) || tx.id === transactionId,
286287
);
287-
if (!originalTransaction) {
288+
289+
if (!transactionsToFail.length) {
288290
throw new Error('Cannot find regular transaction to mark it as failed');
289291
}
290-
if (originalTransaction.status === TransactionStatus.failed) {
291-
return; // Already marked as failed.
292+
293+
for (const tx of transactionsToFail) {
294+
if (tx.status === TransactionStatus.failed) {
295+
continue; // Already marked as failed.
296+
}
297+
const updatedTransaction: TransactionMeta = {
298+
...tx,
299+
status: TransactionStatus.failed,
300+
error: {
301+
name: 'SmartTransactionFailed',
302+
message: `Smart transaction failed with status: ${status}`,
303+
},
304+
};
305+
306+
updateTransaction(
307+
updatedTransaction,
308+
`Smart transaction status: ${status}`,
309+
);
292310
}
293-
const updatedTransaction: TransactionMeta = {
294-
...originalTransaction,
295-
status: TransactionStatus.failed,
296-
error: {
297-
name: 'SmartTransactionFailed',
298-
message: `Smart transaction failed with status: ${status}`,
299-
},
300-
};
301-
updateTransaction(updatedTransaction, `Smart transaction status: ${status}`);
302311
};

0 commit comments

Comments
 (0)