1
1
use crate :: lnurlauth:: AuthManager ;
2
2
use crate :: logging:: LOGGING_KEY ;
3
- use crate :: payjoin:: PayjoinStorage ;
3
+ use crate :: payjoin:: { Error as PayjoinError , PayjoinStorage } ;
4
4
use crate :: redshift:: { RedshiftManager , RedshiftStatus , RedshiftStorage } ;
5
5
use crate :: storage:: { MutinyStorage , DEVICE_ID_KEY , KEYCHAIN_STORE_KEY , NEED_FULL_SYNC_KEY } ;
6
6
use crate :: utils:: { sleep, spawn} ;
@@ -52,6 +52,7 @@ use lnurl::lnurl::LnUrl;
52
52
use lnurl:: { AsyncClient as LnUrlClient , LnUrlResponse , Response } ;
53
53
use nostr:: key:: XOnlyPublicKey ;
54
54
use nostr:: { EventBuilder , Keys , Kind , Tag , TagKind } ;
55
+ use payjoin:: receive:: v2:: Enrolled ;
55
56
use payjoin:: Uri ;
56
57
use reqwest:: Client ;
57
58
use serde:: { Deserialize , Serialize } ;
@@ -807,15 +808,7 @@ impl<S: MutinyStorage> NodeManager<S> {
807
808
pub ( crate ) fn resume_payjoins ( nm : Arc < NodeManager < S > > ) {
808
809
let all = nm. storage . get_payjoins ( ) . unwrap_or_default ( ) ;
809
810
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) ;
819
812
}
820
813
}
821
814
@@ -1021,53 +1014,18 @@ impl<S: MutinyStorage> NodeManager<S> {
1021
1014
return Err ( MutinyError :: WalletOperationFailed ) ;
1022
1015
} ;
1023
1016
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
+ }
1071
1029
} ;
1072
1030
1073
1031
Ok ( MutinyBip21RawMaterials {
@@ -1079,6 +1037,31 @@ impl<S: MutinyStorage> NodeManager<S> {
1079
1037
} )
1080
1038
}
1081
1039
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
+
1082
1065
// Send v1 payjoin request
1083
1066
pub async fn send_payjoin (
1084
1067
& self ,
@@ -1151,38 +1134,45 @@ impl<S: MutinyStorage> NodeManager<S> {
1151
1134
Ok ( txid)
1152
1135
}
1153
1136
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
+
1154
1150
/// 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 (
1156
1152
wallet : Arc < OnChainWallet < S > > ,
1157
1153
stop : Arc < AtomicBool > ,
1158
1154
storage : Arc < S > ,
1159
1155
mut session : crate :: payjoin:: Session ,
1160
- ) -> Result < Txid , MutinyError > {
1156
+ ) -> Result < Txid , PayjoinError > {
1161
1157
let http_client = reqwest:: Client :: builder ( )
1162
1158
//.danger_accept_invalid_certs(true) ? is tls unchecked :O
1163
- . build ( )
1164
- . unwrap ( ) ;
1159
+ . build ( ) ?;
1165
1160
let proposal: payjoin:: receive:: v2:: UncheckedProposal =
1166
1161
Self :: poll_for_fallback_psbt ( stop, storage, & http_client, & mut session)
1167
1162
. await
1168
1163
. 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 ) ?;
1170
1167
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 ?;
1179
1171
// 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) ?;
1183
1173
// convert from bitcoin 29 to 30
1184
1174
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 ) ? ;
1186
1176
Ok ( txid)
1187
1177
}
1188
1178
0 commit comments