From dfa88a2648ed1095b79c81a64cbb788cc50909df Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 2 Jun 2026 11:20:20 +0530 Subject: [PATCH 1/8] feat: adding support for postQuote transactions with paymentProvider defined --- .../src/strategy/relay/relay-quotes.ts | 75 +++++++++++++++++++ .../transaction-pay-controller/src/types.ts | 3 + 2 files changed, 78 insertions(+) diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts index 4d1bb5fca2..242d3f902c 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts @@ -19,6 +19,7 @@ import { PERPS_DEPOSIT_TYPES, USDC_DECIMALS, STABLECOINS, + PaymentOverride, } from '../../constants'; import { projectLogger } from '../../logger'; import type { @@ -265,6 +266,11 @@ async function getSingleQuote( // bridged token transfer, not a contract call to embed. if (!request.isPostQuote && !request.isPolymarketDepositWallet) { await processTransactions(transaction, request, body, messenger); + } else if ( + request.isPostQuote && + request.paymentOverride === PaymentOverride.MoneyAccount + ) { + await processMoneyAccountPostQuote(transaction, request, body, messenger); } else if (request.refundTo) { // For post-quote flows, honour the caller-specified refund address so that // failed Relay transactions refund to the correct account (e.g. the Predict @@ -378,6 +384,75 @@ async function processTransactions( ]; } +async function processMoneyAccountPostQuote( + transaction: TransactionMeta, + request: QuoteRequest, + requestBody: RelayQuoteRequest, + messenger: TransactionPayControllerMessenger, +): Promise { + const { transactionData: transactionDataList } = messenger.call( + 'TransactionPayController:getState', + ); + + const transactionData = transactionDataList[transaction.id]; + const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0'; + + const { calls: overrideCalls, recipient } = await messenger.call( + 'TransactionPayController:getPaymentOverrideData', + { + amount: amountHuman, + transaction, + transactionData, + }, + ); + + if (!overrideCalls.length) { + log('No payment override calls for money account post-quote'); + return; + } + + const amountRaw = + transactionData?.tokens?.[0]?.amountRaw ?? request.sourceTokenAmount; + const fundingRecipient = recipient ?? request.from; + + const delegation = await messenger.call( + 'TransactionPayController:getDelegationTransaction', + { transaction }, + ); + + const normalizedAuthorizationList = delegation.authorizationList?.map( + (a) => ({ + ...a, + chainId: Number(a.chainId), + nonce: Number(a.nonce), + r: a.r as Hex, + s: a.s as Hex, + yParity: Number(a.yParity), + }), + ); + + requestBody.authorizationList = normalizedAuthorizationList; + requestBody.tradeType = 'EXACT_OUTPUT'; + requestBody.amount = amountRaw; + + requestBody.txs = [ + { + to: request.targetTokenAddress, + data: buildTokenTransferData(fundingRecipient, amountRaw), + value: '0x0', + }, + ...overrideCalls.map((call) => ({ + to: call.to as Hex, + data: call.data as Hex, + value: (call.value as Hex) ?? '0x0', + })), + ]; + + log('Added money account deposit calls to quote body', { + callCount: overrideCalls.length, + }); +} + /** * Normalizes requests for Relay. * diff --git a/packages/transaction-pay-controller/src/types.ts b/packages/transaction-pay-controller/src/types.ts index fa95fa1f2d..b611e401c5 100644 --- a/packages/transaction-pay-controller/src/types.ts +++ b/packages/transaction-pay-controller/src/types.ts @@ -167,6 +167,9 @@ export type GetPaymentOverrideDataRequest = { export type GetPaymentOverrideDataResponse = { /** Batch transaction params to prepend to the submit batch. */ calls: BatchTransactionParams[]; + + /** Optional recipient address for the funding token transfer. */ + recipient?: Hex; }; /** From 31ecac36745d00c9f95a5e06bf7b19c4628385dd Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 2 Jun 2026 18:02:17 +0530 Subject: [PATCH 2/8] update --- .../transaction-pay-controller/CHANGELOG.md | 5 + .../src/strategy/relay/relay-quotes.test.ts | 246 ++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/packages/transaction-pay-controller/CHANGELOG.md b/packages/transaction-pay-controller/CHANGELOG.md index 806da575a4..095f5bba4c 100644 --- a/packages/transaction-pay-controller/CHANGELOG.md +++ b/packages/transaction-pay-controller/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `processMoneyAccountPostQuote` to relay quote flow, enabling post-quote transactions with `PaymentOverride.MoneyAccount` to include delegation calls, authorization list, and funding token transfer in the Relay quote request ([#8967](https://github.com/MetaMask/core/pull/8967)) +- Add optional `recipient` field to `GetPaymentOverrideDataResponse` for specifying the funding token transfer recipient ([#8967](https://github.com/MetaMask/core/pull/8967)) + ## [23.1.0] ### Changed diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts index c20aa399dc..200c583479 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts @@ -181,9 +181,11 @@ describe('Relay Quotes Utils', () => { estimateGasMock, estimateGasBatchMock, findNetworkClientIdByChainIdMock, + getControllerStateMock, getDelegationTransactionMock, getGasFeeTokensMock, getKeyringControllerStateMock, + getPaymentOverrideDataMock, getRemoteFeatureFlagControllerStateMock, polymarketGetDepositWalletAddressMock, } = getMessengerMock(); @@ -2723,6 +2725,250 @@ describe('Relay Quotes Utils', () => { }); }); + describe('Money Account post-quote (processMoneyAccountPostQuote)', () => { + const TRANSACTION_ID_MOCK = 'money-account-tx-1'; + const MONEY_ACCOUNT_RECIPIENT_MOCK = + '0xaa00000000000000000000000000000000000001' as Hex; + const AMOUNT_HUMAN_MOCK = '100.5'; + const AMOUNT_RAW_MOCK = '100500000'; + const OVERRIDE_CALL_MOCK = { + to: '0xbb00000000000000000000000000000000000001' as Hex, + data: '0xcc' as Hex, + value: '0x0' as Hex, + }; + + const MONEY_ACCOUNT_TX_MOCK = { + ...TRANSACTION_META_MOCK, + id: TRANSACTION_ID_MOCK, + } as TransactionMeta; + + const MONEY_ACCOUNT_REQUEST_MOCK: QuoteRequest = { + ...QUOTE_REQUEST_MOCK, + isPostQuote: true, + paymentOverride: PaymentOverride.MoneyAccount, + }; + + function setupMoneyAccountMocks({ + amountHuman = AMOUNT_HUMAN_MOCK, + amountRaw = AMOUNT_RAW_MOCK, + overrideCalls = [OVERRIDE_CALL_MOCK], + recipient, + }: { + amountHuman?: string; + amountRaw?: string; + overrideCalls?: { to: Hex; data: Hex; value: Hex }[]; + recipient?: Hex; + } = {}): void { + getControllerStateMock.mockReturnValue({ + transactionData: { + [TRANSACTION_ID_MOCK]: { + tokens: [{ amountHuman, amountRaw }], + }, + }, + } as never); + + getPaymentOverrideDataMock.mockResolvedValue({ + calls: overrideCalls, + ...(recipient ? { recipient } : {}), + }); + } + + it('sets tradeType to EXACT_OUTPUT and amount from transactionData', async () => { + setupMoneyAccountMocks(); + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.tradeType).toBe('EXACT_OUTPUT'); + expect(body.amount).toBe(AMOUNT_RAW_MOCK); + }); + + it('includes token transfer and override calls in txs', async () => { + setupMoneyAccountMocks({ recipient: MONEY_ACCOUNT_RECIPIENT_MOCK }); + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.txs).toHaveLength(2); + expect(body.txs[0].to).toBe(QUOTE_REQUEST_MOCK.targetTokenAddress); + expect(body.txs[1].to).toBe(OVERRIDE_CALL_MOCK.to); + expect(body.txs[1].data).toBe(OVERRIDE_CALL_MOCK.data); + }); + + it('uses request.from as funding recipient when override provides no recipient', async () => { + setupMoneyAccountMocks(); + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.txs[0].data).toContain( + QUOTE_REQUEST_MOCK.from.slice(2).toLowerCase(), + ); + }); + + it('uses override recipient as funding recipient when provided', async () => { + setupMoneyAccountMocks({ recipient: MONEY_ACCOUNT_RECIPIENT_MOCK }); + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.txs[0].data).toContain( + MONEY_ACCOUNT_RECIPIENT_MOCK.slice(2).toLowerCase(), + ); + }); + + it('does not set txs when payment override returns no calls', async () => { + setupMoneyAccountMocks({ overrideCalls: [] }); + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.txs).toBeUndefined(); + expect(body.tradeType).not.toBe('EXACT_OUTPUT'); + }); + + it('normalizes authorization list from delegation', async () => { + setupMoneyAccountMocks(); + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.authorizationList).toStrictEqual([ + expect.objectContaining({ + chainId: 1, + nonce: 2, + yParity: 1, + }), + ]); + }); + + it('falls back to sourceTokenAmount when transactionData has no amountRaw', async () => { + getControllerStateMock.mockReturnValue({ + transactionData: { + [TRANSACTION_ID_MOCK]: { + tokens: [{ amountHuman: '10' }], + }, + }, + } as never); + + getPaymentOverrideDataMock.mockResolvedValue({ + calls: [OVERRIDE_CALL_MOCK], + }); + + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.amount).toBe(QUOTE_REQUEST_MOCK.sourceTokenAmount); + }); + + it('passes amountHuman and transactionData to getPaymentOverrideData', async () => { + setupMoneyAccountMocks(); + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + expect(getPaymentOverrideDataMock).toHaveBeenCalledWith( + expect.objectContaining({ + amount: AMOUNT_HUMAN_MOCK, + transaction: MONEY_ACCOUNT_TX_MOCK, + }), + ); + }); + }); + describe('HyperLiquid source (isHyperliquidSource)', () => { const HL_REQUEST: QuoteRequest = { ...QUOTE_REQUEST_MOCK, From 915f368cd649ea49bf00a426e1ab158bc976c231 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 2 Jun 2026 18:11:00 +0530 Subject: [PATCH 3/8] update --- .../src/strategy/relay/relay-quotes.test.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts index 200c583479..d6f1d5d8e0 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts @@ -2967,6 +2967,71 @@ describe('Relay Quotes Utils', () => { }), ); }); + + it('defaults amountHuman to 0 when transactionData has no tokens', async () => { + getControllerStateMock.mockReturnValue({ + transactionData: { + [TRANSACTION_ID_MOCK]: {}, + }, + } as never); + + getPaymentOverrideDataMock.mockResolvedValue({ + calls: [OVERRIDE_CALL_MOCK], + }); + + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + expect(getPaymentOverrideDataMock).toHaveBeenCalledWith( + expect.objectContaining({ amount: '0' }), + ); + }); + + it('defaults call value to 0x0 when override call omits value', async () => { + getControllerStateMock.mockReturnValue({ + transactionData: { + [TRANSACTION_ID_MOCK]: { + tokens: [ + { + amountHuman: AMOUNT_HUMAN_MOCK, + amountRaw: AMOUNT_RAW_MOCK, + }, + ], + }, + }, + } as never); + + getPaymentOverrideDataMock.mockResolvedValue({ + calls: [{ to: OVERRIDE_CALL_MOCK.to, data: OVERRIDE_CALL_MOCK.data }], + }); + + successfulFetchMock.mockResolvedValue({ + ok: true, + json: async () => QUOTE_MOCK, + } as never); + + await getRelayQuotes({ + accountSupports7702: true, + messenger, + requests: [MONEY_ACCOUNT_REQUEST_MOCK], + transaction: MONEY_ACCOUNT_TX_MOCK, + }); + + const body = JSON.parse( + successfulFetchMock.mock.calls[0][1]?.body as string, + ); + + expect(body.txs[1].value).toBe('0x0'); + }); }); describe('HyperLiquid source (isHyperliquidSource)', () => { From d017a0a357ac082f66e75efc21876d27b3789e00 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 3 Jun 2026 11:37:01 +0530 Subject: [PATCH 4/8] update --- .../src/strategy/relay/relay-quotes.test.ts | 5 +- .../src/strategy/relay/relay-quotes.ts | 55 +++++++++---------- .../transaction-pay-controller/src/types.ts | 3 + 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts index d6f1d5d8e0..f5212db1ae 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts @@ -2753,11 +2753,13 @@ describe('Relay Quotes Utils', () => { amountRaw = AMOUNT_RAW_MOCK, overrideCalls = [OVERRIDE_CALL_MOCK], recipient, + authorizationList = DELEGATION_RESULT_MOCK.authorizationList, }: { amountHuman?: string; amountRaw?: string; overrideCalls?: { to: Hex; data: Hex; value: Hex }[]; recipient?: Hex; + authorizationList?: typeof DELEGATION_RESULT_MOCK.authorizationList; } = {}): void { getControllerStateMock.mockReturnValue({ transactionData: { @@ -2770,6 +2772,7 @@ describe('Relay Quotes Utils', () => { getPaymentOverrideDataMock.mockResolvedValue({ calls: overrideCalls, ...(recipient ? { recipient } : {}), + ...(authorizationList ? { authorizationList } : {}), }); } @@ -2887,7 +2890,7 @@ describe('Relay Quotes Utils', () => { expect(body.tradeType).not.toBe('EXACT_OUTPUT'); }); - it('normalizes authorization list from delegation', async () => { + it('normalizes authorization list from payment override data', async () => { setupMoneyAccountMocks(); successfulFetchMock.mockResolvedValue({ ok: true, diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts index 242d3f902c..9daf7c3124 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts @@ -2,7 +2,10 @@ import { Interface } from '@ethersproject/abi'; import { toHex } from '@metamask/controller-utils'; -import type { TransactionMeta } from '@metamask/transaction-controller'; +import type { + AuthorizationList, + TransactionMeta, +} from '@metamask/transaction-controller'; import type { Hex } from '@metamask/utils'; import { createModuleLogger } from '@metamask/utils'; import { BigNumber } from 'bignumber.js'; @@ -291,6 +294,19 @@ async function getSingleQuote( } } +function normalizeAuthorizationList( + authorizationList: AuthorizationList | undefined, +) { + return authorizationList?.map((a) => ({ + ...a, + chainId: Number(a.chainId), + nonce: Number(a.nonce), + r: a.r as Hex, + s: a.s as Hex, + yParity: Number(a.yParity), + })); +} + /** * Add tranasction data to request body if needed. * @@ -340,18 +356,9 @@ async function processTransactions( { transaction }, ); - const normalizedAuthorizationList = delegation.authorizationList?.map( - (a) => ({ - ...a, - chainId: Number(a.chainId), - nonce: Number(a.nonce), - r: a.r as Hex, - s: a.s as Hex, - yParity: Number(a.yParity), - }), + requestBody.authorizationList = normalizeAuthorizationList( + delegation.authorizationList, ); - - requestBody.authorizationList = normalizedAuthorizationList; requestBody.tradeType = 'EXACT_OUTPUT'; const tokenTransferData = nestedTransactions?.find((nestedTx) => @@ -397,7 +404,11 @@ async function processMoneyAccountPostQuote( const transactionData = transactionDataList[transaction.id]; const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0'; - const { calls: overrideCalls, recipient } = await messenger.call( + const { + calls: overrideCalls, + recipient, + authorizationList, + } = await messenger.call( 'TransactionPayController:getPaymentOverrideData', { amount: amountHuman, @@ -415,23 +426,7 @@ async function processMoneyAccountPostQuote( transactionData?.tokens?.[0]?.amountRaw ?? request.sourceTokenAmount; const fundingRecipient = recipient ?? request.from; - const delegation = await messenger.call( - 'TransactionPayController:getDelegationTransaction', - { transaction }, - ); - - const normalizedAuthorizationList = delegation.authorizationList?.map( - (a) => ({ - ...a, - chainId: Number(a.chainId), - nonce: Number(a.nonce), - r: a.r as Hex, - s: a.s as Hex, - yParity: Number(a.yParity), - }), - ); - - requestBody.authorizationList = normalizedAuthorizationList; + requestBody.authorizationList = normalizeAuthorizationList(authorizationList); requestBody.tradeType = 'EXACT_OUTPUT'; requestBody.amount = amountRaw; diff --git a/packages/transaction-pay-controller/src/types.ts b/packages/transaction-pay-controller/src/types.ts index b611e401c5..574cc18b3f 100644 --- a/packages/transaction-pay-controller/src/types.ts +++ b/packages/transaction-pay-controller/src/types.ts @@ -170,6 +170,9 @@ export type GetPaymentOverrideDataResponse = { /** Optional recipient address for the funding token transfer. */ recipient?: Hex; + + /** Optional EIP-7702 authorization list from delegation. */ + authorizationList?: AuthorizationList; }; /** From d1988020ae056080455ae0e983fa1688e58f4d0f Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 3 Jun 2026 11:39:26 +0530 Subject: [PATCH 5/8] update --- .../src/strategy/relay/relay-quotes.ts | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts index 9daf7c3124..c29e8e1f9b 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts @@ -403,33 +403,28 @@ async function processMoneyAccountPostQuote( const transactionData = transactionDataList[transaction.id]; const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0'; + const amountRaw = + transactionData?.tokens?.[0]?.amountRaw ?? request.sourceTokenAmount; const { calls: overrideCalls, recipient, authorizationList, - } = await messenger.call( - 'TransactionPayController:getPaymentOverrideData', - { - amount: amountHuman, - transaction, - transactionData, - }, - ); + } = await messenger.call('TransactionPayController:getPaymentOverrideData', { + amount: amountHuman, + transaction, + transactionData, + }); if (!overrideCalls.length) { log('No payment override calls for money account post-quote'); return; } - const amountRaw = - transactionData?.tokens?.[0]?.amountRaw ?? request.sourceTokenAmount; const fundingRecipient = recipient ?? request.from; requestBody.authorizationList = normalizeAuthorizationList(authorizationList); requestBody.tradeType = 'EXACT_OUTPUT'; - requestBody.amount = amountRaw; - requestBody.txs = [ { to: request.targetTokenAddress, From c36ae2eb0cf67c10860ed4873360fef2b4f77462 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 3 Jun 2026 11:42:44 +0530 Subject: [PATCH 6/8] update --- .../src/strategy/relay/relay-quotes.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts index c29e8e1f9b..903bf4fc18 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts @@ -425,6 +425,7 @@ async function processMoneyAccountPostQuote( requestBody.authorizationList = normalizeAuthorizationList(authorizationList); requestBody.tradeType = 'EXACT_OUTPUT'; + requestBody.amount = amountRaw; requestBody.txs = [ { to: request.targetTokenAddress, From 24c33f4ccffb8eff9afd1b7cf6975fdf5571b666 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 3 Jun 2026 11:49:57 +0530 Subject: [PATCH 7/8] update --- .../src/strategy/relay/relay-quotes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts index 903bf4fc18..9dcfe9f5fb 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts @@ -296,7 +296,7 @@ async function getSingleQuote( function normalizeAuthorizationList( authorizationList: AuthorizationList | undefined, -) { +): RelayQuoteRequest['authorizationList'] { return authorizationList?.map((a) => ({ ...a, chainId: Number(a.chainId), From 13ecb54df16684ff73d2c99529dba9c70c411eea Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Thu, 4 Jun 2026 16:15:27 +0530 Subject: [PATCH 8/8] update --- .../transaction-pay-controller/CHANGELOG.md | 2 +- .../src/strategy/relay/relay-quotes.test.ts | 40 ++----------------- .../src/strategy/relay/relay-quotes.ts | 6 +-- 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/packages/transaction-pay-controller/CHANGELOG.md b/packages/transaction-pay-controller/CHANGELOG.md index 7f5121fc15..dc6fdedf17 100644 --- a/packages/transaction-pay-controller/CHANGELOG.md +++ b/packages/transaction-pay-controller/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Adding processing for postQuote transactions with paymentProvider defined ([#8967](https://github.com/MetaMask/core/pull/8967)) +- Adding processing for postQuote transactions with paymentOverride defined ([#8967](https://github.com/MetaMask/core/pull/8967)) - Add `@metamask/keyring-controller` `^26.0.0` as a dependency ([#8972](https://github.com/MetaMask/core/pull/8972)) - The package was already imported at runtime by `src/strategy/relay/hyperliquid-withdraw.ts` but wasn't declared in `package.json`; this PR fixes the omission. diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts index f5212db1ae..9b1639f7d3 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.test.ts @@ -2750,13 +2750,11 @@ describe('Relay Quotes Utils', () => { function setupMoneyAccountMocks({ amountHuman = AMOUNT_HUMAN_MOCK, - amountRaw = AMOUNT_RAW_MOCK, overrideCalls = [OVERRIDE_CALL_MOCK], recipient, authorizationList = DELEGATION_RESULT_MOCK.authorizationList, }: { amountHuman?: string; - amountRaw?: string; overrideCalls?: { to: Hex; data: Hex; value: Hex }[]; recipient?: Hex; authorizationList?: typeof DELEGATION_RESULT_MOCK.authorizationList; @@ -2764,7 +2762,7 @@ describe('Relay Quotes Utils', () => { getControllerStateMock.mockReturnValue({ transactionData: { [TRANSACTION_ID_MOCK]: { - tokens: [{ amountHuman, amountRaw }], + tokens: [{ amountHuman }], }, }, } as never); @@ -2776,7 +2774,7 @@ describe('Relay Quotes Utils', () => { }); } - it('sets tradeType to EXACT_OUTPUT and amount from transactionData', async () => { + it('sets tradeType to EXACT_OUTPUT and amount from request sourceTokenAmount', async () => { setupMoneyAccountMocks(); successfulFetchMock.mockResolvedValue({ ok: true, @@ -2795,7 +2793,7 @@ describe('Relay Quotes Utils', () => { ); expect(body.tradeType).toBe('EXACT_OUTPUT'); - expect(body.amount).toBe(AMOUNT_RAW_MOCK); + expect(body.amount).toBe(QUOTE_REQUEST_MOCK.sourceTokenAmount); }); it('includes token transfer and override calls in txs', async () => { @@ -2917,38 +2915,6 @@ describe('Relay Quotes Utils', () => { ]); }); - it('falls back to sourceTokenAmount when transactionData has no amountRaw', async () => { - getControllerStateMock.mockReturnValue({ - transactionData: { - [TRANSACTION_ID_MOCK]: { - tokens: [{ amountHuman: '10' }], - }, - }, - } as never); - - getPaymentOverrideDataMock.mockResolvedValue({ - calls: [OVERRIDE_CALL_MOCK], - }); - - successfulFetchMock.mockResolvedValue({ - ok: true, - json: async () => QUOTE_MOCK, - } as never); - - await getRelayQuotes({ - accountSupports7702: true, - messenger, - requests: [MONEY_ACCOUNT_REQUEST_MOCK], - transaction: MONEY_ACCOUNT_TX_MOCK, - }); - - const body = JSON.parse( - successfulFetchMock.mock.calls[0][1]?.body as string, - ); - - expect(body.amount).toBe(QUOTE_REQUEST_MOCK.sourceTokenAmount); - }); - it('passes amountHuman and transactionData to getPaymentOverrideData', async () => { setupMoneyAccountMocks(); successfulFetchMock.mockResolvedValue({ diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts index 9dcfe9f5fb..3ee17c4af7 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts @@ -403,8 +403,6 @@ async function processMoneyAccountPostQuote( const transactionData = transactionDataList[transaction.id]; const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0'; - const amountRaw = - transactionData?.tokens?.[0]?.amountRaw ?? request.sourceTokenAmount; const { calls: overrideCalls, @@ -425,11 +423,11 @@ async function processMoneyAccountPostQuote( requestBody.authorizationList = normalizeAuthorizationList(authorizationList); requestBody.tradeType = 'EXACT_OUTPUT'; - requestBody.amount = amountRaw; + requestBody.amount = request.sourceTokenAmount; requestBody.txs = [ { to: request.targetTokenAddress, - data: buildTokenTransferData(fundingRecipient, amountRaw), + data: buildTokenTransferData(fundingRecipient, request.sourceTokenAmount), value: '0x0', }, ...overrideCalls.map((call) => ({