We have increased our customers privacy by implementing payjoin when using bitcoin. If your wallet is payjoin enabled you can now send bitcoin even more securely.
Payjoin is a generic term for any privacy mechanism where merchants can protect their own and the privacy of their customers by mixing merchant's UTXOs with customer's payment.
This has two purposes:
- It protects the sender by fighting against one of the biggest heuristic used by privacy invading technology: No longer can it be assumed that all the inputs in a transaction belongs to the same entity
- It allows the receiver to consolidate UTXOs and batch his own payments to economize on-chain fee.
Below is a video overview from BTC Sessions explaining how it works.
Defeating heuristics based on the fee calculation
Most wallets are creating a round fee rate (like 2 sat/b). If the payjoin transaction's fee was not increased by the added size, then those payjoin transaction could easily be identifiable on the blockchain.
Not only would those transactions would stand out by not having a round fee (like 1.87 sat/b), but any suspicion of payjoin could be confirmed by checking if removing one input would create a round fee rate.
Receiver side
- The original PSBT must be finalized (Fails with error
psbt-not-finalized
) - All the inputs must be P2WPKH or P2SH-P2WPKH and only if the the store has utxos that match the original tx inputs (Fails with error
unsupported-inputs
) * - The PSBT is sane (Fails with error
insane-psbt
) - All inputs have the
witnessUTXO
(Fails with errorneed-utxo-information
) - Check that there is no global xpubs, HD Key or public key information in the PSBT (Fails with error
leaking-data
) - Check that the extracted transaction can be accepted by mempool (Fails with error
invalid-transaction
)
Then the original PSBT is deemed valid, however, other checks are done which depends on the state of the receiver's state.
- Check that it pays an actual invoice (Fails with error
invoice-not-found
) - Check that the invoice does not have any outstanding payment (Fails with error
already-paid
) - Check that the whole amount of the invoice is paid (Fails with error
invoice-not-fully-paid
) - Check that the inputs used in the original PSBT have never been used for another payjoin (Fails with
inputs-already-used
) - Check that the receiver has available UTXO to contribute to the payjoin (Fails with error
out-of-utxos
, the receiver will broadcast the original transaction) - Check that the receiver can actually sign (Fails with error
unavailable
)
From this point, the receiver will automatically try to broadcast the original transaction after 1 minute, whatever happens. Then, we proceed to create the payjoin transaction by cloning the original transaction:
- If there is only one output, we add a second output *
- We include some of the receiver's inputs
Finally, we need to increase the fees to pay for the increased size of the payjoin transaction to pay for additional inputs and outputs of the receiver.
- If the sender overpaid the invoice, we substract fees on the overpaid part of the output paying the invoice. **
- We substract the rest to other outputs that we assume are change outputs, making sure their value does not go below dust.
- If there is not enough money to pay for the increased fee, check that the fee rate of the payjoin transaction is above the minimum relay fee (today 1 satoshi per byte). If not, fails with error
not-enough-money
.
Before sending the original PSBT to the receiver, the sender should make sure that the original PSBT is at least attempted to be broadcasted automatically after 1 minute of submission.
The sender then follows the steps:
- Check that the payjoin PSBT must not contain global xpub, hd key path or public key information.
- Check that the PSBT is sane.
- Check that all the spent outpoints in the original PSBT still exists in the coinjoin PSBT.
- Check that all the spent outpoints in the original PSBT does not have any partial signature.
- Check that the receiver added at least one input.
- Check that the receiver added P2WPKH or P2SH-P2WPKH inputs.
- Check that the receiver inputs type match the inputs type of the sender. (ie. both using P2SH-P2WPKH or both using P2WPKH)
- Check that any other outpoints (those added by the receiver) are finalized.
- Check that the transaction version, and nLockTime are unchanged.
- Check that the sender's input's sequence numbers are unchanged.
- Update
WitnessUTXO
of the PSBT. - Fill out only the HD Key paths and public keys of inputs and outputs that were present in the original PSBT.
- Check that the sent amount in the payjoin transaction is the same as the sent amount of the original transaction. *
- If those are different:
- Check that the additional paid amount is not more than the additional fee paid in the payjoin transaction.
- Check that the additional paid amount is not more than twice the original fee
- Check that the additional paid amount is not more than the expected fee once the payjoin transaction is fully signed **
After all those checks, the sender can proceed to sign the payjoin transaction.
Our client is able to pay a onion payjoin endpoint, this will allow wallets hosted on BTCPay Server to pay desktop or mobile wallets without any NAT configuration.
Note:
- The sender does NOT check whether ouputs have been removed or modified. This allows flexibility to the receiver to adapt his receiving address type to match the other outputs's address type of the sender, or, on the contrary, to create a payment output which would be considered a change address by common chain analysis heuristic. For example, if the receiver supports both P2WPKH and P2SH-P2WPKH, even if the invoice's address in the original transaction was P2WPKH, the receiver may change the address to be P2SH-P2WPKH to match sender's change address format. This is safe because the sender only cares that they do not send too much money in the payjoin transaction. It is also useful if the receiver wants to batch some of their own payments in the transaction.
- Our method of checking fee allows the receiver to batch payments in the payjoin transaction as long as they pay the fee above the sender's expected amount. (See batching)
*: For calculating the sent amount of the payjoin transaction, you must only include in the calculation the inputs and outputs that were also present in the original PSBT. (in other words, those with HD key paths and public keys set)
**: To calculate the expected fee once the payjoin transaction is fully signed, we estimate its virtual size and multiply by the fee rate of the original transaction, then we add: fee_rate * 2 * input_count
. This allow small error of fee estimation and account for outputs that may have been removed if they ended up below dust.
BLUE Wallet has PayJoin feature enabled and is recommended for use. Below is a video showing how to send in Blue Wallet and select PayJoin.
Checkout out Article with even more in depth details and which Wallets to use with PayJoin HERE.
References
- BIP174: Partially Signed Bitcoin Transaction Format
- BIP69: Lexicographical Indexing of Transaction Inputs and Outputs
- BIP79: Bustapay
- Segwit input type distribution
- Wasabi wallet: Privacy best practices on change coins
- Bitcoin wiki: Payjoin