Skip to content

fix: give mainnet and testnet wallets separate keys - #19

Open
Yamaguchi wants to merge 5 commits into
chaintope:mainfrom
Yamaguchi:fix/derive_separate_keys_per_network
Open

Yamaguchi wants to merge 5 commits into
chaintope:mainfrom
Yamaguchi:fix/derive_separate_keys_per_network

Conversation

@Yamaguchi

@Yamaguchi Yamaguchi commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Switching between mainnet and testnet in the extension only changed which explorer it talked to — the wallet's address and private key stayed exactly the same on both networks. Traced to @tapylet/core always deriving the key with the testnet coin type, whichever network was selected.

Details

Mainnet and testnet now derive genuinely separate keys (see the companion @tapylet/core change). Addresses stay in the prod format on both networks; only the derivation path's coin type differs. A wallet created from now on gets both keys up front. An existing wallet gets its missing keys derived right after unlock; its previous single address is carried forward untouched as a "legacy mainnet address" — real funds may be sitting there — rather than recomputed, and a one-time notice tells the user their mainnet address has changed and where the old one went.

Changes

  • PasswordSetupScreen: derive and store both mainnet/testnet keys on creation.
  • UnlockScreen + storage/migrations.ts#ensureWalletNetworkKeys: backfill missing per-network keys after unlock; each network is derived independently so one failing doesn't block the other.
  • New screens: LegacyMigrationNoticeScreen (one-time notice), MissingNetworkKeyScreen (retry when a key failed to derive), LegacyAddressScreen (view balance / send from the legacy mainnet address, reachable from Settings).
  • SendModal takes an explicit networkId and an optional fromLegacyMainnetWallet flag, reused by both normal sends and legacy-address sends.
  • WalletData moved from a single address/publicKey to networks: Record<networkId, {address, publicKey}> plus legacyMainnetAddress.
  • Bump @tapylet/core to ^0.0.8.

Impact

  • Every existing installed wallet: on first unlock after this update, the mainnet address shown changes to a freshly derived one. The previous address, and any funds on it, is reachable from Settings → "Previous mainnet address".
  • The previous address is the same as the new testnet address, since both use the same derivation path and address format.

Verification Steps

  • npm test — 128 tests
  • npx tsc --noEmit
  • pnpm build
  • Needs a load-unpacked run through: create a wallet (check both addresses differ), unlock an existing wallet (check the migration notice and the legacy address screen), switch networks, send from the legacy address.

Related Issues

chaintope/tapylet-core#8

Notes

- derive and store both mainnet/testnet keys on wallet creation, and
  backfill missing ones (per network) right after unlock
- carry a pre-split wallet's address forward as legacyMainnetAddress
  instead of losing access to funds sent there
- add screens for the one-time migration notice, a missing network key,
  and viewing/sending from the legacy mainnet address
- reuse SendModal for both normal and legacy-address sends
@Yamaguchi

Yamaguchi commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor Author

ロック解除時(1回だけ表示)

image

設定画面

image

「確認する」クリック時

image

「新しいアドレスに送金する」クリック時

image

@Yamaguchi
Yamaguchi force-pushed the fix/derive_separate_keys_per_network branch from 77283dc to ee9c7be Compare October 7, 2026 06:03
@Yamaguchi
Yamaguchi marked this pull request as ready for review October 7, 2026 07:57
@Yamaguchi
Yamaguchi requested a review from azuchi October 7, 2026 08:28

This branch has not been deployed

No deployments
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