Skip to content

feat(transaction-pay-controller)!: send post-quote quotes from the transaction account - #10992

Open
dan437 wants to merge 22 commits into
mainfrom
cursor/account-override-recipient-only-a87f
Open

dan437 wants to merge 22 commits into
mainfrom
cursor/account-override-recipient-only-a87f

Conversation

@dan437

@dan437 dan437 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Explanation

In post-quote flows, accountOverride was both the quote sender and the output recipient, so a Money Account withdrawal to a hardware wallet had to be signed by the hardware wallet even though the Money Account holds the funds.

Post-quote quotes are now always requested and submitted from the transaction's own from. Post-quote requests carry accountOverride, which Relay and Server pay through the shared recipient resolution from #10887 and Across pays directly. This needs no new config property. Non-post-quote flows are unchanged.

This is breaking for clients that move a withdrawal's funds to accountOverride before the Relay deposit: they must leave the funds on the transaction's from. For example, a Money Account withdrawal that needs a quote must no longer transfer the withdrawn mUSD to accountOverride in its nested calls.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them
Open in Web Open in Cursor 

Note

Medium Risk
Breaking contract for post-quote fund placement and signing; wrong client nesting could leave quotes unfunded or sent from the wrong account.

Reviewed by Cursor Bugbot for commit e1c2e9e. Bugbot is set up for automated code reviews on this repo. Configure here.

Post-quote flows use accountOverride as both the quote sender and the
output recipient. A Money Account withdrawal to a hardware wallet then
quotes and submits the Relay deposit from the hardware account, so the
device must sign, even though the Money Account holds the funds.

Add an opt-in isAccountOverrideRecipientOnly config. When set on a
post-quote transaction, quotes are requested and submitted from the
transaction's own from, and accountOverride is only the Relay
recipient. The payment token balance is still read for accountOverride.
@dan437
dan437 marked this pull request as ready for review October 22, 2026 12:01
@dan437
dan437 requested review from a team as code owners October 22, 2026 12:01
@dan437
dan437 deployed to default-branch October 22, 2026 12:01 — with GitHub Actions Active
matthewwalsh0 and others added 2 commits October 22, 2026 20:45
…de-recipient-only-a87f

# Conflicts:
#	packages/transaction-pay-controller/CHANGELOG.md

Co-authored-by: Daniel <[email protected]>
Comment thread packages/transaction-pay-controller/src/utils/quotes.ts Outdated
const recipient =
isPostQuote && isAccountOverrideRecipientOnly ? accountOverride : undefined;

const quoteFrom = recipient ? (transaction.txParams.from as Hex) : from;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we can avoid being so explicit with the new config property which adds complexity.

The Perps withdraw goes via signatures, so no gas needed, so from can be Perps account.

Predict withdraw goes via the Polymarket relayer so also gasless so from should be fine as Polymarket account?

And then a normal money account withdraw is sponsored as on Monad so normal from should always be fine?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder to test the legacy Predict withdraw flow via Safe account also.

…de-recipient-only-a87f

# Conflicts:
#	packages/transaction-pay-controller/CHANGELOG.md
Recipient selection moves into the strategies with #10887, so the
explicit config property is no longer needed.
…/account-override-recipient-only-a87f

# Conflicts:
#	packages/transaction-pay-controller/CHANGELOG.md
…ansaction account

Post-quote quotes are now requested and submitted from the transaction's
own from, and the shared quote recipient resolution pays accountOverride.
An account that cannot sign, such as a hardware wallet, can then receive
a withdrawal without a dedicated config property.
@cursor cursor Bot changed the title feat(transaction-pay-controller): add isAccountOverrideRecipientOnly feat(transaction-pay-controller)!: send post-quote quotes from the transaction account Oct 29, 2026
…de-recipient-only-a87f

# Conflicts:
#	oxlint-suppressions.json
#	packages/transaction-pay-controller/src/utils/quote-recipient.test.ts
#	packages/transaction-pay-controller/src/utils/quote-recipient.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f34790e. Configure here.

Comment thread packages/transaction-pay-controller/src/utils/quotes.ts Outdated
…-quote withdrawals

Across post-quote quotes now use the shared post-quote recipient lookup, so they pay `accountOverride` like Relay and Server instead of the sending account.
…de-recipient-only-a87f

# Conflicts:
#	packages/transaction-pay-controller/CHANGELOG.md

### Changed

- **BREAKING:** Request and submit post-quote quotes from the transaction's own `from`, so `accountOverride` only receives the output and never signs ([#10992](https://github.com/MetaMask/core/pull/10992))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this breaking? What change is needed in the client?

const from = accountOverride ?? (transaction.txParams.from as Hex);

// Post-quote output goes to `accountOverride`, so the funds holder sends.
const quoteFrom = isPostQuote ? (transaction.txParams.from as Hex) : from;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than defining a from and a quoteFrom, could we define a local function like getFrom that early returns for better readability?

'TransactionPayController:getState',
);

return transactionData[transaction.id]?.accountOverride ?? request.from;

@matthewwalsh0 matthewwalsh0 Oct 30, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're now explicitly getting the account override from the messenger, as it's not always encapsulated behind the from, then should we simply pass the accountOverride explicitly into QuoteRequest and the above resolveQuoteRecipient so it's more readable?

Then we wouldn't need to use request.from at all but make the logic clearer when we're using accountOverride?

return {
actions: [],
recipient,
recipient: getPostQuoteRecipient({ messenger, request, transaction }),

@matthewwalsh0 matthewwalsh0 Oct 30, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the other comment, this could just become request.accountOverride and we wouldn't need to export a getPostQuoteRecipient function?

…From

Replace the `from` and `quoteFrom` pair in `updateQuotes` with a local `getFrom` helper that returns early for post-quote flows.
…ote quote requests

Add `accountOverride` to `QuoteRequest` for post-quote flows, so `resolveQuoteRecipient` and the Across post-quote destination read it from the request instead of looking it up through the messenger. This removes `getPostQuoteRecipient`.
…t-quote senders

Name the concrete client change behind the breaking entry: a Money Account withdrawal that needs a quote must keep the withdrawn mUSD on the transaction's `from`.

This branch was successfully deployed

1 active (outdated) deployment
default-branch — b16cf178 Deployed Oct 22, 2026 by dan437 via Determine whether this PR is a release PR #5862
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants