Skip to content

feat(transaction-pay-controller): send v2 metamask envelope and alternate caveats for subsidized executes#9298

Draft
matthewwalsh0 wants to merge 12 commits into
mainfrom
feat/pay-subsidized-submit
Draft

feat(transaction-pay-controller): send v2 metamask envelope and alternate caveats for subsidized executes#9298
matthewwalsh0 wants to merge 12 commits into
mainfrom
feat/pay-subsidized-submit

Conversation

@matthewwalsh0

@matthewwalsh0 matthewwalsh0 commented Jun 28, 2026

Copy link
Copy Markdown
Member

Explanation

Relay execute quotes are now requested as v2, and execute requests forward a metamask envelope.

  • v2 quotes. Execute quote requests send metamask.executeVersion: 2.
  • metamask envelope on execute. The execute body includes { isSubsidized, quoteRequest, signature }, where signature is the token the server returned on the quote (quote.metamask.signature) — forwarded, not generated. Execute is rejected if the token is absent.
  • Alternate caveats when subsidized. Subsidized executes build a different set of delegation caveats, passed through a new optional caveats argument on getDelegationTransaction. Non-subsidized executes are unchanged.
  • Server requestId swap. After submit, the quote step's requestId is replaced with the one the server returns so status polling targets the correct request.
  • Supporting changes. Execute extracted into relay-submit-execute.ts; new utils/delegation.ts caveat builders + redeemDelegations helpers; shallow-clone of Immer-frozen quote.original; guard undefined gas params.

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 subsidized Relay submit via /relay/subsidize feat(transaction-pay-controller): subsidized submit Jun 28, 2026
@matthewwalsh0 matthewwalsh0 force-pushed the feat/pay-subsidized-submit branch from ea5c3ac to 7867e7c Compare July 2, 2026 11:13
…lay/subsidize

Subsidized Relay quotes (non-zero fees.subsidized.amountUsd) now bypass
/execute and submit through the intents-API POST /relay/subsidize endpoint
instead. The client signs two ERC20BalanceChange + LimitedCalls delegations
server-side; the server JIT-fetches a fresh Relay quote, pairs each delegation
with a step, builds redeemDelegations calldata, and submits to Relay — returning
a new request ID for status polling.

Key changes:
- utils/delegation.ts: buildAndSignSubsidizedDelegation with ERC20BalanceChange
  and LimitedCalls caveats, ANY_BENEFICIARY delegate, 20% amount buffer
- relay-api.ts: submitRelaySubsidize() calling POST /relay/subsidize
- relay-submit.ts: submitViaRelaySubsidize signs 2 delegations in parallel and
  sends delegations:[ctx0,ctx1] matching server schema; isSubsidizedRelayQuote
  detects subsidized quotes from fees.subsidized.amountUsd
- types.ts: RelaySubsidizeRequest / RelaySubsidizeResponse
- feature-flags.ts: relaySubsidizeUrl flag with DEFAULT_RELAY_SUBSIDIZE_URL
  default; fix localhost hardcoded URLs for relayQuoteUrl and relaySubsidizeUrl

Fix crash when subsidized preview quotes have steps: undefined — server
toSafeSubsidizedQuote() strips steps entirely; submitTransactions now uses
quote.original.steps ?? [] and submitViaRelaySubsidize initialises
quote.original.steps ??= [] before element access.
…ginal before subsidized submit

quote.original is read from Immer-frozen controller state. The subsidized
path injects a server-returned requestId into original.steps (absent on
preview quotes), which throws 'Cannot add new property' on a frozen object.

Shallow-clone quote.original into mutableOriginal before the submit/poll
cycle so submitTransactions and waitForRelayCompletion operate on a mutable
copy while the frozen state tree is left untouched.
…etDelegationTransactionCallback

- Export Caveat type, buildLimitedCallsCaveat, buildAllowedTargetsCaveat,
  buildAllowedCalldataCaveat, packSingleExecution, packBatchExecution,
  encodeRedeemDelegations, and extractRedeemDelegationsParams from delegation.ts
- Add optional caveats param to GetDelegationTransactionCallback so callers
  can supply pre-built caveats (e.g. subsidy enforcer set) instead of the
  default ones built inside the callback
- Re-export Caveat from types.ts for downstream consumers
…step mutation in subsidized submit

- normalizeParams guards maxFeePerGas and maxPriorityFeePerGas with undefined
  checks before calling toHex — sanitizeSteps strips these fields from quote
  steps so they arrive as undefined, causing a toString crash on Hermes
- Replace direct mutation of quote.original.steps[0].requestId with a full
  steps array reassignment; the step objects are Immer-frozen so property
  addition throws 'Cannot add new property' in strict mode
- submitViaRelaySubsidize builds three subsidy caveats (LimitedCalls,
  AllowedTargets, AllowedCalldata) from the sanitized ERC20 step and passes
  them to getDelegationTransaction; sends new RelaySubsidizeRequest shape
- Tests: add gas-fee-params-missing case and update subsidize body assertions
…velope

The intents-api no longer accepts or expects orderId in the /relay/execute metamask envelope; the order ID is derived server-side. Remove it from the execute request, the type definitions, and the associated guard.
@matthewwalsh0 matthewwalsh0 force-pushed the feat/pay-subsidized-submit branch from 7aa8583 to f2d9f00 Compare July 3, 2026 23:04
@matthewwalsh0 matthewwalsh0 changed the title feat(transaction-pay-controller): subsidized submit feat(transaction-pay-controller): add subsidized Relay execute support Jul 3, 2026
@matthewwalsh0 matthewwalsh0 changed the title feat(transaction-pay-controller): add subsidized Relay execute support feat(transaction-pay-controller): send v2 metamask envelope and alternate caveats on subsidized Relay executes Jul 3, 2026
@matthewwalsh0

Copy link
Copy Markdown
Member Author

@metamaskbot publish-preview

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@7.5.3-preview-8b02acdf0
@metamask-previews/accounts-controller@39.0.4-preview-8b02acdf0
@metamask-previews/address-book-controller@7.1.2-preview-8b02acdf0
@metamask-previews/ai-controllers@0.7.0-preview-8b02acdf0
@metamask-previews/analytics-controller@1.2.1-preview-8b02acdf0
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-8b02acdf0
@metamask-previews/announcement-controller@8.1.0-preview-8b02acdf0
@metamask-previews/app-metadata-controller@2.0.1-preview-8b02acdf0
@metamask-previews/approval-controller@9.0.2-preview-8b02acdf0
@metamask-previews/assets-controller@10.0.1-preview-8b02acdf0
@metamask-previews/assets-controllers@109.3.0-preview-8b02acdf0
@metamask-previews/authenticated-user-storage@3.0.0-preview-8b02acdf0
@metamask-previews/base-controller@9.1.0-preview-8b02acdf0
@metamask-previews/base-data-service@0.1.3-preview-8b02acdf0
@metamask-previews/bitcoin-regtest-up@1.0.0-preview-8b02acdf0
@metamask-previews/bridge-controller@77.3.2-preview-8b02acdf0
@metamask-previews/bridge-status-controller@74.0.2-preview-8b02acdf0
@metamask-previews/build-utils@3.0.4-preview-8b02acdf0
@metamask-previews/chain-agnostic-permission@1.6.2-preview-8b02acdf0
@metamask-previews/chomp-api-service@3.1.0-preview-8b02acdf0
@metamask-previews/claims-controller@0.5.3-preview-8b02acdf0
@metamask-previews/client-controller@1.0.1-preview-8b02acdf0
@metamask-previews/client-utils@0.0.0-preview-8b02acdf0
@metamask-previews/compliance-controller@2.1.0-preview-8b02acdf0
@metamask-previews/composable-controller@12.0.1-preview-8b02acdf0
@metamask-previews/config-registry-controller@0.4.1-preview-8b02acdf0
@metamask-previews/connectivity-controller@0.2.0-preview-8b02acdf0
@metamask-previews/controller-utils@12.3.0-preview-8b02acdf0
@metamask-previews/core-backend@6.5.0-preview-8b02acdf0
@metamask-previews/delegation-controller@3.0.2-preview-8b02acdf0
@metamask-previews/earn-controller@12.2.2-preview-8b02acdf0
@metamask-previews/eip-5792-middleware@3.0.4-preview-8b02acdf0
@metamask-previews/eip-7702-internal-rpc-middleware@0.1.1-preview-8b02acdf0
@metamask-previews/eip1193-permission-middleware@2.0.1-preview-8b02acdf0
@metamask-previews/ens-controller@19.1.5-preview-8b02acdf0
@metamask-previews/eth-block-tracker@15.0.1-preview-8b02acdf0
@metamask-previews/eth-json-rpc-middleware@23.1.3-preview-8b02acdf0
@metamask-previews/eth-json-rpc-provider@6.0.1-preview-8b02acdf0
@metamask-previews/foundryup@1.0.1-preview-8b02acdf0
@metamask-previews/gas-fee-controller@26.2.4-preview-8b02acdf0
@metamask-previews/gator-permissions-controller@4.2.2-preview-8b02acdf0
@metamask-previews/geolocation-controller@0.1.3-preview-8b02acdf0
@metamask-previews/java-tron-up@1.0.0-preview-8b02acdf0
@metamask-previews/json-rpc-engine@10.5.0-preview-8b02acdf0
@metamask-previews/json-rpc-middleware-stream@8.0.8-preview-8b02acdf0
@metamask-previews/keyring-controller@27.1.0-preview-8b02acdf0
@metamask-previews/local-node-utils@1.0.0-preview-8b02acdf0
@metamask-previews/logging-controller@8.0.2-preview-8b02acdf0
@metamask-previews/message-manager@14.1.2-preview-8b02acdf0
@metamask-previews/messenger@1.2.0-preview-8b02acdf0
@metamask-previews/messenger-cli@0.2.0-preview-8b02acdf0
@metamask-previews/money-account-balance-service@2.1.2-preview-8b02acdf0
@metamask-previews/money-account-controller@0.3.3-preview-8b02acdf0
@metamask-previews/money-account-upgrade-controller@2.2.1-preview-8b02acdf0
@metamask-previews/multichain-account-service@11.1.0-preview-8b02acdf0
@metamask-previews/multichain-api-middleware@4.0.0-preview-8b02acdf0
@metamask-previews/multichain-network-controller@3.2.1-preview-8b02acdf0
@metamask-previews/multichain-transactions-controller@7.1.1-preview-8b02acdf0
@metamask-previews/name-controller@9.1.2-preview-8b02acdf0
@metamask-previews/network-controller@34.0.0-preview-8b02acdf0
@metamask-previews/network-enablement-controller@5.4.1-preview-8b02acdf0
@metamask-previews/notification-services-controller@24.3.0-preview-8b02acdf0
@metamask-previews/passkey-controller@2.0.1-preview-8b02acdf0
@metamask-previews/permission-controller@13.1.1-preview-8b02acdf0
@metamask-previews/permission-log-controller@5.1.0-preview-8b02acdf0
@metamask-previews/perps-controller@9.2.0-preview-8b02acdf0
@metamask-previews/phishing-controller@17.2.0-preview-8b02acdf0
@metamask-previews/platform-api-docs@0.0.0-preview-8b02acdf0
@metamask-previews/polling-controller@16.0.8-preview-8b02acdf0
@metamask-previews/preferences-controller@23.1.0-preview-8b02acdf0
@metamask-previews/profile-metrics-controller@4.0.1-preview-8b02acdf0
@metamask-previews/profile-sync-controller@28.2.0-preview-8b02acdf0
@metamask-previews/ramps-controller@15.0.0-preview-8b02acdf0
@metamask-previews/rate-limit-controller@7.0.1-preview-8b02acdf0
@metamask-previews/react-data-query@0.2.1-preview-8b02acdf0
@metamask-previews/remote-feature-flag-controller@4.2.2-preview-8b02acdf0
@metamask-previews/sample-controllers@5.0.3-preview-8b02acdf0
@metamask-previews/seedless-onboarding-controller@10.0.3-preview-8b02acdf0
@metamask-previews/selected-network-controller@26.1.5-preview-8b02acdf0
@metamask-previews/shield-controller@5.1.2-preview-8b02acdf0
@metamask-previews/signature-controller@39.2.7-preview-8b02acdf0
@metamask-previews/smart-transactions-controller@24.2.4-preview-8b02acdf0
@metamask-previews/snap-account-service@1.0.0-preview-8b02acdf0
@metamask-previews/social-controllers@2.3.1-preview-8b02acdf0
@metamask-previews/solana-test-validator-up@1.0.0-preview-8b02acdf0
@metamask-previews/stellar-quickstart-up@0.0.0-preview-8b02acdf0
@metamask-previews/storage-service@1.0.2-preview-8b02acdf0
@metamask-previews/subscription-controller@6.2.0-preview-8b02acdf0
@metamask-previews/transaction-controller@68.2.2-preview-8b02acdf0
@metamask-previews/transaction-pay-controller@23.17.4-preview-8b02acdf0
@metamask-previews/user-operation-controller@41.2.6-preview-8b02acdf0
@metamask-previews/wallet@6.0.0-preview-8b02acdf0
@metamask-previews/wallet-cli@0.0.0-preview-8b02acdf0

@matthewwalsh0 matthewwalsh0 changed the title feat(transaction-pay-controller): send v2 metamask envelope and alternate caveats on subsidized Relay executes feat(transaction-pay-controller): send v2 metamask envelope and alternate caveats for subsidized executes Jul 4, 2026
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.

1 participant