From 0c58e0afe4b35ed9c4e7ca17078f88c3a940aebe Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Sun, 14 Jun 2026 10:23:07 +0100 Subject: [PATCH 1/6] feat(multichain-transactions-controller): add pending universal transaction state --- ...nsactionsController-method-action-types.ts | 48 ++++++++- .../MultichainTransactionsController.test.ts | 75 +++++++++++++- .../src/MultichainTransactionsController.ts | 97 ++++++++++++++++++- .../src/index.ts | 1 + 4 files changed, 218 insertions(+), 3 deletions(-) diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts index 6a825efeec..5b29efa9b1 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts @@ -5,6 +5,48 @@ import type { MultichainTransactionsController } from './MultichainTransactionsController'; +/** + * Adds or replaces a pending multichain transaction by approval ID. + * + * @param entry - Pending transaction entry to add. + */ +export type MultichainTransactionsControllerAddPendingTransactionAction = { + type: `MultichainTransactionsController:addPendingTransaction`; + handler: MultichainTransactionsController['addPendingTransaction']; +}; + +/** + * Updates a pending multichain transaction by approval ID. + * + * @param approvalId - Approval ID for the pending transaction. + * @param patch - Shallow patch to apply to the pending transaction. + */ +export type MultichainTransactionsControllerUpdatePendingTransactionAction = { + type: `MultichainTransactionsController:updatePendingTransaction`; + handler: MultichainTransactionsController['updatePendingTransaction']; +}; + +/** + * Removes a pending multichain transaction by approval ID. + * + * @param approvalId - Approval ID for the pending transaction. + */ +export type MultichainTransactionsControllerRemovePendingTransactionAction = { + type: `MultichainTransactionsController:removePendingTransaction`; + handler: MultichainTransactionsController['removePendingTransaction']; +}; + +/** + * Gets a pending multichain transaction by approval ID. + * + * @param approvalId - Approval ID for the pending transaction. + * @returns Pending transaction entry, if found. + */ +export type MultichainTransactionsControllerGetPendingTransactionAction = { + type: `MultichainTransactionsController:getPendingTransaction`; + handler: MultichainTransactionsController['getPendingTransaction']; +}; + /** * Updates transactions for a specific account. This is used for the initial fetch * when an account is first added. @@ -21,4 +63,8 @@ export type MultichainTransactionsControllerUpdateTransactionsForAccountAction = * Union of all MultichainTransactionsController action types. */ export type MultichainTransactionsControllerMethodActions = - MultichainTransactionsControllerUpdateTransactionsForAccountAction; + | MultichainTransactionsControllerAddPendingTransactionAction + | MultichainTransactionsControllerUpdatePendingTransactionAction + | MultichainTransactionsControllerRemovePendingTransactionAction + | MultichainTransactionsControllerGetPendingTransactionAction + | MultichainTransactionsControllerUpdateTransactionsForAccountAction; diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts index cf1ac2319d..97451db2fe 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts @@ -32,6 +32,7 @@ import { import type { MultichainTransactionsControllerState, MultichainTransactionsControllerMessenger, + PendingMultichainTransaction, } from './MultichainTransactionsController'; const mockBtcAccount = { @@ -255,11 +256,30 @@ async function waitForAllPromises(): Promise { const NEW_ACCOUNT_ID = 'new-account-id'; const TEST_ACCOUNT_ID = 'test-account-id'; +const MOCK_PENDING_TRANSACTION: PendingMultichainTransaction = { + approvalId: 'approval-id', + chainNamespace: 'solana', + chain: MultichainNetwork.Solana, + accountId: TEST_ACCOUNT_ID, + from: 'from-address', + to: 'to-address', + value: '1000000', + assetType: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501', + assetSymbol: 'SOL', + assetDecimals: 9, + feeRaw: '5000', + feeAssetType: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501', + origin: 'mock-snap', + createdAt: 123, +}; describe('MultichainTransactionsController', () => { it('initialize with default state', () => { const { controller } = setupController({}); - expect(controller.state).toStrictEqual({ nonEvmTransactions: {} }); + expect(controller.state).toStrictEqual({ + nonEvmTransactions: {}, + pendingTransactions: {}, + }); }); it('updates transactions when "AccountsController:accountAdded" is fired', async () => { @@ -322,7 +342,51 @@ describe('MultichainTransactionsController', () => { expect(controller.state).toStrictEqual({ nonEvmTransactions: {}, + pendingTransactions: {}, + }); + }); + + it('adds, updates, gets, and removes pending multichain transactions', () => { + const { controller } = setupController(); + + controller.addPendingTransaction(MOCK_PENDING_TRANSACTION); + + expect( + controller.getPendingTransaction(MOCK_PENDING_TRANSACTION.approvalId), + ).toStrictEqual(MOCK_PENDING_TRANSACTION); + + controller.updatePendingTransaction(MOCK_PENDING_TRANSACTION.approvalId, { + value: '2000000', }); + + expect( + controller.getPendingTransaction(MOCK_PENDING_TRANSACTION.approvalId), + ).toStrictEqual({ + ...MOCK_PENDING_TRANSACTION, + value: '2000000', + }); + + controller.removePendingTransaction(MOCK_PENDING_TRANSACTION.approvalId); + + expect( + controller.getPendingTransaction(MOCK_PENDING_TRANSACTION.approvalId), + ).toBeUndefined(); + }); + + it('warns when updating or removing a missing pending multichain transaction', () => { + const { controller } = setupController(); + const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); + + controller.updatePendingTransaction('missing-approval-id', { value: '1' }); + controller.removePendingTransaction('missing-approval-id'); + + expect(warnSpy).toHaveBeenCalledTimes(2); + expect(warnSpy).toHaveBeenCalledWith( + 'Pending multichain transaction not found for approvalId', + 'missing-approval-id', + ); + + warnSpy.mockRestore(); }); it('updates transactions for a specific account', async () => { @@ -564,6 +628,7 @@ describe('MultichainTransactionsController', () => { }, }, }, + pendingTransactions: {}, }, }); @@ -597,6 +662,7 @@ describe('MultichainTransactionsController', () => { }, }, }, + pendingTransactions: {}, }, }); @@ -621,6 +687,7 @@ describe('MultichainTransactionsController', () => { const { controller, rootMessenger } = setupController({ state: { nonEvmTransactions: {}, + pendingTransactions: {}, }, }); @@ -653,6 +720,7 @@ describe('MultichainTransactionsController', () => { }, }, }, + pendingTransactions: {}, }, mocks: { listMultichainAccounts: [], @@ -707,6 +775,7 @@ describe('MultichainTransactionsController', () => { }, }, }, + pendingTransactions: {}, }, }); @@ -755,6 +824,7 @@ describe('MultichainTransactionsController', () => { }, }, }, + pendingTransactions: {}, }, }); @@ -844,6 +914,7 @@ describe('MultichainTransactionsController', () => { }, }, }, + pendingTransactions: {}, }, }); @@ -1027,6 +1098,7 @@ describe('MultichainTransactionsController', () => { ).toMatchInlineSnapshot(` { "nonEvmTransactions": {}, + "pendingTransactions": {}, } `); }); @@ -1059,6 +1131,7 @@ describe('MultichainTransactionsController', () => { ).toMatchInlineSnapshot(` { "nonEvmTransactions": {}, + "pendingTransactions": {}, } `); }); diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts index d51575beb8..b43d082141 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts @@ -28,7 +28,15 @@ import type { MultichainTransactionsControllerMethodActions } from './Multichain const controllerName = 'MultichainTransactionsController'; -const MESSENGER_EXPOSED_METHODS = ['updateTransactionsForAccount'] as const; +const MESSENGER_EXPOSED_METHODS = [ + 'addPendingTransaction', + 'getPendingTransaction', + 'removePendingTransaction', + 'updatePendingTransaction', + 'updateTransactionsForAccount', +] as const; +const MISSING_PENDING_TRANSACTION_MESSAGE = + 'Pending multichain transaction not found for approvalId'; /** * PaginationOptions @@ -42,6 +50,23 @@ export type PaginationOptions = { next?: string | null; }; +export type PendingMultichainTransaction = { + approvalId: string; + chainNamespace: 'solana' | 'bip122' | 'tron'; + chain: string; + accountId: string; + from: string; + to: string; + value: string; + assetType: string; + assetSymbol: string; + assetDecimals: number; + feeRaw?: string; + feeAssetType?: string; + origin?: string; + createdAt: number; +}; + /** * State used by the {@link MultichainTransactionsController} to cache account transactions. */ @@ -51,6 +76,7 @@ export type MultichainTransactionsControllerState = { [chain: CaipChainId]: TransactionStateEntry; }; }; + pendingTransactions: Record; }; /** @@ -61,6 +87,7 @@ export type MultichainTransactionsControllerState = { export function getDefaultMultichainTransactionsControllerState(): MultichainTransactionsControllerState { return { nonEvmTransactions: {}, + pendingTransactions: {}, }; } @@ -152,6 +179,13 @@ const multichainTransactionsControllerMetadata = { includeInDebugSnapshot: false, usedInUi: true, }, + pendingTransactions: { + includeInStateLogs: true, + persist: false, + includeInDebugSnapshot: false, + usedInUi: true, + anonymous: false, + }, }; /** @@ -219,6 +253,67 @@ export class MultichainTransactionsController extends BaseController< ); } + /** + * Adds or replaces a pending multichain transaction by approval ID. + * + * @param entry - Pending transaction entry to add. + */ + addPendingTransaction(entry: PendingMultichainTransaction): void { + this.update((state: Draft) => { + state.pendingTransactions[entry.approvalId] = entry; + }); + } + + /** + * Updates a pending multichain transaction by approval ID. + * + * @param approvalId - Approval ID for the pending transaction. + * @param patch - Shallow patch to apply to the pending transaction. + */ + updatePendingTransaction( + approvalId: string, + patch: Partial, + ): void { + this.update((state: Draft) => { + const pendingTransaction = state.pendingTransactions[approvalId]; + + if (!pendingTransaction) { + console.warn(MISSING_PENDING_TRANSACTION_MESSAGE, approvalId); + return; + } + + Object.assign(pendingTransaction, patch); + }); + } + + /** + * Removes a pending multichain transaction by approval ID. + * + * @param approvalId - Approval ID for the pending transaction. + */ + removePendingTransaction(approvalId: string): void { + this.update((state: Draft) => { + if (!state.pendingTransactions[approvalId]) { + console.warn(MISSING_PENDING_TRANSACTION_MESSAGE, approvalId); + return; + } + + delete state.pendingTransactions[approvalId]; + }); + } + + /** + * Gets a pending multichain transaction by approval ID. + * + * @param approvalId - Approval ID for the pending transaction. + * @returns Pending transaction entry, if found. + */ + getPendingTransaction( + approvalId: string, + ): PendingMultichainTransaction | undefined { + return this.state.pendingTransactions[approvalId]; + } + /** * Lists the multichain accounts coming from the `AccountsController`. * diff --git a/packages/multichain-transactions-controller/src/index.ts b/packages/multichain-transactions-controller/src/index.ts index ed5c590d95..c295a72de6 100644 --- a/packages/multichain-transactions-controller/src/index.ts +++ b/packages/multichain-transactions-controller/src/index.ts @@ -2,6 +2,7 @@ export { MultichainTransactionsController } from './MultichainTransactionsContro export type { MultichainTransactionsControllerState, PaginationOptions, + PendingMultichainTransaction, TransactionStateEntry, MultichainTransactionsControllerStateChange, MultichainTransactionsControllerGetStateAction, From 1fedda8710c6738f1af2d88aa93efade7cfba004 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Sun, 14 Jun 2026 11:17:23 +0100 Subject: [PATCH 2/6] feat(multichain-transactions-controller): simplify pending transaction payload --- .../MultichainTransactionsController.test.ts | 20 +++++++--------- .../src/MultichainTransactionsController.ts | 23 +++++++++++-------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts index 97451db2fe..ecf3c58da2 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts @@ -258,17 +258,13 @@ const NEW_ACCOUNT_ID = 'new-account-id'; const TEST_ACCOUNT_ID = 'test-account-id'; const MOCK_PENDING_TRANSACTION: PendingMultichainTransaction = { approvalId: 'approval-id', - chainNamespace: 'solana', - chain: MultichainNetwork.Solana, + chainId: MultichainNetwork.Solana, accountId: TEST_ACCOUNT_ID, - from: 'from-address', to: 'to-address', - value: '1000000', - assetType: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501', - assetSymbol: 'SOL', - assetDecimals: 9, - feeRaw: '5000', - feeAssetType: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501', + amount: '1000000', + fee: { + amount: '5000', + }, origin: 'mock-snap', createdAt: 123, }; @@ -356,14 +352,14 @@ describe('MultichainTransactionsController', () => { ).toStrictEqual(MOCK_PENDING_TRANSACTION); controller.updatePendingTransaction(MOCK_PENDING_TRANSACTION.approvalId, { - value: '2000000', + amount: '2000000', }); expect( controller.getPendingTransaction(MOCK_PENDING_TRANSACTION.approvalId), ).toStrictEqual({ ...MOCK_PENDING_TRANSACTION, - value: '2000000', + amount: '2000000', }); controller.removePendingTransaction(MOCK_PENDING_TRANSACTION.approvalId); @@ -377,7 +373,7 @@ describe('MultichainTransactionsController', () => { const { controller } = setupController(); const warnSpy = jest.spyOn(console, 'warn').mockImplementation(); - controller.updatePendingTransaction('missing-approval-id', { value: '1' }); + controller.updatePendingTransaction('missing-approval-id', { amount: '1' }); controller.removePendingTransaction('missing-approval-id'); expect(warnSpy).toHaveBeenCalledTimes(2); diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts index b43d082141..696c943f74 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts @@ -21,7 +21,12 @@ import type { Messenger } from '@metamask/messenger'; import type { SnapControllerHandleRequestAction } from '@metamask/snaps-controllers'; import type { SnapId } from '@metamask/snaps-sdk'; import { HandlerType } from '@metamask/snaps-utils'; -import type { CaipChainId, Json, JsonRpcRequest } from '@metamask/utils'; +import type { + CaipAssetType, + CaipChainId, + Json, + JsonRpcRequest, +} from '@metamask/utils'; import type { Draft } from 'immer'; import type { MultichainTransactionsControllerMethodActions } from './MultichainTransactionsController-method-action-types'; @@ -52,17 +57,15 @@ export type PaginationOptions = { export type PendingMultichainTransaction = { approvalId: string; - chainNamespace: 'solana' | 'bip122' | 'tron'; - chain: string; + chainId: CaipChainId; accountId: string; - from: string; to: string; - value: string; - assetType: string; - assetSymbol: string; - assetDecimals: number; - feeRaw?: string; - feeAssetType?: string; + amount: string; + assetId?: CaipAssetType; + fee?: { + amount: string; + assetId?: CaipAssetType; + }; origin?: string; createdAt: number; }; From 25b9e9e30fd45076995be9d004bceed94dd88c98 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Sun, 14 Jun 2026 14:02:05 +0100 Subject: [PATCH 3/6] feat(multichain-transactions-controller): support pending transaction custom data --- .../src/MultichainTransactionsController.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts index 696c943f74..fd17b6179c 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts @@ -55,7 +55,9 @@ export type PaginationOptions = { next?: string | null; }; -export type PendingMultichainTransaction = { +export type PendingMultichainTransaction< + CustomData extends Record = Record, +> = { approvalId: string; chainId: CaipChainId; accountId: string; @@ -66,6 +68,7 @@ export type PendingMultichainTransaction = { amount: string; assetId?: CaipAssetType; }; + custom?: CustomData; origin?: string; createdAt: number; }; From 3cf505af7346cfa6539e064312c1352bcf3c244d Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Sun, 14 Jun 2026 14:28:12 +0100 Subject: [PATCH 4/6] refactor(multichain-transactions-controller): remove pending transaction getter --- ...ainTransactionsController-method-action-types.ts | 12 ------------ .../src/MultichainTransactionsController.test.ts | 8 ++++---- .../src/MultichainTransactionsController.ts | 13 ------------- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts index 5b29efa9b1..7c5a0523fb 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController-method-action-types.ts @@ -36,17 +36,6 @@ export type MultichainTransactionsControllerRemovePendingTransactionAction = { handler: MultichainTransactionsController['removePendingTransaction']; }; -/** - * Gets a pending multichain transaction by approval ID. - * - * @param approvalId - Approval ID for the pending transaction. - * @returns Pending transaction entry, if found. - */ -export type MultichainTransactionsControllerGetPendingTransactionAction = { - type: `MultichainTransactionsController:getPendingTransaction`; - handler: MultichainTransactionsController['getPendingTransaction']; -}; - /** * Updates transactions for a specific account. This is used for the initial fetch * when an account is first added. @@ -66,5 +55,4 @@ export type MultichainTransactionsControllerMethodActions = | MultichainTransactionsControllerAddPendingTransactionAction | MultichainTransactionsControllerUpdatePendingTransactionAction | MultichainTransactionsControllerRemovePendingTransactionAction - | MultichainTransactionsControllerGetPendingTransactionAction | MultichainTransactionsControllerUpdateTransactionsForAccountAction; diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts index ecf3c58da2..04ea438546 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController.test.ts @@ -342,13 +342,13 @@ describe('MultichainTransactionsController', () => { }); }); - it('adds, updates, gets, and removes pending multichain transactions', () => { + it('adds, updates, and removes pending multichain transactions', () => { const { controller } = setupController(); controller.addPendingTransaction(MOCK_PENDING_TRANSACTION); expect( - controller.getPendingTransaction(MOCK_PENDING_TRANSACTION.approvalId), + controller.state.pendingTransactions[MOCK_PENDING_TRANSACTION.approvalId], ).toStrictEqual(MOCK_PENDING_TRANSACTION); controller.updatePendingTransaction(MOCK_PENDING_TRANSACTION.approvalId, { @@ -356,7 +356,7 @@ describe('MultichainTransactionsController', () => { }); expect( - controller.getPendingTransaction(MOCK_PENDING_TRANSACTION.approvalId), + controller.state.pendingTransactions[MOCK_PENDING_TRANSACTION.approvalId], ).toStrictEqual({ ...MOCK_PENDING_TRANSACTION, amount: '2000000', @@ -365,7 +365,7 @@ describe('MultichainTransactionsController', () => { controller.removePendingTransaction(MOCK_PENDING_TRANSACTION.approvalId); expect( - controller.getPendingTransaction(MOCK_PENDING_TRANSACTION.approvalId), + controller.state.pendingTransactions[MOCK_PENDING_TRANSACTION.approvalId], ).toBeUndefined(); }); diff --git a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts index fd17b6179c..8507f8a6fd 100644 --- a/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts +++ b/packages/multichain-transactions-controller/src/MultichainTransactionsController.ts @@ -35,7 +35,6 @@ const controllerName = 'MultichainTransactionsController'; const MESSENGER_EXPOSED_METHODS = [ 'addPendingTransaction', - 'getPendingTransaction', 'removePendingTransaction', 'updatePendingTransaction', 'updateTransactionsForAccount', @@ -308,18 +307,6 @@ export class MultichainTransactionsController extends BaseController< }); } - /** - * Gets a pending multichain transaction by approval ID. - * - * @param approvalId - Approval ID for the pending transaction. - * @returns Pending transaction entry, if found. - */ - getPendingTransaction( - approvalId: string, - ): PendingMultichainTransaction | undefined { - return this.state.pendingTransactions[approvalId]; - } - /** * Lists the multichain accounts coming from the `AccountsController`. * From 688a4a9094bfe501ddddd9420e3e94d633967b8f Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Sun, 14 Jun 2026 18:46:52 +0100 Subject: [PATCH 5/6] docs(multichain-transactions-controller): add pending transaction changelog --- packages/multichain-transactions-controller/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/multichain-transactions-controller/CHANGELOG.md b/packages/multichain-transactions-controller/CHANGELOG.md index 6143bafd60..7052e457c7 100644 --- a/packages/multichain-transactions-controller/CHANGELOG.md +++ b/packages/multichain-transactions-controller/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Pending universal transaction state on `MultichainTransactionsController` ([#TBD](https://github.com/MetaMask/core/pull/TBD)) + - New non-persisted `pendingTransactions` state keyed by approval ID. + - New `addPendingTransaction`, `updatePendingTransaction`, and `removePendingTransaction` messenger actions. + - New `PendingMultichainTransaction` type for protocol-agnostic pending confirmation display data. + ### Changed - Bump `@metamask/accounts-controller` from `^38.0.0` to `^38.1.1` ([#8755](https://github.com/MetaMask/core/pull/8755), [#8774](https://github.com/MetaMask/core/pull/8774)) From 99853e773834169f41f9737d1184654ea26375fa Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Sun, 14 Jun 2026 18:47:42 +0100 Subject: [PATCH 6/6] docs(multichain-transactions-controller): link pending transaction changelog --- packages/multichain-transactions-controller/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/multichain-transactions-controller/CHANGELOG.md b/packages/multichain-transactions-controller/CHANGELOG.md index 7052e457c7..393aa39ac6 100644 --- a/packages/multichain-transactions-controller/CHANGELOG.md +++ b/packages/multichain-transactions-controller/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Pending universal transaction state on `MultichainTransactionsController` ([#TBD](https://github.com/MetaMask/core/pull/TBD)) +- Pending universal transaction state on `MultichainTransactionsController` ([#9115](https://github.com/MetaMask/core/pull/9115)) - New non-persisted `pendingTransactions` state keyed by approval ID. - New `addPendingTransaction`, `updatePendingTransaction`, and `removePendingTransaction` messenger actions. - New `PendingMultichainTransaction` type for protocol-agnostic pending confirmation display data.