Skip to content

feat(transaction-controller): prepare transactions for approval - #10109

Open
pedronfigueiredo wants to merge 3 commits into
mainfrom
pnf/canonical-transaction-approval-preparation-handoff-implementation
Open

feat(transaction-controller): prepare transactions for approval#10109
pedronfigueiredo wants to merge 3 commits into
mainfrom
pnf/canonical-transaction-approval-preparation-handoff-implementation

Conversation

@pedronfigueiredo

@pedronfigueiredo pedronfigueiredo commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Related pull requests

Summary

  • add a pure, exported prepareTransactionForApproval API to @metamask/transaction-controller
  • normalize isGasFeeSponsored and isExternalSign from explicit sponsorship and publication-path facts without mutating the input
  • cover the complete 32-row boolean truth table, required-path rejection, stale external-sign cleanup, unrelated metadata preservation, immutability, and idempotence
  • keep gas-fee-token batch construction and checkGasFeeTokenBeforePublish behavior unchanged

Public API

prepareTransactionForApproval({
  transactionMeta,
  sponsorship: {
    available,
    supported,
    optedOut,
    required,
  },
  signing: {
    externalSigningSupported,
  },
});

The package also exports:

  • PrepareTransactionForApprovalRequest
  • PrepareTransactionForApprovalResult
  • TransactionApprovalSponsorshipFacts
  • TransactionApprovalSigningFacts
  • TransactionApprovalSigningMode

Behavior decisions

  • isExternalSign describes the selected publication path, not the account alone. When true, TransactionController skips local keyring signing.
  • Sponsorship does not imply external signing. A valid sponsored Smart Transaction or similar path may remain locally signed.
  • Sponsorship availability is supplied explicitly, typically from the latest simulation. Clients remain responsible for actual account and publication-path capability discovery.
  • Explicit sponsorship opt-out is authoritative, including for product-required flows.
  • Product-required sponsorship is supplied explicitly rather than inferred from TransactionType.
  • A required, non-opted-out transaction with no available sponsored publication path throws during preparation rather than falling back to potentially invalid parent publication.
  • checkGasFeeTokenBeforePublish remains authoritative for final native-balance validation, token-quote refresh, fee-token selection fallback, nonce removal, and publication-time external-signing selection.

Client integration

Extension and Mobile adapters should provide final publication-path capability rather than only lower-level account capability:

  • available: current simulation/caller sponsorship result
  • supported: whether optional sponsorship works for the actual account and selected path
  • required: explicit product-domain requirement
  • externalSigningSupported: whether the selected sponsored path publishes without local keyring signing

This PR intentionally does not move gas-fee-token batch construction, UI, navigation, hardware transport, approval dispatch, or publication behavior into Core.

Validation

  • yarn workspace @metamask/transaction-controller run jest --no-coverage src/utils/prepare-transaction-for-approval.test.ts src/utils/gas-fee-tokens.test.ts src/TransactionController.test.ts — 306 tests passed, 4 snapshots passed
  • yarn build — passed
  • yarn workspace @metamask/transaction-controller run build — passed
  • yarn lint:tsc — passed
  • yarn lint:misc --check — passed
  • yarn workspace @metamask/transaction-controller run changelog:validate — passed

Note

Medium Risk
The helper directly drives execution-sensitive approval flags (sponsorship and local vs external signing); incorrect caller-supplied facts or integration mistakes could mis-publish transactions, though required-path failures fail closed with an error.

Overview
Adds a pure, exported prepareTransactionForApproval API (plus request/result and sponsorship/signing fact types) so clients can normalize approval-time isGasFeeSponsored and isExternalSign from explicit simulation and publication-path facts without mutating the input TransactionMeta.

Sponsorship is enabled when it is available, the user has not opted out, and either optional sponsorship is supported or a required flow can use an externally signable sponsored path; external signing is chosen only when sponsorship is enabled and the path supports it (sponsored local signing remains possible). If sponsorship is required, not opted out, and no valid sponsored path exists, preparation throws instead of falling back to unsponsored publication.

Tests cover the full boolean decision matrix, required-path rejection, immutability, unrelated field preservation, and idempotence. Gas-fee token handling and checkGasFeeTokenBeforePublish are unchanged and stay outside this helper.

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

@pedronfigueiredo
pedronfigueiredo requested review from a team as code owners September 4, 2026 10:26
@matthewwalsh0
matthewwalsh0 requested a review from jpuri September 4, 2026 11:01
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.

2 participants