Skip to content

Commit 974ed12

Browse files
committed
Add PayjoinHandler
Add two new structs `PayjoinHandler` and `PayjoinReceiver`. The first is public and holds the later as a property and can be used in order to serve incoming payjoin transactions. `PayjoinReceiver` implemented `lightning_payjoin::Receiver` trait to allow us to receive payjoin transactions or open a channel.
1 parent 57aea0b commit 974ed12

File tree

4 files changed

+134
-11
lines changed

4 files changed

+134
-11
lines changed

Cargo.toml

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,23 @@ panic = 'abort' # Abort on panic
2828
default = []
2929

3030
[dependencies]
31-
lightning = { version = "0.0.121", features = ["std"] }
32-
lightning-invoice = { version = "0.29.0" }
33-
lightning-net-tokio = { version = "0.0.121" }
34-
lightning-persister = { version = "0.0.121" }
35-
lightning-background-processor = { version = "0.0.121", features = ["futures"] }
36-
lightning-rapid-gossip-sync = { version = "0.0.121" }
37-
lightning-transaction-sync = { version = "0.0.121", features = ["esplora-async-https", "time"] }
38-
lightning-liquidity = { version = "0.1.0-alpha.1", features = ["std"] }
39-
31+
# lightning = { version = "0.0.121", features = ["std"] }
32+
# lightning-invoice = { version = "0.29.0" }
33+
# lightning-net-tokio = { version = "0.0.121" }
34+
# lightning-persister = { version = "0.0.121" }
35+
# lightning-background-processor = { version = "0.0.121", features = ["futures"] }
36+
# lightning-rapid-gossip-sync = { version = "0.0.121" }
37+
# lightning-transaction-sync = { version = "0.0.121", features = ["esplora-async-https", "time"] }
38+
# lightning-liquidity = { version = "0.1.0-alpha.1", features = ["std"] }
39+
lightning = { git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a", features = ["std"] }
40+
lightning-invoice = {git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a"}
41+
lightning-net-tokio = {git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a"}
42+
lightning-persister = {git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a"}
43+
lightning-background-processor = { git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a", features = ["futures"] }
44+
lightning-rapid-gossip-sync = { git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a" }
45+
lightning-transaction-sync = { git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a", features = ["esplora-async-https", "time"] }
46+
lightning-liquidity = { git = "https://github.com/jbesraa/lightning-liquidity.git", rev = "0588dd4", version = "0.1.0-alpha.1", features = ["std"] }
47+
lightning-payjoin = { path = "./lightning-payjoin" }
4048
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std"] }
4149
#lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
4250
#lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main" }
@@ -54,7 +62,6 @@ lightning-liquidity = { version = "0.1.0-alpha.1", features = ["std"] }
5462
#lightning-rapid-gossip-sync = { path = "../rust-lightning/lightning-rapid-gossip-sync" }
5563
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync", features = ["esplora-async"] }
5664
#lightning-liquidity = { path = "../lightning-liquidity", features = ["std"] }
57-
5865
bdk = { version = "0.29.0", default-features = false, features = ["std", "async-interface", "use-esplora-async", "sqlite-bundled", "keys-bip39"]}
5966

6067
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
@@ -78,7 +85,8 @@ prost = { version = "0.11.6", default-features = false}
7885
winapi = { version = "0.3", features = ["winbase"] }
7986

8087
[dev-dependencies]
81-
lightning = { version = "0.0.121", features = ["std", "_test_utils"] }
88+
lightning = { git = "https://github.com/jbesraa/rust-lightning.git", rev = "d3e2d5a", features = ["std", "_test_utils"] }
89+
# lightning = { version = "0.0.121", features = ["std", "_test_utils"] }
8290
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std", "_test_utils"] }
8391
electrum-client = { version = "0.15.1", default-features = true }
8492
bitcoincore-rpc = { version = "0.17.0", default-features = false }

src/error.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,19 @@ impl From<lightning_transaction_sync::TxSyncError> for Error {
139139
Self::TxSyncFailed
140140
}
141141
}
142+
143+
impl From<Error> for lightning_payjoin::error::Error {
144+
fn from(e: Error) -> Self {
145+
match e {
146+
Error::WalletOperationFailed => lightning_payjoin::error::Error::Internal(
147+
lightning_payjoin::error::InternalError::WalletOperationFailed,
148+
),
149+
Error::OnchainTxSigningFailed => lightning_payjoin::error::Error::Internal(
150+
lightning_payjoin::error::InternalError::OnchainTxSigningFailed,
151+
),
152+
_ => lightning_payjoin::error::Error::Internal(
153+
lightning_payjoin::error::InternalError::NodeFailed,
154+
),
155+
}
156+
}
157+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ use error::Error;
108108

109109
pub use event::Event;
110110
pub use types::{BestBlock, ChannelConfig};
111+
mod payjoin_handler;
111112

112113
pub use io::utils::generate_entropy_mnemonic;
113114

src/payjoin_handler.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use crate::types::{ChannelManager, Wallet};
2+
use bdk::SignOptions;
3+
use bitcoin::address::NetworkChecked;
4+
use bitcoin::psbt::Psbt;
5+
use bitcoin::secp256k1::PublicKey;
6+
use bitcoin::ScriptBuf;
7+
use lightning::ln::ChannelId;
8+
use lightning::util::persist::KVStore;
9+
use lightning_payjoin::error::Error as PayjoinError;
10+
use lightning_payjoin::scheduler::ChannelScheduler;
11+
use lightning_payjoin::{LightningPayjoin, Receiver};
12+
use std::sync::Arc;
13+
use tokio::sync::Mutex;
14+
15+
#[derive(Clone)]
16+
pub(crate) struct PayjoinHandler<K: KVStore + Sync + Send + 'static> {
17+
inner: Arc<Mutex<LightningPayjoin<PayjoinReceiver<K>>>>,
18+
}
19+
20+
impl<K: KVStore + Sync + Send + 'static> PayjoinHandler<K> {
21+
pub(crate) fn new(
22+
wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager<K>>,
23+
scheduler: Arc<Mutex<ChannelScheduler>>, payjoin_directory: lightning_payjoin::Url,
24+
payjoin_relay: lightning_payjoin::Url,
25+
) -> Self {
26+
let payjoin_receiver = PayjoinReceiver::new(wallet, channel_manager);
27+
let lightning_payjoin =
28+
LightningPayjoin::new(payjoin_receiver, scheduler, payjoin_directory, payjoin_relay);
29+
let inner = Arc::new(Mutex::new(lightning_payjoin));
30+
Self { inner }
31+
}
32+
33+
pub(crate) async fn process_request(&self) -> Result<(), PayjoinError> {
34+
self.inner.lock().await.process_request().await
35+
}
36+
37+
pub(crate) async fn payjoin_uri(&self, amount: bitcoin::Amount) -> String {
38+
self.inner.lock().await.construct_payjoin_uri(amount)
39+
}
40+
}
41+
42+
struct PayjoinReceiver<K: KVStore + Sync + Send> {
43+
channel_manager: Arc<ChannelManager<K>>,
44+
wallet: Arc<Wallet>,
45+
}
46+
47+
impl<K> std::ops::Deref for PayjoinReceiver<K>
48+
where
49+
K: KVStore + Sync + Send + 'static,
50+
{
51+
type Target = dyn Receiver;
52+
53+
fn deref(&self) -> &Self::Target {
54+
self
55+
}
56+
}
57+
58+
impl<K: KVStore + Sync + Send> PayjoinReceiver<K> {
59+
fn new(wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager<K>>) -> Self {
60+
Self { wallet, channel_manager }
61+
}
62+
}
63+
64+
impl<K: KVStore + Sync + Send> Receiver for PayjoinReceiver<K> {
65+
fn get_new_address(&self) -> Result<bitcoin::Address<NetworkChecked>, PayjoinError> {
66+
Ok(self.wallet.get_new_address()?)
67+
}
68+
69+
fn check_inputs_not_owned(&self, script: &ScriptBuf) -> Result<bool, PayjoinError> {
70+
Ok(self.wallet.is_mine(script)?)
71+
}
72+
73+
fn identify_my_outputs(&self, script: &ScriptBuf) -> Result<bool, PayjoinError> {
74+
Ok(self.wallet.is_mine(script)?)
75+
}
76+
77+
fn funding_transaction_generated(
78+
&self, temporary_channel_id: &ChannelId, counterparty_node_id: PublicKey,
79+
funding_tx: bitcoin::Transaction,
80+
) -> Result<(), PayjoinError> {
81+
Ok(self.channel_manager.funding_transaction_generated(
82+
temporary_channel_id,
83+
&counterparty_node_id,
84+
funding_tx,
85+
)?)
86+
}
87+
88+
fn sign_tx(&self, psbt: &Psbt) -> Result<Psbt, PayjoinError> {
89+
let mut sign_options = SignOptions::default();
90+
sign_options.try_finalize = false;
91+
Ok(self.wallet.sign_tx(psbt, Some(sign_options))?)
92+
}
93+
94+
fn can_broadcast(&self, _transaction: &bitcoin::Transaction) -> Result<bool, PayjoinError> {
95+
// unimplemented!()
96+
Ok(true)
97+
}
98+
}

0 commit comments

Comments
 (0)