Deterministic NIP-60 Wallets
Deterministic NIP-60 Wallets
NUT-13 from the Cashu protocol defines how a wallet must generate deterministically its secrets on token creation. This allows wallets in case of any loss to recover the funds from seed words with mint collaboration.
This proposal extends NIP-60 to support NUT-13 defining how the wallet seed (generated from the seed words according to BIP-39) and the counter state for every mint and keyset should be stored in a new Nostr event kind. In NIP-60, kind 17375 stores both a private key (used to lock tokens for exclusive spending) and the user's selected mints. To maintain backward compatibility and reduce the risk of affecting existing clients, we introduce a new event kind rather than modifying the existing 17375 schema, we define a new kind.
Deterministic Wallet Event
{
"kind": 17376,
"content": nip44_encrypt({
"bip39seed": "hexkey",
"counters": {
"<normalized-mint1-url>|<keyset=keyset-id-1>": "<counter-1>",
"<normalized-mint1-url>|<keyset=keyset-id-2>": "<counter-2>",
"<normalized-mint2-url>|<keyset=keyset-id-3>": "<counter-3>",
}
}),
"tags": [],
...
}As in the kind 17375 it is an replaceable event and the event content is encrypted according to NIP-44. In the encrypted content the relevant information get stored. The bip39seed field contains the 32-byte seed in hexadecimal format. Upon initialization, the counters map is empty ({}).
The map keys are formed by combining a normalized, unique mint URL, with its keyset ID. To Normalize a mint URL to a canonical stable representation, the following criteria are applied:
- Only http/https are accepted,
- lowercase scheme and host,
- strip username/password, query and fragment, if present,
- strip default ports (http:80, https:443), if present,
- normalize path:
- "/" for root,
- no trailing slash for non-root, if present.
Implementation Notes
Wallet implementations must fetch both kinds 17375 and the new 17376 to initialize their state properly. The Cashu NUT-13 specifies how to proceed to obtain deterministic proofs from the corresponding mint and how to implement the restore process. The counter state for every mint and keyset ID must be kept up to date by publishing updates of the kind 17376. Cashu libraries like cachu-ts (Typescript) and cdk (Rust) support NUT-13 and simplify the proof creation and recovery.
This proposal has been implemented in a fork of nostr-dev-kit and is demonstrated in the latest Satshoot 1.0.0 release: Satshoot.