zinc-wallet-cli 0.3.0

Agent-first Bitcoin + Ordinals CLI wallet with account-based taproot ordinals + native segwit payment addresses (optional human mode)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# zinc-cli Usage (Human + Agent)

This guide is task-oriented. For strict response contracts, see `COMMAND_CONTRACT_V1.md` and `SCHEMAS.md`.

## 1) Command Shape

Global flags can appear before or after command tokens:

```bash
zinc-cli [global flags] <command> [command flags]
```

`dashboard` and the interactive setup wizard are available only in builds compiled with the `ui` feature (for example: `cargo install zinc-wallet-cli --features ui`).
With `ui` enabled, the basic dashboard shows account balance, inscriptions, and ordinals/payment addresses for each account.

Useful globals:

- `--agent` machine output mode (returns structured JSON)
- `--profile <name>` select profile (default: `default`)
- `--data-dir <path>` override data root
- `--password <value>`
- `--password-env <ENV_NAME>` (default env: `ZINC_WALLET_PASSWORD`)
- `--password-stdin`
- `--reveal` show mnemonic fields in `--agent` mode, and on `wallet import`
- `--correlation-id <id>` set a stable workflow/request identifier
- `--log-json` emit structured lifecycle logs to stderr (`command_start|command_finish|command_error`)
- `--idempotency-key <key>` de-duplicate mutating commands for retry-safe automation
- `--network-timeout-secs <n>` timeout for remote calls (default: `30`)
- `--network-retries <n>` retry count for transient network failures/timeouts (default: `0`)
- `--policy-mode warn|strict` transaction safety behavior (default: `warn`)
- `--thumb` force inscription thumbnails on
- `--no-thumb` disable inscription thumbnails

Environment defaults (optional):

- `ZINC_CLI_PROFILE`
- `ZINC_CLI_DATA_DIR`
- `ZINC_CLI_PASSWORD_ENV`
- `ZINC_CLI_OUTPUT` (`human|agent`)
- `ZINC_CLI_NETWORK`
- `ZINC_CLI_SCHEME`
- `ZINC_CLI_ESPLORA_URL`
- `ZINC_CLI_ORD_URL`
- `ZINC_CLI_CORRELATION_ID`
- `ZINC_CLI_LOG_JSON` (`1|true|yes|on`)
- `ZINC_CLI_IDEMPOTENCY_KEY`
- `ZINC_CLI_NETWORK_TIMEOUT_SECS`
- `ZINC_CLI_NETWORK_RETRIES`
- `ZINC_CLI_POLICY_MODE` (`warn|strict`)

Inspect effective config:

```bash
zinc-cli --agent config show
```

Persist config defaults:

```bash
zinc-cli setup
zinc-cli setup --profile bot-a --data-dir /var/lib/zinc --password-env BOT_PASS
zinc-cli config set network signet
zinc-cli config set scheme unified
```

`zinc-cli setup` starts an interactive wizard when run in a terminal and can initialize a wallet profile at the end (generate new or restore existing mnemonic).

Password precedence:

1. `--password`
2. `--password-stdin`
3. `--password-env`

## 2) Human Quick Start

Set a default password env once:

```bash
export ZINC_WALLET_PASSWORD='your-wallet-password'
```

Initialize wallet:

```bash
zinc-cli wallet init --network signet --overwrite
```

Show wallet info:

```bash
zinc-cli wallet info
```

Reveal seed phrase (sensitive):

```bash
zinc-cli --yes --agent wallet reveal-mnemonic
```

Sync and check balance:

```bash
zinc-cli sync chain
zinc-cli sync ordinals
zinc-cli balance
zinc-cli inscription list
```

Get addresses:

```bash
zinc-cli address taproot
zinc-cli address payment
```



## 3) Agent Mode (Recommended)

Use `--agent` and parse stdout as one JSON object.

```bash
zinc-cli --agent wallet info
```

Expected envelope:

```json
{
  "ok": true,
  "schema_version": "1.0",
  "command": "wallet info"
}
```

Error envelope:

```json
{
  "ok": false,
  "schema_version": "1.0",
  "command": "wallet info",
  "error": {
    "type": "config",
    "message": "failed to read profile: ...",
    "exit_code": 10
  }
}
```

Bash error handling pattern:

```bash
out="$(zinc-cli --agent wallet info)"
ok="$(printf '%s' "$out" | jq -r '.ok')"
if [ "$ok" != "true" ]; then
  printf '%s\n' "$out" | jq -r '.error.type + ": " + .error.message' >&2
  exit "$(printf '%s' "$out" | jq -r '.error.exit_code')"
fi
```

## 4) Agent Reliability Controls

Use strict policy, idempotency, and retry controls together:

```bash
CID="agent-run-42"
zinc-cli --agent \
  --correlation-id "$CID" \
  --log-json \
  --idempotency-key "send-0001" \
  --network-timeout-secs 20 \
  --network-retries 2 \
  --policy-mode strict \
  psbt broadcast --psbt-file /tmp/send.signed.psbt
```

Behavior:
- repeated call with the same `--idempotency-key` + same mutating payload replays cached success
- reusing the same key with a different mutating payload returns `error.type=invalid`
- in `--policy-mode strict`, risky/unknown PSBT policy outcomes are blocked with `error.type=policy`

## 5) PSBT Flow

Create:

```bash
zinc-cli --agent psbt create \
  --to <address> --amount-sats 10000 --fee-rate 2 --out-file /tmp/send.psbt
```

Analyze:

```bash
zinc-cli --agent psbt analyze --psbt-file /tmp/send.psbt
```

Sign:

```bash
zinc-cli --agent psbt sign \
  --psbt-file /tmp/send.psbt --finalize --out-file /tmp/send.signed.psbt
```

Broadcast:

```bash
zinc-cli --agent psbt broadcast --psbt-file /tmp/send.signed.psbt
```

Rules:

- For `psbt analyze/sign/broadcast`, exactly one of `--psbt`, `--psbt-file`, `--psbt-stdin` is required.
- `--password-stdin` cannot be combined with `--psbt-stdin` in one invocation.

## 6) Offer Commands (Nostr + Ord, Advanced)

`offer` is callable directly (`zinc-cli offer ...`) but intentionally hidden from top-level `zinc-cli --help`.

Create an ord-compatible buyer offer PSBT and a relay-ready offer envelope:

```bash
zinc-cli --agent --ord-url https://ord.example offer create \
  --inscription <inscription-id> \
  --amount 100000 \
  --fee-rate 1 \
  --expires-in-secs 3600 \
  --seller-payout-address <seller-payment-address> \
  --publisher-pubkey-hex <xonly-pubkey-hex> \
  --offer-out-file /tmp/offer.json \
  --psbt-out-file /tmp/offer.psbt
```

Create and immediately submit the PSBT to ord:

```bash
zinc-cli --agent --ord-url https://ord.example offer create \
  --inscription <inscription-id> \
  --amount 100000 \
  --fee-rate 1 \
  --submit-ord
```

Publish a signed offer event to one or more relays:

```bash
zinc-cli --agent offer publish \
  --offer-json '{"version":1,"seller_pubkey_hex":"<xonly-pubkey-hex>","network":"regtest","inscription_id":"<inscription-id>","seller_outpoint":"<txid:vout>","ask_sats":100000,"fee_rate_sat_vb":1,"psbt_base64":"<base64-psbt>","created_at_unix":1710000000,"expires_at_unix":1710003600,"nonce":42}' \
  --secret-key-hex <seller-secret-key-hex> \
  --relay wss://nostr.example
```

Human-focused, glanceable offer output (great for demos):

```bash
zinc-cli --ord-url https://ord.example --thumb offer create \
  --inscription <inscription-id> \
  --amount 100000 \
  --fee-rate 1
```

```bash
zinc-cli --ord-url https://ord.example --thumb offer discover \
  --relay wss://nostr.example
```

```bash
zinc-cli --ord-url https://ord.example --thumb offer accept \
  --offer-file /tmp/offer.json
```

Discover offers from one or more relays:

```bash
zinc-cli --agent offer discover \
  --relay wss://nostr.example \
  --limit 256 \
  --timeout-ms 5000
```

Accept an offer from an offer envelope (sign seller input and optionally broadcast):

```bash
zinc-cli --agent offer accept \
  --offer-file /tmp/offer.json \
  --expect-inscription <inscription-id> \
  --expect-ask-sats 100000
```

Dry run acceptance checks (no broadcast):

```bash
zinc-cli --agent offer accept \
  --offer-file /tmp/offer.json \
  --dry-run
```

Submit an offer PSBT to ord:

```bash
zinc-cli --agent --ord-url https://ord.example \
  offer submit-ord --psbt-file /tmp/offer.psbt
```

List offer PSBTs from ord:

```bash
zinc-cli --agent --ord-url https://ord.example \
  offer list-ord
```

Rules:

- For `offer publish`, exactly one of `--offer-json`, `--offer-file`, `--offer-stdin` is required.
- For `offer accept`, exactly one of `--offer-json`, `--offer-file`, `--offer-stdin` is required.
- For `offer submit-ord`, exactly one of `--psbt`, `--psbt-file`, `--psbt-stdin` is required.
- `offer create` requires `--ord-url` and inscription metadata available from ord indexer.
- `offer create --seller-payout-address` is optional; when omitted, payout defaults to the inscription output address from ord metadata.
- For dual-scheme sellers, pass `--seller-payout-address <payment-address>` to direct proceeds to the seller payment branch.
- `offer create --publisher-pubkey-hex` can override the default publisher pubkey embedded in the offer envelope.
- `offer publish` and `offer discover` require at least one `--relay`.
- `--thumb` and `--no-thumb` are boolean toggles.
- In human mode, thumbnails are enabled by default unless `--no-thumb` or `--no-images` is set.
- In `--agent` mode, thumbnails are disabled by default unless `--thumb` is explicitly set.

## 7) Profiles, Accounts, and Waits

Use named profile and custom data directory:

```bash
zinc-cli --agent --profile bot-a --data-dir /var/lib/zinc wallet info
```

Switch account:

```bash
zinc-cli --agent account use --index 1
```

Wait for confirmation:

```bash
zinc-cli --agent wait tx-confirmed --txid <txid> --timeout-secs 300
```

## 8) Safety Notes

- Prefer setting `ZINC_WALLET_PASSWORD` once for automation.
- Use `--password-env` only when you need a non-default env var name.
- Avoid `--password` in shared process environments.
- `wallet init` in human mode prints the new seed phrase once; in `--agent` mode mnemonic output is redacted unless `--reveal` is set.
- In `--agent` mode, consume stdout as machine data and treat stderr as diagnostics only.

## 9) Agent Flow Integration Test

Run the complete agentic wallet flow:

```bash
ZINC_CLI_LIVE_TESTS=1 cargo test --test agent_flow test_agent_wallet_workflow -- --nocapture
```

Run the live offer create -> accept integration test:

```bash
ZINC_CLI_LIVE_TESTS=1 cargo test --test offer_live test_offer_create_and_accept_live -- --nocapture
```

Sample run from a funded regtest environment:

```text
[1] Import wallet with seed phrase (dual scheme)
  ✓ Network: regtest, Scheme: dual
[2] Get wallet info
  ✓ Profile: default, Network: regtest, Scheme: dual
[3] Sync chain
  ✓ Chain synced
[4] Sync ordinals
  ✓ Ordinals synced: 3 inscriptions
[5] List inscriptions
  ✓ Inscriptions listed: 3
[6] Get account 0 taproot/payment addresses
  ✓ A0 taproot=bcrt1p...lts0 payment=bcrt1q...pee3
[7] Get taproot address at index 3
  ✓ Taproot[3]: bcrt1p...yk0g
[8] Get account 0 balance
  ✓ Account 0 total sats before transfer: 3118181 (spendable: 3117191)
[9] Account list
  ✓ Account 0 taproot=bcrt1p...lts0 payment=bcrt1q...pee3
[10] Switch to account 1
  ✓ Switched to account 1 taproot=bcrt1p...emmn payment=bcrt1q...36mn
[11] Verify new taproot after account switch
  ✓ Address changed: bcrt1p...lts0 -> bcrt1p...ydta
  ✓ Account 1 total sats before transfer: 0
[12] Switch back to account 0
  ✓ Switched back to account 0
[13] Create PSBT to transfer 1000 sats from account 0 -> account 1 payment
  ✓ PSBT created
[14] Analyze PSBT
  ✓ PSBT analyzed
[15] Sign + finalize PSBT
  ✓ PSBT signed
[16] Broadcast transaction
  ✓ Broadcast txid=eb7696...6017
[17] Verify account 0 sees transfer tx
  ✓ Account 0 total sats after transfer: 3117040 (before 3118181)
[18] Verify account 1 sees transfer tx + balance increase
  ✓ Account 1 total sats after transfer: 1000 (before 0)

✅ Wallet workflow test passed!
test test_agent_wallet_workflow ... ok
```

If account 0 does not have enough spendable balance, the transfer portion is skipped by design.

## 10) Offer Live Integration Tests (Ord + Nostr)

Run the ord submit/list live round-trip:

```bash
ZINC_CLI_LIVE_TESTS=1 \
cargo test --test offer_live test_offer_ord_submit_and_list_live -- --nocapture
```

Run the nostr publish/discover live round-trip using default relay:

```bash
ZINC_CLI_LIVE_TESTS=1 \
cargo test --test offer_live test_offer_nostr_publish_discover_live -- --nocapture
```

Use a custom nostr relay endpoint:

```bash
ZINC_CLI_LIVE_TESTS=1 \
ZINC_CLI_TEST_NOSTR_RELAY_URL=wss://nostr-regtest.exittheloop.com \
cargo test --test offer_live test_offer_nostr_publish_discover_live -- --nocapture
```

Notes:
- Tests are opt-in and skipped unless `ZINC_CLI_LIVE_TESTS=1` is set.
- Live infra defaults used by the suite:
  - Esplora: `https://regtest.exittheloop.com/api`
  - Ord: `https://ord-regtest.exittheloop.com`
  - Nostr relay: `wss://nostr-regtest.exittheloop.com`