Skip to content

Commit 575a876

Browse files
committed
Open LN channel from incoming Payjoin tx
This commit allows users to schedule a channel that will opened once a Payjoin request received. This can save users 1 extra onchain transaction fees. The Payjoin flow is normal with the following caveats: 1. We use `Payjoin::ProvisionalProposal::substitue_output_address` to point to the multisig output script as retrived from `LdkEvent::FundingGeneratingReady`. 2. We dont try to preserve privacy in Payjoin channel opening transactions. 3. We wait with our response to the Payjoin sender until a `Ldk::Event::FundingTxBroadcastSafe` event is received.
1 parent 0d31424 commit 575a876

10 files changed

+639
-39
lines changed

Cargo.toml

+19-19
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,23 @@ panic = 'abort' # Abort on panic
2828
default = []
2929

3030
[dependencies]
31-
lightning = { version = "0.0.123", features = ["std"] }
32-
lightning-invoice = { version = "0.31.0" }
33-
lightning-net-tokio = { version = "0.0.123" }
34-
lightning-persister = { version = "0.0.123" }
35-
lightning-background-processor = { version = "0.0.123", features = ["futures"] }
36-
lightning-rapid-gossip-sync = { version = "0.0.123" }
37-
lightning-transaction-sync = { version = "0.0.123", features = ["esplora-async-https", "time"] }
38-
lightning-liquidity = { version = "0.1.0-alpha.4", features = ["std"] }
39-
40-
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std"] }
41-
#lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
42-
#lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
43-
#lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
44-
#lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["futures"] }
45-
#lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
46-
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["esplora-async"] }
47-
#lightning-liquidity = { git = "https://github.com/lightningdevkit/lightning-liquidity", branch="main", features = ["std"] }
31+
# lightning = { version = "0.0.123", features = ["std"] }
32+
# lightning-invoice = { version = "0.31.0" }
33+
# lightning-net-tokio = { version = "0.0.123" }
34+
# lightning-persister = { version = "0.0.123" }
35+
# lightning-background-processor = { version = "0.0.123", features = ["futures"] }
36+
# lightning-rapid-gossip-sync = { version = "0.0.123" }
37+
# lightning-transaction-sync = { version = "0.0.123", features = ["esplora-async-https", "time"] }
38+
# lightning-liquidity = { version = "0.1.0-alpha.4", features = ["std"] }
39+
40+
lightning = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event", features = ["std"] }
41+
lightning-invoice = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event" }
42+
lightning-net-tokio = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event" }
43+
lightning-persister = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event" }
44+
lightning-background-processor = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event", features = ["futures"] }
45+
lightning-rapid-gossip-sync = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event" }
46+
lightning-transaction-sync = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event", features = ["esplora-async"] }
47+
lightning-liquidity = { git = "https://github.com/jbesraa/lightning-liquidity", branch="pj-fixes", features = ["std"] }
4848

4949
#lightning = { path = "../rust-lightning/lightning", features = ["std"] }
5050
#lightning-invoice = { path = "../rust-lightning/lightning-invoice" }
@@ -78,8 +78,8 @@ prost = { version = "0.11.6", default-features = false}
7878
winapi = { version = "0.3", features = ["winbase"] }
7979

8080
[dev-dependencies]
81-
lightning = { version = "0.0.123", features = ["std", "_test_utils"] }
82-
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std", "_test_utils"] }
81+
# lightning = { version = "0.0.123", features = ["std", "_test_utils"] }
82+
lightning = { git = "https://github.com/jbesraa/rust-lightning.git", branch="0.0.123-with-funding-brodsafe-event", features = ["std", "_test_utils"] }
8383
electrum-client = { version = "0.15.1", default-features = true }
8484
bitcoincore-rpc = { version = "0.17.0", default-features = false }
8585
proptest = "1.0.0"

src/builder.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,8 @@ fn build_with_store_internal(
10231023
match PayjoinReceiver::new(
10241024
Arc::clone(&logger),
10251025
Arc::clone(&wallet),
1026+
Arc::clone(&channel_manager),
1027+
Arc::clone(&config),
10261028
&payjoin_directory,
10271029
&payjoin_relay,
10281030
ohttp_keys,
@@ -1035,7 +1037,6 @@ fn build_with_store_internal(
10351037
},
10361038
};
10371039
}
1038-
10391040
let is_listening = Arc::new(AtomicBool::new(false));
10401041
let latest_wallet_sync_timestamp = Arc::new(RwLock::new(None));
10411042
let latest_onchain_wallet_sync_timestamp = Arc::new(RwLock::new(None));

src/event.rs

+58-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::payjoin_receiver::PayjoinReceiver;
12
use crate::types::{DynStore, Sweeper, Wallet};
23

34
use crate::{
@@ -347,6 +348,7 @@ where
347348
network_graph: Arc<Graph>,
348349
payment_store: Arc<PaymentStore<L>>,
349350
peer_store: Arc<PeerStore<L>>,
351+
payjoin_receiver: Option<Arc<PayjoinReceiver>>,
350352
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
351353
logger: L,
352354
config: Arc<Config>,
@@ -361,8 +363,9 @@ where
361363
bump_tx_event_handler: Arc<BumpTransactionEventHandler>,
362364
channel_manager: Arc<ChannelManager>, connection_manager: Arc<ConnectionManager<L>>,
363365
output_sweeper: Arc<Sweeper>, network_graph: Arc<Graph>,
364-
payment_store: Arc<PaymentStore<L>>, peer_store: Arc<PeerStore<L>>,
365-
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>, logger: L, config: Arc<Config>,
366+
payment_store: Arc<PaymentStore<L>>, payjoin_receiver: Option<Arc<PayjoinReceiver>>,
367+
peer_store: Arc<PeerStore<L>>, runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
368+
logger: L, config: Arc<Config>,
366369
) -> Self {
367370
Self {
368371
event_queue,
@@ -373,6 +376,7 @@ where
373376
output_sweeper,
374377
network_graph,
375378
payment_store,
379+
payjoin_receiver,
376380
peer_store,
377381
logger,
378382
runtime,
@@ -387,6 +391,7 @@ where
387391
counterparty_node_id,
388392
channel_value_satoshis,
389393
output_script,
394+
user_channel_id,
390395
..
391396
} => {
392397
// Construct the raw transaction with the output that is paid the amount of the
@@ -397,6 +402,18 @@ where
397402
let cur_height = self.channel_manager.current_best_block().height;
398403
let locktime = LockTime::from_height(cur_height).unwrap_or(LockTime::ZERO);
399404

405+
if let Some(payjoin_receiver) = self.payjoin_receiver.clone() {
406+
if payjoin_receiver
407+
.set_channel_accepted(
408+
user_channel_id,
409+
&output_script,
410+
temporary_channel_id.0,
411+
)
412+
.await
413+
{
414+
return;
415+
}
416+
}
400417
// Sign the final funding transaction and broadcast it.
401418
match self.wallet.create_funding_transaction(
402419
output_script,
@@ -1004,6 +1021,45 @@ where
10041021
);
10051022
}
10061023
},
1024+
LdkEvent::FundingTxBroadcastSafe { funding_tx, .. } => {
1025+
use crate::io::utils::ohttp_headers;
1026+
if let Some(payjoin_receiver) = self.payjoin_receiver.clone() {
1027+
let is_payjoin_channel =
1028+
payjoin_receiver.set_funding_tx_signed(funding_tx.clone()).await;
1029+
if let Some((url, body)) = is_payjoin_channel {
1030+
log_info!(
1031+
self.logger,
1032+
"Detected payjoin channel transaction. Sending payjoin sender request for transaction {}",
1033+
funding_tx.txid()
1034+
);
1035+
let headers = ohttp_headers();
1036+
let client = reqwest::Client::builder().build().unwrap();
1037+
match client.post(url).body(body).headers(headers).send().await {
1038+
Ok(response) => {
1039+
if response.status().is_success() {
1040+
log_info!(
1041+
self.logger,
1042+
"Responded to 'Payjoin Sender' successfuly"
1043+
);
1044+
} else {
1045+
log_info!(
1046+
self.logger,
1047+
"Got unsuccessful response from 'Payjoin Sender': {}",
1048+
response.status()
1049+
);
1050+
}
1051+
},
1052+
Err(e) => {
1053+
log_error!(
1054+
self.logger,
1055+
"Failed to send a response to 'Payjoin Sender': {}",
1056+
e
1057+
);
1058+
},
1059+
};
1060+
}
1061+
}
1062+
},
10071063
LdkEvent::ChannelPending {
10081064
channel_id,
10091065
user_channel_id,

src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub mod io;
8989
mod liquidity;
9090
mod logger;
9191
mod message_handler;
92+
mod payjoin_channel_scheduler;
9293
mod payjoin_receiver;
9394
mod payjoin_sender;
9495
pub mod payment;
@@ -681,6 +682,7 @@ impl Node {
681682
Arc::clone(&self.output_sweeper),
682683
Arc::clone(&self.network_graph),
683684
Arc::clone(&self.payment_store),
685+
self.payjoin_receiver.clone(),
684686
Arc::clone(&self.peer_store),
685687
Arc::clone(&self.runtime),
686688
Arc::clone(&self.logger),
@@ -994,6 +996,9 @@ impl Node {
994996
payjoin_receiver.map(Arc::clone),
995997
Arc::clone(&self.config),
996998
Arc::clone(&self.event_queue),
999+
Arc::clone(&self.peer_store),
1000+
Arc::clone(&self.channel_manager),
1001+
Arc::clone(&self.connection_manager),
9971002
)
9981003
}
9991004

@@ -1013,6 +1018,9 @@ impl Node {
10131018
payjoin_receiver.map(Arc::clone),
10141019
Arc::clone(&self.config),
10151020
Arc::clone(&self.event_queue),
1021+
Arc::clone(&self.peer_store),
1022+
Arc::clone(&self.channel_manager),
1023+
Arc::clone(&self.connection_manager),
10161024
))
10171025
}
10181026

0 commit comments

Comments
 (0)