Skip to content

Commit 7ce2b03

Browse files
committed
feat: added a command to send dm with attachment to admin to help disputes solving - added some docs for AI generated code
1 parent 9b0ecb2 commit 7ce2b03

8 files changed

Lines changed: 825 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ pretty_env_logger = "0.5.0"
4747
sqlx = { version = "0.8.6", features = ["sqlite", "runtime-tokio-rustls"] }
4848
bip39 = { version = "2.2.0", features = ["rand"] }
4949
dirs = "6.0.0"
50+
chacha20poly1305 = "0.10.1"
51+
rand_core = "0.6.4"
52+
bitcoin = "0.32.2"
5053

5154
[package.metadata.release]
5255
# (Default: true) Set to false to prevent automatically running `cargo publish`.

docs/architecture.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
## Architecture & Code Structure
2+
3+
This document describes the internal structure of `mostro-cli`, how major modules interact, and the main data/control flows. It is intentionally high-level to stay stable across refactors.
4+
5+
### Entry point and CLI wiring
6+
7+
- **`src/main.rs`**
8+
- Initializes the async runtime and delegates to `cli::run()`.
9+
- Very thin; most logic is in `src/cli.rs`.
10+
11+
- **`src/cli.rs`**
12+
- Declares submodules for each logical command group: `add_invoice`, `adm_send_dm`, `conversation_key`, `dm_to_user`, `get_dm`, `get_dm_user`, `last_trade_index`, `list_disputes`, `list_orders`, `new_order`, `orders_info`, `rate_user`, `restore`, `send_dm`, `send_admin_dm_attach`, `send_msg`, `take_dispute`, `take_order`.
13+
- Defines:
14+
- `Context`: runtime dependencies required by commands (Nostr client, keys, trade index, DB pool, optional admin context keys, and Mostro pubkey).
15+
- `Cli`: top-level arguments parsed by `clap` (subcommand, verbosity, Mostro pubkey override, relay list, PoW, secret mode).
16+
- `Commands`: enum containing all subcommands and their structured arguments.
17+
- `run()`:
18+
- Parses CLI args via `Cli::parse()`.
19+
- Constructs a `Context` using `init_context(&cli)`.
20+
- Dispatches: `if let Some(cmd) = &cli.command { cmd.run(&ctx).await?; }`.
21+
- `init_context()`:
22+
- Sets environment variables from CLI flags (e.g. `MOSTRO_PUBKEY`, `RELAYS`, `POW`, `SECRET`).
23+
- Connects to SQLite via `db::connect()`.
24+
- Loads identity and per-trade keys from the local `users` table.
25+
- Optionally loads `ADMIN_NSEC` into `context_keys` for admin commands.
26+
- Resolves `MOSTRO_PUBKEY` via CLI flag or environment.
27+
- Connects to Nostr relays via `util::connect_nostr()`.
28+
29+
### Utilities and shared infrastructure
30+
31+
- **`src/util/mod.rs`**
32+
- Organizes utility modules:
33+
- `events`: event filtering and retrieval from Nostr.
34+
- `messaging`: higher-level DM helpers (gift-wrapped messages, admin keys, etc.).
35+
- `misc`: small helpers such as `get_mcli_path` and string utilities.
36+
- `net`: Nostr network connection setup.
37+
- `storage`: thin storage helpers for orders and DMs.
38+
- `types`: small shared enums/wrappers.
39+
- Re-exports commonly used symbols (`create_filter`, `send_dm`, `connect_nostr`, `save_order`, etc.) so other modules can import from `crate::util` directly.
40+
41+
- **`src/util/storage.rs`**
42+
- `save_order(order, trade_keys, request_id, trade_index, pool)`:
43+
- Wraps `Order::new` to insert/update an order row.
44+
- Logs created order IDs.
45+
- Updates the `User`'s `last_trade_index` in the `users` table.
46+
- `run_simple_order_msg(command, order_id, ctx)`:
47+
- Convenience wrapper that forwards to `cli::send_msg::execute_send_msg(...)` for simple order messages (e.g. `FiatSent`, `Release`, `Cancel`, `Dispute`).
48+
- `admin_send_dm(ctx, msg)`:
49+
- Uses `util::messaging::get_admin_keys` and `util::send_dm` to send an admin DM via Nostr.
50+
51+
- **`src/util/types.rs`**
52+
- `Event` enum:
53+
- Wraps `SmallOrder`, `Dispute`, and a `Message` tuple `(Message, u64, PublicKey)` for use in parsers and event handling.
54+
- `ListKind` enum:
55+
- Identifies what is being listed: `Orders`, `Disputes`, `DirectMessagesUser`, `DirectMessagesAdmin`, `PrivateDirectMessagesUser`.
56+
- `MessageType` (internal to `util`) distinguishes DM/gift-wrap styles.
57+
58+
### Database layer
59+
60+
- **`src/db.rs`**
61+
- Connection:
62+
- `connect()` creates or opens `mcli.db` in the CLI data directory from `get_mcli_path()`.
63+
- On first run, it creates the `orders` and `users` tables via raw SQL.
64+
- On subsequent runs, it applies a small migration to drop legacy `buyer_token`/`seller_token` columns if present.
65+
- Models:
66+
- `User`:
67+
- Represents the local identity (mnemonic, root pubkey, last trade index).
68+
- Handles creation (`User::new`), loading (`User::get`), updating (`save`), and key derivation helpers (identity keys and per-trade keys using `nip06`).
69+
- `Order`:
70+
- Represents cached orders with fields mapped to the `orders` table.
71+
- Provides `new`, `insert_db`, `update_db`, fluent setters, `save`, `save_new_id`, `get_by_id`, `get_all_trade_keys`, and `delete_by_id`.
72+
- See `database.md` for schema details.
73+
74+
### Parsers and protocol types
75+
76+
- **`src/parser/*`**
77+
- Interpret raw Nostr events into higher-level `Event` variants based on `mostro_core` types.
78+
- Responsibility split:
79+
- `orders.rs`: parsing order-related events.
80+
- `disputes.rs`: parsing dispute events.
81+
- `dms.rs`: parsing direct messages.
82+
- `common.rs`: shared parsing helpers.
83+
- `mod.rs`: module glue.
84+
85+
### Lightning integration
86+
87+
- **`src/lightning/mod.rs`**
88+
- Houses Lightning Network–specific helpers used by order flows and invoice handling (exact functions depend on the current version of the file).
89+
- Typically used by `add_invoice`, `new_order`, and `take_order` modules.
90+
91+
### Command modules
92+
93+
Each file in `src/cli/` encapsulates the logic of a specific feature or a group of related commands:
94+
95+
- Order-related: `add_invoice.rs`, `list_orders.rs`, `new_order.rs`, `take_order.rs`, `orders_info.rs`, `rate_user.rs`, `restore.rs`, `last_trade_index.rs`.
96+
- Disputes and admin: `list_disputes.rs`, `take_dispute.rs`, `adm_send_dm.rs`.
97+
- Messaging: `send_dm.rs`, `send_msg.rs`, `dm_to_user.rs`, `get_dm.rs`, `get_dm_user.rs`, `send_admin_dm_attach.rs`, `conversation_key.rs`.
98+
99+
Each module exports an `execute_*` function that `Commands::run` calls. This keeps `src/cli.rs` as a central router while pushing feature logic into focused files.
100+
101+
### Typical flow: creating a new order
102+
103+
1. User runs `mostro-cli neworder ...`.
104+
2. `clap` parses CLI arguments into `Cli` and `Commands::NewOrder { ... }`.
105+
3. `cli::run()` calls `init_context()` to build `Context` (DB, keys, Nostr client, Mostro pubkey).
106+
4. `Commands::run` matches `Commands::NewOrder` and calls `execute_new_order(...)`.
107+
5. The handler:
108+
- Uses `mostro_core` types to construct an order message.
109+
- Sends it to the Mostro backend over Nostr via `util::connect_nostr`/messaging helpers.
110+
- Persists or updates the local representation via `util::save_order` and `db::Order`.
111+
112+
### Extension guidelines
113+
114+
When adding new features:
115+
116+
- **New command**:
117+
- Add a variant to `Commands` in `src/cli.rs`.
118+
- Add the corresponding `execute_*` function in a `src/cli/*.rs` module.
119+
- Extend the `Commands::run` match arm.
120+
- Update `docs/commands.md` to keep documentation in sync.
121+
122+
- **New database fields / tables**:
123+
- Update `connect()` schema creation and migrations in `src/db.rs`.
124+
- Extend the relevant model structs and methods.
125+
- Update `docs/database.md`.
126+
127+
- **New protocol/event type**:
128+
- Extend `util::types::Event` and the relevant parser module in `src/parser/*`.
129+
- Adjust listing or DM flows as needed.
130+

docs/commands.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
## CLI Commands Reference
2+
3+
This document lists all `mostro-cli` subcommands defined in `src/cli.rs`, their main arguments, and the Rust handler that implements each command. Use this when wiring new commands or changing existing flows.
4+
5+
All commands are part of the `Commands` enum and are dispatched via `Commands::run(&self, ctx: &Context)`.
6+
7+
### Orders
8+
9+
- **`listorders`**
10+
- **Description**: Requests open orders from the configured Mostro pubkey.
11+
- **Args**:
12+
- `--status <STRING>`: Optional order status filter.
13+
- `--currency <STRING>`: Optional fiat currency code.
14+
- `--kind <STRING>`: Optional order kind (buy/sell).
15+
- **Handler**: `execute_list_orders(kind, currency, status, ctx)` in `src/cli/list_orders.rs`.
16+
17+
- **`neworder`**
18+
- **Description**: Create a new buy/sell order on Mostro.
19+
- **Args**:
20+
- `--kind <STRING>`: Order kind (e.g. `buy` or `sell`).
21+
- `--amount <i64>`: Sats amount; `0` means market price.
22+
- `-c, --fiat-code <STRING>`: Fiat currency code.
23+
- `--fiat-amount <RANGE>`: Fiat amount or range, validated by `check_fiat_range`.
24+
- `-m, --payment-method <STRING>`: Payment method identifier.
25+
- `--premium <i64>`: Premium on the price (can be negative).
26+
- `--invoice <STRING>`: Optional Lightning invoice.
27+
- `--expiration-days <i64>`: Expiration time in days for pending orders.
28+
- **Handler**: `execute_new_order(...)` in `src/cli/new_order.rs`.
29+
30+
- **`takesell`**
31+
- **Description**: Take a sell order from a Mostro pubkey.
32+
- **Args**:
33+
- `--order-id <UUID>`: Order identifier.
34+
- `--invoice <STRING>`: Optional Lightning invoice.
35+
- `--amount <u32>`: Fiat amount to buy.
36+
- **Handler**: `execute_take_order(order_id, Action::TakeSell, invoice, amount, ctx)` in `src/cli/take_order.rs`.
37+
38+
- **`takebuy`**
39+
- **Description**: Take a buy order from a Mostro pubkey.
40+
- **Args**:
41+
- `--order-id <UUID>`: Order identifier.
42+
- `--amount <u32>`: Fiat amount to sell.
43+
- **Handler**: `execute_take_order(order_id, Action::TakeBuy, &None, amount, ctx)` in `src/cli/take_order.rs`.
44+
45+
- **`addinvoice`**
46+
- **Description**: Buyer adds a new invoice to receive the payment.
47+
- **Args**:
48+
- `--order-id <UUID>`: Order identifier.
49+
- `--invoice <STRING>`: Lightning invoice.
50+
- **Handler**: `execute_add_invoice(order_id, invoice, ctx)` in `src/cli/add_invoice.rs`.
51+
52+
- **`fiatsent`**
53+
- **Description**: Send a "fiat sent" message to confirm payment to the counterparty.
54+
- **Args**:
55+
- `--order-id <UUID>`: Order identifier.
56+
- **Handler**: `util::run_simple_order_msg(Commands::FiatSent { .. }, Some(order_id), ctx)`.
57+
58+
- **`release`**
59+
- **Description**: Settle the hold invoice and pay to the buyer.
60+
- **Args**:
61+
- `--order-id <UUID>`: Order identifier.
62+
- **Handler**: `util::run_simple_order_msg(Commands::Release { .. }, Some(order_id), ctx)`.
63+
64+
- **`cancel`**
65+
- **Description**: Cancel a pending order.
66+
- **Args**:
67+
- `--order-id <UUID>`: Order identifier.
68+
- **Handler**: `util::run_simple_order_msg(Commands::Cancel { .. }, Some(order_id), ctx)`.
69+
70+
- **`ordersinfo`**
71+
- **Description**: Request detailed information for specific orders.
72+
- **Args**:
73+
- `--order-ids <UUID>...`: One or more order IDs.
74+
- **Handler**: `execute_orders_info(order_ids, ctx)` in `src/cli/orders_info.rs`.
75+
76+
### Disputes
77+
78+
- **`dispute`**
79+
- **Description**: Start a dispute for an order.
80+
- **Args**:
81+
- `--order-id <UUID>`: Order identifier.
82+
- **Handler**: `util::run_simple_order_msg(Commands::Dispute { .. }, Some(order_id), ctx)`.
83+
84+
- **`listdisputes`**
85+
- **Description**: Request open disputes from the Mostro pubkey.
86+
- **Args**: None.
87+
- **Handler**: `execute_list_disputes(ctx)` in `src/cli/list_disputes.rs`.
88+
89+
### Direct messages (user)
90+
91+
- **`getdm`**
92+
- **Description**: Get the latest direct messages.
93+
- **Args**:
94+
- `--since <i64>`: Minutes back from now to query (default: 30).
95+
- `--from-user`: If true, get messages from the counterparty instead of Mostro.
96+
- **Handler**: `execute_get_dm(since, false, from_user, ctx)` in `src/cli/get_dm.rs`.
97+
98+
- **`getdmuser`**
99+
- **Description**: Get direct messages sent to any trade keys.
100+
- **Args**:
101+
- `--since <i64>`: Minutes back from now to query (default: 30).
102+
- **Handler**: `execute_get_dm_user(since, ctx)` in `src/cli/get_dm_user.rs`.
103+
104+
- **`senddm`**
105+
- **Description**: Send a direct message to a user.
106+
- **Args**:
107+
- `--pubkey <NPUB/HEX>`: Pubkey of the counterpart.
108+
- `--order-id <UUID>`: Order identifier (for context).
109+
- `--message <STRING>...`: Message parts; joined with spaces.
110+
- **Handler**: `execute_send_dm(PublicKey::from_str(pubkey)?, ctx, order_id, &msg)` in `src/cli/send_dm.rs`.
111+
112+
- **`dmtouser`**
113+
- **Description**: Send a gift-wrapped direct message to a user.
114+
- **Args**:
115+
- `--pubkey <NPUB/HEX>`: Recipient pubkey.
116+
- `--order-id <UUID>`: Order id to derive ephemeral keys.
117+
- `--message <STRING>...`: Message parts; joined with spaces.
118+
- **Handler**: `execute_dm_to_user(PublicKey::from_str(pubkey)?, &ctx.client, order_id, &msg, &ctx.pool)` in `src/cli/dm_to_user.rs`.
119+
120+
### Direct messages (admin / solver)
121+
122+
- **`getadmindm`**
123+
- **Description**: Get the latest direct messages for admin.
124+
- **Args**:
125+
- `--since <i64>`: Minutes back from now to query (default: 30).
126+
- `--from-user`: If true, get messages from the counterparty instead of Mostro.
127+
- **Handler**: `execute_get_dm(since, true, from_user, ctx)` in `src/cli/get_dm.rs`.
128+
129+
- **`admsenddm`** *(admin only)*
130+
- **Description**: Send a gift-wrapped direct message to a user as admin/solver.
131+
- **Args**:
132+
- `--pubkey <NPUB/HEX>`: Recipient pubkey.
133+
- `--message <STRING>...`: Message parts; joined with spaces.
134+
- **Handler**: `execute_adm_send_dm(PublicKey::from_str(pubkey)?, ctx, &msg)` in `src/cli/adm_send_dm.rs`.
135+
136+
- **`sendadmindmattach`** *(admin only)*
137+
- **Description**: Send an admin DM with an encrypted attachment stored on a Blossom server.
138+
- **Args**:
139+
- `--pubkey <NPUB/HEX>`: Admin recipient pubkey.
140+
- `--order-id <UUID>`: Order id to derive the correct trade key.
141+
- `--file <PATH>`: Path to the file to encrypt and upload.
142+
- **Handler**: `execute_send_admin_dm_attach(PublicKey::from_str(pubkey)?, ctx, order_id, file)` in `src/cli/send_admin_dm_attach.rs`.
143+
144+
### Identity & keys
145+
146+
- **`conversationkey`**
147+
- **Description**: Get the conversation key for direct messaging with a user.
148+
- **Args**:
149+
- `--pubkey <NPUB/HEX>`: Counterparty pubkey.
150+
- **Handler**: `execute_conversation_key(&ctx.trade_keys, PublicKey::from_str(pubkey)?)` in `src/cli/conversation_key.rs`.
151+
152+
- **`getlasttradeindex`**
153+
- **Description**: Get last trade index of the user.
154+
- **Args**: None.
155+
- **Handler**: `execute_last_trade_index(&ctx.identity_keys, ctx.mostro_pubkey, ctx)` in `src/cli/last_trade_index.rs`.
156+
157+
- **`getlasttradeprivkey`**
158+
- **Description**: Get private key of the last trade index public key.
159+
- **Args**: None.
160+
- **Handler**: `execute_last_trade_index_private_key(ctx)` in `src/cli/last_trade_index.rs`.
161+
162+
### Session & restore
163+
164+
- **`restore`**
165+
- **Description**: Restore session to recover all pending orders and disputes.
166+
- **Args**: None.
167+
- **Handler**: `execute_restore(&ctx.identity_keys, ctx.mostro_pubkey, ctx)` in `src/cli/restore.rs`.
168+
169+
### Admin / solver dispute management
170+
171+
- **`admcancel`** *(admin only)*
172+
- **Description**: Cancel an order / dispute as admin.
173+
- **Args**:
174+
- `--order-id <UUID>`: Order identifier.
175+
- **Handler**: `execute_admin_cancel_dispute(order_id, ctx)` in `src/cli/take_dispute.rs`.
176+
177+
- **`admsettle`** *(admin only)*
178+
- **Description**: Settle a seller's hold invoice.
179+
- **Args**:
180+
- `--order-id <UUID>`: Order identifier.
181+
- **Handler**: `execute_admin_settle_dispute(order_id, ctx)` in `src/cli/take_dispute.rs`.
182+
183+
- **`admaddsolver`** *(admin only)*
184+
- **Description**: Add a new dispute solver.
185+
- **Args**:
186+
- `--npubkey <NPUB>`: Nostr pubkey of the solver.
187+
- **Handler**: `execute_admin_add_solver(npubkey, ctx)` in `src/cli/take_dispute.rs`.
188+
189+
- **`admtakedispute`** *(admin/solver only)*
190+
- **Description**: Admin or solver takes a pending dispute.
191+
- **Args**:
192+
- `--dispute-id <UUID>`: Dispute identifier.
193+
- **Handler**: `execute_take_dispute(dispute_id, ctx)` in `src/cli/take_dispute.rs`.
194+
195+
### Rating
196+
197+
- **`rate`**
198+
- **Description**: Rate counterpart after a successful trade.
199+
- **Args**:
200+
- `--order-id <UUID>`: Order identifier.
201+
- `--rating <u8>`: Rating from 1 to 5.
202+
- **Handler**: `execute_rate_user(order_id, rating, ctx)` in `src/cli/rate_user.rs`.
203+
204+
---
205+
206+
If you add a new variant to the `Commands` enum:
207+
208+
1. Add the subcommand and its arguments in `src/cli.rs`.
209+
2. Add its handler function in an appropriate `src/cli/*.rs` module.
210+
3. Extend the `Commands::run` match to call the handler.
211+
4. Update this `commands.md` file so documentation stays in sync for humans and AI tools.
212+

0 commit comments

Comments
 (0)