Skip to content

chore: support custom address derivation#8450

Draft
ashutoshkumar-6 wants to merge 1 commit intomasterfrom
SI-271
Draft

chore: support custom address derivation#8450
ashutoshkumar-6 wants to merge 1 commit intomasterfrom
SI-271

Conversation

@ashutoshkumar-6
Copy link
Copy Markdown
Contributor

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.

Change Guard condition Fallback for all other coins
Address verification `baseAddressDerivationPath === 'm'` must be explicitly passed `m/{index}` — unchanged
Recovery derivation `params.baseAddressDerivationPath` must be explicitly passed `?? 'm/0'` — unchanged
Recovery DSG 5th arg must be explicitly passed default `= 'm/0'` — unchanged
Message signing `wallet.coinSpecific().baseAddressDerivationPath` must be set on the wallet `
`generateWallet()` `sourceFlrpWalletId` is optional, ignored by all other coin handlers in wallet-platform no-op

`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

  • 7 new unit tests for `verifyMPCWalletAddress` path-selection logic covering: root path (`m`), standard path (`m/0`), non-zero indices, SMC prefix, and string-index variants
  • All existing address verification and recovery tests pass without regression
  • Manually verify `generateWallet()` passes `sourceFlrpWalletId` through to the API call

Ticket: SI-271

🤖 Generated with Claude Code

TICKET: SI-271
Made-with: Cursor
@linear
Copy link
Copy Markdown

linear bot commented Apr 9, 2026

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