diff --git a/packages/transaction-pay-controller/CHANGELOG.md b/packages/transaction-pay-controller/CHANGELOG.md index cd90bf6e15..76bdc5548b 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 + +- Fix cross-chain Money Account deposits (e.g. Predict withdraw to a Money Account) reverting with `InvalidEOASignature()` (`0x3db6791c`) by only prepending the payment override onto the source Relay execute batch for same-chain flows ([#9439](https://github.com/MetaMask/core/pull/9439)) + ## [24.0.1] ### Changed @@ -15,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bump `@metamask/assets-controllers` from `^109.3.1` to `^109.4.0` ([#9450](https://github.com/MetaMask/core/pull/9450)) - Bump `@metamask/transaction-controller` from `^68.3.0` to `^68.4.0` ([#9456](https://github.com/MetaMask/core/pull/9456)) +### Fixed + +- Fix cross-chain Money Account deposits (e.g. Predict withdraw to a Money Account) reverting with `InvalidEOASignature()` (`0x3db6791c`) by only prepending the payment override onto the source Relay execute batch for same-chain flows ([#9449](https://github.com/MetaMask/core/pull/9449)) + ## [24.0.0] ### Added diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-submit.test.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-submit.test.ts index 395c4a75bb..aa3f6e2c5e 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-submit.test.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-submit.test.ts @@ -966,6 +966,12 @@ describe('Relay Submit Utils', () => { [ORIGINAL_TRANSACTION_ID_MOCK]: TRANSACTION_DATA_MOCK, }, }); + + // The payment override is only prepended onto the source execute batch + // for same-chain flows, so align the quote's source and destination + // chains for these override-prepend assertions. + request.quotes[0].original.details.currencyOut.currency.chainId = + request.quotes[0].original.details.currencyIn.currency.chainId; }); it('prepends override tx params to submit batch', async () => { @@ -999,6 +1005,20 @@ describe('Relay Submit Utils', () => { expect(getPaymentOverrideDataMock).not.toHaveBeenCalled(); }); + it('does not prepend override for cross-chain flows', async () => { + request.quotes[0].request.paymentOverride = + PaymentOverride.MoneyAccount; + request.quotes[0].original.details.currencyIn.currency.chainId = 137; + request.quotes[0].original.details.currencyOut.currency.chainId = 143; + getPaymentOverrideDataMock.mockResolvedValue({ + calls: [PAYMENT_OVERRIDE_TX_MOCK], + }); + + await submitRelayQuotes(request); + + expect(getPaymentOverrideDataMock).not.toHaveBeenCalled(); + }); + it('does not prepend when callback returns empty array', async () => { request.quotes[0].request.paymentOverride = PaymentOverride.MoneyAccount; diff --git a/packages/transaction-pay-controller/src/strategy/relay/relay-submit.ts b/packages/transaction-pay-controller/src/strategy/relay/relay-submit.ts index 5f7da9bbec..ed3142a52a 100644 --- a/packages/transaction-pay-controller/src/strategy/relay/relay-submit.ts +++ b/packages/transaction-pay-controller/src/strategy/relay/relay-submit.ts @@ -430,9 +430,20 @@ async function submitTransactions( quote.request.from.toLowerCase() !== (transaction.txParams.from as Hex).toLowerCase(); + // Only prepend the payment override onto the source execute batch for + // same-chain flows. For cross-chain flows (e.g. Predict withdraw on Polygon + // depositing to a Money Account on Monad) the deposit is carried in the relay + // quote's destination txs[] and runs on the destination chain; its delegation + // is signed for the destination chainId, so redeeming it inside the + // source-chain batch recovers a wrong signer and reverts. In that case we + // fall through and prepend the original (e.g. Predict withdraw) tx instead. + const isSameChainOverride = + quote.original.details.currencyIn.currency.chainId === + quote.original.details.currencyOut.currency.chainId; + let allParams = normalizedParams; - if (quote.request.paymentOverride) { + if (quote.request.paymentOverride && isSameChainOverride) { const { transactionData } = messenger.call( 'TransactionPayController:getState', );