Skip to content

feat(transaction-pay-controller): add subsidized Relay submit via /relay/subsidize#9298

Draft
matthewwalsh0 wants to merge 1 commit into
mainfrom
feat/pay-subsidized-submit
Draft

feat(transaction-pay-controller): add subsidized Relay submit via /relay/subsidize#9298
matthewwalsh0 wants to merge 1 commit into
mainfrom
feat/pay-subsidized-submit

Conversation

@matthewwalsh0

Copy link
Copy Markdown
Member

Explanation

Subsidized Relay quotes currently flow through the same /execute path as non-subsidized quotes. This exposes Relay quote internals (request IDs, exact calldata) to clients and couples the sponsorship model to specific Relay steps decided at quote time.

This PR introduces a dedicated subsidized submit path. When a Relay quote carries a non-zero fees.subsidized.amountUsd, the client signs two ERC20BalanceChange + LimitedCalls delegations (one per possible Relay step) instead of committing to exact step calldata. These delegations are sent to POST /relay/subsidize on the intents-API. The server JIT-fetches a fresh Relay quote server-side, pairs each delegation with a step, builds redeemDelegations calldata entirely on the server, and submits to Relay — returning a new request ID used for status polling.

Key design decisions:

  • The client always sends exactly 2 signed delegations (covers 1-step and 2-step Relay Pay quotes). The server validates delegations.length >= steps.length and ignores extras.
  • Each delegation uses an ERC20BalanceChangeEnforcer caveat (spending cap = preview amount + 20% buffer) and a LimitedCallsEnforcer caveat (single use), with an ANY_BENEFICIARY delegate so Relay gas sponsorship is compatible.
  • The returned server request ID overwrites the stale preview quote request ID so the shared waitForRelayCompletion polling loop polls the correct Relay request.
  • Non-subsidized quotes are unaffected; the subsidized branch is taken only when isSubsidizedRelayQuote() returns true.

Also fixes a crash introduced by the server's toSafeSubsidizedQuote() function, which strips steps from subsidized preview quotes entirely (field absent, not empty array). Two sites in relay-submit.ts that accessed steps without guarding against undefined would throw TypeError on every subsidized submit attempt.

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

…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.
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