@did-btcr2/cli 0.22.0 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -396
- package/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +404 -83
- package/dist/esm/src/cli.js +2 -1
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/commands/completion.js +20 -7
- package/dist/esm/src/commands/completion.js.map +1 -1
- package/dist/esm/src/commands/create.js +33 -41
- package/dist/esm/src/commands/create.js.map +1 -1
- package/dist/esm/src/commands/genesis.js +119 -0
- package/dist/esm/src/commands/genesis.js.map +1 -0
- package/dist/esm/src/commands/identifier.js +3 -17
- package/dist/esm/src/commands/identifier.js.map +1 -1
- package/dist/esm/src/commands/index.js +1 -0
- package/dist/esm/src/commands/index.js.map +1 -1
- package/dist/esm/src/commands/resolve.js +15 -1
- package/dist/esm/src/commands/resolve.js.map +1 -1
- package/dist/esm/src/commands/write.js +10 -7
- package/dist/esm/src/commands/write.js.map +1 -1
- package/dist/esm/src/genesis-document-file.js +26 -0
- package/dist/esm/src/genesis-document-file.js.map +1 -0
- package/dist/esm/src/genesis-spec.js +93 -0
- package/dist/esm/src/genesis-spec.js.map +1 -0
- package/dist/esm/src/genesis-wizard.js +132 -0
- package/dist/esm/src/genesis-wizard.js.map +1 -0
- package/dist/esm/src/hints.js +14 -3
- package/dist/esm/src/hints.js.map +1 -1
- package/dist/esm/src/network-option.js +39 -0
- package/dist/esm/src/network-option.js.map +1 -0
- package/dist/esm/src/resolution-options.js +19 -2
- package/dist/esm/src/resolution-options.js.map +1 -1
- package/dist/types/src/cli.d.ts.map +1 -1
- package/dist/types/src/commands/completion.d.ts.map +1 -1
- package/dist/types/src/commands/create.d.ts +5 -4
- package/dist/types/src/commands/create.d.ts.map +1 -1
- package/dist/types/src/commands/genesis.d.ts +20 -0
- package/dist/types/src/commands/genesis.d.ts.map +1 -0
- package/dist/types/src/commands/identifier.d.ts.map +1 -1
- package/dist/types/src/commands/index.d.ts +1 -0
- package/dist/types/src/commands/index.d.ts.map +1 -1
- package/dist/types/src/commands/resolve.d.ts +7 -0
- package/dist/types/src/commands/resolve.d.ts.map +1 -1
- package/dist/types/src/commands/write.d.ts +2 -1
- package/dist/types/src/commands/write.d.ts.map +1 -1
- package/dist/types/src/genesis-document-file.d.ts +11 -0
- package/dist/types/src/genesis-document-file.d.ts.map +1 -0
- package/dist/types/src/genesis-spec.d.ts +70 -0
- package/dist/types/src/genesis-spec.d.ts.map +1 -0
- package/dist/types/src/genesis-wizard.d.ts +30 -0
- package/dist/types/src/genesis-wizard.d.ts.map +1 -0
- package/dist/types/src/hints.d.ts +7 -0
- package/dist/types/src/hints.d.ts.map +1 -1
- package/dist/types/src/network-option.d.ts +15 -0
- package/dist/types/src/network-option.d.ts.map +1 -0
- package/dist/types/src/resolution-options.d.ts +6 -2
- package/dist/types/src/resolution-options.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +18 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/cli.ts +2 -0
- package/src/commands/completion.ts +21 -7
- package/src/commands/create.ts +39 -55
- package/src/commands/genesis.ts +149 -0
- package/src/commands/identifier.ts +3 -25
- package/src/commands/index.ts +1 -0
- package/src/commands/resolve.ts +20 -1
- package/src/commands/write.ts +10 -7
- package/src/genesis-document-file.ts +35 -0
- package/src/genesis-spec.ts +149 -0
- package/src/genesis-wizard.ts +163 -0
- package/src/hints.ts +13 -2
- package/src/network-option.ts +50 -0
- package/src/resolution-options.ts +21 -2
- package/src/types.ts +17 -2
package/README.md
CHANGED
|
@@ -6,13 +6,15 @@ Part of the [`did-btcr2-js`](https://github.com/dcdpr/did-btcr2-js) monorepo.
|
|
|
6
6
|
|
|
7
7
|
## Summary
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The `btcr2` command creates, resolves, updates, and deactivates did:btcr2 identifiers. It decodes and validates identifiers offline. It builds the genesis document of an external identifier. It manages the keys in an encrypted keystore. It reads and writes the CLI config and its profiles. It prints shell completion scripts.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
The CLI wraps the `@did-btcr2/api` SDK. It parses the arguments with [commander.js](https://github.com/tj/commander.js/).
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
`btcr2 resolve` works with no config. The identifier names its network, and the CLI uses public endpoints (mempool.space, ipfs.io) by default. A flag, an environment variable, or the config file can override each endpoint.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
`update` and `deactivate` read the signing key from the keystore. Select a key with `--signing-key <ref>`, or set the active key with `btcr2 key use <ref>`.
|
|
16
|
+
|
|
17
|
+
The reference documentation is in [`docs/`](./docs/README.md). It has one page per command, the global flags, the environment variables, and the precedence rules. [`docs/DEMO.md`](./docs/DEMO.md) is a walkthrough of the full lifecycle on mutinynet.
|
|
16
18
|
|
|
17
19
|
## Install
|
|
18
20
|
|
|
@@ -26,9 +28,9 @@ Or with pnpm:
|
|
|
26
28
|
pnpm add -g @did-btcr2/cli
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
The CLI needs Node.js 22 or newer.
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
To run the CLI without a global install, use npx:
|
|
32
34
|
|
|
33
35
|
```bash
|
|
34
36
|
npx @did-btcr2/cli resolve -i did:btcr2:k1qq...
|
|
@@ -38,409 +40,47 @@ npx @did-btcr2/cli resolve -i did:btcr2:k1qq...
|
|
|
38
40
|
|
|
39
41
|
| Command | Alias | Description |
|
|
40
42
|
|---|---|---|
|
|
41
|
-
| `init` |
|
|
42
|
-
| `quickstart` |
|
|
43
|
-
| `create` |
|
|
44
|
-
| `resolve` | `read` | Resolve
|
|
45
|
-
| `update` |
|
|
46
|
-
| `deactivate` | `delete` | Deactivate
|
|
47
|
-
| `identifier` |
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
Creates an identifier and initial DID document. Two identifier types, selected by `-t/--type`:
|
|
57
|
-
|
|
58
|
-
- **`k`** (deterministic): a 33-byte compressed secp256k1 public key. Three mutually-exclusive input modes:
|
|
59
|
-
- **generate** (neither `--bytes` nor `--signing-key`): mint a fresh key, persist it to the keystore, set it active, and print the identifier. Sealing the secret prompts for the keystore passphrase.
|
|
60
|
-
- **existing** (`--signing-key <ref>`): use a stored key's public key as the genesis bytes. Reading a public key never decrypts, so this never prompts.
|
|
61
|
-
- **raw** (`--bytes <hex>`): a 33-byte public key as hex. Offline and keystore-free.
|
|
62
|
-
- **`x`** (external): raw-bytes only, the 32-byte SHA-256 hash of a genesis document via `--bytes`.
|
|
63
|
-
|
|
64
|
-
| Flag | Description |
|
|
65
|
-
|---|---|
|
|
66
|
-
| `-t, --type <type>` | Identifier type: `k` (deterministic) or `x` (external). Default: `k` |
|
|
67
|
-
| `-n, --network <network>` | Bitcoin network: `bitcoin`, `testnet3`, `testnet4`, `signet`, `mutinynet`, or `regtest`. Default: config `defaults.network`, else the active profile's network, else `regtest` |
|
|
68
|
-
| `-b, --bytes <bytes>` | Genesis bytes as a hex string. For type=k, a 33-byte public key (omit to generate a key); for type=x, the 32-byte genesis-document hash |
|
|
69
|
-
|
|
70
|
-
`--signing-key <ref>` (global) selects a stored key for the existing-key mode; it applies only to `-t k`.
|
|
71
|
-
|
|
72
|
-
On a testnet with a public faucet, text-mode `create` (for a `-t k` identifier) also prints a **funding hint** on stderr: the initial P2WPKH beacon address next to its faucet and explorer links, from the per-network preset. It is suppressed under `--quiet` and `-o json`, and absent on regtest and mainnet.
|
|
73
|
-
|
|
74
|
-
### resolve (alias: read)
|
|
75
|
-
|
|
76
|
-
Required flag: `-i/--identifier`. If both `-r` and `-p` are given, `-r` wins and `-p` is silently ignored.
|
|
77
|
-
|
|
78
|
-
| Flag | Description |
|
|
79
|
-
|---|---|
|
|
80
|
-
| `-i, --identifier <identifier>` | did:btcr2 identifier to resolve (required) |
|
|
81
|
-
| `-r, --resolution-options <json>` | Resolution options as an inline JSON string |
|
|
82
|
-
| `-p, --resolution-options-path <path>` | Path to a JSON file containing resolution options |
|
|
83
|
-
| `--min-conf <n>` | Minimum block confirmations a beacon signal needs before resolution applies it. A positive integer; default `6`, the specification value. Overrides a `minConf` inside `-r`/`-p`. Pass `1` to see a fresh update after one block |
|
|
84
|
-
|
|
85
|
-
### update
|
|
86
|
-
|
|
87
|
-
Signs and broadcasts an update to a DID document. The signing key comes from the encrypted keystore (choose one with `--signing-key <ref>` or set an active key with `btcr2 key use`).
|
|
88
|
-
|
|
89
|
-
Required flags: `-i/--identifier`, `-p/--patches`. The command resolves the current document from the network unless you supply the source pair `-s/--source-document` and `--source-version-id` (both or neither). The api derives the verification method and the beacon unless you pass `-m` or `-b`.
|
|
90
|
-
|
|
91
|
-
| Flag | Description |
|
|
92
|
-
|---|---|
|
|
93
|
-
| `-i, --identifier <identifier>` | did:btcr2 identifier to update (required) |
|
|
94
|
-
| `-p, --patches <json>` | JSON Patch operations as a JSON array string (required) |
|
|
95
|
-
| `-s, --source-document <json>` | Source DID document as a JSON string. Requires `--source-version-id`. Omit both to resolve the current document first |
|
|
96
|
-
| `--source-version-id <number>` | Version ID of the source document, a non-negative integer. Requires `--source-document` |
|
|
97
|
-
| `-m, --verification-method-id <id>` | Verification method that signs the update. Default: the one method of the document that publishes the signing key. Pass it when the api names several candidates |
|
|
98
|
-
| `-b, --beacon-id <id>` | Beacon service that announces the update, as a DID URL (`#initialP2WPKH` or absolute). Default: the only beacon of the document, else the one beacon with a spendable UTXO. Pass it when the api names several funded beacons |
|
|
99
|
-
| `-r, --resolution-options <json>` | Resolution options as an inline JSON string, for the resolution of the source document. Supply sidecar data here if the DID's prior updates are not in a CAS. Not allowed with the source pair |
|
|
100
|
-
| `--resolution-options-path <path>` | Path to a JSON file containing resolution options (`-r` wins if both are given). Not allowed with the source pair |
|
|
101
|
-
| `--min-conf <n>` | Minimum block confirmations a beacon signal needs before the source resolution applies it. A positive integer; default `6`, the specification value. Overrides a `minConf` inside `-r`/`--resolution-options-path`. Not allowed with the source pair |
|
|
102
|
-
| `--publish-to-cas <mode>` | Publish update artifacts to a writable CAS before broadcast: `auto`, `always`, or `never` (default: `never`). See [Publishing updates to CAS](#publishing-updates-to-cas) |
|
|
103
|
-
| `--fee-rate <satsPerVByte>` | Fee rate in sats/vByte for the beacon transaction (default: `5`). Raise it under congestion so the transaction confirms (also `BTCR2_FEE_RATE`, profile `btc.feeRate`) |
|
|
104
|
-
| `--change-address <address>` | Send transaction change to this address instead of the beacon address, so a DID's announcements are not linked on-chain (profile `btc.changeAddress`) |
|
|
105
|
-
|
|
106
|
-
On a network with a block explorer, text-mode `update` (and `deactivate`) also prints a `Watch:` link on stderr for the broadcast txid, suppressed under `--quiet` and `-o json`.
|
|
107
|
-
|
|
108
|
-
### deactivate (alias: delete)
|
|
109
|
-
|
|
110
|
-
Permanently deactivates a DID. This is irreversible. The command calls the api's `deactivateDid`, which applies the `{ "op": "add", "path": "/deactivated", "value": true }` patch and refuses a DID that is deactivated already. It signs via the keystore like `update`.
|
|
111
|
-
|
|
112
|
-
Required flag: `-i/--identifier`. Optional: the same source, derivation, resolution, CAS, fee, and change-address flags as `update`, minus `-p`.
|
|
113
|
-
|
|
114
|
-
### identifier
|
|
115
|
-
|
|
116
|
-
Decodes and validates identifiers. Both subcommands are offline and keystore-free. The identifier is a positional argument.
|
|
117
|
-
|
|
118
|
-
| Subcommand | Description |
|
|
119
|
-
|---|---|
|
|
120
|
-
| `identifier decode <did>` | Print the identifier type, the `hrp`, the version, the network, and the genesis bytes as hex. `--initial-document` adds the initial DID document; an `x` identifier needs `--genesis-document <path>` for it. |
|
|
121
|
-
| `identifier validate <did>` | Run the checks of the identifier decoding algorithm in order and print the report. Exit code `1` if a check fails. `-b, --bytes <hex>` adds the `genesisBytesMatch` check: the identifier must encode these genesis bytes (`k` or `x`). `--genesis-document <path>` adds the `genesisDocument` check for an `x` identifier. |
|
|
122
|
-
|
|
123
|
-
See [`docs/identifier.md`](./docs/identifier.md) for the check list and the output fields.
|
|
124
|
-
|
|
125
|
-
### init
|
|
126
|
-
|
|
127
|
-
`btcr2 init` is the one-command setup: it creates the btcr2 home directory, writes a default config if none exists, and establishes the keystore if none exists. It is idempotent (existing files are left untouched unless `--force`). For a single command that also records the network and (optionally) caches the session and probes the endpoints, see [`quickstart`](#quickstart).
|
|
128
|
-
|
|
129
|
-
| Flag | Description |
|
|
130
|
-
|---|---|
|
|
131
|
-
| `-n, --network <network>` | Bitcoin network to record as `defaults.network` so later commands can drop `-n`. Written idempotently: it never clobbers a network you set earlier |
|
|
132
|
-
| `--dev` | Establish an **unencrypted** dev keystore (plaintext keys, no passphrase). Testnet/regtest only; mainnet operations are refused |
|
|
133
|
-
| `--force` | Re-create the config even if it exists. **Never** re-creates the keystore (re-establishing one is the explicit `keystore init --force`) |
|
|
134
|
-
|
|
135
|
-
By default `init` establishes an **encrypted** keystore and prompts (with confirmation) for a passphrase up front, so the first `key generate` never seals the keystore under an unconfirmed, mistyped passphrase. Supply the passphrase non-interactively with `BTCR2_KEYSTORE_PASSPHRASE` or `--passphrase-file` for scripted setup. The output envelope reports the resolved `network` alongside the paths and `protection`.
|
|
136
|
-
|
|
137
|
-
### quickstart
|
|
138
|
-
|
|
139
|
-
`btcr2 quickstart` collapses onboarding into one step: it runs `init`'s scaffold, records the network (default **mutinynet**), and optionally caches the session and probes the endpoints. It reimplements nothing - it composes `init`, `keystore unlock`, and `config doctor` - so the keystore and session guarantees hold unchanged.
|
|
140
|
-
|
|
141
|
-
| Flag | Description |
|
|
142
|
-
|---|---|
|
|
143
|
-
| `-n, --network <network>` | Bitcoin network to set up. Default: `mutinynet` |
|
|
144
|
-
| `--dev` | Establish an unencrypted dev keystore (testnet only) |
|
|
145
|
-
| `--unlock` | Cache the passphrase for the session so later commands do not re-prompt. Opt-in; on a fresh encrypted keystore it reuses the establish-time passphrase with no second prompt |
|
|
146
|
-
| `--ttl <duration>` | Session lifetime with `--unlock`: bare seconds or an `s`/`m`/`h` suffix (default `1h`, max `24h`; also `BTCR2_KEYSTORE_TTL`) |
|
|
147
|
-
| `--no-doctor` | Skip the endpoint reachability probe (which is on by default and **advisory**: a failed probe warns but `quickstart` still exits 0) |
|
|
148
|
-
| `--allow-mainnet` | Permit `-n bitcoin` (records mainnet as the default; dev keystores are still refused). Guarded before any writes |
|
|
149
|
-
| `--force` | Re-create the config even if it exists (never the keystore) |
|
|
150
|
-
|
|
151
|
-
The workshop happy path:
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
btcr2 quickstart -n mutinynet --unlock --ttl 2h # (or: --dev for an unencrypted dev keystore)
|
|
155
|
-
btcr2 key generate --set-active
|
|
156
|
-
btcr2 create # network comes from defaults.network
|
|
157
|
-
# ...fund the beacon (create prints the faucet + explorer links), resolve, update, deactivate...
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### key
|
|
161
|
-
|
|
162
|
-
Manage keypairs in the keystore. All subcommands operate offline (no Bitcoin connection).
|
|
163
|
-
|
|
164
|
-
| Subcommand | Alias | Description |
|
|
165
|
-
|---|---|---|
|
|
166
|
-
| `key generate` | - | Generate a new keypair and store it. Flags: `--name <name>`, `--set-active` |
|
|
167
|
-
| `key list` | `ls` | List stored keys (id, fingerprint, name, active) |
|
|
168
|
-
| `key show <ref>` | - | Show a key's public material and tags (never prints the secret) |
|
|
169
|
-
| `key import` | - | Import a secret from a hex file (`--secret-file`) or a public key as watch-only (`--public`). Flags: `--name`, `--set-active` |
|
|
170
|
-
| `key export <ref>` | - | Export public material by default; `--secret --out <path>` writes the secret to a new 0600 file |
|
|
171
|
-
| `key delete <ref>` | `rm` | Delete a key. `--force` deletes even the active key |
|
|
172
|
-
| `key use <ref>` | - | Set the active key, persisted across invocations |
|
|
173
|
-
|
|
174
|
-
A key reference is a full URN, a unique `name` tag, or a unique fingerprint prefix.
|
|
175
|
-
|
|
176
|
-
### keystore
|
|
177
|
-
|
|
178
|
-
Establish, inspect, and re-key the keystore. These operate on the keystore file directly (no Bitcoin connection).
|
|
179
|
-
|
|
180
|
-
| Subcommand | Alias | Description |
|
|
181
|
-
|---|---|---|
|
|
182
|
-
| `keystore init` | - | Establish the keystore (encrypted by default; prompts and confirms the passphrase). `--dev` creates an unencrypted dev keystore; `--force` re-establishes an existing one (discards its keys) |
|
|
183
|
-
| `keystore status` | - | Show the resolved path, protection mode (`encrypted`/`dev`/`absent`), whether a passphrase is established, the key count, and the `session` state (whether one is live and its remaining lifetime). Never decrypts or prompts |
|
|
184
|
-
| `keystore change-passphrase` | `passwd` | Re-seal every key under a new passphrase (encrypted keystores only). Prompts for the current passphrase, then a new one (with confirmation). Clears any cached session |
|
|
185
|
-
| `keystore unlock` | - | Cache the verified passphrase for the session so later commands do not re-prompt. `--ttl <duration>` sets the lifetime (default `1h`, max `24h`; also `BTCR2_KEYSTORE_TTL`); `--allow-mainnet` permits unlocking a `bitcoin`-default context |
|
|
186
|
-
| `keystore lock` | - | Revoke the cached session so later commands prompt again. Idempotent; needs no passphrase |
|
|
187
|
-
|
|
188
|
-
**Encrypted vs dev keystores.** An encrypted keystore seals each secret with argon2id + XChaCha20-Poly1305 under one passphrase, and records a verifier so a mistyped passphrase fails loudly (with `Incorrect passphrase`) instead of sealing a key under an unknown or divergent passphrase. A **dev keystore** (`--dev`) stores secrets in plaintext and never prompts: it is for disposable testnet/regtest keys only, and the CLI **hard-refuses** to sign or generate a mainnet (`bitcoin`) key with one.
|
|
189
|
-
|
|
190
|
-
**Session unlock.** `keystore unlock` caches the verified passphrase in `<home>/session.json` (`0600`) so a returning operator authenticates once instead of on every signing command. A cached session sits below `BTCR2_KEYSTORE_PASSPHRASE` / `--passphrase-file` and above the interactive prompt, so unattended and CI paths still win. Mainnet keeps per-use authentication: a `bitcoin` operation is withheld from a session that was not unlocked with `--allow-mainnet`. The cached passphrase is base64url-encoded, not encrypted; its only protection at rest is the `0600` file mode.
|
|
191
|
-
|
|
192
|
-
### config
|
|
193
|
-
|
|
194
|
-
Read and write CLI configuration.
|
|
195
|
-
|
|
196
|
-
| Subcommand | Alias | Description |
|
|
197
|
-
|---|---|---|
|
|
198
|
-
| `config init` | - | Create a default config file with one profile per network. `--force` overwrites |
|
|
199
|
-
| `config get [path]` | - | Print a value at a dotted path, or the whole config. Secret values are redacted; `--show-secrets` reveals them |
|
|
200
|
-
| `config set <path> <value>` | - | Set a value at a dotted path (value parsed as JSON when valid, else a string; known endpoint/credential/name paths are always stored as strings). An invalid enum for a known key is rejected; an unknown path warns but writes |
|
|
201
|
-
| `config unset <path>` | - | Delete a value at a dotted path |
|
|
202
|
-
| `config list` | `ls` | Print the entire config file. Secret values are redacted; `--show-secrets` reveals them |
|
|
203
|
-
| `config validate` | - | Report unknown keys, invalid enum values, and an unsupported schema version |
|
|
204
|
-
| `config effective` | - | Print the resolved connection config with per-value provenance (`flag`/`env`/`file`/`default`). `-n, --network <n>` selects the network; `--show-secrets` reveals the RPC password |
|
|
205
|
-
| `config path` | - | Print the resolved home directory, config-file, and keystore paths |
|
|
206
|
-
| `config doctor` | - | Probe reachability of the resolved endpoints (read-only; touches the network). `-n, --network <n>` selects the network |
|
|
207
|
-
|
|
208
|
-
### profile
|
|
209
|
-
|
|
210
|
-
Manage configuration profiles.
|
|
211
|
-
|
|
212
|
-
| Subcommand | Alias | Description |
|
|
213
|
-
|---|---|---|
|
|
214
|
-
| `profile add <name>` | - | Add an empty profile |
|
|
215
|
-
| `profile use <name>` | - | Set the active profile (writes `defaults.profile`) |
|
|
216
|
-
| `profile show [name]` | - | Show a profile (defaults to the active profile). Secret values are redacted; `--show-secrets` reveals them |
|
|
217
|
-
| `profile remove <name>` | `rm` | Remove a profile |
|
|
218
|
-
|
|
219
|
-
### completion
|
|
220
|
-
|
|
221
|
-
`btcr2 completion [shell]` prints a shell completion script (bash, zsh, or fish) to stdout. Defaults to bash. For example: `eval "$(btcr2 completion bash)"`.
|
|
43
|
+
| [`init`](./docs/init.md) | | Set up the home: create the directory, a default config file, and the keystore. |
|
|
44
|
+
| [`quickstart`](./docs/quickstart.md) | | Set up the home in one command, record the network, and (optional) cache the session and probe the endpoints. |
|
|
45
|
+
| [`create`](./docs/create.md) | | Create an identifier and its initial DID document (offline). |
|
|
46
|
+
| [`resolve`](./docs/resolve.md) | `read` | Resolve the DID document of an identifier. |
|
|
47
|
+
| [`update`](./docs/update.md) | | Update a DID document. The keystore signs the update. |
|
|
48
|
+
| [`deactivate`](./docs/deactivate.md) | `delete` | Deactivate an identifier. This is permanent. The keystore signs the deactivation. |
|
|
49
|
+
| [`identifier`](./docs/identifier.md) | | Decode and validate identifiers (offline). |
|
|
50
|
+
| [`genesis`](./docs/genesis.md) | | Build the genesis document of an external identifier (offline). |
|
|
51
|
+
| [`key`](./docs/key.md) | | Manage the keys in the keystore. |
|
|
52
|
+
| [`keystore`](./docs/keystore.md) | | Create, inspect, re-key, and unlock the keystore. |
|
|
53
|
+
| [`config`](./docs/config.md) | | Read and write the CLI config. |
|
|
54
|
+
| [`profile`](./docs/profile.md) | | Manage the config profiles. |
|
|
55
|
+
| [`completion`](./docs/completion.md) | | Print a shell completion script. |
|
|
56
|
+
|
|
57
|
+
Each page lists the flags, the output, the environment variables, and examples of the command. `btcr2 <command> --help` prints the flags of a command.
|
|
222
58
|
|
|
223
59
|
## Usage
|
|
224
60
|
|
|
225
|
-
### Create a DID
|
|
226
|
-
|
|
227
|
-
```bash
|
|
228
|
-
# Generate a fresh key (type=k), store it in the keystore, and print the identifier
|
|
229
|
-
btcr2 create -n regtest
|
|
230
|
-
|
|
231
|
-
# Deterministic (type=k): from an explicit compressed secp256k1 public key (33 bytes hex)
|
|
232
|
-
btcr2 create -t k -n regtest -b 02aa...
|
|
233
|
-
|
|
234
|
-
# Deterministic (type=k): from a stored key's public key
|
|
235
|
-
btcr2 create -t k -n regtest --signing-key mykey
|
|
236
|
-
|
|
237
|
-
# External (type=x): from a SHA-256 hash of a genesis document (32 bytes hex)
|
|
238
|
-
btcr2 create -t x -n bitcoin -b bb...
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### Resolve a DID
|
|
242
|
-
|
|
243
61
|
```bash
|
|
244
|
-
#
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
# Alias: read
|
|
248
|
-
btcr2 read -i did:btcr2:k1qq...
|
|
249
|
-
|
|
250
|
-
# With resolution options as inline JSON
|
|
251
|
-
btcr2 resolve -i did:btcr2:k1qq... -r '{"versionId":"1"}'
|
|
62
|
+
# Set up the home, the config file, and an encrypted keystore on mutinynet.
|
|
63
|
+
# Cache the passphrase for two hours.
|
|
64
|
+
btcr2 quickstart -n mutinynet --unlock --ttl 2h
|
|
252
65
|
|
|
253
|
-
#
|
|
254
|
-
btcr2
|
|
66
|
+
# Generate a key, store it as the active key, and create an identifier (offline).
|
|
67
|
+
btcr2 create -n mutinynet
|
|
255
68
|
|
|
256
|
-
#
|
|
257
|
-
btcr2 resolve -i did:btcr2:
|
|
69
|
+
# Resolve the DID document from Bitcoin.
|
|
70
|
+
btcr2 resolve -i did:btcr2:k1q5p...
|
|
258
71
|
|
|
259
|
-
# JSON
|
|
260
|
-
btcr2
|
|
72
|
+
# Update the DID document: sign a JSON Patch and broadcast a beacon signal.
|
|
73
|
+
btcr2 update -i did:btcr2:k1q5p... \
|
|
74
|
+
-p '[{"op":"add","path":"/alsoKnownAs","value":["https://example.com/demo"]}]'
|
|
261
75
|
```
|
|
262
76
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
```bash
|
|
266
|
-
# Signs with the active keystore key (or one chosen via --signing-key).
|
|
267
|
-
# The command resolves the current document, derives the verification
|
|
268
|
-
# method and the beacon, then signs and broadcasts.
|
|
269
|
-
btcr2 update -i did:btcr2:k1qq... \
|
|
270
|
-
-p '[{"op":"add","path":"/service/-","value":{"id":"#svc","type":"X","serviceEndpoint":"https://x"}}]'
|
|
271
|
-
|
|
272
|
-
# A DID whose prior update is sidecar-only: hand that update to the source resolution
|
|
273
|
-
btcr2 update -i did:btcr2:k1qq... --min-conf 1 -r '{"sidecar":{"updates":[...]}}' \
|
|
274
|
-
-p '[{"op":"remove","path":"/service/1"}]'
|
|
275
|
-
|
|
276
|
-
# Offline source: supply the document and its version, and name the method and the beacon
|
|
277
|
-
btcr2 update -i did:btcr2:k1qq... \
|
|
278
|
-
-s "$(cat did.json)" --source-version-id 1 \
|
|
279
|
-
-p '[{"op":"remove","path":"/service/1"}]' \
|
|
280
|
-
-m '#initialKey' -b '#initialP2WPKH'
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### Deactivate a DID
|
|
284
|
-
|
|
285
|
-
```bash
|
|
286
|
-
# Irreversible. Resolves the current document, then signs the deactivation via the keystore.
|
|
287
|
-
btcr2 deactivate -i did:btcr2:k1qq... --min-conf 1 -r '{"sidecar":{"updates":[...]}}'
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Manage keys
|
|
291
|
-
|
|
292
|
-
```bash
|
|
293
|
-
btcr2 key generate --name mykey --set-active
|
|
294
|
-
btcr2 key list
|
|
295
|
-
btcr2 key use mykey
|
|
296
|
-
```
|
|
77
|
+
An update needs a funded beacon. On a test network, `create` prints the beacon address and the faucet link. [`docs/DEMO.md`](./docs/DEMO.md) has the full sequence.
|
|
297
78
|
|
|
298
79
|
## Configuration
|
|
299
80
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
### Global flags
|
|
303
|
-
|
|
304
|
-
| Flag | Description |
|
|
305
|
-
|---|---|
|
|
306
|
-
| `-v, --version` | Output the current version |
|
|
307
|
-
| `-o, --output <format>` | Output format: `json` or `text` (default: config `defaults.output`, else `text`) |
|
|
308
|
-
| `--verbose` | Verbose output |
|
|
309
|
-
| `--quiet` | Suppress non-essential output |
|
|
310
|
-
| `--home <dir>` | btcr2 home directory holding `config.json` + `keystore.json` (default: `~/.btcr2`, `%LOCALAPPDATA%\btcr2` on Windows; overrides `$BTCR2_HOME`) |
|
|
311
|
-
| `-c, --config <path>` | Path to config file (default: `<home>/config.json`) |
|
|
312
|
-
| `--profile <name>` | Config profile name (default: auto-detected from network) |
|
|
313
|
-
| `--btc-rest <url>` | Override Bitcoin REST endpoint (Esplora API) |
|
|
314
|
-
| `--btc-rpc-url <url>` | Override Bitcoin Core RPC endpoint |
|
|
315
|
-
| `--btc-rpc-user <user>` | Bitcoin Core RPC username |
|
|
316
|
-
| `--btc-rpc-wallet <name>` | Bitcoin Core wallet name for wallet-scoped RPCs (`/wallet/<name>`) |
|
|
317
|
-
| `--btc-rpc-header <header>` | Extra Bitcoin Core RPC header `"Key: Value"` (repeatable). A credential passed here is on argv: prefer `btc.rpcHeaders` in a profile |
|
|
318
|
-
| `--btc-signal-discovery <mode>` | Where beacon signals are read from `<indexer\|fullnode>` (default: `indexer`; `fullnode` scans blocks over Bitcoin Core RPC) |
|
|
319
|
-
| `--btc-rest-header <header>` | Extra Bitcoin REST header `"Key: Value"` (repeatable). A credential passed here (an API key, a bearer token) is on argv and readable through `ps`: prefer `btc.headers` in a profile |
|
|
320
|
-
| `--btc-timeout <ms>` | Bitcoin REST/RPC request timeout in milliseconds (default: unbounded) |
|
|
321
|
-
| `--cas-gateway <url>` | IPFS HTTP gateway for CAS reads (read-only) |
|
|
322
|
-
| `--cas-rpc-url <url>` | IPFS HTTP RPC endpoint for a writable CAS (reads + writes; enables `--publish-to-cas`) |
|
|
323
|
-
| `--cas-timeout <ms>` | CAS request timeout in milliseconds (default: `30000`; `0` disables) |
|
|
324
|
-
| `--keystore <path>` | Path to the keystore file (default: `<home>/keystore.json`) |
|
|
325
|
-
| `--passphrase-file <path>` | Read the keystore passphrase from a file (unattended use) |
|
|
326
|
-
| `--signing-key <ref>` | Key for create/update/deactivate signing: a URN, fingerprint prefix, or name |
|
|
327
|
-
|
|
328
|
-
### Environment variables
|
|
81
|
+
The CLI keeps its state in one home directory: `~/.btcr2` on Linux and macOS, `%LOCALAPPDATA%\btcr2` on Windows. The home holds `config.json`, `keystore.json`, and `session.json`. `--home <dir>` or `BTCR2_HOME` moves the home.
|
|
329
82
|
|
|
330
|
-
|
|
331
|
-
|---|---|
|
|
332
|
-
| `BTCR2_BTC_REST` | `--btc-rest` |
|
|
333
|
-
| `BTCR2_BTC_RPC_URL` | `--btc-rpc-url` |
|
|
334
|
-
| `BTCR2_BTC_RPC_USER` | `--btc-rpc-user` |
|
|
335
|
-
| `BTCR2_BTC_RPC_PASS` | no flag: a password on argv is readable through `ps` and shell history |
|
|
336
|
-
| `BTCR2_BTC_RPC_PASS_FILE` | file whose contents are the RPC password |
|
|
337
|
-
| `BTCR2_CAS_GATEWAY` | `--cas-gateway` |
|
|
338
|
-
| `BTCR2_CAS_RPC_URL` | `--cas-rpc-url` |
|
|
339
|
-
| `BTCR2_BTC_SIGNAL_DISCOVERY` | `--btc-signal-discovery` |
|
|
340
|
-
| `BTCR2_BTC_TIMEOUT` | `--btc-timeout` |
|
|
341
|
-
| `BTCR2_CAS_TIMEOUT` | `--cas-timeout` |
|
|
342
|
-
| `BTCR2_FEE_RATE` | `--fee-rate` |
|
|
343
|
-
| `BTCR2_OUTPUT` | `-o, --output` |
|
|
344
|
-
| `BTCR2_HOME` | `--home` |
|
|
345
|
-
| `BTCR2_KEYSTORE_PASSPHRASE` | keystore passphrase (unattended use) |
|
|
346
|
-
| `BTCR2_KEYSTORE_TTL` | session lifetime for `keystore unlock` / `quickstart --unlock` (default `1h`, max `24h`) |
|
|
347
|
-
|
|
348
|
-
### Home directory
|
|
349
|
-
|
|
350
|
-
The CLI keeps its config and keystore side by side in one home directory, resolved as `--home <dir>`, then `$BTCR2_HOME`, then the platform default: `~/.btcr2` on Linux/macOS and `%LOCALAPPDATA%\btcr2` on Windows. Both files live directly under it (`<home>/config.json`, `<home>/keystore.json`); `btcr2 config path` prints the resolved locations. `--config` and `--keystore` still override each file individually, so the historical XDG split can be reproduced explicitly.
|
|
351
|
-
|
|
352
|
-
### Config file
|
|
353
|
-
|
|
354
|
-
Default location: `<home>/config.json`. A malformed config file fails loudly (the CLI never silently falls back to public endpoints, and never overwrites an unparseable file).
|
|
355
|
-
|
|
356
|
-
Profiles are matched by network name when neither `--profile` nor the config's `defaults.profile` selects one. For example, with no active profile set, resolving a regtest DID automatically selects the `"regtest"` profile. A profile that is not named after a network can declare its network with a `network` field.
|
|
357
|
-
|
|
358
|
-
```json
|
|
359
|
-
{
|
|
360
|
-
"schemaVersion": 1,
|
|
361
|
-
"defaults": {
|
|
362
|
-
"profile": "production",
|
|
363
|
-
"network": "bitcoin",
|
|
364
|
-
"output": "text"
|
|
365
|
-
},
|
|
366
|
-
"profiles": {
|
|
367
|
-
"regtest": {
|
|
368
|
-
"btc": {
|
|
369
|
-
"rest": "http://localhost:3000",
|
|
370
|
-
"rpcUrl": "http://localhost:18443",
|
|
371
|
-
"rpcUser": "polaruser",
|
|
372
|
-
"rpcPass": "polarpass",
|
|
373
|
-
"wallet": "primary",
|
|
374
|
-
"feeRate": 5,
|
|
375
|
-
"timeoutMs": 30000
|
|
376
|
-
}
|
|
377
|
-
},
|
|
378
|
-
"production": {
|
|
379
|
-
"network": "bitcoin",
|
|
380
|
-
"btc": {
|
|
381
|
-
"rest": "https://my-mempool/api",
|
|
382
|
-
"headers": { "Authorization": "Bearer <api-key>" },
|
|
383
|
-
"feeRate": 20
|
|
384
|
-
},
|
|
385
|
-
"cas": { "gateway": "https://ipfs.io", "rpcUrl": "http://127.0.0.1:5001", "timeoutMs": 30000 },
|
|
386
|
-
"identity": { "keystore": "/secure/prod-keystore.json", "default": "did:btcr2:...#key-0" }
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
Field notes:
|
|
393
|
-
|
|
394
|
-
- **`defaults`**: `profile` selects the active profile; `network` fixes the network `create` encodes when `-n` is absent; `output` sets the default output format. `schemaVersion` is stamped on every write; a file written by a newer CLI is refused.
|
|
395
|
-
- **`btc`**: `rest`/`rpcUrl`/`rpcUser`/`rpcPass` are endpoints and credentials; `wallet` targets a Bitcoin Core wallet (`/wallet/<name>`); `headers`/`rpcHeaders` add REST/RPC headers; `feeRate` (sats/vByte), `changeAddress`, and `timeoutMs` set broadcast and request behavior;
|
|
396
|
-
`signalDiscovery` (`"indexer"` or `"fullnode"`) picks where beacon signals are read from. The RPC url, user, and pass are resolved as one atomic unit, so a URL from a higher-precedence layer never inherits credentials from a lower one.
|
|
397
|
-
- **`cas`**: `gateway` is a read-only IPFS HTTP gateway; `cas.rpcUrl` is a writable IPFS HTTP RPC endpoint (enables `--publish-to-cas`; `rpcUrl` wins over `gateway`); `timeoutMs` bounds CAS operations (`0` disables).
|
|
398
|
-
- **`identity`**: `keystore` points the profile at its own keystore file, and `default` is the profile's default signing key. Both fall **below** the corresponding `--keystore` / `--signing-key` flags.
|
|
399
|
-
|
|
400
|
-
Use `config validate` to check a file, and `config effective` to see the resolved values with their provenance.
|
|
401
|
-
|
|
402
|
-
### RPC password and secrets
|
|
403
|
-
|
|
404
|
-
`config get`, `config list`, and `profile show` redact secret-looking values (the RPC password and any key matching `pass`/`secret`/`token`/`auth`/`api-key`/`credential`/`bearer`, e.g. an `Authorization` header) by default; pass `--show-secrets` to reveal them.
|
|
405
|
-
|
|
406
|
-
An `rpcPass` written directly into `config.json` is stored in cleartext (the file is mode 0600 but not encrypted). For anything sensitive, keep the secret out of the file with a reference or an RPC-URL-embedded credential:
|
|
407
|
-
|
|
408
|
-
- `"rpcPass": "env:MY_RPC_PASS"` reads the password from the `MY_RPC_PASS` environment variable.
|
|
409
|
-
- `"rpcPass": "file:/run/secrets/rpc-pass"` reads it from a file (a single trailing newline is trimmed).
|
|
410
|
-
- `BTCR2_BTC_RPC_PASS_FILE=/run/secrets/rpc-pass` names a file to read when no other RPC password source applies.
|
|
411
|
-
|
|
412
|
-
### Defaults
|
|
413
|
-
|
|
414
|
-
When no overrides are configured:
|
|
415
|
-
|
|
416
|
-
- **Bitcoin REST**: [mempool.space](https://mempool.space) for `bitcoin`, `testnet3`, `testnet4`, and `signet`; [mutinynet.com](https://mutinynet.com) for `mutinynet`; `http://localhost:3000` for `regtest`
|
|
417
|
-
- **Bitcoin RPC**: `http://localhost:18443` for `regtest` (credentials required), not configured for public networks
|
|
418
|
-
- **CAS**: [ipfs.io](https://ipfs.io) HTTP gateway (read-only). Configure a writable CAS with `--cas-rpc-url` (or `cas.rpcUrl`) to publish with `--publish-to-cas`
|
|
419
|
-
|
|
420
|
-
## Publishing updates to CAS
|
|
421
|
-
|
|
422
|
-
CAS publication is **optional and never required**. Every `update` and `deactivate` can be completed and shared entirely via sidecar: the command always prints the artifacts a resolver needs (the signed update, the transaction id, the CAS announcement for CAS beacons, and the SMT proof for SMT beacons) for you to distribute yourself.
|
|
423
|
-
|
|
424
|
-
Optionally, the signed update (and, for CAS beacons, the announcement) can be published to a content-addressed store before the on-chain broadcast, so any OP_RETURN update hash is fetchable from CAS at resolution time without sidecar data. This is opt-in via `--publish-to-cas`:
|
|
425
|
-
|
|
426
|
-
| Mode | Behavior |
|
|
427
|
-
|---|---|
|
|
428
|
-
| `never` (default) | Publish nothing. Distribute the printed artifacts via sidecar. |
|
|
429
|
-
| `auto` | Best-effort. Publish when a writable CAS is configured; otherwise skip publication silently for every beacon type and proceed. Never blocks an update. |
|
|
430
|
-
| `always` | Require a writable CAS; error up-front for every beacon type when none is configured. |
|
|
431
|
-
|
|
432
|
-
A writable CAS is configured with `--cas-rpc-url <url>` (an IPFS HTTP RPC endpoint, e.g. a local Kubo node at `http://127.0.0.1:5001`), the `BTCR2_CAS_RPC_URL` environment variable, or a profile's `cas.rpcUrl`. The default IPFS gateway is read-only, so without a configured `--cas-rpc-url`, `--publish-to-cas auto` publishes nothing and completes the update sidecar-only, while `--publish-to-cas always` errors up-front (naming the fix) for every beacon type.
|
|
433
|
-
|
|
434
|
-
**Privacy:** under `auto`/`always`, canonical signed updates (and announcements) are published to the configured, possibly public, CAS before the on-chain anchor. Keep `never` (the default) to distribute update data privately via sidecar.
|
|
435
|
-
|
|
436
|
-
```bash
|
|
437
|
-
# Opt into CAS publication against a local IPFS (Kubo) node
|
|
438
|
-
btcr2 update \
|
|
439
|
-
--cas-rpc-url http://127.0.0.1:5001 \
|
|
440
|
-
--publish-to-cas auto \
|
|
441
|
-
-i did:btcr2:k1qq... \
|
|
442
|
-
-p '[{"op":"add","path":"/service/-","value":{"id":"#svc","type":"X","serviceEndpoint":"https://x"}}]'
|
|
443
|
-
```
|
|
83
|
+
A value comes from the first of these sources: a flag, an environment variable, the active profile in the config file, the built-in default of the network. [`docs/config.md`](./docs/config.md) describes the config file and the `config` subcommands. [`docs/README.md`](./docs/README.md) lists the global flags, the environment variables, and the precedence of each value.
|
|
444
84
|
|
|
445
85
|
## Links
|
|
446
86
|
|