Repository navigation
refactor(transaction-pay-controller): consolidate origin gas payment resolution - #10404
Merged
Merged
Conversation
matthewwalsh0
force-pushed
the
refactor/transaction-pay-gas-payment
branch
from
September 23, 2026 16:10
0a6e11f to
930a36c
Compare
matthewwalsh0
changed the base branch from
main
to
feat/pay-server-exact-output
September 23, 2026 16:10
matthewwalsh0
force-pushed
the
refactor/transaction-pay-gas-payment
branch
2 times, most recently
from
September 25, 2026 12:02
3a95931 to
ddbc208
Compare
matthewwalsh0
changed the base branch from
main
to
perf/transaction-pay-direct-assets
September 25, 2026 12:02
3 of 4 tasks
matthewwalsh0
force-pushed
the
perf/transaction-pay-direct-assets
branch
from
September 28, 2026 09:42
ff2ab05 to
3d5bb62
Compare
matthewwalsh0
force-pushed
the
refactor/transaction-pay-gas-payment
branch
from
September 28, 2026 16:59
2229830 to
93984a0
Compare
matthewwalsh0
force-pushed
the
refactor/transaction-pay-gas-payment
branch
from
September 29, 2026 12:19
93984a0 to
71ec7a0
Compare
matthewwalsh0
added a commit
that referenced
this pull request
Sep 30, 2026
…eased The rebase onto the 30.0.0 release re-filed the #10404 entry under the published 29.2.2 heading, describing a change that is not in that release.
matthewwalsh0
added a commit
that referenced
this pull request
Sep 30, 2026
…eased The rebase onto the 30.0.0 release re-filed the #10404 entry under the published 29.2.2 heading, describing a change that is not in that release.
matthewwalsh0
force-pushed
the
refactor/transaction-pay-gas-payment
branch
from
September 30, 2026 15:45
fc6005d to
b868774
Compare
…resolution Replace `utils/gas-station.ts` with `utils/gas-payment.ts`, which owns both quote-time gas-station cost estimation and submit-time payment-mode resolution. Each strategy previously re-derived whether the origin gas fee should be paid from the source token, duplicating native-balance checks, gas-station eligibility probes and sponsorship predicates across the Across, Relay and Server strategies. Those modules now delegate to `resolveGasStationCost`, `resolveGasPayment` and `shouldUseGasStation`. This also unifies the Relay single-transaction and batch submit paths, which had diverged: the batch builder set `gasFeeToken` without checking sponsorship, whereas the single-transaction path did. Internal only; none of this surface is exported from the package index.
…route Relay delegation through the resolver Fold the Relay execute and HyperLiquid withdrawal branches into `resolveGasPayment` via `isDelegated`, so "a relayer pays origin gas" is decided in one place rather than being hand-rolled per flow. The module already documented HyperLiquid withdrawals as a delegation case, so leaving that branch outside the resolver contradicted its stated contract. Both branches previously returned identical values and the resolver short-circuits on `isDelegated` before evaluating sponsorship, so the precedence and results are unchanged; the two log messages collapse into one carrying the flow as structured fields. Also stop exporting `GasPaymentRequest`, `GasStationCost`, `GasStationCostRequest`, `GasStationStepData` and `SponsorshipRequest`, none of which are referenced outside the module.
…when origin gas uses the source token Only the across strategy set `excludeNativeTokenForFee`, so for the relay and server strategies the `TransactionController` re-checked the native balance at publish time and silently dropped the gas fee token, charging the user in native token instead of the quoted source token. Resolve the flag centrally in `resolveGasPayment` and propagate it from every strategy that submits via the `TransactionController`, so the fee shown in the quote is the fee the user is charged. Also route the server strategy's source network cost through the shared resolver so sponsored same-chain routes zero their fees via the gas station hook, and add `logGasPaymentOutcome` to surface cases where the gas fee token is still dropped before publish.
The entry was added under the already-released 29.2.0 heading.
…t is decided `resolveGasPayment` runs twice: at quote time to estimate the fee, and at submit time to build the `TransactionController` options. At quote time the gas station has not been consulted, so an absent `isSourceGasFeeToken` collapses the mode to `Native` by default rather than by decision. Logging it announced that the user pays gas in native token while the source token was still in play. Log only when `isSourceGasFeeToken` is present, i.e. at submit time.
…eased The rebase onto the 30.0.0 release re-filed the #10404 entry under the published 29.2.2 heading, describing a change that is not in that release.
…e gas payment split Both suppression files key on file path, so renaming `gas-station.test.ts` to `gas-payment.test.ts` orphaned its oxlint entry and surfaced the carried-over mock violations as new. Move the entry to the new path and drop the stale one. Also raise the `server-quotes.test.ts` tsc counts to cover the request literals added by the new tests. These omit the required `from`, matching the 32 call sites already suppressed in that file; supplying a value would change what the tests feed the code under test.
matthewwalsh0
force-pushed
the
refactor/transaction-pay-gas-payment
branch
from
October 1, 2026 12:31
d062d63 to
f58e3a8
Compare
matthewwalsh0
marked this pull request as ready for review
October 1, 2026 12:36
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 f58e3a8. Configure here.
OGPoyraz
approved these changes
Oct 5, 2026
Naz-Ovh
pushed a commit
to 0x-fork/metamask-core
that referenced
this pull request
Oct 10, 2026
## Explanation Scoped release so clients can pick up MetaMask#10749. Monorepo release **1320.0.0**, following merged [Release/1319.0.0](MetaMask#10756). - **`@metamask/ramps-controller` 26.3.0 → 27.0.0** (major). `hydrateVbaOnboarding` is a read: it no longer signs a wallet, posts a self-hosted address, creates an autoramp, or starts the KYC poll. Callers create an autoramp with `createAutoramp(buildMusdAutorampRequest(...))`. Messenger now requires `KycController:readSessionStatus` and `KycController:fetchSessionStatusOnce`. Also includes the unpublished MetaMask#10743 additions (`needs_source_currency`, `buildMusdAutorampRequest`) and the profile-sync range bump to `^34.0.2`. - **`@metamask/kyc-controller` 0.6.1 → 0.7.0** (minor, matching earlier 0.x breaking bumps). Publishes `readSessionStatus` and `fetchSessionStatusOnce` from MetaMask#10749. The same version also ships the unpublished breaking `aal2Token` requirement on `startSession` / `createUkycSession` (MetaMask#10632) and the 72-hour capability token (MetaMask#10679). - **`@metamask/transaction-pay-controller` 30.0.1 → 30.0.2** (patch). Published because ramps-controller is a major and this is its only dependent. The range moves to `^27.0.0`. This version also includes the unpublished gas-fee fix from MetaMask#10404. Other packages with unreleased changes are deferred. `ramps-controller` keeps its existing dependency ranges, including `@metamask/profile-sync-controller` at `^34.0.2` from MetaMask#10756. ## References - Ships MetaMask#10749 - Also publishes unpublished changes already on main: MetaMask#10743, MetaMask#10632, MetaMask#10679, MetaMask#10404, MetaMask#10752, MetaMask#10756 ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > The release ships major ramps-controller and breaking KYC/VBA onboarding API changes; this PR only versions and documents them, but client upgrades must adopt new messenger delegations and onboarding call patterns. > > **Overview** > Cuts **monorepo release 1320.0.0** by moving unreleased changelog notes into versioned sections and bumping published package versions—no new runtime code in this diff. > > **`@metamask/ramps-controller` 27.0.0** (major) documents shipping MetaMask#10749/MetaMask#10743: `hydrateVbaOnboarding` becomes a read-only snapshot (wallet sign, registration POST, autoramp creation, and KYC polling move to callers), new persisted wallet-registration state and `needs_wallet_registration` / `needs_source_currency` statuses, and messenger now requires `KycController:readSessionStatus` and `KycController:fetchSessionStatusOnce`. > > **`@metamask/kyc-controller` 0.7.0** publishes those KYC actions plus breaking **`aal2Token`** requirements on UKYC session creation/`startSession`. > > **`@metamask/transaction-pay-controller` 30.0.2** updates its dependency range to **`@metamask/ramps-controller` ^27.0.0** and records the ramps bump in its changelog (along with fixes already on main such as MetaMask#10404). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6cb8531. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Oct 12, 2026
…rget calls (#10501) ## Explanation Server quote providers either execute the target calls or decline the request, and the server strategy declined non-atomic requests outright, so flows whose calls no provider can run were unsupported. - Server quote requests now set `supportsDeferredCalls`, so a provider that can't execute the calls returns a funds-only quote (`callsDeferred: true`) instead of declining. - These quotes are flagged `requiresSecondLeg`, and the calls are submitted separately on the target chain once the funds settle. - The server strategy now accepts non-atomic requests. - Every strategy (Relay, Server, Fiat) submits its second leg through a shared `submitSecondLeg` util, which: - Reads the settled amount and block from the settlement transaction's transfer logs. - Throws when there is no settlement hash or no matching transfer, rather than falling back to the quote minimum or the fiat order amount. - Applies CHOMP race handling for Money Account deposits, which previously only ran for fiat. - Non-atomic quotes now settle funds on the account that executes the calls rather than the funding account, shared by the Relay and Server strategies. - `ma-vault-deposit` is removed in favour of the shared util. - Server provider names are typed as plain strings, so new backend providers need no client change. ## References Stacked on #10404. ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **High Risk** > Changes multi-leg settlement, amount resolution, and completion semantics across Relay, Server, and Fiat paths; stricter on-chain reads can fail flows that previously fell back to provider-reported amounts. > > **Overview** > Adds **non-atomic pay flows** where a quote may only move funds and the target calls run afterward on the chain where they settled. > > Quotes can now carry **`requiresSecondLeg`** (driven by server `callsDeferred` / `supportsDeferredCalls`, explicit `atomic: false`, etc.). **Relay**, **Server**, and **Fiat** (including direct mUSD vault) all submit that follow-up through shared **`submitSecondLeg`**, replacing **`ma-vault-deposit`**. Settlement amounts come **only from on-chain transfer logs** via a settlement hash; missing hash or transfer **fails** instead of using ramp `cryptoAmount` or quote minimums. > > **Server** quotes settle on the **executing account** (`txParams.from`) vs the payer, Money Account post-quote drops the forwarding transfer, and **non-atomic** requests are allowed. **`isIntentComplete`** is set **after** a successful second leg (Relay/Server). Relay **zeros origin network fees** for Polymarket deposit-wallet Predict withdraws. CHOMP race recovery moves into **`withChompRecovery`** around second-leg vault deposits. Server provider IDs are plain **strings** instead of an enum. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6244985. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Explanation
Origin gas payment was decided independently inside each strategy. The Across, Relay and Server quote/submit modules each re-derived whether the origin gas fee could be paid from the source token, duplicating native-balance checks, gas-station eligibility probes and sponsorship predicates — and they did not always agree with one another.
utils/gas-station.tsis replaced byutils/gas-payment.ts, which owns the whole decision:resolveGasStationCostfor quote-time cost estimation,resolveGasPaymentfor submit-time payment-mode resolution, andshouldUseGasStationfor the "is the gas station both needed and available" predicate.isDelegatedinput, rather than each carrying its own bespoke branch.gasFeeTokendirectly from the quote without consulting sponsorship, whereas the single-transaction path did consult it.One reviewer-visible behaviour change falls out of that last point: a Relay batch request now omits
gasFeeTokenwhen gas is sponsored, matching what the single-transaction path already did. No existing test exercised the sponsored-plus-batch combination, so this is not covered by a test-diff.Otherwise this is a pure refactor, covered by the existing suites passing unchanged. Nothing touched here is exported from the package index, so there is no consumer-facing change and no changelog entry.
References
Checklist
Note
Medium Risk
Changes how origin gas is resolved and billed across all pay strategies at quote and submit time, including TransactionController options that affect what users are charged.
Overview
Introduces
utils/gas-payment.tsin place ofgas-station.ts, centralizing quote-time gas-station pricing (resolveGasStationCost), submit-time mode selection (resolveGasPayment), and post-submit verification (logGasPaymentOutcome). Across, Relay, and Server quote/submit paths now share one priority order: delegation → sponsored → source-token gas fee → native.User-visible fix: when a quote prices origin gas in the source token, submit now always passes
excludeNativeTokenForFee: truewithgasFeeToken(Relay and Server previously omitted this, soTransactionControllercould drop the fee token at publish and charge native instead). Sponsored same-chain routes and relayer/HyperLiquid “no user origin gas” cases are handled through the same resolver rather than duplicated branches.Relay batch submit now aligns with single-tx submit by suppressing
gasFeeTokenwhen gas is sponsored.gas-station.tsis removed; tests move togas-payment.test.tswith expanded server/relay coverage.Reviewed by Cursor Bugbot for commit f58e3a8. Bugbot is set up for automated code reviews on this repo. Configure here.