Conversation
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/max-amount-with-gas-station-fallback.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/max-amount-with-gas-station-fallback.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/max-amount-with-gas-station-fallback.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/max-amount-with-gas-station-fallback.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/max-amount-with-gas-station-fallback.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/types.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-quotes.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/gas-station.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/max-amount-with-gas-station-fallback.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Outdated
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Show resolved
Hide resolved
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Show resolved
Hide resolved
| return primaryEstimate; | ||
| } | ||
|
|
||
| const probeCost = await getProbeGasCostInSourceTokenRaw(context); |
There was a problem hiding this comment.
How can the above fail?
If no gas fee tokens are returned from the original quote, then should we not just fallback at that point?
Why would it help to try get another quote with a smaller amount?
There was a problem hiding this comment.
From testing, at full max, fee-token estimation/simulation can return no usable gas-fee-token result (or no match) because the transaction is too tight at the balance boundary.
With a smaller probe amount, the same route often becomes estimable and returns either:
isSourceGasFeeToken directly, or a usable getGasFeeTokens result we can normalize.
So this is a recovery path, not a bypass. It lets us rescue cases that would otherwise unnecessarily fall back.
There was a problem hiding this comment.
You're absolutely right, I'm missing the obvious, we will never get gas fee tokens in the original request since it's max so there is no remaining balance post-transaction for gas.
In that case, can we save time and skip the original identical request and go straight to the probe?
There was a problem hiding this comment.
Great question. We’re not doing an extra "original identical" quote request here. At this point, phase-1 is already fetched (and needed for fallback + phase-1/phase-2 validation), so we first try to derive gas cost from that existing quote (isSourceGasFeeToken or getGasFeeTokens via gas-station).
Probe is intentionally a recovery fallback when that estimate is unavailable. Going straight to probe would add an extra quote call for all max requests (typically 2 calls to 3), increasing latency/failure surface, while many flows already succeed without probing.
Should we add a short inline comment in getInitialGasCostEstimate to make this ordering explicit?
packages/transaction-pay-controller/src/strategy/relay/relay-max-gas-station.ts
Outdated
Show resolved
Hide resolved
| return primaryEstimate; | ||
| } | ||
|
|
||
| const probeCost = await getProbeGasCostInSourceTokenRaw(context); |
There was a problem hiding this comment.
You're absolutely right, I'm missing the obvious, we will never get gas fee tokens in the original request since it's max so there is no remaining balance post-transaction for gas.
In that case, can we save time and skip the original identical request and go straight to the probe?
| .multipliedBy(PROBE_AMOUNT_PERCENTAGE) | ||
| .integerValue(BigNumber.ROUND_FLOOR); | ||
|
|
||
| const targetProbeRaw = new BigNumber(1).shiftedBy( |
There was a problem hiding this comment.
Minor, could we call this minimumProbeRaw for readability?
With a comment such as 0.01 Tokens?
Explanation
This PR introduces a dedicated max-amount gas-station fallback flow for Relay, extracted into a focused helper and wired into quote orchestration. The goal was fixing max-amount mUSD conversion failures caused by gas-fee-token estimation dead-ends but in fact it fixes for any kind of intent.
The helper (
getMaxAmountQuoteWithGasStationFallback) now implements a clear two-phase flow with explicit fallback points:maxGaslessEnabledisfalse.PROBE_AMOUNT_PERCENTAGE = 0.25) to discover gas fee token + amount.TransactionController:getGasFeeTokensandcalculateGasFeeTokenCostto normalize source-token gas fee amount.twoPhaseQuoteForMaxAmount = trueand return phase-2.References
gasless.max.mov
Checklist
Note
Medium Risk
Changes Relay quote selection and gas-fee-token estimation for
isMaxAmountflows, which can affect how much users spend and whether quotes/transactions succeed. Risk is mitigated by conservative phase-1 fallback paths and extensive new unit tests, but it still touches core quoting/gas logic.Overview
Implements a dedicated two-phase Relay max-amount quoting flow that falls back to gas-station pricing when native gas is insufficient, using
getRelayMaxGasStationQuoteto estimate gas in source-token units (directly or via a probe quote), request an adjusted max quote, and only accept it after gas-limit/affordability validation.Refactors gas-station handling into a new
gas-stationhelper (eligibility + normalized gas-fee-token costing) and wires it into Relay quote generation, including improved normalization for multi-item/post-quote gas limits. Successful adjusted quotes are tagged viaoriginal.metamask.isMaxGasStation, and Relay submit logic is verified to keep max-gas-station submissions on the existinggasFeeToken-only path.Written by Cursor Bugbot for commit 4b10f5d. This will update automatically on new commits. Configure here.