From 39099ee430a29d018b5a0d5fc38a5810e8052a42 Mon Sep 17 00:00:00 2001 From: Goktug Poyraz Date: Tue, 16 Jun 2026 20:05:02 +0200 Subject: [PATCH] fix(transaction-pay-controller): sync transaction metadata when fiat payment has no payment token --- .../transaction-pay-controller/CHANGELOG.md | 4 +++ .../src/utils/quotes.test.ts | 26 ++++++++++++++++++- .../src/utils/quotes.ts | 10 ++++--- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/packages/transaction-pay-controller/CHANGELOG.md b/packages/transaction-pay-controller/CHANGELOG.md index 17116e6f03..2ea1775f32 100644 --- a/packages/transaction-pay-controller/CHANGELOG.md +++ b/packages/transaction-pay-controller/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Sync transaction metadata when fiat payment is selected but no payment token is present ([#TBD](https://github.com/MetaMask/core/pull/TBD)) + ## [23.8.0] ### Changed diff --git a/packages/transaction-pay-controller/src/utils/quotes.test.ts b/packages/transaction-pay-controller/src/utils/quotes.test.ts index 69fe267549..a4b047aeae 100644 --- a/packages/transaction-pay-controller/src/utils/quotes.test.ts +++ b/packages/transaction-pay-controller/src/utils/quotes.test.ts @@ -566,7 +566,7 @@ describe('Quotes Utils', () => { expect(strategy.getQuotes).toHaveBeenCalled(); }); - it('clears state if no payment token', async () => { + it('clears state if no payment token and no fiat payment', async () => { await run({ transactionData: { ...TRANSACTION_DATA_MOCK, @@ -772,6 +772,30 @@ describe('Quotes Utils', () => { }); }); + it('updates metrics in metadata for fiat payment with no payment token', async () => { + await run({ + transactionData: { + ...TRANSACTION_DATA_MOCK, + paymentToken: undefined, + fiatPayment: { selectedPaymentMethodId: 'card-123' }, + }, + }); + + const transactionMetaMock = {} as TransactionMeta; + updateTransactionMock.mock.calls[0][1](transactionMetaMock); + + expect(transactionMetaMock).toMatchObject({ + metamaskPay: { + bridgeFeeFiat: TOTALS_MOCK.fees.provider.usd, + chainId: undefined, + networkFeeFiat: TOTALS_MOCK.fees.sourceNetwork.estimate.usd, + targetFiat: TOTALS_MOCK.targetAmount.usd, + tokenAddress: undefined, + totalFiat: TOTALS_MOCK.total.usd, + }, + }); + }); + it('uses provider fee directly as bridgeFeeFiat even when providerFiat breakdown exists', async () => { calculateTotalsMock.mockReturnValue({ ...TOTALS_MOCK, diff --git a/packages/transaction-pay-controller/src/utils/quotes.ts b/packages/transaction-pay-controller/src/utils/quotes.ts index 098911a2de..c8d0d99134 100644 --- a/packages/transaction-pay-controller/src/utils/quotes.ts +++ b/packages/transaction-pay-controller/src/utils/quotes.ts @@ -163,6 +163,7 @@ export async function updateQuotes( syncTransaction({ batchTransactions, + selectedFiatPayment: fiatPayment?.selectedPaymentMethodId, hasQuotes: quotes.length > 0, isPostQuote, messenger: messenger as never, @@ -203,6 +204,7 @@ export async function updateQuotes( * @param request.isPostQuote - Whether this is a post-quote flow. * @param request.messenger - Messenger instance. * @param request.paymentToken - Payment token (source for standard flows, destination for post-quote). + * @param request.selectedFiatPayment - Selected fiat payment method ID. * @param request.totals - Calculated totals. * @param request.transactionId - ID of the transaction to sync. */ @@ -212,10 +214,12 @@ function syncTransaction({ isPostQuote, messenger, paymentToken, + selectedFiatPayment, totals, transactionId, }: { batchTransactions: BatchTransaction[]; + selectedFiatPayment?: string; hasQuotes: boolean; isPostQuote?: boolean; messenger: TransactionPayControllerMessenger; @@ -223,7 +227,7 @@ function syncTransaction({ totals: TransactionPayTotals; transactionId: string; }): void { - if (!paymentToken) { + if (!paymentToken && !selectedFiatPayment) { return; } @@ -247,11 +251,11 @@ function syncTransaction({ tx.metamaskPay = { bridgeFeeFiat: totals.fees.provider.usd, - chainId: paymentToken.chainId, + chainId: paymentToken?.chainId, isPostQuote, networkFeeFiat: totals.fees.sourceNetwork.estimate.usd, targetFiat: totals.targetAmount.usd, - tokenAddress: paymentToken.address, + tokenAddress: paymentToken?.address, totalFiat: totals.total.usd, }; },