Skip to content

feat(transaction-pay-controller): add generic signature steps to server pay strategy#9051

Open
matthewwalsh0 wants to merge 19 commits into
mainfrom
feat/generic-signature-steps
Open

feat(transaction-pay-controller): add generic signature steps to server pay strategy#9051
matthewwalsh0 wants to merge 19 commits into
mainfrom
feat/generic-signature-steps

Conversation

@matthewwalsh0

@matthewwalsh0 matthewwalsh0 commented Jun 9, 2026

Copy link
Copy Markdown
Member

Explanation

The server pay strategy previously supported only on-chain transaction steps. Certain provider flows (e.g. perps withdraw via Relay/HyperLiquid) require an off-chain EIP-712 signature step submitted to a provider endpoint before any on-chain work happens. This change extends the server strategy to support a flat steps array containing both transaction and signature steps.

The execution model is now a strict three-phase sequence per quote:

  1. Signature steps — sign typed data with the user's key and POST the result to the provider endpoint. Two signatureFormat values are supported: queryParam (appends ?signature=… to the endpoint URL) and rsv (sends split r/s/v fields in the request body). Signed with quote.request.from so account-override flows — where the delegating EOA differs from the sending account — work correctly.
  2. Transaction steps — validate source balance via live RPC, build params (including any prepends for post-quote or payment-override flows), then dispatch to the gasless execute path or TransactionController. Payment-override calls are prepended before relay steps at submit time; post-quote flows prepend the original transaction, wrapped in a delegation tx when an account override is active.
  3. Status polling — unchanged.

Source token balance validation is skipped for HyperLiquid source flows (no on-chain debit from the user) and post-quote flows (funds come from the Safe after the original transaction executes).

Quote re-evaluation is extended to fire when txParams.to or requiredAssets changes on a transaction, not just txParams.data, so perps flows that rewrite the destination address trigger a fresh quote.

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

Note

High Risk
Changes payment submission, EIP-712 signing, balance validation, and batch transaction construction for server intents—including perps withdraw and money-account flows—where mistakes could block or mis-route user funds.

Overview
Extends the server pay strategy so quote steps can mix EIP-712 signature steps with on-chain transaction steps, then runs them in order: sign typed data (using quote.request.from for account override), POST to the provider (queryParam or rsv), build/submit transaction batches (with live balance checks and Money Account / post-quote prepends), then poll intent status as before.

Quote & perps: Server step types are discriminated by type: 'transaction' | 'signature'. Signature-only quotes zero source network fees like gasless. Hyperliquid withdraw requests (isHyperliquidSource) normalize source chain/token/amount in normalizeServerPerpsRequest, use exact-input quoting, skip gasless/delegation on HyperCore source, and skip balance validation at submit. Money Account post-quote quotes inject override calls + transfer into the server quote body via processMoneyAccountPostQuote.

Controller: Quote refresh now also triggers when txParams.to or requiredAssets change, not only txParams.data.

Reviewed by Cursor Bugbot for commit c75fcc1. Bugbot is set up for automated code reviews on this repo. Configure here.

@matthewwalsh0 matthewwalsh0 force-pushed the feat/generic-signature-steps branch 2 times, most recently from 7a54326 to 1099b1f Compare June 9, 2026 09:01
@matthewwalsh0 matthewwalsh0 marked this pull request as ready for review June 9, 2026 09:33
@matthewwalsh0 matthewwalsh0 requested review from a team as code owners June 9, 2026 09:33
@matthewwalsh0 matthewwalsh0 force-pushed the feat/generic-signature-steps branch from 5615aaf to 773fc89 Compare June 9, 2026 16:27
@matthewwalsh0 matthewwalsh0 force-pushed the feat/generic-signature-steps branch from 773fc89 to c83e4c2 Compare June 11, 2026 08:15

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ 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 c83e4c2. Configure here.

@matthewwalsh0 matthewwalsh0 requested review from dan437 and removed request for dan437 June 11, 2026 11:00
…tegy

Replace separate steps and signatureSteps arrays with a single flat
ServerStep union discriminated by type ('transaction' | 'signature').

- ServerTransactionStep for on-chain steps
- ServerSignatureStep for off-chain EIP-712 sign + POST flows
- signatureFormat is required ('queryParam' | 'rsv'), drop 'field'
- submitSignatureStep processes each signature step individually
- Filter transaction steps for gas estimation and on-chain submission
Bring the server strategy closer to relay strategy standards:

- Fix accountOverride: sign signature steps with quote.request.from
  (already resolved override account) not transaction.txParams.from
- Validate HyperLiquid deposit response: assert status === 'ok' for
  rsv-format signature steps; throw on failure instead of silently
  continuing to polling
- Validate source balance before on-chain submission; skip for
  isHyperliquidSource and isPostQuote flows
- Migrate isPostQuote prepend: detect hasAccountOverride and prepend
  raw original tx or delegation-wrapped version accordingly
- Migrate paymentOverride at quote time: processMoneyAccountPostQuote
  rewrites server quote body with money-account override calls
- Migrate paymentOverride at submit time: prependPaymentOverrideParams
  prepends getPaymentOverrideData calls before relay deposit steps
- Extract buildTransactionParams: pure function mapping transaction
  steps + gas context to TransactionParams[]
- Migrate transaction type logic: getRelayDepositType,
  getEffectiveTransactionType, getTransactionType reusing
  RELAY_DEPOSIT_TYPES from the relay strategy constants
…ilding and submission

- buildTransactionParams now async and owns full allParams construction:
  takes quote + transaction + messenger, maps steps via stepToParams, then
  prepends payment override or post-quote calls internally
- submitTransactionSteps extracted: owns validate + build + gasless branch;
  no-ops for signature-only quotes
- executeSingleServerQuote reduced to a clean 3-phase sequence:
  submitSignatureSteps → submitTransactionSteps → waitForCompletion
- stepToParams extracted as private helper for single-step conversion
…c steps

- Add type: 'transaction' to step fixtures in server-quotes and server-submit tests
- Mock getLiveTokenBalance in server-submit tests (validateSourceBalance path)
- Add fees, chainId/decimals/token fields to ORIGINAL_QUOTE_MOCK to match ServerQuote type
- Throw 'Server quote has no steps to submit' for non-gasless quotes with no transaction steps
- Rename stepToParams -> transactionStepToParams for clarity
…o and requiredAssets changes

Previously subscribeTransactionChanges only detected txParams.data changes
as a signal to re-evaluate a transaction. Add txParams.to and requiredAssets
to the change detection so quote requests are refreshed when the destination
or required asset list changes.
…ayment override, and perps withdraw

- Add tests for signature step sign+POST with queryParam and rsv formats
- Add tests for gasless no-op and insufficient balance paths
- Add tests for processMoneyAccountPostQuote in server-quotes
- Add tests for normalizePerpsWithdrawRequest isHyperliquidSource path
- Fix perps.ts decimal shift bug: withdraw converts 8→6 decimals (÷100)
- Remove dead code in calculateSourceNetworkCost (unreachable steps guard)
- 1126/1126 tests passing, 100% coverage
@matthewwalsh0 matthewwalsh0 force-pushed the feat/generic-signature-steps branch from c83e4c2 to c75fcc1 Compare June 11, 2026 12:44
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