Skip to content

feat(transaction-pay-controller): support second-leg submission of target calls - #10501

Merged
matthewwalsh0 merged 18 commits into
mainfrom
feat/transaction-pay-non-atomic-second-leg
Oct 12, 2026
Merged

matthewwalsh0 merged 18 commits into
mainfrom
feat/transaction-pay-non-atomic-second-leg

Conversation

@matthewwalsh0

@matthewwalsh0 matthewwalsh0 commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Explanation

Server quote providers either execute the target calls or decline the request, and the server strategy declined non-atomic requests outright, so flows whose calls no provider can run were unsupported.

  • Server quote requests now set supportsDeferredCalls, so a provider that can't execute the calls returns a funds-only quote (callsDeferred: true) instead of declining.
  • These quotes are flagged requiresSecondLeg, and the calls are submitted separately on the target chain once the funds settle.
  • The server strategy now accepts non-atomic requests.
  • Every strategy (Relay, Server, Fiat) submits its second leg through a shared submitSecondLeg util, which:
    • Reads the settled amount and block from the settlement transaction's transfer logs.
    • Throws when there is no settlement hash or no matching transfer, rather than falling back to the quote minimum or the fiat order amount.
    • Applies CHOMP race handling for Money Account deposits, which previously only ran for fiat.
  • Non-atomic quotes now settle funds on the account that executes the calls rather than the funding account, shared by the Relay and Server strategies.
  • ma-vault-deposit is removed in favour of the shared util.
  • Server provider names are typed as plain strings, so new backend providers need no client change.

References

Stacked on #10404.

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 multi-leg settlement, amount resolution, and completion semantics across Relay, Server, and Fiat paths; stricter on-chain reads can fail flows that previously fell back to provider-reported amounts.

Overview
Adds non-atomic pay flows where a quote may only move funds and the target calls run afterward on the chain where they settled.

Quotes can now carry requiresSecondLeg (driven by server callsDeferred / supportsDeferredCalls, explicit atomic: false, etc.). Relay, Server, and Fiat (including direct mUSD vault) all submit that follow-up through shared submitSecondLeg, replacing ma-vault-deposit. Settlement amounts come only from on-chain transfer logs via a settlement hash; missing hash or transfer fails instead of using ramp cryptoAmount or quote minimums.

Server quotes settle on the executing account (txParams.from) vs the payer, Money Account post-quote drops the forwarding transfer, and non-atomic requests are allowed. isIntentComplete is set after a successful second leg (Relay/Server). Relay zeros origin network fees for Polymarket deposit-wallet Predict withdraws. CHOMP race recovery moves into withChompRecovery around second-leg vault deposits. Server provider IDs are plain strings instead of an enum.

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

@matthewwalsh0
matthewwalsh0 force-pushed the refactor/transaction-pay-gas-payment branch 2 times, most recently from 93984a0 to 71ec7a0 Compare September 29, 2026 12:19
@matthewwalsh0
matthewwalsh0 force-pushed the feat/transaction-pay-non-atomic-second-leg branch from fa035bc to a0834c6 Compare September 29, 2026 13:41
@matthewwalsh0
matthewwalsh0 force-pushed the refactor/transaction-pay-gas-payment branch from fc6005d to b868774 Compare September 30, 2026 15:45
@matthewwalsh0
matthewwalsh0 force-pushed the feat/transaction-pay-non-atomic-second-leg branch 2 times, most recently from 0fe4cf7 to 4791df2 Compare October 1, 2026 11:47
@matthewwalsh0
matthewwalsh0 force-pushed the refactor/transaction-pay-gas-payment branch from d062d63 to f58e3a8 Compare October 1, 2026 12:31
@matthewwalsh0
matthewwalsh0 force-pushed the feat/transaction-pay-non-atomic-second-leg branch from 4791df2 to 2552899 Compare October 1, 2026 12:32
@matthewwalsh0 matthewwalsh0 changed the title feat(transaction-pay-controller): submit target calls as a second leg when the provider cannot execute them feat(transaction-pay-controller): support second-leg submission of target calls Oct 3, 2026
Base automatically changed from refactor/transaction-pay-gas-payment to main October 5, 2026 08:15
@matthewwalsh0
matthewwalsh0 force-pushed the feat/transaction-pay-non-atomic-second-leg branch from f46884a to acf8b02 Compare October 7, 2026 13:43
@matthewwalsh0
matthewwalsh0 force-pushed the feat/transaction-pay-non-atomic-second-leg branch from acf8b02 to e912f9f Compare October 8, 2026 08:47
@matthewwalsh0
matthewwalsh0 marked this pull request as ready for review October 8, 2026 11:03
@matthewwalsh0
matthewwalsh0 requested review from a team as code owners October 8, 2026 11:03
@matthewwalsh0
matthewwalsh0 deployed to default-branch October 8, 2026 11:03 — with GitHub Actions Active

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

Stale Bugbot comment from a previous run.

@matthewwalsh0
matthewwalsh0 requested a review from jpuri October 8, 2026 11:30
Comment thread packages/transaction-pay-controller/src/strategy/server/server-submit.ts Outdated
jpuri
jpuri previously approved these changes Oct 9, 2026

@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 e2cc524. Configure here.

Comment thread packages/transaction-pay-controller/src/utils/second-leg.ts
… when the provider cannot execute them

Server quote providers either execute the target calls as part of the
quote or decline the request outright, so flows whose calls no provider
can run were simply unsupported.

Request such calls as optional, so providers that cannot execute them
still return a funds-only quote flagged with `callsSupported: false`.
When that happens the quote is marked `requiresSecondLeg` and the calls
are submitted separately on the target chain once the quote settles.

Extract the second-leg submission that the Money Account vault deposit
already performed into a shared `second-leg` util, reading the settled
amount from the settlement transfer logs so the second leg spends what
actually landed rather than the quoted amount. `ma-vault-deposit` is now
a thin Monad-pinned wrapper that layers on CHOMP race handling, and the
relay strategy's recipient resolution moves into the same util so both
strategies settle non-atomic funds on the executing account.
…second leg tests

Raise the `server-quotes.test.ts` counts and add a `second-leg.test.ts`
entry to cover the literals added by the new tests, matching the call
sites already suppressed in those files.

Drop the `ma-vault-deposit.test.ts` entries, whose violations no longer
occur now that the second leg resolves its own execution account.
…t HyperCore from the built quote request

- Send the embedded server transfer to the account the delegated calls run
  from, rather than the paying account, when an account override is active.
- Check the built request body for HyperCore when deciding whether a second
  leg is required, since perps deposits are only rewritten there.
- Read the execution account from txParams.from directly and drop
  resolveExecutionAccount, as from is always set.
…second leg

Mark the parent transaction complete once the second leg has been
submitted, for both the server and relay strategies, so a failed second leg
no longer leaves a failed transaction flagged as complete.
…n has nested calls

The second leg only re-encodes nested transactions, so a funds-only quote for calls that exist only on the top-level transaction would complete without running them. Temporarily skip opting in to deferred calls in that case.
@matthewwalsh0
matthewwalsh0 force-pushed the feat/transaction-pay-non-atomic-second-leg branch from 5429248 to fd5bbe3 Compare October 11, 2026 12:33
@matthewwalsh0
matthewwalsh0 added this pull request to the merge queue Oct 12, 2026
Merged via the queue into main with commit a17a621 Oct 12, 2026
346 checks passed
@matthewwalsh0
matthewwalsh0 deleted the feat/transaction-pay-non-atomic-second-leg branch October 12, 2026 12:49
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.

3 participants