From 499d0977bdce21ed4f8f8c416e91aa40149bce84 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 11 Dec 2025 13:29:13 +0000 Subject: [PATCH 1/2] Handle authorization nonces --- .../src/utils/nonce.test.ts | 78 +++++++++++++++++++ .../transaction-controller/src/utils/nonce.ts | 50 ++++++++---- 2 files changed, 111 insertions(+), 17 deletions(-) diff --git a/packages/transaction-controller/src/utils/nonce.test.ts b/packages/transaction-controller/src/utils/nonce.test.ts index c3323c61cd8..07750aa5813 100644 --- a/packages/transaction-controller/src/utils/nonce.test.ts +++ b/packages/transaction-controller/src/utils/nonce.test.ts @@ -165,6 +165,32 @@ describe('nonce', () => { }, status: TransactionStatus.confirmed, }, + { + id: '5', + chainId: '0x2', + networkClientId: 'testNetworkClientId', + isUserOperation: true, + time: 123460, + txParams: { + from: fromAddress, + gas: '0x104', + value: '0x204', + nonce: '0x5', + }, + status: TransactionStatus.confirmed, + }, + { + id: '5', + chainId: '0x2', + networkClientId: 'testNetworkClientId', + time: 123460, + txParams: { + from: fromAddress, + gas: '0x104', + value: '0x204', + }, + status: TransactionStatus.confirmed, + }, ]; const expectedResult: NonceTrackerTransaction[] = [ @@ -189,5 +215,57 @@ describe('nonce', () => { expect(result).toStrictEqual(expectedResult); }); + + it('includes authorization nonces from authorizationList', () => { + const fromAddress = '0x123'; + const inputTransactions: TransactionMeta[] = [ + { + id: '1', + chainId: '0x1', + networkClientId: 'testNetworkClientId', + time: 123456, + txParams: { + from: fromAddress, + gas: '0x100', + value: '0x200', + nonce: '0x1', + authorizationList: [ + { + chainId: '0x1', + address: '0xabc', + nonce: '0x2', + r: '0x0', + s: '0x0', + yParity: '0x0', + }, + { + chainId: '0x1', + address: '0xdef', + nonce: '0x3', + r: '0x0', + s: '0x0', + yParity: '0x0', + }, + ], + }, + status: TransactionStatus.confirmed, + }, + ]; + + const result = getAndFormatTransactionsForNonceTracker( + '0x1', + fromAddress, + [TransactionStatus.confirmed], + inputTransactions, + ); + + expect(result).toHaveLength(3); + expect(result[0].txParams.nonce).toBe('0x1'); + expect(result[1].txParams.nonce).toBe('0x2'); + expect(result[2].txParams.nonce).toBe('0x3'); + expect(result[0].status).toBe(TransactionStatus.confirmed); + expect(result[1].status).toBe(TransactionStatus.confirmed); + expect(result[2].status).toBe(TransactionStatus.confirmed); + }); }); }); diff --git a/packages/transaction-controller/src/utils/nonce.ts b/packages/transaction-controller/src/utils/nonce.ts index 21eac6df987..8c17ee5c12a 100644 --- a/packages/transaction-controller/src/utils/nonce.ts +++ b/packages/transaction-controller/src/utils/nonce.ts @@ -69,27 +69,43 @@ export function getAndFormatTransactionsForNonceTracker( ): NonceTrackerTransaction[] { return transactions .filter( - ({ chainId, isTransfer, isUserOperation, status, txParams: { from } }) => + ({ + chainId, + isTransfer, + isUserOperation, + status, + txParams: { from, nonce }, + }) => !isTransfer && !isUserOperation && chainId === currentChainId && transactionStatuses.includes(status) && - from.toLowerCase() === fromAddress.toLowerCase(), + from.toLowerCase() === fromAddress.toLowerCase() && + nonce, ) - .map(({ status, txParams: { from, gas, value, nonce } }) => { - // the only value we care about is the nonce - // but we need to return the other values to satisfy the type - // TODO: refactor nonceTracker to not require this - /* istanbul ignore next */ - return { + .flatMap( + ({ status, - history: [{}], - txParams: { - from: from ?? '', - gas: gas ?? '', - value: value ?? '', - nonce: nonce ?? '', - }, - }; - }); + txParams: { authorizationList, from, gas, value, nonce }, + }) => { + const authorizationNonces = (authorizationList ?? []) + .map((authorization) => authorization.nonce) + .filter((authorizationNonce) => authorizationNonce !== undefined); + + // the only value we care about is the nonce + // but we need to return the other values to satisfy the type + // TODO: refactor nonceTracker to not require this + /* istanbul ignore next */ + return [nonce, ...authorizationNonces].map((currentNonce) => ({ + status, + history: [{}], + txParams: { + from: from ?? '', + gas: gas ?? '', + value: value ?? '', + nonce: currentNonce ?? '', + }, + })); + }, + ); } From d2037635d5ab5d69c39c841ffcb4abaf418511d0 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 11 Dec 2025 13:45:58 +0000 Subject: [PATCH 2/2] Update changelog --- packages/transaction-controller/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/transaction-controller/CHANGELOG.md b/packages/transaction-controller/CHANGELOG.md index bf8e207d0fe..0b85a18c967 100644 --- a/packages/transaction-controller/CHANGELOG.md +++ b/packages/transaction-controller/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Include pending authorizations in nonce calculation ([#7446](https://github.com/MetaMask/core/pull/7446)) + ## [62.6.0] ### Added