Skip to content

feat(transaction-pay-controller): add server intents-api pay strategy#8894

Draft
matthewwalsh0 wants to merge 26 commits into
mainfrom
feat/generic-intents-pay-strategy
Draft

feat(transaction-pay-controller): add server intents-api pay strategy#8894
matthewwalsh0 wants to merge 26 commits into
mainfrom
feat/generic-intents-pay-strategy

Conversation

@matthewwalsh0
Copy link
Copy Markdown
Member

@matthewwalsh0 matthewwalsh0 commented May 26, 2026

Explanation

TransactionPayController previously supported Relay, Bridge, Across, and Fiat strategies but had no way to consume the MetaMask intents API's provider-agnostic /quote, /submit, and /status endpoints. Adding the Server strategy unifies quote fetching across Relay and Across under a single backend surface, removing duplicate provider-specific client code from core and enabling new providers to be added on the backend without client changes.

The Server strategy plugs into the existing getStrategies fallback chain and is gated by the payStrategies.server.enabled remote feature flag (default: disabled), so it can be enabled per-environment without a client release.

Quote and submission flow:

  • Fans out to configured providers (Relay, Across) via POST /quote and normalizes results through a { provider, quote?, error? } discriminated union — presence of quote indicates success, error indicates failure.
  • When the backend reports gasless: true, executes via POST /submit (relayer covers origin-chain gas). When gasless: false, falls back to submitting steps directly through TransactionController with EIP-7702 batching and gas-station token support, matching existing Relay strategy capabilities.
  • Polls GET /status after submission and sets isIntentComplete on the parent transaction once the intent reaches CONFIRMED, matching the Relay and Across strategies.

Perps / HyperCore:

  • Detects Hyperliquid perps deposits by sniffing parent transaction calldata for the Hyperliquid bridge contract address and rewrites the destination to a provider-agnostic HyperCore sentinel that backend providers translate to their native identifiers.

Gasless eligibility:

  • Sends supportsGasless: true on outgoing quote requests when the account supports EIP-7702 and the source chain is EIP-7702-capable, so backend providers can enable gasless execution paths.

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

@matthewwalsh0 matthewwalsh0 changed the title feat(transaction-pay-controller): add generic intents-api pay strategy feat(transaction-pay-controller): add server intents-api pay strategy May 27, 2026
…for non-gasless generic quotes

The generic strategy now branches on the backend's gasless flag: gasless quotes still go through POST /submit; non-gasless quotes are submitted through TransactionController.addTransaction or addTransactionBatch, including EIP-7702 batching and gas-station support, mirroring the existing Relay strategy. Status is polled via /status on both paths until CONFIRMED. Source network fees are computed for non-gasless quotes; gasless quotes remain zeroed since the relayer covers gas.
…s in generic strategy

Detects Hyperliquid perps deposits by sniffing the parent transaction calldata
for the Hyperliquid bridge contract address (no transaction-type coupling) and
rewrites the destination to a provider-agnostic HyperCore sentinel
(`0x2100…`) with 8-decimal amount. Backend providers translate the sentinel
to their own native HyperCore identifiers.
…ic quote requests

Adds an optional `supportsGasless` field to `GenericQuoteRequest` and sets it
in `buildGenericQuoteRequest` when:

- the calling account supports EIP-7702,
- Relay execute is enabled via the remote feature flag, and
- the source chain is EIP-7702-capable.

This mirrors the existing Relay strategy condition and lets backend providers
opt into gasless execution paths (notably `originGasOverhead` on Relay)
without coupling the client to any one provider's wire format.
… generic supportsGasless

Removes the `isRelayExecuteEnabled` gate from `supportsGasless`. The flag is
not yet rolled out in the relevant environments, but generic gasless flow
should remain available whenever the account itself supports EIP-7702 on a
7702-capable chain. Backend providers remain the source of truth for whether
they actually return a gasless quote.
…ntent confirms

Mirrors the Relay and Across strategies: once the generic /status endpoint
reports CONFIRMED, mark the parent transaction's `isIntentComplete` so
downstream UI (activity list, confirmation cleanup) treats the pay flow as
done. Previously the generic strategy returned the target hash but left
`isIntentComplete` unset, causing the parent transaction to linger in an
incomplete state.
…-api v2 request format

- Update GenericQuoteRequest to use source/target envelope (source.chainId,
  source.token, target.chainId, target.token) replacing flat originChainId,
  destinationChainId, originToken, destinationToken fields
- Replace single provider field with providers[] array
- Rename slippageBps to slippage
- Add refundTo optional field
- Update GenericQuoteAmount to include chainId, token, decimals fields
- Replace flat GenericQuoteResult shape (status/id/input/output/...) with
  { provider, quote?, error? } discriminated union matching backend response
- Add GenericQuotePayload and GenericQuoteFees types
- Add fees field to GenericQuote
- Fix isFulfilledResult discriminator (was result.status === 'fulfilled',
  now result.quote !== undefined)
- Add optional hash param to getGenericStatus for Across status calls
- Update all tests to match new shapes
… generic strategy

- Set default intents API URL to prod (https://intents.api.cx.metamask.io)
- Remove unnecessary Boolean() wrapper in buildGenericQuoteRequest
- Use Array.at(-1) instead of slice(-1)[0]
- Simplify URLSearchParams optional hash param
- Rename datas to fragments in transactionDataReferencesBridge with clarifying comment
- Simplify GENERIC_DEFAULT_PROVIDER_PRIORITY cast
- Remove obfuscated string-concat mock accessors in generic-submit test
- Trim changelog entry to consumer-facing surface area
@matthewwalsh0 matthewwalsh0 force-pushed the feat/generic-intents-pay-strategy branch from e5c9ffc to 0c91233 Compare May 27, 2026 10:53
@matthewwalsh0 matthewwalsh0 reopened this May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant