|
1 | 1 | use crate::logging::LOGGING_KEY;
|
2 |
| -use crate::payjoin::PayjoinStorage; |
| 2 | +use crate::payjoin::{Error as PayjoinError, PayjoinStorage}; |
3 | 3 | use crate::redshift::{RedshiftManager, RedshiftStatus, RedshiftStorage};
|
4 | 4 | use crate::storage::{MutinyStorage, DEVICE_ID_KEY, KEYCHAIN_STORE_KEY, NEED_FULL_SYNC_KEY};
|
5 | 5 | 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};
|
@@ -709,15 +710,7 @@ impl<S: MutinyStorage> NodeManager<S> {
|
709 | 710 | pub(crate) fn resume_payjoins(nm: Arc<NodeManager<S>>) {
|
710 | 711 | let all = nm.storage.get_payjoins().unwrap_or_default();
|
711 | 712 | for payjoin in all {
|
712 |
| - let wallet = nm.wallet.clone(); |
713 |
| - let stop = nm.stop.clone(); |
714 |
| - let storage = Arc::new(nm.storage.clone()); |
715 |
| - utils::spawn(async move { |
716 |
| - let pj_txid = Self::receive_payjoin(wallet, stop, storage, payjoin) |
717 |
| - .await |
718 |
| - .unwrap(); |
719 |
| - log::info!("Received payjoin txid: {}", pj_txid); |
720 |
| - }); |
| 713 | + nm.clone().spawn_payjoin_receiver(payjoin); |
721 | 714 | }
|
722 | 715 | }
|
723 | 716 |
|
@@ -880,6 +873,31 @@ impl<S: MutinyStorage> NodeManager<S> {
|
880 | 873 | Err(MutinyError::WalletOperationFailed)
|
881 | 874 | }
|
882 | 875 |
|
| 876 | + pub async fn start_payjoin_session(&self) -> Result<Enrolled, PayjoinError> { |
| 877 | + // DANGER! TODO get from &self config, do not get config directly from PAYJOIN_DIR ohttp-gateway |
| 878 | + // That would reveal IP address |
| 879 | + |
| 880 | + let http_client = reqwest::Client::builder().build()?; |
| 881 | + |
| 882 | + let ohttp_config_base64 = http_client |
| 883 | + .get(format!("{}/ohttp-config", crate::payjoin::PAYJOIN_DIR)) |
| 884 | + .send() |
| 885 | + .await? |
| 886 | + .text() |
| 887 | + .await?; |
| 888 | + |
| 889 | + let mut enroller = payjoin::receive::v2::Enroller::from_relay_config( |
| 890 | + crate::payjoin::PAYJOIN_DIR, |
| 891 | + &ohttp_config_base64, |
| 892 | + crate::payjoin::OHTTP_RELAYS[0], // TODO pick ohttp relay at random |
| 893 | + ); |
| 894 | + // enroll client |
| 895 | + let (req, context) = enroller.extract_req()?; |
| 896 | + let ohttp_response = http_client.post(req.url).body(req.body).send().await?; |
| 897 | + let ohttp_response = ohttp_response.bytes().await?; |
| 898 | + Ok(enroller.process_res(ohttp_response.as_ref(), context)?) |
| 899 | + } |
| 900 | + |
883 | 901 | // Send v1 payjoin request
|
884 | 902 | pub async fn send_payjoin(
|
885 | 903 | &self,
|
@@ -952,38 +970,45 @@ impl<S: MutinyStorage> NodeManager<S> {
|
952 | 970 | Ok(txid)
|
953 | 971 | }
|
954 | 972 |
|
| 973 | + pub fn spawn_payjoin_receiver(&self, session: crate::payjoin::Session) { |
| 974 | + let logger = self.logger.clone(); |
| 975 | + let wallet = self.wallet.clone(); |
| 976 | + let stop = self.stop.clone(); |
| 977 | + let storage = Arc::new(self.storage.clone()); |
| 978 | + utils::spawn(async move { |
| 979 | + match Self::receive_payjoin(wallet, stop, storage, session).await { |
| 980 | + Ok(txid) => log_info!(logger, "Received payjoin txid: {txid}"), |
| 981 | + Err(e) => log_error!(logger, "Error receiving payjoin: {e}"), |
| 982 | + }; |
| 983 | + }); |
| 984 | + } |
| 985 | + |
955 | 986 | /// Poll the payjoin relay to maintain a payjoin session and create a payjoin proposal.
|
956 |
| - pub async fn receive_payjoin( |
| 987 | + async fn receive_payjoin( |
957 | 988 | wallet: Arc<OnChainWallet<S>>,
|
958 | 989 | stop: Arc<AtomicBool>,
|
959 | 990 | storage: Arc<S>,
|
960 | 991 | mut session: crate::payjoin::Session,
|
961 |
| - ) -> Result<Txid, MutinyError> { |
| 992 | + ) -> Result<Txid, PayjoinError> { |
962 | 993 | let http_client = reqwest::Client::builder()
|
963 | 994 | //.danger_accept_invalid_certs(true) ? is tls unchecked :O
|
964 |
| - .build() |
965 |
| - .unwrap(); |
| 995 | + .build()?; |
966 | 996 | let proposal: payjoin::receive::v2::UncheckedProposal =
|
967 | 997 | Self::poll_for_fallback_psbt(stop, storage, &http_client, &mut session)
|
968 | 998 | .await
|
969 | 999 | .unwrap();
|
970 |
| - let payjoin_proposal = wallet.process_payjoin_proposal(proposal).unwrap(); |
| 1000 | + let payjoin_proposal = wallet |
| 1001 | + .process_payjoin_proposal(proposal) |
| 1002 | + .map_err(PayjoinError::Wallet)?; |
971 | 1003 |
|
972 |
| - let (req, ohttp_ctx) = payjoin_proposal.extract_v2_req().unwrap(); // extraction failed |
973 |
| - let res = http_client |
974 |
| - .post(req.url) |
975 |
| - .body(req.body) |
976 |
| - .send() |
977 |
| - .await |
978 |
| - .unwrap(); |
979 |
| - let res = res.bytes().await.unwrap(); |
| 1004 | + let (req, ohttp_ctx) = payjoin_proposal.extract_v2_req()?; // extraction failed |
| 1005 | + let res = http_client.post(req.url).body(req.body).send().await?; |
| 1006 | + let res = res.bytes().await?; |
980 | 1007 | // enroll must succeed
|
981 |
| - let _res = payjoin_proposal |
982 |
| - .deserialize_res(res.to_vec(), ohttp_ctx) |
983 |
| - .unwrap(); |
| 1008 | + let _res = payjoin_proposal.deserialize_res(res.to_vec(), ohttp_ctx)?; |
984 | 1009 | // convert from bitcoin 29 to 30
|
985 | 1010 | let txid = payjoin_proposal.psbt().clone().extract_tx().txid();
|
986 |
| - let txid = Txid::from_str(&txid.to_string()).unwrap(); |
| 1011 | + let txid = Txid::from_str(&txid.to_string()).map_err(PayjoinError::Txid)?; |
987 | 1012 | Ok(txid)
|
988 | 1013 | }
|
989 | 1014 |
|
|
0 commit comments