Skip to content

feat(sdk-coin-dot): add MPCv2 signed hot recovery support - #9484

Open
ralph-bitgo[bot] wants to merge 1 commit into
masterfrom
wci-1227-dot-mpcv2-recovery
Open

feat(sdk-coin-dot): add MPCv2 signed hot recovery support#9484
ralph-bitgo[bot] wants to merge 1 commit into
masterfrom
wci-1227-dot-mpcv2-recovery

Conversation

@ralph-bitgo

@ralph-bitgo ralph-bitgo Bot commented Aug 12, 2026

Copy link
Copy Markdown

What

  • Adds isMpcv2SigningMaterial() and addRecoverySignature() private methods to Dot (modules/sdk-coin-dot/src/dot.ts), and updates recover() to detect the keycard format once (MPCv1 JSON vs MPCv2 CBOR) and dispatch signing accordingly.
  • Reuses the shared EdDSA MPCv2 recovery helpers already extracted into @bitgo/sdk-core (getEddsaSigningMaterial, signEddsaMpcV2RecoveryTx) rather than duplicating logic — same pattern as sdk-coin-sol (WCI-398) and abstract-substrate (WCI-1276/WCI-1239).
  • The MPCv2 path runs the MPS DSG protocol locally and hands the raw 64-byte Ed25519 signature to the transaction builder without manually prepending the 0x00 Substrate discriminant, because Transaction#constructSignedPayload already prepends it unconditionally for every signature (the same mechanism the pre-existing MPCv1 path relies on). Manually prepending it, as literally described in the ticket and mirrored from the already-merged abstract-substrate code, double-prefixes and corrupts the signature — verified empirically by round-tripping a signed transaction through decode.
  • Adds a describe('Recover Transactions (MPCv2):') test block covering: MPCv2 signed recovery returning { serializedTx, scanIndex }, MPCv1 regression (still uses getTSSSignature), mismatched bitgoKey vs keycard commonKeyChain throwing, and a cryptographic verification (via nacl.sign.detached.verify against the transaction's signable payload and derived pubkey) that the extrinsic signature is exactly 64 bytes with the discriminant applied once — not just a length check, which would not catch the double-prefix corruption class.
  • recoverConsolidations() MPCv2 support is intentionally out of scope here — tracked separately in WCI-1236.

Why

Wallets are migrating EdDSA MPC from the Zengo implementation (MPCv1) to Silence Labs (MPCv2). DOT's recover() only handled MPCv1 keycards, so self-custody hot recovery would fail for any wallet backed by an MPCv2 keycard. This closes that gap for DOT, matching the detection + signing path already shipped for SOL (WCI-398) and the shared helpers extracted for Substrate coins (WCI-1276/WCI-1239).

Test plan

  • yarn unit-test in modules/sdk-coin-dot — 205 passing, 0 failing (includes the 5 new MPCv2 tests)
  • yarn build:cjs (tsc --build) — compiles cleanly
  • yarn eslint --quiet src/dot.ts test/unit/dot.ts — no errors
  • Manually confirmed the "0x00 discriminant" test fails if the double-prefix bug is reintroduced (temporarily re-added the manual prefix, observed the cryptographic verification correctly fail, then reverted)

Ticket: WCI-1227

@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

WCI-1227

@bitgo-ai-agent-dev
bitgo-ai-agent-dev Bot force-pushed the wci-1227-dot-mpcv2-recovery branch from 0a4c3b5 to 02798b6 Compare August 12, 2026 11:32
@ralph-bitgo
ralph-bitgo Bot force-pushed the wci-1227-dot-mpcv2-recovery branch from 02798b6 to a079856 Compare August 12, 2026 11:32
@vibhavgo
vibhavgo force-pushed the wci-1227-dot-mpcv2-recovery branch 2 times, most recently from edfac9b to 47b6045 Compare August 13, 2026 06:36
Detect CBOR (MPCv2) vs JSON (MPCv1) keycards in Dot.recover() using
the shared getEddsaSigningMaterial/signDotMpcV2Recovery helpers from
sdk-core. Uses assert() for guards in newly introduced recovery code.

Ticket: WCI-1227
@vibhavgo
vibhavgo force-pushed the wci-1227-dot-mpcv2-recovery branch from 47b6045 to 5b6afb7 Compare August 13, 2026 06:43
@vibhavgo
vibhavgo marked this pull request as ready for review August 13, 2026 07:08
@vibhavgo
vibhavgo requested a review from a team as a code owner August 13, 2026 07:08
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