| 
					
				 | 
			
			
				@@ -1,5 +1,10 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use anyhow::Result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-use cdk::nuts::nut18::TransportType; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::str::FromStr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use anyhow::{bail, Result}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use bitcoin::hashes::sha256::Hash as Sha256Hash; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::nuts::nut01::PublicKey; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::nuts::nut11::{Conditions, SigFlag, SpendingConditions}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::nuts::nut18::{Nut10SecretRequest, TransportType}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use cdk::nuts::{CurrencyUnit, PaymentRequest, PaymentRequestPayload, Token, Transport}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use cdk::wallet::{MultiMintWallet, ReceiveOptions}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 use clap::Args; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -16,23 +21,41 @@ pub struct CreateRequestSubCommand { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     unit: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /// Quote description 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     description: Option<String>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// P2PK: Public key(s) for which the token can be spent with valid signature(s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Can be specified multiple times for multiple pubkeys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(long, action = clap::ArgAction::Append)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pubkey: Option<Vec<String>>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Number of required signatures (for multiple pubkeys) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Defaults to 1 if not specified 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(long, default_value = "1")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    num_sigs: u64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// HTLC: Hash for hash time locked contract 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(long, conflicts_with = "preimage")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    hash: Option<String>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// HTLC: Preimage of the hash (to be used instead of hash) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(long, conflicts_with = "hash")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    preimage: Option<String>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Transport type to use (nostr, http, or none) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - nostr: Use Nostr transport and listen for payment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - http: Use HTTP transport but only print the request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// - none: Don't use any transport, just print the request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(long, default_value = "nostr")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transport: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// URL for HTTP transport (only used when transport=http) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(long)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    http_url: Option<String>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Nostr relays to use (only used when transport=nostr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Can be specified multiple times for multiple relays 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// If not provided, defaults to standard relays 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    #[arg(long, action = clap::ArgAction::Append)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    nostr_relay: Option<Vec<String>>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 pub async fn create_request( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     multi_mint_wallet: &MultiMintWallet, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     sub_command_args: &CreateRequestSubCommand, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) -> Result<()> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let keys = Keys::generate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let relays = vec!["wss://relay.nos.social", "wss://relay.damus.io"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let nprofile = Nip19Profile::new(keys.public_key, relays.clone())?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let nostr_transport = Transport { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        _type: TransportType::Nostr, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        target: nprofile.to_bech32()?, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        tags: Some(vec![vec!["n".to_string(), "17".to_string()]]), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Get available mints from the wallet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     let mints: Vec<cdk::mint_url::MintUrl> = multi_mint_wallet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         .get_balances(&CurrencyUnit::Sat) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         .await? 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -40,58 +63,234 @@ pub async fn create_request( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         .cloned() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         .collect(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Process transport based on command line args 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let transport_type = sub_command_args.transport.to_lowercase(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let transports = match transport_type.as_str() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        "nostr" => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let keys = Keys::generate(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Use custom relays if provided, otherwise use defaults 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let relays = if let Some(custom_relays) = &sub_command_args.nostr_relay { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if !custom_relays.is_empty() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    println!("Using custom Nostr relays: {:?}", custom_relays); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    custom_relays.clone() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // Empty vector provided, fall back to defaults 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    vec![ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        "wss://relay.nos.social".to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        "wss://relay.damus.io".to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // No relays provided, use defaults 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                vec![ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "wss://relay.nos.social".to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "wss://relay.damus.io".to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let nprofile = Nip19Profile::new(keys.public_key, relays.clone())?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let nostr_transport = Transport { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _type: TransportType::Nostr, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                target: nprofile.to_bech32()?, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                tags: Some(vec![vec!["n".to_string(), "17".to_string()]]), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // We'll need the Nostr keys and relays later for listening 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let transport_info = Some((keys, relays, nprofile.public_key)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (Some(vec![nostr_transport]), transport_info) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        "http" => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if let Some(url) = &sub_command_args.http_url { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let http_transport = Transport { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _type: TransportType::HttpPost, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    target: url.clone(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    tags: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (Some(vec![http_transport]), None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                println!( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "Warning: HTTP transport selected but no URL provided, skipping transport" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (None, None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        "none" => (None, None), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        _ => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            println!( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "Warning: Unknown transport type '{}', defaulting to none", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                transport_type 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (None, None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Create spending conditions based on provided arguments 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Handle the following cases: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 1. Only P2PK condition 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 2. Only HTLC condition with hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 3. Only HTLC condition with preimage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 4. Both P2PK and HTLC conditions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let spending_conditions = if let Some(pubkey_strings) = &sub_command_args.pubkey { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Parse all pubkeys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut parsed_pubkeys = Vec::new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for pubkey_str in pubkey_strings { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            match PublicKey::from_str(pubkey_str) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Ok(pubkey) => parsed_pubkeys.push(pubkey), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Err(err) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    println!("Error parsing pubkey {}: {}", pubkey_str, err); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // Continue with other pubkeys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if parsed_pubkeys.is_empty() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            println!("No valid pubkeys provided"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // We have pubkeys for P2PK condition 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            let num_sigs = sub_command_args.num_sigs.min(parsed_pubkeys.len() as u64); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Check if we also have an HTLC condition 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if let Some(hash_str) = &sub_command_args.hash { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Create conditions with the pubkeys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let conditions = Conditions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    locktime: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    pubkeys: Some(parsed_pubkeys), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    refund_keys: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    num_sigs: Some(num_sigs), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    sig_flag: SigFlag::SigInputs, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Try to parse the hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                match Sha256Hash::from_str(hash_str) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Ok(hash) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        // Create HTLC condition with P2PK in the conditions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        Some(SpendingConditions::HTLCConditions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            data: hash, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            conditions: Some(conditions), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Err(err) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        println!("Error parsing hash: {}", err); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        // Fallback to just P2PK with multiple pubkeys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        bail!("Error parsing hash"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else if let Some(preimage) = &sub_command_args.preimage { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Create conditions with the pubkeys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let conditions = Conditions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    locktime: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    pubkeys: Some(parsed_pubkeys), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    refund_keys: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    num_sigs: Some(num_sigs), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    sig_flag: SigFlag::SigInputs, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Create HTLC conditions with the hash and pubkeys in conditions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Some(SpendingConditions::new_htlc( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    preimage.to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Some(conditions), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                )?) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Only P2PK condition with multiple pubkeys 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Some(SpendingConditions::new_p2pk( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    *parsed_pubkeys.first().unwrap(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Some(Conditions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        locktime: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        pubkeys: Some(parsed_pubkeys[1..].to_vec()), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        refund_keys: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        num_sigs: Some(num_sigs), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        sig_flag: SigFlag::SigInputs, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                )) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if let Some(hash_str) = &sub_command_args.hash { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Only HTLC condition with provided hash 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        match Sha256Hash::from_str(hash_str) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Ok(hash) => Some(SpendingConditions::HTLCConditions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                data: hash, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                conditions: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Err(err) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                println!("Error parsing hash: {}", err); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if let Some(preimage) = &sub_command_args.preimage { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Only HTLC condition with provided preimage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // For HTLC, create the hash from the preimage and use it directly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Some(SpendingConditions::new_htlc(preimage.to_string(), None)?) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Convert SpendingConditions to Nut10SecretRequest 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let nut10 = spending_conditions.map(Nut10SecretRequest::from); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Extract the transports option from our match result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let (transports_option, nostr_info) = transports; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     let req = PaymentRequest { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         payment_id: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         amount: sub_command_args.amount.map(|a| a.into()), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        unit: None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        unit: Some(CurrencyUnit::from_str(&sub_command_args.unit)?), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         single_use: Some(true), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         mints: Some(mints), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         description: sub_command_args.description.clone(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        transports: vec![nostr_transport], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        transports: transports_option, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        nut10, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Always print the request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     println!("{req}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let client = NostrClient::new(keys); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    let filter = Filter::new().pubkey(nprofile.public_key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    for relay in relays { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        client.add_read_relay(relay).await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    client.connect().await; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    client.subscribe(vec![filter], None).await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Only listen for Nostr payment if Nostr transport was selected 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if let Some((keys, relays, pubkey)) = nostr_info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        println!("Listening for payment via Nostr..."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // Handle subscription notifications with `handle_notifications` method 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        .handle_notifications(|notification| async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            let mut exit = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if let RelayPoolNotification::Event { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                subscription_id: _, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                event, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } = notification 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                let unwrapped = client.unwrap_gift_wrap(&event).await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let client = NostrClient::new(keys); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let filter = Filter::new().pubkey(pubkey); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                let rumor = unwrapped.rumor; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for relay in relays { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            client.add_read_relay(relay).await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                let payload: PaymentRequestPayload = serde_json::from_str(&rumor.content)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        client.connect().await; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        client.subscribe(vec![filter], None).await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                let token = Token::new(payload.mint, payload.proofs, payload.memo, payload.unit); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // Handle subscription notifications with `handle_notifications` method 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .handle_notifications(|notification| async { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let mut exit = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if let RelayPoolNotification::Event { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    subscription_id: _, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    event, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    .. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } = notification 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let unwrapped = client.unwrap_gift_wrap(&event).await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let rumor = unwrapped.rumor; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let payload: PaymentRequestPayload = serde_json::from_str(&rumor.content)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let token = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        Token::new(payload.mint, payload.proofs, payload.memo, payload.unit); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                let amount = multi_mint_wallet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    .receive(&token.to_string(), ReceiveOptions::default()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    .await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let amount = multi_mint_wallet 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .receive(&token.to_string(), ReceiveOptions::default()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        .await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                println!("Received {amount}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                exit = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Ok(exit) // Set to true to exit from the loop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        .await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    println!("Received {amount}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    exit = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Ok(exit) // Set to true to exit from the loop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     Ok(()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |