Skip to content

Commit 175a606

Browse files
committed
Merge #200: feat: add non-persisted Async Payjoin support
c6bce58 docs: add Payjoin capability to the README (Mehmet Efe Umit) 4cab2fa feat: add payjoin receive support (Mehmet Efe Umit) 0112c92 feat: add payjoin send support (Mehmet Efe Umit) f62287a refactor: move broadcast to a helper function (Mehmet Efe Umit) a28076a refactor: move sync to a helper function (Mehmet Efe Umit) Pull request description: ### Description This change implements the online commands for both sending and receiving a Payjoin. Note that this PR does not implement Payjoin persistence. ### Notes to the reviewers Tested on my local regtest with rpc using the OHTTP relays and directories in the [payjoin-cli README](https://github.com/payjoin/rust-payjoin/tree/master/payjoin-cli). Feel free to do the same, and let me know if there are comments, documentation, etc. which should be changed with this. I was not able to find any... Here are the sample command you can use to test on regtest: **Send** ``` cargo run --features=rpc -- -n regtest wallet -a USERNAME:PASSWORD -w WALLET_NAME -e "DESCRIPTOR" send_payjoin --ohttp_relay "RELAY1" --ohttp_relay "RELAY2" --fee_rate 1 --uri "URI" ``` **Receive** ``` cargo run --features=rpc -- -n regtest wallet -a USERNAME:PASSWORD -w WALLET_NAME -e "DESCRIPTOR" receive_payjoin --max_fee_rate 1000 --directory "https://payjo.in" --ohttp_relay "RELAY1" --ohttp_relay "RELAY2" --amount AMOUNT ``` ### Checklists #### All Submissions: * [x] I've signed all my commits * [X] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md) * [X] I ran `cargo fmt` and `cargo clippy` before committing #### New Features: * [] I've added tests for the new feature <--- There is no testing suite for this. * [X] I've added docs for the new feature * [N/A] I've updated `CHANGELOG.md` #### Bugfixes: * [ ] This pull request breaks the existing API * [ ] I've added tests to reproduce the issue which are now passing * [ ] I'm linking the issue being fixed by this PR ACKs for top commit: tvpeter: tACK c6bce58 spacebear21: utACK c6bce58 Tree-SHA512: 1da8295d0eedf6fd31095085e6ef0d90ab46d5eed6c2f21a7539a6c3ff6d1127d0cdbb664d519bcb4a783ea2707452bf8cd3cb961a67ba3e61d989701e205dca
2 parents 7df419a + c6bce58 commit 175a606

File tree

9 files changed

+1897
-160
lines changed

9 files changed

+1897
-160
lines changed

Cargo.lock

Lines changed: 671 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ serde_json = "1.0"
2121
thiserror = "2.0.11"
2222
tokio = { version = "1", features = ["full"] }
2323
cli-table = "0.5.0"
24+
tracing = "0.1.41"
25+
tracing-subscriber = "0.3.20"
2426

2527
# Optional dependencies
2628
bdk_bitcoind_rpc = { version = "0.21.0", features = ["std"], optional = true }
@@ -29,8 +31,9 @@ bdk_esplora = { version = "0.22.1", features = ["async-https", "tokio"], optiona
2931
bdk_kyoto = { version = "0.15.1", optional = true }
3032
bdk_redb = { version = "0.1.0", optional = true }
3133
shlex = { version = "1.3.0", optional = true }
32-
tracing = "0.1.41"
33-
tracing-subscriber = "0.3.20"
34+
payjoin = { version = "1.0.0-rc.1", features = ["v1", "v2", "io", "_test-utils"], optional = true}
35+
reqwest = { version = "0.12.23", default-features = false, optional = true }
36+
url = { version = "2.5.4", optional = true }
3437

3538
[features]
3639
default = ["repl", "sqlite"]
@@ -43,10 +46,13 @@ sqlite = ["bdk_wallet/rusqlite"]
4346
redb = ["bdk_redb"]
4447

4548
# Available blockchain client options
46-
cbf = ["bdk_kyoto"]
47-
electrum = ["bdk_electrum"]
48-
esplora = ["bdk_esplora"]
49-
rpc = ["bdk_bitcoind_rpc"]
49+
cbf = ["bdk_kyoto", "_payjoin-dependencies"]
50+
electrum = ["bdk_electrum", "_payjoin-dependencies"]
51+
esplora = ["bdk_esplora", "_payjoin-dependencies"]
52+
rpc = ["bdk_bitcoind_rpc", "_payjoin-dependencies"]
53+
54+
# Internal features
55+
_payjoin-dependencies = ["payjoin", "reqwest", "url"]
5056

5157
# Use this to consensus verify transactions at sync time
5258
verify = []

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ And yes, it can do Taproot!!
3535
This crate can be used for the following purposes:
3636
- Instantly create a miniscript based wallet and connect to your backend of choice (Electrum, Esplora, Core RPC, Kyoto etc) and quickly play around with your own complex bitcoin scripting workflow. With one or many wallets, connected with one or many backends.
3737
- The `tests/integration.rs` module is used to document high level complex workflows between BDK and different Bitcoin infrastructure systems, like Core, Electrum and Lightning(soon TM).
38+
- Receive and send Async Payjoins. Note that even though Async Payjoin as a protocol allows the receiver and sender to go offline during the payjoin, the BDK CLI implementation currently does not support persisting.
3839
- (Planned) Expose the basic command handler via `wasm` to integrate `bdk-cli` functionality natively into the web platform. See also the [playground](https://bitcoindevkit.org/bdk-cli/playground/) page.
3940

4041
If you are considering using BDK in your own wallet project bdk-cli is a nice playground to get started with. It allows easy testnet and regtest wallet operations, to try out what's possible with descriptors, miniscript, and BDK APIs. For more information on BDK refer to the [website](https://bitcoindevkit.org/) and the [rust docs](https://docs.rs/bdk_wallet/1.0.0/bdk_wallet/index.html)
@@ -112,6 +113,18 @@ To generate a new extended master key, suitable for use in a descriptor:
112113
cargo run -- key generate
113114
```
114115

116+
To start a Payjoin session as the receiver with regtest RPC and example OHTTP relays:
117+
118+
```
119+
cargo run --features rpc -- wallet --wallet sample_wallet --url="127.0.0.1:18443" --ext-descriptor "wpkh(tprv8ZgxMBicQKsPd2PoUEcGNDHPZmVWgtPYERAwMG6qHheX6LN4oaazp3qZU7mykiaAZga1ZB2SJJR6Mriyq8MocMs7QTe7toaabSwTWu5fRFz/84h/1h/0h/0/*)#8guqp7rn" receive_payjoin --amount 21120000 --max_fee_rate 1000 --directory "https://payjo.in" --ohttp_relay "https://pj.bobspacebkk.com" --ohttp_relay "https://pj.benalleng.com"
120+
```
121+
122+
To send a Payjoin with regtest RPC and example OHTTP relays:
123+
124+
```
125+
cargo run --features rpc -- wallet --wallet sample_wallet --url="127.0.0.1:18443" --ext-descriptor "wpkh(tprv8ZgxMBicQKsPd2PoUEcGNDHPZmVWgtPYERAwMG6qHheX6LN4oaazp3qZU7mykiaAZga1ZB2SJJR6Mriyq8MocMs7QTe7toaabSwTWu5fRFz/84h/1h/0h/0/*)#8guqp7rn" send_payjoin --ohttp_relay "https://pj.bobspacebkk.com" --ohttp_relay "https://pj.benalleng.com" --fee_rate 1 --uri "<URI>"
126+
```
127+
115128
## Justfile
116129

117130
We have added the `just` command runner to help you with common commands (during development) and running regtest `bitcoind` if you are using the `rpc` feature.

src/commands.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,41 @@ pub enum OnlineWalletSubCommand {
430430
)]
431431
tx: Option<String>,
432432
},
433+
// Generates a Payjoin receive URI and processes the sender's Payjoin proposal.
434+
ReceivePayjoin {
435+
/// Amount to be received in sats.
436+
#[arg(env = "PAYJOIN_AMOUNT", long = "amount", required = true)]
437+
amount: u64,
438+
/// Payjoin directory which will be used to store the PSBTs which are pending action
439+
/// from one of the parties.
440+
#[arg(env = "PAYJOIN_DIRECTORY", long = "directory", required = true)]
441+
directory: String,
442+
/// URL of the Payjoin OHTTP relay. Can be repeated multiple times to attempt the
443+
/// operation with multiple relays for redundancy.
444+
#[arg(env = "PAYJOIN_OHTTP_RELAY", long = "ohttp_relay", required = true)]
445+
ohttp_relay: Vec<String>,
446+
/// Maximum effective fee rate the receiver is willing to pay for their own input/output contributions.
447+
#[arg(env = "PAYJOIN_RECEIVER_MAX_FEE_RATE", long = "max_fee_rate")]
448+
max_fee_rate: Option<u64>,
449+
},
450+
/// Sends an original PSBT to a BIP 21 URI and broadcasts the returned Payjoin PSBT.
451+
SendPayjoin {
452+
/// BIP 21 URI for the Payjoin.
453+
#[arg(env = "PAYJOIN_URI", long = "uri", required = true)]
454+
uri: String,
455+
/// URL of the Payjoin OHTTP relay. Can be repeated multiple times to attempt the
456+
/// operation with multiple relays for redundancy.
457+
#[arg(env = "PAYJOIN_OHTTP_RELAY", long = "ohttp_relay", required = true)]
458+
ohttp_relay: Vec<String>,
459+
/// Fee rate to use in sat/vbyte.
460+
#[arg(
461+
env = "PAYJOIN_SENDER_FEE_RATE",
462+
short = 'f',
463+
long = "fee_rate",
464+
required = true
465+
)]
466+
fee_rate: u64,
467+
},
433468
}
434469

435470
/// Subcommands for Key operations.

src/error.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ pub enum BDKCliError {
103103
#[cfg(feature = "cbf")]
104104
#[error("BDK-Kyoto update error: {0}")]
105105
KyotoUpdateError(#[from] bdk_kyoto::UpdateError),
106+
107+
#[cfg(any(
108+
feature = "electrum",
109+
feature = "esplora",
110+
feature = "rpc",
111+
feature = "cbf",
112+
))]
113+
#[error("Reqwest error: {0}")]
114+
ReqwestError(#[from] reqwest::Error),
106115
}
107116

108117
impl From<ExtractTxError> for BDKCliError {

0 commit comments

Comments
 (0)