mostro_client/cli/
take_order.rs1use anyhow::Result;
2use lnurl::lightning_address::LightningAddress;
3use mostro_core::prelude::*;
4use nostr_sdk::prelude::*;
5use std::str::FromStr;
6use uuid::Uuid;
7
8use crate::cli::Context;
9use crate::lightning::is_valid_invoice;
10use crate::util::{send_dm, wait_for_dm};
11
12fn create_take_order_payload(
14 action: Action,
15 invoice: &Option<String>,
16 amount: Option<u32>,
17) -> Result<Option<Payload>> {
18 match action {
19 Action::TakeBuy => Ok(amount.map(|amt: u32| Payload::Amount(amt as i64))),
20 Action::TakeSell => Ok(Some(match invoice {
21 Some(inv) => {
22 let initial_payload = match LightningAddress::from_str(inv) {
23 Ok(_) => Payload::PaymentRequest(None, inv.to_string(), None),
24 Err(_) => match is_valid_invoice(inv) {
25 Ok(i) => Payload::PaymentRequest(None, i.to_string(), None),
26 Err(e) => {
27 println!("{}", e);
28 Payload::PaymentRequest(None, inv.to_string(), None)
29 }
30 },
31 };
32
33 match amount {
34 Some(amt) => match initial_payload {
35 Payload::PaymentRequest(a, b, _) => {
36 Payload::PaymentRequest(a, b, Some(amt as i64))
37 }
38 payload => payload,
39 },
40 None => initial_payload,
41 }
42 }
43 None => amount
44 .map(|amt| Payload::Amount(amt.into()))
45 .unwrap_or(Payload::Amount(0)),
46 })),
47 _ => Err(anyhow::anyhow!("Invalid action for take order")),
48 }
49}
50
51#[allow(clippy::too_many_arguments)]
53pub async fn execute_take_order(
54 order_id: &Uuid,
55 action: Action,
56 invoice: &Option<String>,
57 amount: Option<u32>,
58 ctx: &Context,
59) -> Result<()> {
60 let action_name = match action {
61 Action::TakeBuy => "take buy",
62 Action::TakeSell => "take sell",
63 _ => return Err(anyhow::anyhow!("Invalid action for take order")),
64 };
65
66 println!(
67 "Request of {} order {} from mostro pubId {}",
68 action_name, order_id, ctx.mostro_pubkey
69 );
70
71 let payload = create_take_order_payload(action.clone(), invoice, amount)?;
73
74 let request_id = Uuid::new_v4().as_u128() as u64;
75
76 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 println!(
87 "SENDING DM with trade keys: {:?}",
88 ctx.trade_keys.public_key().to_hex()
89 );
90
91 let message_json = take_order_message
92 .as_json()
93 .map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
94
95 let identity_keys_clone = ctx.identity_keys.clone();
97 let trade_keys_clone = ctx.trade_keys.clone();
98 let client_clone = ctx.client.clone();
99 let mostro_pubkey_clone = ctx.mostro_pubkey;
100
101 let subscription = Filter::new()
103 .pubkey(ctx.trade_keys.public_key())
104 .kind(nostr_sdk::Kind::GiftWrap)
105 .limit(0);
106
107 let opts = SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::WaitForEvents(1));
108 ctx.client.subscribe(subscription, Some(opts)).await?;
109
110 tokio::spawn(async move {
113 let _ = send_dm(
114 &client_clone,
115 Some(&identity_keys_clone),
116 &trade_keys_clone,
117 &mostro_pubkey_clone,
118 message_json,
119 None,
120 false,
121 )
122 .await;
123 });
124
125 if action == Action::TakeSell {
127 let subscription = Filter::new()
128 .pubkey(ctx.trade_keys.public_key())
129 .kind(nostr_sdk::Kind::GiftWrap)
130 .since(Timestamp::from(chrono::Utc::now().timestamp() as u64))
131 .limit(0);
132
133 ctx.client.subscribe(subscription, None).await?;
134 }
135
136 wait_for_dm(
138 &ctx.client,
139 &ctx.trade_keys,
140 request_id,
141 Some(ctx.trade_index),
142 None,
143 &ctx.pool,
144 )
145 .await?;
146
147 Ok(())
148}