Skip to content

Commit 2cc6132

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 816fa47 commit 2cc6132

10 files changed

+639
-39
lines changed

Cargo.toml

Lines changed: 19 additions & 19 deletions
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,12 +1024,13 @@ fn build_with_store_internal(
10241024
payjoin_receiver = Some(Arc::new(PayjoinReceiver::new(
10251025
Arc::clone(&logger),
10261026
Arc::clone(&wallet),
1027+
Arc::clone(&channel_manager),
1028+
Arc::clone(&config),
10271029
pj_config.payjoin_directory.clone(),
10281030
pj_config.payjoin_relay.clone(),
10291031
pj_config.ohttp_keys.clone(),
10301032
)));
10311033
}
1032-
10331034
let is_listening = Arc::new(AtomicBool::new(false));
10341035
let latest_wallet_sync_timestamp = Arc::new(RwLock::new(None));
10351036
let latest_onchain_wallet_sync_timestamp = Arc::new(RwLock::new(None));

src/event.rs

Lines changed: 58 additions & 2 deletions
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::{
@@ -375,6 +376,7 @@ where
375376
network_graph: Arc<Graph>,
376377
payment_store: Arc<PaymentStore<L>>,
377378
peer_store: Arc<PeerStore<L>>,
379+
payjoin_receiver: Option<Arc<PayjoinReceiver>>,
378380
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
379381
logger: L,
380382
config: Arc<Config>,
@@ -389,8 +391,9 @@ where
389391
bump_tx_event_handler: Arc<BumpTransactionEventHandler>,
390392
channel_manager: Arc<ChannelManager>, connection_manager: Arc<ConnectionManager<L>>,
391393
output_sweeper: Arc<Sweeper>, network_graph: Arc<Graph>,
392-
payment_store: Arc<PaymentStore<L>>, peer_store: Arc<PeerStore<L>>,
393-
runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>, logger: L, config: Arc<Config>,
394+
payment_store: Arc<PaymentStore<L>>, payjoin_receiver: Option<Arc<PayjoinReceiver>>,
395+
peer_store: Arc<PeerStore<L>>, runtime: Arc<RwLock<Option<tokio::runtime::Runtime>>>,
396+
logger: L, config: Arc<Config>,
394397
) -> Self {
395398
Self {
396399
event_queue,
@@ -401,6 +404,7 @@ where
401404
output_sweeper,
402405
network_graph,
403406
payment_store,
407+
payjoin_receiver,
404408
peer_store,
405409
logger,
406410
runtime,
@@ -415,6 +419,7 @@ where
415419
counterparty_node_id,
416420
channel_value_satoshis,
417421
output_script,
422+
user_channel_id,
418423
..
419424
} => {
420425
// Construct the raw transaction with the output that is paid the amount of the
@@ -425,6 +430,18 @@ where
425430
let cur_height = self.channel_manager.current_best_block().height;
426431
let locktime = LockTime::from_height(cur_height).unwrap_or(LockTime::ZERO);
427432

433+
if let Some(payjoin_receiver) = self.payjoin_receiver.clone() {
434+
if payjoin_receiver
435+
.set_channel_accepted(
436+
user_channel_id,
437+
&output_script,
438+
temporary_channel_id.0,
439+
)
440+
.await
441+
{
442+
return;
443+
}
444+
}
428445
// Sign the final funding transaction and broadcast it.
429446
match self.wallet.create_funding_transaction(
430447
output_script,
@@ -1087,6 +1104,45 @@ where
10871104
);
10881105
}
10891106
},
1107+
LdkEvent::FundingTxBroadcastSafe { funding_tx, .. } => {
1108+
use crate::io::utils::ohttp_headers;
1109+
if let Some(payjoin_receiver) = self.payjoin_receiver.clone() {
1110+
let is_payjoin_channel =
1111+
payjoin_receiver.set_funding_tx_signed(funding_tx.clone()).await;
1112+
if let Some((url, body)) = is_payjoin_channel {
1113+
log_info!(
1114+
self.logger,
1115+
"Detected payjoin channel transaction. Sending payjoin sender request for transaction {}",
1116+
funding_tx.txid()
1117+
);
1118+
let headers = ohttp_headers();
1119+
let client = reqwest::Client::builder().build().unwrap();
1120+
match client.post(url).body(body).headers(headers).send().await {
1121+
Ok(response) => {
1122+
if response.status().is_success() {
1123+
log_info!(
1124+
self.logger,
1125+
"Responded to 'Payjoin Sender' successfuly"
1126+
);
1127+
} else {
1128+
log_info!(
1129+
self.logger,
1130+
"Got unsuccessful response from 'Payjoin Sender': {}",
1131+
response.status()
1132+
);
1133+
}
1134+
},
1135+
Err(e) => {
1136+
log_error!(
1137+
self.logger,
1138+
"Failed to send a response to 'Payjoin Sender': {}",
1139+
e
1140+
);
1141+
},
1142+
};
1143+
}
1144+
}
1145+
},
10901146
LdkEvent::ChannelPending {
10911147
channel_id,
10921148
user_channel_id,

src/lib.rs

Lines changed: 8 additions & 0 deletions
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;
@@ -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),
@@ -1111,6 +1113,9 @@ impl Node {
11111113
payjoin_receiver.map(Arc::clone),
11121114
Arc::clone(&self.config),
11131115
Arc::clone(&self.event_queue),
1116+
Arc::clone(&self.peer_store),
1117+
Arc::clone(&self.channel_manager),
1118+
Arc::clone(&self.connection_manager),
11141119
)
11151120
}
11161121

@@ -1130,6 +1135,9 @@ impl Node {
11301135
payjoin_receiver.map(Arc::clone),
11311136
Arc::clone(&self.config),
11321137
Arc::clone(&self.event_queue),
1138+
Arc::clone(&self.peer_store),
1139+
Arc::clone(&self.channel_manager),
1140+
Arc::clone(&self.connection_manager),
11331141
))
11341142
}
11351143

0 commit comments

Comments
 (0)