Create and restore ask the person to pick ML-DSA-65 or ML-DSA-87, and the wallet then derives only that account. The same phrase gives a different account under each scheme, so a person who picks the one they did not use sees an empty balance while their funds sit on the other account. That is the kind of mistake a wallet should make impossible rather than warn about.
Scope
Remove the scheme selection from create and restore (and from the commands behind them: wallet_create_begin, wallet_import_phrase).
Opening a wallet whose file carries a phrase derives both accounts, each at its conventional path (…/0'/0'/0' for ML-DSA-87, …/0'/0'/1' for ML-DSA-65), plus the file's own stored keypair if it sits at another path, de-duplicated by account id. A file with no phrase (a raw-seed or CLI-generated key) keeps its one account.
Every screen that lists accounts (accounts, receive, send's from, history, the other-networks overview) shows both, each with its balance. The scheme stays visible as a label, never as a choice.
Whichever scheme Quantus's own docs and tools steer people toward is the default: it is written to the keystore file, listed first, and preselected on receive and send. The other is shown alongside, not hidden.
The keystore file format stays quantus-cli's. The file records one keypair (the default scheme's); the second account is derived in memory from the phrase on every open.
Acceptance
Restore the public dev phrase once: both qz… accounts appear with their balances without choosing anything, the default one first. A wallet file written by quantus wallet import under either scheme opens with both accounts. A CLI raw-seed file (crystal_alice) opens with its one account. The secret-leak test still passes with both signers held.
Parent: #4
## Why
Create and restore ask the person to pick ML-DSA-65 or ML-DSA-87, and the wallet then derives only that account. The same phrase gives a different account under each scheme, so a person who picks the one they did not use sees an empty balance while their funds sit on the other account. That is the kind of mistake a wallet should make impossible rather than warn about.
## Scope
- Remove the scheme selection from create and restore (and from the commands behind them: `wallet_create_begin`, `wallet_import_phrase`).
- Opening a wallet whose file carries a phrase derives **both** accounts, each at its conventional path (`…/0'/0'/0'` for ML-DSA-87, `…/0'/0'/1'` for ML-DSA-65), plus the file's own stored keypair if it sits at another path, de-duplicated by account id. A file with no phrase (a raw-seed or CLI-generated key) keeps its one account.
- Every screen that lists accounts (accounts, receive, send's from, history, the other-networks overview) shows both, each with its balance. The scheme stays visible as a label, never as a choice.
- Whichever scheme Quantus's own docs and tools steer people toward is the default: it is written to the keystore file, listed first, and preselected on receive and send. The other is shown alongside, not hidden.
- The keystore file format stays quantus-cli's. The file records one keypair (the default scheme's); the second account is derived in memory from the phrase on every open.
## Acceptance
Restore the public dev phrase once: both `qz…` accounts appear with their balances without choosing anything, the default one first. A wallet file written by `quantus wallet import` under either scheme opens with both accounts. A CLI raw-seed file (`crystal_alice`) opens with its one account. The secret-leak test still passes with both signers held.
## Depends on
#15 (keystore), #17 (session).
grenade
added the child label 2026-09-16 15:22:35 +00:00
Which scheme is the default, from Quantus's own clients: quantus-cli (--schemedefault_value_t = DilithiumScheme::MlDsa65; README "default scheme: ml-dsa-65, HD path …/1'"), the mobile SDK (DilithiumSchemeExtension.current = mlDsa65, legacy = mlDsa87), the cold wallet ("New wallets stay ML-DSA-65 unless the user opts into ML-DSA-87") and the browser extension (DEFAULT_TYPE = 'dilithium65'; ML-DSA-87 "must remain importable but is never offered as a choice", and it shows the ML-DSA-65, ML-DSA-87 and wormhole accounts together). The chain node's own key command still defaults to 87, and docs.quantus.com gives no guidance. So: ML-DSA-65 current and first, ML-DSA-87 shown beside it labelled legacy.
Not done here, noted for later: the mobile wallet's import goes further, running a BIP-44 gap-limit scan over account indices (m/44'/189189'/<i>'/0'/<scheme>') for both schemes against its indexer, so a phrase that was used for account 2 or 3 shows those too. This wallet derives account 0 under each scheme. A child for discovery can follow if it matters.
Which scheme is the default, from Quantus's own clients: quantus-cli (`--scheme` `default_value_t = DilithiumScheme::MlDsa65`; README "default scheme: ml-dsa-65, HD path …/1'"), the mobile SDK (`DilithiumSchemeExtension.current = mlDsa65`, `legacy = mlDsa87`), the cold wallet ("New wallets stay ML-DSA-65 unless the user opts into ML-DSA-87") and the browser extension (`DEFAULT_TYPE = 'dilithium65'`; ML-DSA-87 "must remain importable but is never offered as a choice", and it shows the ML-DSA-65, ML-DSA-87 and wormhole accounts together). The chain node's own `key` command still defaults to 87, and docs.quantus.com gives no guidance. So: ML-DSA-65 current and first, ML-DSA-87 shown beside it labelled legacy.
Not done here, noted for later: the mobile wallet's import goes further, running a BIP-44 gap-limit scan over account indices (`m/44'/189189'/<i>'/0'/<scheme>'`) for both schemes against its indexer, so a phrase that was used for account 2 or 3 shows those too. This wallet derives account 0 under each scheme. A child for discovery can follow if it matters.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Parent: #4
Why
Create and restore ask the person to pick ML-DSA-65 or ML-DSA-87, and the wallet then derives only that account. The same phrase gives a different account under each scheme, so a person who picks the one they did not use sees an empty balance while their funds sit on the other account. That is the kind of mistake a wallet should make impossible rather than warn about.
Scope
wallet_create_begin,wallet_import_phrase).…/0'/0'/0'for ML-DSA-87,…/0'/0'/1'for ML-DSA-65), plus the file's own stored keypair if it sits at another path, de-duplicated by account id. A file with no phrase (a raw-seed or CLI-generated key) keeps its one account.Acceptance
Restore the public dev phrase once: both
qz…accounts appear with their balances without choosing anything, the default one first. A wallet file written byquantus wallet importunder either scheme opens with both accounts. A CLI raw-seed file (crystal_alice) opens with its one account. The secret-leak test still passes with both signers held.Depends on
#15 (keystore), #17 (session).
Which scheme is the default, from Quantus's own clients: quantus-cli (
--schemedefault_value_t = DilithiumScheme::MlDsa65; README "default scheme: ml-dsa-65, HD path …/1'"), the mobile SDK (DilithiumSchemeExtension.current = mlDsa65,legacy = mlDsa87), the cold wallet ("New wallets stay ML-DSA-65 unless the user opts into ML-DSA-87") and the browser extension (DEFAULT_TYPE = 'dilithium65'; ML-DSA-87 "must remain importable but is never offered as a choice", and it shows the ML-DSA-65, ML-DSA-87 and wormhole accounts together). The chain node's ownkeycommand still defaults to 87, and docs.quantus.com gives no guidance. So: ML-DSA-65 current and first, ML-DSA-87 shown beside it labelled legacy.Not done here, noted for later: the mobile wallet's import goes further, running a BIP-44 gap-limit scan over account indices (
m/44'/189189'/<i>'/0'/<scheme>') for both schemes against its indexer, so a phrase that was used for account 2 or 3 shows those too. This wallet derives account 0 under each scheme. A child for discovery can follow if it matters.