mostro_client/cli/
take_order.rs

1use anyhow::Result;
2use lnurl::lightning_address::LightningAddress;
3use mostro_core::prelude::*;
4use std::str::FromStr;
5use uuid::Uuid;
6
7use crate::cli::Context;
8use crate::lightning::is_valid_invoice;
9use crate::util::{print_dm_events, send_dm, wait_for_dm};
10
11/// Create payload based on action type and parameters
12fn create_take_order_payload(
13    action: Action,
14    invoice: &Option<String>,
15    amount: Option<u32>,
16) -> Result<Option<Payload>> {
17    match action {
18        Action::TakeBuy => Ok(amount.map(|amt: u32| Payload::Amount(amt as i64))),
19        Action::TakeSell => Ok(Some(match invoice {
20            Some(inv) => {
21                let initial_payload = match LightningAddress::from_str(inv) {
22                    Ok(_) => Payload::PaymentRequest(None, inv.to_string(), None),
23                    Err(_) => match is_valid_invoice(inv) {
24                        Ok(i) => Payload::PaymentRequest(None, i.to_string(), None),
25                        Err(e) => {
26                            println!("{}", e);
27                            Payload::PaymentRequest(None, inv.to_string(), None)
28                        }
29                    },
30                };
31
32                match amount {
33                    Some(amt) => match initial_payload {
34                        Payload::PaymentRequest(a, b, _) => {
35                            Payload::PaymentRequest(a, b, Some(amt as i64))
36                        }
37                        payload => payload,
38                    },
39                    None => initial_payload,
40                }
41            }
42            None => amount
43                .map(|amt| Payload::Amount(amt.into()))
44                .unwrap_or(Payload::Amount(0)),
45        })),
46        _ => Err(anyhow::anyhow!("Invalid action for take order")),
47    }
48}
49
50/// Unified function to handle both take buy and take sell orders
51#[allow(clippy::too_many_arguments)]
52pub async fn execute_take_order(
53    order_id: &Uuid,
54    action: Action,
55    invoice: &Option<String>,
56    amount: Option<u32>,
57    ctx: &Context,
58) -> Result<()> {
59    let action_name = match action {
60        Action::TakeBuy => "take buy",
61        Action::TakeSell => "take sell",
62        _ => return Err(anyhow::anyhow!("Invalid action for take order")),
63    };
64
65    println!(
66        "Request of {} order {} from mostro pubId {}",
67        action_name, order_id, ctx.mostro_pubkey
68    );
69
70    // Create payload based on action type
71    let payload = create_take_order_payload(action.clone(), invoice, amount)?;
72
73    // Create request id
74    let request_id = Uuid::new_v4().as_u128() as u64;
75
76    // Create message
77    let take_order_message = Message::new_order(
78        Some(*order_id),
79        Some(request_id),
80        Some(ctx.trade_index),
81        action.clone(),
82        payload,
83    );
84
85    // Send dm to receiver pubkey
86    println!(
87        "SENDING DM with trade index: {} and trade keys: {:?}",
88        ctx.trade_index,
89        ctx.trade_keys.public_key().to_hex()
90    );
91
92    let message_json = take_order_message
93        .as_json()
94        .map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
95
96    // Send the DM
97    // This is so we can wait for the gift wrap event in the main thread
98    let sent_message = send_dm(
99        &ctx.client,
100        Some(&ctx.identity_keys),
101        &ctx.trade_keys,
102        &ctx.mostro_pubkey,
103        message_json,
104        None,
105        false,
106    );
107
108    // Wait for the DM to be sent from mostro
109    let recv_event = wait_for_dm(ctx, None, sent_message).await?;
110
111    // Parse the incoming DM
112    print_dm_events(recv_event, request_id, ctx, None).await?;
113
114    Ok(())
115}