#bitcoin #payjoin #bip78

app payjoin-cli

A command-line Payjoin client for Bitcoin Core

1 unstable release

0.1.0 Apr 2, 2025
0.0.9-alpha Aug 13, 2024
0.0.8-alpha Jul 18, 2024
0.0.7-alpha Jun 27, 2024
0.0.1-alpha Nov 29, 2023

#233 in #bitcoin

Download history 124/week @ 2025-03-29 29/week @ 2025-04-05

153 downloads per month

MITNFA license

410KB
8K SLoC

payjoin-cli

A command-line payjoin client for Bitcoin Core in Rust.

payjoin-cli is the reference implementation for the payjoin protocol, written using the Payjoin Dev Kit.

It enables sending and receiving BIP 78 Payjoin (v1) and Draft BIP 77 Async Payjoin (v2) transactions via bitcoind. By default it supports Payjoin v2, which is backwards compatible with v1. Enable the v1 feature to disable Payjoin v2 to send and receive using only v1.

While this code and design have had significant testing, it is still alpha-quality experimental software. Use at your own risk.

Independent audit is welcome.

Quick Start

Here's a minimal payjoin example using payjoin-cli with the v2 feature connected to bitcoind on regtest. This example uses nigiri to setup a regtest environment.

Payjoin v2 allows for transactions to be completed asynchronously. Thus the sender and receiver do not need to be online at the same time to payjoin. Learn more about how v2 works here.

To get started, install nigiri. Payjoin requires the sender and receiver each to have spendable UTXOs, so we'll create two wallets and fund each.

cargo install nigiri

nigiri rpc createwallet "sender"
nigiri rpc createwallet "receiver"

# We need 101 blocks for the UTXOs to be spendable due to the coinbase maturity requirement.
nigiri rpc generatetoaddress $(nigiri rpc getnewaddress "sender") 101
nigiri rpc generatetoaddress $(nigiri rpc getnewaddress "receiver") 101

Great! Our wallets are setup, now let's do an async payjoin.

Install payjoin-cli

cargo install payjoin-cli --version $VERSION

where $VERSION is the latest version.

Next, create a directory for the sender & receiver and create a config.toml file for each:

mkdir sender receiver
touch sender/config.toml receiver/config.toml

Edit the config.toml files. Note that the v2 feature requires a payjoin directory server and OHTTP relay.

# sender/config.toml

# Nigiri uses the following RPC credentials
[bitcoind]
rpcuser = "admin1"
rpcpassword = "123"
rpchost = "http://localhost:18443/wallet/sender"

# For v2, our config also requires a payjoin directory server and OHTTP relay
[v2]
pj_directory = "https://payjo.in"
ohttp_relay = "https://pj.bobspacebkk.com"
# receiver/config.toml

# Nigiri uses the following RPC credentials
[bitcoind]
rpcuser = "admin1"
rpcpassword = "123"
rpchost = "http://localhost:18443/wallet/receiver"

# For v2, our config also requires a payjoin directory server and OHTTP relay
[v2]
pj_directory = "https://payjo.in"
ohttp_relay = "https://pj.bobspacebkk.com"

Now, the receiver must generate an address to receive the payment. The format is:

payjoin-cli receive <AMOUNT_SATS>

For example, to receive 10000 sats from our top-level directory:

receiver/payjoin-cli receive 10000

This will output a bitcoin URI containing the receiver's address, amount, payjoin directory, and other session information the client needs. For example:

bitcoin:tb1qfttmt4z68cfyn2z25t3dusp03rq6gxrucfxs5a?amount=0.0001&pj=HTTPS://PAYJO.IN/EUQKYLU92GC6U%23RK1QFWVXS2LQ2VD4T6DUMQ0F4RZQ5NL9GM0EFWVHJZ9L796L20Z7SL3J+OH1QYP87E2AVMDKXDTU6R25WCPQ5ZUF02XHNPA65JMD8ZA2W4YRQN6UUWG+EX10T57UE```

Note that the session can be paused by pressing `Ctrl+C`. The receiver can come back online and resume the session by running `payjoin-cli resume` again, and the sender may do a `send` against it while the receiver is offline.

### Send a Payjoin

Now, let's send the payjoin. Here is an example format:

```sh
payjoin-cli send <BIP21> --fee-rate <FEE_SAT_PER_VB>

Where <BIP21> is the BIP21 URL containing the receiver's address, amount, payjoin directory, and OHTTP relay. Using the example from above:

sender/payjoin-cli send "bitcoin:tb1qfttmt4z68cfyn2z25t3dusp03rq6gxrucfxs5a?amount=0.0001&pj=HTTPS://PAYJO.IN/EUQKYLU92GC6U%23RK1QFWVXS2LQ2VD4T6DUMQ0F4RZQ5NL9GM0EFWVHJZ9L796L20Z7SL3J+OH1QYP87E2AVMDKXDTU6R25WCPQ5ZUF02XHNPA65JMD8ZA2W4YRQN6UUWG+EX10T57UE" --fee-rate 1

Congratulations! You've completed a version 2 payjoin, which can be used for cheaper, more efficient, and more private on-chain payments. Additionally, because we're using v2, the sender and receiver don't need to be online at the same time to do the payjoin.

Configuration

Config options can be passed from the command line, or manually edited in a config.toml file within the directory you run payjoin-cli from.

see the example.config.toml for inspiration.

Asynchronous Operation

Sender and receiver state is saved to a database in the directory from which payjoin-cli is run, called payjoin.sled. Once a send or receive session is started, it may resume using the resume argument if prior payjoin sessions have not yet complete.

Usage

Get a list of commands and options:

payjoin-cli --help

or with a subcommand e.g.

payjoin-cli send --help

Dependencies

~19–35MB
~502K SLoC