feat(sdk-coin-ada): add MPCv2 support to recoverConsolidations - #9497
feat(sdk-coin-ada): add MPCv2 support to recoverConsolidations#9497ralph-bitgo[bot] wants to merge 2 commits into
Conversation
Add MPCv2 signed recovery to Ada.recover() via an optional precomputedMaterial parameter, and hoist signing-material detection in Ada.recoverConsolidations() to run once before the scan loop instead of once per recover() call, guarding on userKey the same way recover() already does. Reuses the shared getEddsaSigningMaterial / signEddsaMpcV2RecoveryTx helpers from @bitgo/sdk-core, matching the pattern already established for DOT (WCI-1236) and SOL (WCI-496). Wallets are migrating EdDSA MPC from Zengo (MPCv1) to Silence Labs (MPCv2). recoverConsolidations() scans up to 20+ receive-address indexes and previously called recover() once per index, which for MPCv2 wallets would decrypt the keycard N times unnecessarily since detection happened inside recover() on every call. Ticket: WCI-1232 Session-Id: 31bb6e8e-db75-4405-8c2b-bd05532cd95f Task-Id: e959f25c-1bf7-4294-a67f-904be99c4afe
6b12004 to
e5a1b98
Compare
e5a1b98 to
fd858c9
Compare
Phase 1 — SummaryAdds optional Files changed: 2 — flowchart TD
A["recover(params, precomputedMaterial?)"] --> B{precomputedMaterial\nprovided?}
B -- yes --> C[skip getEddsaSigningMaterial]
B -- no --> D["getEddsaSigningMaterial(userKey, passphrase)"]
C --> E{signingMaterial.version}
D --> E
E -- v2 --> F["signAdaMpcV2Recovery → signEddsaMpcV2RecoveryTx"]
E -- v1 --> G["decryptKeychainPrivateKey → EDDSAMethods.getTSSSignature"]
F --> H[txBuilder.addSignature]
G --> H
RC["recoverConsolidations()"] --> RP{walletPassphrase\nset?}
RP -- yes --> RA["assert(params.userKey)\ngetEddsaSigningMaterial ONCE"]
RP -- no --> RB[signingMaterial = undefined]
RA --> RL["for i in startIdx..endIdx"]
RB --> RL
RL --> RR["recover(recoverParams, signingMaterial)"]
Phase 2 — Ticket AlignmentTicket: WCI-1232 PR title: The implementation matches the ticket scope. The PR also delivers MPCv2 support to Phase 3 — Index AnalysisNo new database queries introduced. Phase 4 — Type SafetyNo Sinon spy cast uses the safe One pre-existing (not introduced) Phase 5 — MPCv2 Correctness & Test QualityCorrectness
Test Quality
Consistency vs DOT (#9484)
Summary of ❌ Findings
None of these are blockers, but items 1 and 2 are the most likely to cause confusion in future debugging. Generated by [ |
Add two regression tests: recoverConsolidations() now throws 'missing userKey' before scanning any address when walletPassphrase is set but userKey is omitted, and recover() throws a clear error when the MPCv1 backup keycard fails to decrypt. Automated review after the MPCv2 recoverConsolidations commit flagged both branches as new but untested, risking a silent regression if a future refactor moved the fail-fast guard or broke the decryptKeychainPrivateKey error path. Ticket: WCI-1232 Session-Id: 31bb6e8e-db75-4405-8c2b-bd05532cd95f Task-Id: e959f25c-1bf7-4294-a67f-904be99c4afe
fd858c9 to
9b72678
Compare
What
precomputedMaterial?: EddsaSigningMaterialparameter toAda.recover(). When supplied,recover()skips its owngetEddsaSigningMaterialcall and dispatches straight to MPCv1 (EDDSAMethods.getTSSSignature) or MPCv2 (signEddsaMpcV2RecoveryTx) signing based onsigningMaterial.version.Ada.recoverConsolidations(), detects signing material once before the scan loop (guarded byassert(params.userKey, 'missing userKey')whenwalletPassphraseis set) and threads it into everyrecover()call via the new parameter, instead of letting each call re-detect it.getEddsaSigningMaterial/signEddsaMpcV2RecoveryTx/decryptKeychainPrivateKeyhelpers from@bitgo/sdk-core(already merged in WCI-1276), matching the pattern established for DOT (WCI-1236) and SOL (WCI-496).getEddsaSigningMaterialcalled exactly once across a multi-index consolidation scan, MPCv1 regression (signing unchanged), unsigned/cold-path regression (no passphrase), the new missing-userKey fail-fast guard, and the backup-keycard decrypt-failure error path.Why
recoverConsolidations()scans up to 20+ receive-address indexes and callsrecover()once per index. For MPCv2 wallets,recover()previously ran keycard detection (getEddsaSigningMaterial) on every call, decrypting the same keycard N times unnecessarily across a scan range. Wallets are migrating EdDSA MPC from the Zengo implementation (MPCv1) to Silence Labs (MPCv2), so this closes the gap for ADA's consolidation recovery hot path, depending onAda.recover()'s own MPCv2 support (WCI-1222).Test plan
nix develop . --command yarn tsc --build --force .inmodules/sdk-coin-ada— compiles cleanlynix develop . --command yarn eslint --quiet src/ada.ts test/unit/ada.ts— no errorsBITGOJS_TEST_PASSWORD=... yarn unit-testinmodules/sdk-coin-ada— 176 passing, 0 failing (includes 9 new MPCv2 tests)Ticket: WCI-1232