Skip to content

feat(sdk-coin-polyx): add MPCv2 signed hot recovery - #9483

Draft
ralph-bitgo[bot] wants to merge 4 commits into
masterfrom
WCI-1228-sdk-coin-polyx-mpcv2-signed-hot-recovery
Draft

feat(sdk-coin-polyx): add MPCv2 signed hot recovery#9483
ralph-bitgo[bot] wants to merge 4 commits into
masterfrom
WCI-1228-sdk-coin-polyx-mpcv2-signed-hot-recovery

Conversation

@ralph-bitgo

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

Copy link
Copy Markdown

What

  • Add isMpcv2SigningMaterial() and addRecoverySignature() private methods to Polyx in modules/sdk-coin-polyx/src/polyx.ts.
  • Polyx.recover() now detects once whether the keycard is MPCv1 (JSON) or MPCv2 (CBOR) and dispatches signing accordingly, reusing the shared getEddsaSigningMaterial/signEddsaMpcV2RecoveryTx helpers from @bitgo/sdk-core (extracted in WCI-1276). No new params — detection is automatic, and the existing MPCv1 / unsigned-sweep behavior is unchanged.
  • Add unit tests: MPCv2 happy path, MPCv1 regression (still works when signing material is MPCv1 format), mismatched bitgoKey vs keycard commonKeyChain throws, and guard-clause/error-path coverage for missing userKey/backupKey/walletPassphrase and decrypt failures.

Why

POLYX wallets are migrating from the Zengo to the Silence Labs EdDSA MPCv2 implementation, but Polyx.recover() only understood the legacy MPCv1 JSON keycard format — customers with MPCv2 keycards could not perform hot wallet recovery. This mirrors the MPCv2 recovery support already shipped for SOL (WCI-398) and TON (WCI-1225), reusing the shared sdk-core helpers instead of duplicating the signing logic, per WCI-1228.

Test plan

  • yarn unit-test --scope @bitgo/sdk-coin-polyx — 259 passing, 2 pending, 0 failing
  • nix develop . --command npx lerna run build --scope @bitgo/sdk-coin-polyx --include-dependencies — builds clean
  • eslint on changed files — no errors

Ticket: WCI-1228

Add isMpcv2SigningMaterial() and addRecoverySignature() private
methods to Polyx so recover() detects CBOR (MPCv2) vs JSON (MPCv1)
keycards once and dispatches signing accordingly, reusing the shared
getEddsaSigningMaterial/signEddsaMpcV2RecoveryTx helpers from
@bitgo/sdk-core. MPCv1 path and unsigned sweep behavior are unchanged.

POLYX customers migrating to the Silence Labs EdDSA MPCv2
implementation could not perform hot wallet recovery with MPCv2
keycards; recover() only understood the legacy MPCv1 JSON format.
This mirrors the MPCv2 recovery support already added for SOL
(WCI-398) and TON (WCI-1225), reusing the shared sdk-core helpers
extracted in WCI-1276 instead of duplicating the signing logic.

Ticket: WCI-1228
Session-Id: 3a00bebe-fe12-4aea-9f1a-5a2d0dd8e94b
Task-Id: dfadd58f-a04c-4dd9-819b-506439735cec
Add two tests asserting 'missing userKey' and 'missing backupKey'
are thrown when only one of the two keys is omitted alongside a
walletPassphrase.

The automated review dispatched after the MPCv2 recovery commit
flagged that these two early-throw branches in
isMpcv2SigningMaterial() had no direct test coverage, unlike the
happy-path and mismatched-bitgoKey cases.

Ticket: WCI-1228
Session-Id: 3a00bebe-fe12-4aea-9f1a-5a2d0dd8e94b
Task-Id: dfadd58f-a04c-4dd9-819b-506439735cec
Add a test asserting 'missing wallet passphrase' is thrown when
userKey and backupKey are present but walletPassphrase is not.

The automated review dispatched after the previous test-coverage
commit flagged that isMpcv2SigningMaterial()'s walletPassphrase
short-circuit and recover()'s outer 'missing wallet passphrase'
check were still only exercised indirectly, never via a real
(non-stubbed) call with that exact param combination.

Ticket: WCI-1228
Session-Id: 3a00bebe-fe12-4aea-9f1a-5a2d0dd8e94b
Task-Id: dfadd58f-a04c-4dd9-819b-506439735cec
Add a test asserting the addRecoverySignature() MPCv1 branch
rethrows a descriptive 'Error decrypting user keychain' message
when bitgo.decrypt() rejects (e.g. wrong wallet passphrase).

The automated review dispatched after the prior test-coverage
commits flagged this catch/rethrow branch, moved out of recover()
and into addRecoverySignature() in the MPCv2 recovery commit, as
still unexercised by any test.

Ticket: WCI-1228
Session-Id: 3a00bebe-fe12-4aea-9f1a-5a2d0dd8e94b
Task-Id: dfadd58f-a04c-4dd9-819b-506439735cec
@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

WCI-1228

@ralph-bitgo
ralph-bitgo Bot force-pushed the WCI-1228-sdk-coin-polyx-mpcv2-signed-hot-recovery branch from 2f801bc to dc26b6c Compare August 12, 2026 11:29
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