chore: support custom address derivation#8450
Draft
ashutoshkumar-6 wants to merge 1 commit intomasterfrom
Draft
Conversation
TICKET: SI-271 Made-with: Cursor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this PR exists
When a user stakes on FLR P (Flare Platform/UTXO chain), the staking protocol pays rewards to an FLR C (Flare Contract/EVM chain) address. That reward address is derived from the root public key (`m`) of the FLR P wallet's MPC key material — not from the child key at `m/0`.
BitGo's normal FLR C TSS wallet creation derives the base address at `m/0`. This produces a different address than where staking rewards land. To fix this, wallet-platform (bitgo-microservices) creates a special FLR C wallet whose base address is derived from the root key (`m`) of the paired FLR P wallet, and stores `baseAddressDerivationPath: 'm'` in the wallet's `coinSpecific`.
A few utility functions in BitGoJS hardcode `m/0` and need to be updated to respect the wallet's configured derivation path. That is what this PR does.
What changed and why
1. Address verification — `addressVerification.ts`
`verifyMPCWalletAddress` always constructed the path as `m/{index}`, so verifying the base address (index 0) would check `m/0` — which is the wrong key for FLR P-derived wallets. Now reads `baseAddressDerivationPath` from params and uses `m` when it equals `'m'` and index is 0.
2. Recovery — `abstractEthLikeNewCoins.ts`
`recoverTSS` hardcoded `MPC.deriveUnhardened(commonKeyChain, 'm/0')`. For FLR P-derived wallets, recovery would compute the wrong address and sign with the wrong key. Now reads `params.baseAddressDerivationPath` with `'m/0'` as the default.
3. Recovery DSG setup — `ecdsaMPCv2.ts` (`signRecoveryMpcV2`)
The recovery signing function hardcoded `'m/0'` in all three `DklsDsg` / `verifyAndConvertDklsSignature` call-sites. Now accepts an optional `derivationPath` parameter (default `'m/0'`), threaded through from `recoverTSS`.
4. Message signing fallback — `ecdsaMPCv2.ts`
Message signing defaulted to `'m/0'` when no `derivationPath` was present in the TxRequest messages. Now checks `wallet.coinSpecific().baseAddressDerivationPath` as a fallback before `'m/0'`.
5. `generateWallet()` — `wallets.ts` / `iWallets.ts` / `iBaseCoin.ts`
Added optional `sourceFlrpWalletId` to `GenerateWalletOptions`, `GenerateBaseMpcWalletOptions`, and `SupplementGenerateWalletOptions`, threaded through to the `/wallet/add` API call. Without this, SDK users had to call the REST API directly to create an FLR P-derived wallet.
Why this is safe and does not affect any other coin
Every change is opt-in via a new optional field. If the field is absent (which is true for every coin except this specific FLR C wallet type), behaviour is identical to before.
`baseAddressDerivationPath` is a new field written to the DB only by wallet-platform's `createTssWalletFromFlrP()` method, exclusively for FLR C wallets derived from FLR P. No existing wallet document in MongoDB has this field, so all other coins — ETH, MATIC, AVAX, and every other TSS coin — continue to use `m/0` exactly as before.
The double-gate in wallet-platform (`isStakingWallet === true && baseAddressDerivationPath === 'm'`) provides an additional layer so the signing path change cannot be triggered by any wallet that was not explicitly created through this new flow.
Test plan
Ticket: SI-271
🤖 Generated with Claude Code