This document defines the recommended product flow for multi-device FrostDAO use. It is written from a user perspective, then maps each step to the protocol messages and commands that already exist.
FrostDAO should feel like five clear jobs:
- Create or join a room.
- Create a wallet with TSS or HTSS.
- Derive receive addresses from the wallet.
- Propose and sign transactions.
- Reshare or recover when membership changes.
Nostr is the message transport. NIP-44 protects sensitive messages. FROST, Birkhoff, and Bitcoin signing remain local cryptographic operations.
Device A Nostr relay Device B
-------- ----------- --------
local share -> encrypted message -> local share
local check <- public status <- local check
The relay should never receive private shares, nonces, or signature shares in plaintext.
Goal: get all devices into the same coordination space.
User steps:
- Organizer creates a room ID.
- Each device opens FrostDAO and chooses
Join room. - Each signer enters:
- room ID
- party index
- threshold
- total parties
- scheme:
TSSorHTSS - rank, only for HTSS
- Each device publishes
room_join. - The room becomes ready when all expected parties are present.
UX requirements:
- Show
Party X of Non every device. - Show scheme clearly:
TSSorHTSS. - For HTSS, show rank and authority meaning.
- Show relay status separately from protocol readiness.
- Allow copying the room ID and showing it as a QR code later.
Protocol:
room_join
room_ready
Goal: create one threshold wallet without any complete private key existing on one device.
User steps:
- Choose wallet name.
- Confirm scheme:
- TSS: any
tofnparties can sign. - HTSS: signers must satisfy rank policy.
- TSS: any
- Each device runs DKG round 1 locally.
- Devices publish public commitments and encryption pubkeys.
- Each device encrypts round 2 shares per recipient.
- Each device receives enough encrypted shares.
- Each device finalizes locally.
- The app shows the shared root Taproot address and first derived receive address.
UX requirements:
- Split the screen by rounds: Round 1, Round 2, Finalize.
- Label messages:
- Round 1 commitment: public
- Round 2 share: encrypted to one party
- Final wallet share: local only
- Show per-party progress.
- Keep a visible warning: never paste plaintext shares into public chat.
- For HTSS, validate rank policy before finalization.
Protocol:
keygen_round1
keygen_round2_encrypted
CLI equivalent:
frostdao keygen-round1 --name treasury --threshold 2 --n-parties 3 --my-index 1
frostdao keygen-round2 --name treasury --data '<round1_outputs>' --encrypt
frostdao keygen-finalize --name treasury --data '<round2_outputs>'For HTSS:
frostdao keygen-round1 --name treasury --threshold 3 --n-parties 5 --my-index 1 --rank 0 --hierarchicalGoal: generate new receive addresses from the same threshold wallet.
User steps:
- Open wallet.
- Choose
Receive. - Pick address index or use next unused index.
- Show derived Taproot address.
- Optionally show path, QR, and copy button.
Important behavior:
- This does not rerun DKG.
- This does not reuse the exact same private key.
- Each derived address is a deterministic tweak of the root threshold key.
- Parties can later sign for that derived path with threshold shares.
CLI equivalent:
frostdao dkg-derive-address --name treasury --change 0 --index 0
frostdao dkg-list-addresses --name treasury --count 10UX requirements:
- Use language like
Derived address, notnew wallet. - Show path with the selected network's BIP-86 coin type:
m/86'/0'/0'/0/indexon mainnet,m/86'/1'/0'/0/indexon testnet, signet, and regtest. - Explain that the same MPC threshold signer set controls all derived addresses.
- Explain that each derived address is controlled by tweaked threshold shares for the selected path, not by a newly reconstructed private key.
- Show a child x-only pubkey fingerprint for HD selections so multiple devices can compare the same threshold-controlled child before signing.
Goal: one signer creates a transaction proposal for the group to review.
User steps:
- Proposer selects wallet and derived address or root address.
- Proposer enters recipient, amount, fee rate, and note.
- App builds unsigned transaction and sighash.
- App publishes transaction proposal.
- Other devices receive proposal and review details.
UX requirements:
- Review screen must show:
- wallet
- source address/path
- recipient
- amount
- fee
- network
- sighash fingerprint
- proposer party
- Mainnet requires a stronger confirmation step.
- Consent should be explicit:
Approve proposalorReject proposal.
Protocol:
tx_proposal
tx_consent
CLI equivalent:
frostdao dkg-build-tx --name treasury --to <address> --amount <sats> --network testnet4Goal: collect enough valid signing material and broadcast a transaction.
User steps:
- After enough consents, each signing device generates a nonce locally.
- Nonces are encrypted per recipient or signing group policy.
- Each signer creates a signature share locally.
- Signature shares are encrypted and sent.
- Aggregator combines enough valid shares.
- App broadcasts transaction.
- All devices receive broadcast result.
UX requirements:
- Warn that nonces are single-use.
- Show valid signer set status:
- TSS:
2 of 3 collected - HTSS:
rank policy satisfiedor specific missing authority
- TSS:
- Do not show raw secret material unless user explicitly opens advanced details.
- If combine fails, show whether the problem is missing shares, invalid ranks, invalid share, or wrong session.
Protocol:
signing_nonce_encrypted
signing_share_encrypted
tx_broadcast
CLI equivalent:
frostdao dkg-nonce --name treasury --session <session>
frostdao dkg-sign --name treasury --session <session> --sighash <hex> --data '<nonces>'
frostdao dkg-broadcast --name treasury --session <session> --unsigned-tx <hex> --data '<shares>'Goal: change or refresh shares without changing the wallet identity.
Use cases:
- Replace a lost or retired device.
- Rotate shares after suspected exposure.
- Change from one party set to another.
- Preserve the same root public key and derived addresses.
User steps:
- Choose source wallet.
- Choose target wallet name.
- Choose new threshold and party count.
- Choose scheme:
- TSS: all new parties rank 0.
- HTSS: define new party ranks.
- Existing parties publish reshare round 1 outputs.
- Existing parties encrypt sub-shares to new parties.
- New parties finalize locally.
- App compares old and new address fingerprints.
UX requirements:
- Make the invariant visible:
Address stays the same. - Show old party set and new party set side by side.
- For HTSS, show old rank map and new rank map.
- Prevent accidental privilege escalation during recovery.
- Require confirmation if target wallet already exists.
Protocol:
reshare_round1
reshare_subshare_encrypted
reshare_finalize
CLI equivalent:
frostdao reshare-round1 --source treasury --new-threshold 2 --new-n-parties 3 --my-index 1
frostdao reshare-finalize --source treasury --target treasury_v2 --my-index 1 --data '<round1_outputs>'Goal: reconstruct a lost party share without exposing the full wallet secret.
User steps:
- Lost party creates target wallet name.
- Helper parties generate recovery sub-shares.
- Lost party receives enough recovery data.
- App reconstructs the lost share locally.
- App verifies the recovered wallet has the same public key/address.
UX requirements:
- Make helper role and lost-party role separate.
- Preserve original rank for HTSS recovery.
- Show that helpers cannot recover their own missing share.
- Show final verification before marking recovery complete.
Protocol:
recovery_round1
recovery_subshare_encrypted
recovery_finalize
CLI equivalent:
frostdao recover-round1 --name treasury --lost-index 2
frostdao recover-finalize --source treasury --target treasury_recovered --my-index 2 --data '<recovery_outputs>'The best UX entry point is not a command list. It should be a task picker:
FrostDAO
What do you want to do?
[ Create wallet ] DKG with TSS or HTSS
[ Join signing room ] Review and sign a proposal
[ Receive bitcoin ] Derive a new address
[ Reshare wallet ] Rotate shares, keep address
[ Recover share ] Restore a lost party
Each task should show:
- current network
- local party identity
- wallet selected
- relay state
- security status
Every device should track the same high-level state:
| State | Meaning |
|---|---|
local_ready |
Local wallet/share material is available |
relay_connected |
Nostr relay is reachable |
room_ready |
Expected parties have joined |
round_ready |
Required messages for current round are present |
policy_valid |
TSS threshold or HTSS rank rule is satisfied |
finalized |
Local ceremony step is complete |
This state model is more useful to users than raw protocol names alone.
Build in this order:
- Room join and participant readiness.
- TSS DKG over Nostr.
- HTSS DKG over Nostr with rank map.
- Transaction proposal and consent.
- Signing nonce/share exchange.
- Reshare over Nostr.
- Recovery over Nostr.
This order gives users a working multi-device story before adding every advanced ceremony.