feat(sdk-coin-iota): add MPCv2 signed hot recovery support - #9426
Conversation
089d472 to
ed08c7c
Compare
|
Claude finished @Marzooqa's task —— View job Code Review for MPCv2 Signed Hot Recovery Support ✅Todo List:
OverviewThis PR successfully adds MPCv2 signed hot recovery support to the IOTA coin implementation. The changes follow the established pattern from SOL implementation and provide good backwards compatibility with MPCv1. ✅ Positive AspectsClean Architecture & Pattern Consistency
Comprehensive Test Coverage
Security & Error Handling
🔍 Technical Implementation DetailsSignature Format -
|
vibhavgo
left a comment
There was a problem hiding this comment.
Code review — local review against the MPCv2 signed hot recovery quality bar established across DOT/POLYX/SUI/ADA. Both helpers (
getEddsaSigningMaterial,signEddsaMpcV2RecoveryTx) are used correctly from@bitgo/sdk-core. MPCv1 regression test is present ✅.
1. Guard tests are in the wrong describe block
should handle error in recover function if a required field is missing lives in the MPCv1 describe('Recover Transactions:') block and uses MPCv1 key fixtures (keys.userKey, keys.backupKey). The describe('Recover Transactions (MPCv2):') block has zero guard tests — missing-field errors on the MPCv2 code path are untested.
Add to the MPCv2 describe:
should throw 'missing userKey'with MPCv2 key fixtures whenuserKeyis omittedshould throw 'missing backupKey'with MPCv2 key fixtures whenbackupKeyis omitted
2. No cryptographic signature verification
The MPCv2 native test validates envelope structure:
sigBuffer.length.should.equal(97);
sigBuffer[0].should.equal(0x00);This confirms the envelope is well-formed but does not verify that the inner 64 bytes are a valid Ed25519 signature over unsignedTx.signablePayload for the derived public key. tweetnacl is available in sdk-coin-iota's package.json (IOTA is SUI-derived, same dep tree). The pattern from prior PRs:
const rawSig = sigBuffer.slice(1, 65);
const isValid = nacl.sign.detached.verify(
new Uint8Array(signablePayload),
new Uint8Array(rawSig),
new Uint8Array(Buffer.from(derivedPublicKey, 'hex'))
);
isValid.should.be.true();Reviewed by Claude Code against the MPCv2 recovery PR series baseline.
ed08c7c to
dc935df
Compare
Detects MPCv1 vs MPCv2 keycard format in Iota.recover() and dispatches signing accordingly, mirroring the SOL implementation. MPCv2 signatures are wrapped in the existing SUI-style envelope (0x00 flag + 64-byte sig + 32-byte pubkey). TICKET: WCI-1226 # Conflicts: # modules/sdk-coin-iota/package.json
dc935df to
f883129
Compare
|
@claude review the pr and also check if Vibhav's comment is addressed |
Summary
Iota.recover(), alongside the existing MPCv1 path (auto-detected, no new params)EDDSAUtils.isEddsaMpcV1SigningMaterialand dispatches signing accordingly, mirroring the SOL implementation (WCI-398)EDDSAUtils.getEddsaMpcV2RecoveryKeySharesFromReducedKey+EDDSAUtils.signRecoveryEddsaMPCv2, validatescommonKeyChainagainstbitgoKey, and wraps the resulting 64-byte signature in the existing SUI-style envelope (0x00flag byte + 64-byte sig + 32-byte pubkey)recoverConsolidations()MPCv2 support is out of scope, tracked separately in WCI-1235Test plan
{ serializedTx, scanIndex }with correctly-formed signature envelopebitgoKeyvs keycardcommonKeyChain— throwsyarn unit-test(251 passing),tsc --noEmit,eslintall cleanTICKET: WCI-1226
🤖 Generated with Claude Code