Skip to content

Commit bd8074f

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 ef8e586 commit bd8074f

10 files changed

+630
-40
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
@@ -1028,12 +1028,13 @@ fn build_with_store_internal(
10281028
payjoin_receiver = Some(Arc::new(PayjoinReceiver::new(
10291029
Arc::clone(&logger),
10301030
Arc::clone(&wallet),
1031+
Arc::clone(&channel_manager),
1032+
Arc::clone(&config),
10311033
pj_config.payjoin_directory.clone(),
10321034
pj_config.payjoin_relay.clone(),
10331035
pj_config.ohttp_keys.clone(),
10341036
)));
10351037
}
1036-
10371038
let is_listening = Arc::new(AtomicBool::new(false));
10381039
let latest_wallet_sync_timestamp = Arc::new(RwLock::new(None));
10391040
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::{
@@ -435,6 +436,7 @@ where
435436
network_graph: Arc<Graph>,
436437
payment_store: Arc<PaymentStore<L>>,
437438
peer_store: Arc<PeerStore<L>>,
439+
payjoin_receiver: Option<Arc<PayjoinReceiver>>,
438440
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
439441
logger: L,
440442
config: Arc<Config>,
@@ -449,8 +451,9 @@ where
449451
bump_tx_event_handler: Arc<BumpTransactionEventHandler>,
450452
channel_manager: Arc<ChannelManager>, connection_manager: Arc<ConnectionManager<L>>,
451453
output_sweeper: Arc<Sweeper>, network_graph: Arc<Graph>,
452-
payment_store: Arc<PaymentStore<L>>, peer_store: Arc<PeerStore<L>>,
453-
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>, logger: L, config: Arc<Config>,
454+
payment_store: Arc<PaymentStore<L>>, payjoin_receiver: Option<Arc<PayjoinReceiver>>,
455+
peer_store: Arc<PeerStore<L>>, runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
456+
logger: L, config: Arc<Config>,
454457
) -> Self {
455458
Self {
456459
event_queue,
@@ -461,6 +464,7 @@ where
461464
output_sweeper,
462465
network_graph,
463466
payment_store,
467+
payjoin_receiver,
464468
peer_store,
465469
logger,
466470
runtime,
@@ -475,6 +479,7 @@ where
475479
counterparty_node_id,
476480
channel_value_satoshis,
477481
output_script,
482+
user_channel_id,
478483
..
479484
} => {
480485
// Construct the raw transaction with the output that is paid the amount of the
@@ -485,6 +490,18 @@ where
485490
let cur_height = self.channel_manager.current_best_block().height;
486491
let locktime = LockTime::from_height(cur_height).unwrap_or(LockTime::ZERO);
487492

493+
if let Some(payjoin_receiver) = self.payjoin_receiver.clone() {
494+
if payjoin_receiver
495+
.set_channel_accepted(
496+
user_channel_id,
497+
&output_script,
498+
temporary_channel_id.0,
499+
)
500+
.await
501+
{
502+
return;
503+
}
504+
}
488505
// Sign the final funding transaction and broadcast it.
489506
match self.wallet.create_funding_transaction(
490507
output_script,
@@ -1147,6 +1164,45 @@ where
11471164
);
11481165
}
11491166
},
1167+
LdkEvent::FundingTxBroadcastSafe { funding_tx, .. } => {
1168+
use crate::io::utils::ohttp_headers;
1169+
if let Some(payjoin_receiver) = self.payjoin_receiver.clone() {
1170+
let is_payjoin_channel =
1171+
payjoin_receiver.set_funding_tx_signed(funding_tx.clone()).await;
1172+
if let Some((url, body)) = is_payjoin_channel {
1173+
log_info!(
1174+
self.logger,
1175+
"Detected payjoin channel transaction. Sending payjoin sender request for transaction {}",
1176+
funding_tx.txid()
1177+
);
1178+
let headers = ohttp_headers();
1179+
let client = reqwest::Client::builder().build().unwrap();
1180+
match client.post(url).body(body).headers(headers).send().await {
1181+
Ok(response) => {
1182+
if response.status().is_success() {
1183+
log_info!(
1184+
self.logger,
1185+
"Responded to 'Payjoin Sender' successfuly"
1186+
);
1187+
} else {
1188+
log_info!(
1189+
self.logger,
1190+
"Got unsuccessful response from 'Payjoin Sender': {}",
1191+
response.status()
1192+
);
1193+
}
1194+
},
1195+
Err(e) => {
1196+
log_error!(
1197+
self.logger,
1198+
"Failed to send a response to 'Payjoin Sender': {}",
1199+
e
1200+
);
1201+
},
1202+
};
1203+
}
1204+
}
1205+
},
11501206
LdkEvent::ChannelPending {
11511207
channel_id,
11521208
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
pub mod payment;
9495
mod peer_store;
@@ -726,6 +727,7 @@ impl Node {
726727
Arc::clone(&self.output_sweeper),
727728
Arc::clone(&self.network_graph),
728729
Arc::clone(&self.payment_store),
730+
self.payjoin_receiver.clone(),
729731
Arc::clone(&self.peer_store),
730732
Arc::clone(&self.runtime),
731733
Arc::clone(&self.logger),
@@ -1112,6 +1114,9 @@ impl Node {
11121114
Arc::clone(&self.config),
11131115
Arc::clone(&self.logger),
11141116
Arc::clone(&self.wallet),
1117+
Arc::clone(&self.peer_store),
1118+
Arc::clone(&self.channel_manager),
1119+
Arc::clone(&self.connection_manager),
11151120
)
11161121
}
11171122

@@ -1132,6 +1137,9 @@ impl Node {
11321137
Arc::clone(&self.config),
11331138
Arc::clone(&self.logger),
11341139
Arc::clone(&self.wallet),
1140+
Arc::clone(&self.peer_store),
1141+
Arc::clone(&self.channel_manager),
1142+
Arc::clone(&self.connection_manager),
11351143
))
11361144
}
11371145

0 commit comments

Comments
 (0)