11use crate :: lnurlauth:: AuthManager ;
22use crate :: logging:: LOGGING_KEY ;
3- use crate :: payjoin:: PayjoinStorage ;
3+ use crate :: payjoin:: { Error as PayjoinError , PayjoinStorage } ;
44use crate :: redshift:: { RedshiftManager , RedshiftStatus , RedshiftStorage } ;
55use crate :: storage:: { MutinyStorage , DEVICE_ID_KEY , KEYCHAIN_STORE_KEY , NEED_FULL_SYNC_KEY } ;
66use crate :: utils:: { sleep, spawn} ;
@@ -52,6 +52,7 @@ use lnurl::lnurl::LnUrl;
5252use lnurl:: { AsyncClient as LnUrlClient , LnUrlResponse , Response } ;
5353use nostr:: key:: XOnlyPublicKey ;
5454use nostr:: { EventBuilder , Keys , Kind , Tag , TagKind } ;
55+ use payjoin:: receive:: v2:: Enrolled ;
5556use payjoin:: Uri ;
5657use reqwest:: Client ;
5758use serde:: { Deserialize , Serialize } ;
@@ -807,15 +808,7 @@ impl<S: MutinyStorage> NodeManager<S> {
807808 pub ( crate ) fn resume_payjoins ( nm : Arc < NodeManager < S > > ) {
808809 let all = nm. storage . get_payjoins ( ) . unwrap_or_default ( ) ;
809810 for payjoin in all {
810- let wallet = nm. wallet . clone ( ) ;
811- let stop = nm. stop . clone ( ) ;
812- let storage = Arc :: new ( nm. storage . clone ( ) ) ;
813- utils:: spawn ( async move {
814- let pj_txid = Self :: receive_payjoin ( wallet, stop, storage, payjoin)
815- . await
816- . unwrap ( ) ;
817- log:: info!( "Received payjoin txid: {}" , pj_txid) ;
818- } ) ;
811+ nm. clone ( ) . spawn_payjoin_receiver ( payjoin) ;
819812 }
820813 }
821814
@@ -1021,53 +1014,18 @@ impl<S: MutinyStorage> NodeManager<S> {
10211014 return Err ( MutinyError :: WalletOperationFailed ) ;
10221015 } ;
10231016
1024- let pj = {
1025- // DANGER! TODO get from &self config, do not get config directly from PAYJOIN_DIR ohttp-gateway
1026- // That would reveal IP address
1027-
1028- let http_client = reqwest:: Client :: builder ( ) . build ( ) . unwrap ( ) ;
1029-
1030- let ohttp_config_base64 = http_client
1031- . get ( format ! ( "{}/ohttp-config" , crate :: payjoin:: PAYJOIN_DIR ) )
1032- . send ( )
1033- . await
1034- . unwrap ( )
1035- . text ( )
1036- . await
1037- . unwrap ( ) ;
1038-
1039- let mut enroller = payjoin:: receive:: v2:: Enroller :: from_relay_config (
1040- crate :: payjoin:: PAYJOIN_DIR ,
1041- & ohttp_config_base64,
1042- crate :: payjoin:: OHTTP_RELAYS [ 0 ] , // TODO pick ohttp relay at random
1043- ) ;
1044- // enroll client
1045- let ( req, context) = enroller. extract_req ( ) . unwrap ( ) ;
1046- let ohttp_response = http_client
1047- . post ( req. url )
1048- . body ( req. body )
1049- . send ( )
1050- . await
1051- . unwrap ( ) ;
1052- let ohttp_response = ohttp_response. bytes ( ) . await . unwrap ( ) ;
1053- let enrolled = enroller
1054- . process_res ( ohttp_response. as_ref ( ) , context)
1055- . map_err ( |e| anyhow ! ( "parse error {}" , e) )
1056- . unwrap ( ) ;
1057- let session = self . storage . persist_payjoin ( enrolled. clone ( ) ) . unwrap ( ) ;
1058- let pj_uri = enrolled. fallback_target ( ) ;
1059- log_debug ! ( self . logger, "{pj_uri}" ) ;
1060- // run await payjoin task in the background as it'll keep polling the relay
1061- let wallet = self . wallet . clone ( ) ;
1062- let stop = self . stop . clone ( ) ;
1063- let storage = Arc :: new ( self . storage . clone ( ) ) ;
1064- utils:: spawn ( async move {
1065- let pj_txid = Self :: receive_payjoin ( wallet, stop, storage, session)
1066- . await
1067- . unwrap ( ) ;
1068- log:: info!( "Received payjoin txid: {}" , pj_txid) ;
1069- } ) ;
1070- Some ( pj_uri)
1017+ let pj = match self . start_payjoin_session ( ) . await {
1018+ Ok ( enrolled) => {
1019+ let session = self . storage . persist_payjoin ( enrolled. clone ( ) ) ?;
1020+ let pj_uri = session. enrolled . fallback_target ( ) ;
1021+ log_debug ! ( self . logger, "{pj_uri}" ) ;
1022+ self . spawn_payjoin_receiver ( session) ;
1023+ Some ( pj_uri)
1024+ }
1025+ Err ( e) => {
1026+ log_error ! ( self . logger, "Error enrolling payjoin: {e}" ) ;
1027+ None
1028+ }
10711029 } ;
10721030
10731031 Ok ( MutinyBip21RawMaterials {
@@ -1079,6 +1037,31 @@ impl<S: MutinyStorage> NodeManager<S> {
10791037 } )
10801038 }
10811039
1040+ async fn start_payjoin_session ( & self ) -> Result < Enrolled , PayjoinError > {
1041+ // DANGER! TODO get from &self config, do not get config directly from PAYJOIN_DIR ohttp-gateway
1042+ // That would reveal IP address
1043+
1044+ let http_client = reqwest:: Client :: builder ( ) . build ( ) ?;
1045+
1046+ let ohttp_config_base64 = http_client
1047+ . get ( format ! ( "{}/ohttp-config" , crate :: payjoin:: PAYJOIN_DIR ) )
1048+ . send ( )
1049+ . await ?
1050+ . text ( )
1051+ . await ?;
1052+
1053+ let mut enroller = payjoin:: receive:: v2:: Enroller :: from_relay_config (
1054+ crate :: payjoin:: PAYJOIN_DIR ,
1055+ & ohttp_config_base64,
1056+ crate :: payjoin:: OHTTP_RELAYS [ 0 ] , // TODO pick ohttp relay at random
1057+ ) ;
1058+ // enroll client
1059+ let ( req, context) = enroller. extract_req ( ) ?;
1060+ let ohttp_response = http_client. post ( req. url ) . body ( req. body ) . send ( ) . await ?;
1061+ let ohttp_response = ohttp_response. bytes ( ) . await ?;
1062+ Ok ( enroller. process_res ( ohttp_response. as_ref ( ) , context) ?)
1063+ }
1064+
10821065 // Send v1 payjoin request
10831066 pub async fn send_payjoin (
10841067 & self ,
@@ -1151,38 +1134,45 @@ impl<S: MutinyStorage> NodeManager<S> {
11511134 Ok ( txid)
11521135 }
11531136
1137+ pub fn spawn_payjoin_receiver ( & self , session : crate :: payjoin:: Session ) {
1138+ let logger = self . logger . clone ( ) ;
1139+ let wallet = self . wallet . clone ( ) ;
1140+ let stop = self . stop . clone ( ) ;
1141+ let storage = Arc :: new ( self . storage . clone ( ) ) ;
1142+ utils:: spawn ( async move {
1143+ match Self :: receive_payjoin ( wallet, stop, storage, session) . await {
1144+ Ok ( txid) => log_info ! ( logger, "Received payjoin txid: {txid}" ) ,
1145+ Err ( e) => log_error ! ( logger, "Error receiving payjoin: {e}" ) ,
1146+ } ;
1147+ } ) ;
1148+ }
1149+
11541150 /// Poll the payjoin relay to maintain a payjoin session and create a payjoin proposal.
1155- pub async fn receive_payjoin (
1151+ async fn receive_payjoin (
11561152 wallet : Arc < OnChainWallet < S > > ,
11571153 stop : Arc < AtomicBool > ,
11581154 storage : Arc < S > ,
11591155 mut session : crate :: payjoin:: Session ,
1160- ) -> Result < Txid , MutinyError > {
1156+ ) -> Result < Txid , PayjoinError > {
11611157 let http_client = reqwest:: Client :: builder ( )
11621158 //.danger_accept_invalid_certs(true) ? is tls unchecked :O
1163- . build ( )
1164- . unwrap ( ) ;
1159+ . build ( ) ?;
11651160 let proposal: payjoin:: receive:: v2:: UncheckedProposal =
11661161 Self :: poll_for_fallback_psbt ( stop, storage, & http_client, & mut session)
11671162 . await
11681163 . unwrap ( ) ;
1169- let payjoin_proposal = wallet. process_payjoin_proposal ( proposal) . unwrap ( ) ;
1164+ let payjoin_proposal = wallet
1165+ . process_payjoin_proposal ( proposal)
1166+ . map_err ( PayjoinError :: Wallet ) ?;
11701167
1171- let ( req, ohttp_ctx) = payjoin_proposal. extract_v2_req ( ) . unwrap ( ) ; // extraction failed
1172- let res = http_client
1173- . post ( req. url )
1174- . body ( req. body )
1175- . send ( )
1176- . await
1177- . unwrap ( ) ;
1178- let res = res. bytes ( ) . await . unwrap ( ) ;
1168+ let ( req, ohttp_ctx) = payjoin_proposal. extract_v2_req ( ) ?; // extraction failed
1169+ let res = http_client. post ( req. url ) . body ( req. body ) . send ( ) . await ?;
1170+ let res = res. bytes ( ) . await ?;
11791171 // enroll must succeed
1180- let _res = payjoin_proposal
1181- . deserialize_res ( res. to_vec ( ) , ohttp_ctx)
1182- . unwrap ( ) ;
1172+ let _res = payjoin_proposal. deserialize_res ( res. to_vec ( ) , ohttp_ctx) ?;
11831173 // convert from bitcoin 29 to 30
11841174 let txid = payjoin_proposal. psbt ( ) . clone ( ) . extract_tx ( ) . txid ( ) ;
1185- let txid = Txid :: from_str ( & txid. to_string ( ) ) . unwrap ( ) ;
1175+ let txid = Txid :: from_str ( & txid. to_string ( ) ) . map_err ( PayjoinError :: Txid ) ? ;
11861176 Ok ( txid)
11871177 }
11881178
0 commit comments