-
Notifications
You must be signed in to change notification settings - Fork 13
Event-kinds-update #154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Event-kinds-update #154
Changes from 2 commits
b77d5bd
fa03943
26637eb
7d6cf0e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # Coding Standards | ||
|
|
||
| This document outlines the coding standards and best practices for the Mostro CLI project. These guidelines ensure code quality, maintainability, and consistency across the codebase. | ||
|
|
||
| ## Core Principles | ||
|
|
||
| ### 1. Readability and Reuse | ||
| **Priority**: Code should be written for humans first, machines second. | ||
| - **Clear naming**: Use descriptive names for functions, variables, and modules (e.g., `parse_dm_events` vs `pde`). | ||
| - **Function reuse**: Extract common logic into reusable functions. Place shared utilities in appropriate modules (`src/util/`, `src/parser/`, etc.). | ||
| - **Module organization**: Group related functionality together (CLI commands in `src/cli/`, Protocol parsing in `src/parser/`, Utilities in `src/util/`). | ||
|
|
||
| ### 2. Avoid Code Duplication (DRY Principle) | ||
| **Don't Repeat Yourself**: If the same logic appears in multiple places, extract it. | ||
| - **Extract common patterns**: Create helper functions for repeated operations like DM sending. | ||
| - **Centralize constants**: Import from `mostro-core::prelude` instead of hardcoding values. | ||
|
|
||
| ### 3. Simplicity | ||
| **Keep It Simple**: Prefer straightforward solutions over clever ones. | ||
| - **Avoid premature optimization**: Write clear code first, optimize only when needed. | ||
| - **Prefer explicit over implicit**: Use `Option` and `Result` types explicitly rather than hiding errors with `unwrap()`. | ||
|
|
||
| ### 4. Function Length Limit | ||
| **Maximum 300 lines per function**: If a function exceeds this limit, split it into smaller, single-responsibility functions. | ||
|
|
||
| ## Rust-Specific Guidelines | ||
|
|
||
| ### Error Handling | ||
| - **Use `Result<T, E>`**: Functions that can fail should return `Result`. | ||
| - **Use `anyhow::Result`**: For application-level errors, use `anyhow::Result<T>`. | ||
| - **Propagate errors**: Use the `?` operator to propagate errors up the call stack. | ||
| - **Add context**: Use `.context("...")` from `anyhow` to add meaningful error messages. | ||
|
|
||
| ### Type Safety | ||
| - **Use strong types**: Prefer newtypes or enums (`Action`, `Status`) over primitive types. | ||
| - **Leverage enums**: Use enums for state machines and role management. | ||
|
|
||
| ### Async/Await | ||
| - **Prefer async/await**: Use `async fn` for I/O and network operations. | ||
| - **Handle timeouts**: Use `tokio::time::timeout` for network operations. | ||
|
|
||
| ### Documentation | ||
| - **Document public APIs**: Use `///` doc comments for public functions and types. | ||
| - **Explain "why"**: Document the reasoning behind complex logic, not just "what". | ||
|
|
||
| ## Nostr and Mostro-Specific Guidelines | ||
|
|
||
| ### Event Kinds | ||
| - **Use constants**: Always use constants from `mostro-core::prelude` (e.g., `NOSTR_ORDER_EVENT_KIND`). | ||
| - **Never hardcode**: Avoid hardcoding event kind numbers like 38383. | ||
|
|
||
| ### Message Handling | ||
| - **Parse DMs consistently**: Use `parse_dm_events` for all DM parsing. | ||
| - **Support multiple message types**: Handle both GiftWrap (NIP-59) and PrivateDirectMessage (NIP-17). | ||
|
|
||
| ### Key Management | ||
| - **Identity vs Trade Keys**: | ||
| - **Identity keys** (index 0): User's main identity, used for signing. | ||
| - **Trade keys** (index 1+): Ephemeral keys for each trade, ensuring privacy. | ||
|
|
||
| ## Code Organization Patterns | ||
|
|
||
| ### Module Structure | ||
| ```text | ||
| src/ | ||
| ├── main.rs # Entry point | ||
| ├── cli.rs # CLI definitions and Context | ||
| ├── db.rs # Database models (User, Order) | ||
| ├── cli/ # CLI command implementations | ||
| ├── parser/ # Event parsing and display | ||
| └── util/ # Core utilities (events, messaging, net) | ||
| ``` | ||
|
|
||
| ### Re-export Pattern | ||
| Use `mod.rs` files to re-export commonly used items from submodules to keep imports clean. | ||
|
|
||
| ## Database Patterns | ||
| - **User Model**: Use chainable setters and the `.save()` pattern. | ||
| - **Order Management**: Use `Order::new()` to handle both insertion and updates. | ||
|
|
||
| ## CLI Command Pattern | ||
| All CLI commands follow a standard flow: | ||
| 1. Validate inputs. | ||
| 2. Get required keys (Identity/Trade). | ||
| 3. Build the Mostro message. | ||
| 4. Send to Mostro (NIP-59). | ||
| 5. Wait for response (Subscription). | ||
| 6. Parse and display results. | ||
|
|
||
| ## Summary Checklist | ||
| - [ ] Code is readable and well-named. | ||
| - [ ] No code duplication (DRY). | ||
| - [ ] Functions are under 300 lines. | ||
| - [ ] Errors are handled properly (`Result`, `?`). | ||
| - [ ] Event kinds use constants from `mostro-core`. | ||
| - [ ] Both GiftWrap and PrivateDirectMessage are supported. | ||
| - [ ] Public APIs are documented. | ||
| - [ ] Code passes `cargo fmt` and `cargo clippy`. | ||
| - [ ] Tests pass (`cargo test`). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # Creating Orders in Mostro CLI | ||
|
|
||
| This document explains how to create new buy and sell orders using Mostro CLI. | ||
|
|
||
| ## Overview | ||
|
|
||
| Creating an order involves: | ||
| 1. Specifying order parameters (type, amount, currency, etc.) | ||
| 2. Building a Mostro message | ||
| 3. Sending it to the Mostro coordinator via Nostr | ||
| 4. Receiving confirmation | ||
| 5. Waiting for someone to take the order | ||
|
|
||
| ## Order Types | ||
|
|
||
| ### Sell Order (Maker sells Bitcoin) | ||
| User wants to **sell Bitcoin** for fiat currency. | ||
| ```bash | ||
| mostro-cli neworder -k sell -c USD -f 100 -a 50000 -m "PayPal" | ||
| ``` | ||
|
|
||
| ### Buy Order (Maker buys Bitcoin) | ||
| User wants to **buy Bitcoin** with fiat currency. | ||
| ```bash | ||
| mostro-cli neworder -k buy -c EUR -f 200 -m "Bank Transfer" -i lnbc... | ||
| ``` | ||
|
|
||
| ## Order Parameters | ||
|
|
||
| ### Required Parameters | ||
| | Parameter | Flag | Description | Example | | ||
| |-----------|------|-------------|---------| | ||
| | Kind | `-k`, `--kind` | "buy" or "sell" | `sell` | | ||
| | Fiat Code | `-c`, `--fiat-code` | Currency code | `USD`, `EUR`, `ARS` | | ||
| | Fiat Amount | `-f`, `--fiat-amount` | Amount in fiat | `100` or `100-500` (range) | | ||
| | Payment Method | `-m`, `--payment-method` | How to pay | `"PayPal"`, `"Bank Transfer"` | | ||
|
|
||
| ### Optional Parameters | ||
| | Parameter | Flag | Description | Default | | ||
| |-----------|------|-------------|---------| | ||
| | Amount | `-a`, `--amount` | Bitcoin in sats | 0 (market price) | | ||
| | Premium | `-p`, `--premium` | Price premium % | 0 | | ||
| | Invoice | `-i`, `--invoice` | Lightning invoice (buy orders) | None | | ||
| | Expiration Days | `-e`, `--expiration-days` | Days until expired | 0 | | ||
|
|
||
| ## Order Examples | ||
|
|
||
| ### 1. Simple Sell Order (Market Price) | ||
| ```bash | ||
| mostro-cli neworder -k sell -c USD -f 100 -m "PayPal" | ||
| ``` | ||
|
|
||
| ### 2. Range Order (Flexible Amount) | ||
| ```bash | ||
| mostro-cli neworder -k sell -c USD -f 100-500 -m "PayPal,Venmo" | ||
| ``` | ||
|
|
||
| ### 3. Buy Order with Lightning Invoice | ||
| ```bash | ||
| mostro-cli neworder -k buy -c USD -f 50 -i lnbc500u1p3.... -m "Cash App" | ||
| ``` | ||
|
|
||
| For technical details on the code flow and message structures, see [ORDER_FLOW_TECHNICAL.md](./ORDER_FLOW_TECHNICAL.md). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # Database Schema | ||
|
|
||
| Mostro CLI uses a local SQLite database (`mcli.db`) to store user identity and trade history. | ||
|
|
||
| ## Table: `users` | ||
| Stores the BIP-39 mnemonic and identity information. | ||
|
|
||
| | Column | Type | Description | | ||
| |--------|------|-------------| | ||
| | `i0_pubkey` | `CHAR(64)` | Primary Key. The user's identity pubkey. | | ||
| | `mnemonic` | `TEXT` | The 12-word seed phrase. | | ||
| | `last_trade_index` | `INTEGER` | The last derived trade key index. | | ||
| | `created_at` | `INTEGER` | Timestamp of creation. | | ||
|
|
||
| ## Table: `orders` | ||
| Stores details of orders created or taken by the user. | ||
|
|
||
| | Column | Type | Description | | ||
| |--------|------|-------------| | ||
| | `id` | `TEXT` | Primary Key. Order UUID. | | ||
| | `kind` | `TEXT` | "buy" or "sell". | | ||
| | `status` | `TEXT` | Current status (pending, active, etc.). | | ||
| | `amount` | `INTEGER` | Satoshis. | | ||
| | `fiat_code` | `TEXT` | e.g., "USD". | | ||
| | `fiat_amount` | `INTEGER` | Fiat units. | | ||
| | `trade_keys` | `TEXT` | Hex-encoded private key for this trade. | | ||
| | `is_mine` | `BOOLEAN` | True if the user created the order. | | ||
| | `created_at` | `INTEGER` | Creation timestamp. | | ||
|
|
||
| ## Implementation Reference | ||
| - `src/db.rs`: Contains the `User` and `Order` structs and SQL queries. | ||
| - `src/util/storage.rs`: Helper functions for database interaction. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # Dispute Management | ||
|
|
||
| This document covers how disputes are handled in Mostro CLI by both users and administrators. | ||
|
|
||
| ## User Dispute Flow | ||
|
|
||
| When a trade goes wrong (e.g., fiat sent but Bitcoin not released), either party can initiate a dispute. | ||
|
|
||
| ### Initiate a Dispute | ||
| ```bash | ||
| mostro-cli dispute -o <order-id> | ||
| ``` | ||
| Mostro changes the order status to `Dispute`. This prevents any further automated transitions and flags the trade for manual intervention. | ||
|
|
||
| ## Admin/Solver Flow | ||
|
|
||
| Admins or designated solvers use special commands to resolve conflicts. These commands require the `ADMIN_NSEC` environment variable to be set. | ||
|
|
||
| ### 1. List Active Disputes | ||
| ```bash | ||
| mostro-cli listdisputes | ||
| ``` | ||
|
|
||
| ### 2. Take a Dispute | ||
| Before resolving, an admin must "take" the dispute to indicate they are handling it. | ||
| ```bash | ||
| mostro-cli admtakedispute -d <dispute-id> | ||
| ``` | ||
|
|
||
| ### 3. Settle (Pay Buyer) | ||
| If the buyer proved they sent fiat, the admin settles the hold invoice to pay the buyer. | ||
| ```bash | ||
| mostro-cli admsettle -o <order-id> | ||
| ``` | ||
|
|
||
| ### 4. Cancel (Refund Seller) | ||
| If the buyer failed to pay, the admin cancels the order to refund the locked Bitcoin to the seller. | ||
| ```bash | ||
| mostro-cli admcancel -o <order-id> | ||
| ``` | ||
|
|
||
| ## Security | ||
| Admin commands are gated by public key verification on the Mostro coordinator side. The CLI must sign these messages with the private key corresponding to a registered admin pubkey. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # Key Management Implementation | ||
|
|
||
| This document provides technical details, code examples, and security practices for Mostro CLI key management. | ||
|
|
||
| ## Database Storage | ||
|
|
||
| ### User Table | ||
| Stores the root secret and identity info. | ||
|
|
||
| ```sql | ||
| CREATE TABLE users ( | ||
| i0_pubkey char(64) PRIMARY KEY, -- Identity public key (hex) | ||
| mnemonic TEXT, -- BIP-39 mnemonic | ||
| last_trade_index INTEGER, -- Last used trade index | ||
| created_at INTEGER | ||
| ); | ||
| ``` | ||
|
|
||
| ### Order Table | ||
| Stores trade-specific keys. | ||
|
|
||
| ```sql | ||
| CREATE TABLE orders ( | ||
| id TEXT PRIMARY KEY, | ||
| trade_keys TEXT, -- Private key for this trade (hex) | ||
| -- ... other fields | ||
| ); | ||
| ``` | ||
|
|
||
| ## Implementation Details | ||
|
|
||
| ### Deriving Identity Keys | ||
| ```rust | ||
| pub async fn get_identity_keys(pool: &SqlitePool) -> Result<Keys> { | ||
| let user = User::get(pool).await?; | ||
| let account = NOSTR_ORDER_EVENT_KIND as u32; // 38383 | ||
|
|
||
| Keys::from_mnemonic_advanced( | ||
| &user.mnemonic, | ||
| None, | ||
| Some(account), | ||
| Some(0), | ||
| Some(0) // Identity is always index 0 | ||
| ) | ||
| } | ||
| ``` | ||
|
|
||
| ### Deriving Trade Keys | ||
| ```rust | ||
| pub async fn get_trade_keys(pool: &SqlitePool, index: i64) -> Result<Keys> { | ||
| let user = User::get(pool).await?; | ||
| let account = NOSTR_ORDER_EVENT_KIND as u32; | ||
|
|
||
| Keys::from_mnemonic_advanced( | ||
| &user.mnemonic, | ||
| None, | ||
| Some(account), | ||
| Some(0), | ||
| Some(index as u32) // Incremental index 1, 2, 3... | ||
| ) | ||
| } | ||
| ``` | ||
|
|
||
| ## Security Best Practices | ||
|
|
||
| ### DO ✅ | ||
| - **Use unique keys**: Always use `get_next_trade_keys()` for new orders. | ||
| - **Sign with identity**: Prove authenticity while maintaining sender privacy. | ||
| - **Update indices**: Ensure `last_trade_index` is updated after successful creation. | ||
|
|
||
| ### DON'T ❌ | ||
| - **Reuse keys**: Never use the same trade key for two different orders. | ||
| - **Author with identity**: Never set the `pubkey` of a public event to your identity key. | ||
| - **Lose mnemonic**: Keys cannot be recovered without the seed phrase. | ||
|
Comment on lines
70
to
80
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarify identity vs trade-key signing guidance. ✏️ Suggested rewording-### DO ✅
-- **Use unique keys**: Always use `get_next_trade_keys()` for new orders.
-- **Sign with identity**: Prove authenticity while maintaining sender privacy.
-- **Update indices**: Ensure `last_trade_index` is updated after successful creation.
+### DO ✅
+- **Use unique keys**: Always use `get_next_trade_keys()` for new orders.
+- **Sign public events with trade keys**: Preserve privacy by authoring events with per-trade keys.
+- **Use identity key only for authentication/registration** (if required by protocol).
+- **Update indices**: Ensure `last_trade_index` is updated after successful creation.🤖 Prompt for AI Agents
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's correct! Identity key is used to seal the nip59 giftwrap, you can read about here. So identity is used in every message but never revealed.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query: 💡 Result: Summary — how Mostro uses NIP-59 (Gift Wrap) for key management
Sources
Your current documentation is technically correct, but it might be helpful to add a brief note explicitly mentioning the NIP-59 giftwrap mechanism to make this clearer for readers unfamiliar with the protocol. Something like:
This would help prevent confusion like mine! But the current version is accurate given the link you provided for additional context. ✏️ Learnings added
🧠 Learnings used |
||
|
|
||
| ## Key Recovery | ||
|
|
||
| If the local database is lost but the mnemonic is saved: | ||
| 1. **Identity**: Re-deriving index 0 restores the original `npub`. | ||
| 2. **Trade History**: Re-deriving indices 1, 2, 3... restores access to trade messages. | ||
| 3. **Session Sync**: Use `mostro-cli restore` to fetch active orders and their associated trade indices from the Mostro coordinator. | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### "Cannot decrypt message" | ||
| Usually means the CLI is trying to use the wrong trade key. Ensure you are loading the key associated with the specific `order_id` from the database. | ||
|
|
||
| ### "Trade index mismatch" | ||
| Occurs when the local database index is behind Mostro's records. Run `mostro-cli restore` to synchronize. | ||
Uh oh!
There was an error while loading. Please reload this page.