Skip to content

fix(sdk-core): restore MPCv2 message /send finalization - #10060

Closed
nvjsr wants to merge 1 commit into
masterfrom
nehakumari/defi-1184-mpcv2-message-finalization-send-fallback
Closed

nvjsr wants to merge 1 commit into
masterfrom
nehakumari/defi-1184-mpcv2-message-finalization-send-fallback

Conversation

@nvjsr

@nvjsr nvjsr commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Problem

Live WC E2E (retail, self-custodial MPCv2 hot wallet, EIP-712 signTypedStructuredData): re-signing after PA approval runs the full DKLS ceremony, but the message is never combined. The txRequest stays pendingDelivery with messages[0].state === 'readyToCombineShares' and no txHash, signAndSendMessageTxRequest throws, the dialog errors, and the dApp is never notified.

Root cause

#10009 assumed wallet-platform combines and delivers messages inside the final share submission, so it replaced the tail POST /send with a plain GET. That ingestion-time combine is custodial-only (wallet-platform signatureShares.ts gates it on walletHasCustodialUserKey). For self-custodial wallets the request stays readyToCombineShares until a client POSTs /messages/0/send, which triggers:

  • internalSendTxRequest → internalCombineSignatureShares (writes messages[0].txHash)
  • markTxRequestAsDeliveredIfAllMessagesSigned → delivered + signed-message Kafka publish

With the GET-only tail nothing ever combines, so the SDK's post-sign assert (wallet.ts: Unable to find txHash in signedMessageRequest.messages) fires and the request is stranded permanently. The Oct 21 evidence that motivated #10009 (signed → delivered 82 ms apart) was actually the pre-#10009 SDK's own /send round-trip, not an ingestion-time combine.

Change

signRequestBase message tail, in order:

  1. GET the request — if already delivered/has txHash (custodial ingestion path), return it without POSTing /send (which wallet-platform rejects on the already-delivered request; this preserves the fix(sdk-core): finalize MPCv2 message signing via GET, not POST /send #10009 intent).
  2. Otherwise POST /send to trigger the combine + delivery + Kafka publish (self-custodial path).
  3. If /send rejects because the request became terminal concurrently, fall back to one more GET; genuine errors still surface.

Transactions keep the unconditional /send (broadcast). EDDSA MPCv2 already POSTs /send and is untouched.

Testing

modules/sdk-core — signRequestBase message finalization (5 passing):

  • custodial (delivered at ingestion) → GET only, no /send
  • self-custodial (un-combined) → exactly one POST .../messages/0/send
  • /send rejected + request terminal concurrently → fallback GET
  • /send rejected + still un-combined → error surfaces
  • transactions → still POST /send

Refs DEFI-1184. Follow-up to #10009.

@nvjsr
nvjsr requested review from a team as code owners October 26, 2026 06:52

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@linear-code

linear-code Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

DEFI-1184

@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Unit tests are failing on Node 26.x (Current release line, non-blocking). This is not an LTS version yet, so it does not block merge, but it signals an incompatibility to fix before Node 26.x becomes LTS.

View run

PR #10009 replaced the MPCv2 ECDSA message finalization POST /send with a
plain GET, assuming wallet-platform always combines and delivers messages
inside the final share submission. That assumption only holds for
custodial wallets (walletHasCustodialUserKey gate in wallet-platform's
share ingestion): for self-custodial wallets the request stays
pendingDelivery/readyToCombineShares until a client POSTs /send, which is
what triggers the share combine, the delivered-state transition and the
signed-message Kafka publish. With the GET-only tail, the post-sign
re-fetch returned an un-combined request without txHash and tripped the
"Unable to find txHash" assert in signAndSendMessageTxRequest, leaving the
message permanently un-combined and the dApp un-notified.

Finalize messages by re-fetching first (custodial requests are already
terminal and must not POST /send, which wallet-platform rejects), then
POST /send to trigger the combine for self-custodial requests. If /send
is rejected because the request became terminal concurrently, fall back
to one more GET instead of surfacing the error.
@nvjsr
nvjsr force-pushed the nehakumari/defi-1184-mpcv2-message-finalization-send-fallback branch from b753ca2 to fa193ec Compare October 26, 2026 07:45
@nvjsr nvjsr closed this Oct 26, 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