Skip to content

feat(abstract-eth): implement deriveAddress for MPC/TSS ETH wallets#9017

Open
rajangarg047 wants to merge 1 commit into
masterfrom
rajangarg047/wcn-916-eth-mpc-derive-address
Open

feat(abstract-eth): implement deriveAddress for MPC/TSS ETH wallets#9017
rajangarg047 wants to merge 1 commit into
masterfrom
rajangarg047/wcn-916-eth-mpc-derive-address

Conversation

@rajangarg047

Copy link
Copy Markdown
Contributor

Summary

Implements deriveAddress on AbstractEthLikeNewCoins for MPC/TSS ETH wallets (Stage A), overriding the BaseCoin default. It locally derives a receive address from the wallet's commonKeychain + index, reusing the shared deriveMPCWalletAddress (secp256k1) helper plus KeyPair.getAddress() — the exact derivation isWalletAddress checks against, so derive and verify can never diverge.

Offline and key-material-free (public keys only). Supports wallet versions 3, 5, 6; legacy BIP32 forwarder wallets (1, 2, 4) throw a clear error and are handled in a separate ticket (WCN-932).

Context

FR-465 Phase 1, Stage A. Builds only on the merged primitive (WCN-912) and shared MPC engine (WCN-913) — independent of the Express endpoint (WCN-914) and the other coin PRs.

Test plan

  • tsc --noEmit clean for abstract-eth and sdk-coin-eth
  • eslint clean (0 errors)
  • 4 new deriveAddress tests (in sdk-coin-eth) pass:
    • exact-match against the existing MPC vector (commonKeychain @ index 0 → 0x01153f3adfe454a72589ca9ef74f013c19e54961)
    • derive→verify round-trip
    • throws for legacy forwarder wallet versions (1/2/4)
    • throws on missing keychains
  • CI

🤖 Generated with Claude Code

Override BaseCoin.deriveAddress on AbstractEthLikeNewCoins to locally derive a
receive address from the wallet's commonKeychain + index for MPC/TSS wallets
(wallet versions 3, 5, 6), reusing the shared deriveMPCWalletAddress (secp256k1)
helper plus KeyPair.getAddress() — the exact derivation isWalletAddress checks
against, so derive and verify can never diverge.

Offline and key-material-free (public keys only). Legacy BIP32 forwarder wallets
(versions 1, 2, 4) throw a clear error and are handled in a separate ticket.

Adds unit coverage (in sdk-coin-eth) asserting exact-match against the existing
MPC test vector, a derive->verify round-trip, the forwarder-version guard, and
the missing-keychains error.

WCN-916

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rajangarg047 rajangarg047 requested a review from a team as a code owner June 12, 2026 19:49
@linear-code

linear-code Bot commented Jun 12, 2026

Copy link
Copy Markdown

WCN-916

@rajangarg047 rajangarg047 marked this pull request as draft June 12, 2026 19:49
@rajangarg047 rajangarg047 marked this pull request as ready for review June 15, 2026 18:15
@rajangarg047

Copy link
Copy Markdown
Contributor Author

@claude

@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @rajangarg047's task —— View job


Code Review for deriveAddress Implementation ✅

Todo List:

  • Read and understand the implementation in abstractEthLikeNewCoins.ts
  • Review the test cases in eth.ts
  • Check code quality and adherence to BitGoJS standards
  • Verify error handling for unsupported wallet versions
  • Assess security implications and best practices
  • Provide comprehensive review feedback

Review Summary

This is a solid, well-implemented addition that follows BitGoJS patterns and addresses the requirements clearly. The implementation correctly overrides BaseCoin.deriveAddress to provide offline MPC wallet address derivation for ETH-like coins.

✅ Strengths

1. Clean Implementation

  • Consistent with existing patterns: Uses the same deriveMPCWalletAddress helper and KeyPairLib.getAddress() that isWalletAddress uses for verification
  • Good separation of concerns: Abstract base class provides the core functionality, concrete coins inherit it
  • Proper TypeScript usage: Correctly typed with DeriveAddressOptions and DeriveAddressResult

2. Robust Error Handling

  • Clear validation: Properly validates wallet version compatibility (lines 3059-3066 in abstractEthLikeNewCoins.ts)
  • Descriptive error messages: Legacy BIP32 wallet rejection is clear about which versions are unsupported and why
  • Runtime validation: The extractCommonKeychain function validates keychain presence at runtime

3. Security Considerations

  • Offline-first: No network access required, works with public keys only
  • Consistent derivation: Uses the exact same cryptographic path as verification, preventing derive/verify divergence
  • No key material exposure: Works with commonKeychain public data, not private keys

4. Comprehensive Test Coverage

The test suite in eth.ts (lines 1489-1537) covers all critical scenarios:

  • Exact match validation: Tests against known MPC vector (commonKeychain @ index 0 → 0x01153f3adfe454a72589ca9ef74f013c19e54961)
  • Round-trip verification: Derived address successfully verifies with isWalletAddress
  • Error cases: Legacy wallet versions (1/2/4) and missing keychains both properly rejected
  • Multiple wallet versions: Tests both V3 and V6 MPC wallets

5. Documentation Quality

  • Clear JSDoc: Well-documented method with purpose, limitations, and parameters explained
  • Implementation comments: Helpful inline comments about validation and keychain handling
  • Commit message: Follows conventional commits and clearly explains the feature scope

🔍 Code Quality Observations

Architecture Alignment

  • ✅ Follows existing BitGoJS derive* method patterns
  • ✅ Properly leverages shared MPC utilities from @bitgo/sdk-core
  • ✅ Maintains consistency with isWalletAddress implementation
  • ✅ Uses established KeyPairLib for address generation

Type Safety

  • ✅ Proper use of existing TypeScript interfaces (DeriveAddressOptions, TssVerifyAddressOptions)
  • ✅ Correct type casting with runtime validation
  • ✅ Return type matches expected DeriveAddressResult structure

Error Handling Patterns

  • ✅ Consistent with BitGoJS error patterns
  • ✅ Descriptive messages that guide users to solutions
  • ✅ Appropriate error types for different failure modes

📋 Minor Observations (No Action Required)

  1. Future Enhancement Opportunity: The method currently throws for BIP32 wallets (V1/V2/V4), which is appropriate given the ticket scope. When legacy support is added (WCN-932), the implementation can be extended.

  2. Test Vector Validation: The test uses a hardcoded test vector which is good for regression testing, ensuring the derivation algorithm remains stable.

  3. Wallet Version Support: The implementation correctly supports the intended MPC wallet versions (3, 5, 6) and provides clear guidance for unsupported versions.

🏆 Final Assessment

This is excellent work that demonstrates:

  • Strong understanding of BitGoJS architecture
  • Proper security-conscious implementation
  • Comprehensive testing approach
  • Clear documentation and error handling

The implementation correctly achieves the Stage A goals of FR-465 Phase 1, providing offline MPC address derivation that maintains cryptographic consistency with address verification. Ready for merge! 🚀


Job run: https://github.com/BitGo/BitGoJS/actions/runs/xyz
Branch: rajangarg047/wcn-916-eth-mpc-derive-address

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.

2 participants