Skip to content

Commit

Permalink
Test non-incentivizing sweep payjoin
Browse files Browse the repository at this point in the history
Such one-output transactions pay the base costs to transact and provide
an incentive for a receiver to contribute with reduced marginal cost of
adding an input rather than an explicit change output. Allowing payjoin
sweeps breaks common input heuristic for them. Sweeps with many inputs
are common, making ~5.2% or ~54M of ~1.037B monetary, non-coinbase txs.

Source monetary non-coinbase transactions count: https://blockchair.com/bitcoin/transactions?q=is_coinbase(false)#f=hash,is_coinbase,time

Source sweep transactions count: https://blockchair.com/bitcoin/transactions?s=time(desc)&q=is_coinbase(false),input_count(2..),output_count(1)#f=hash,time
  • Loading branch information
DanGould committed Jul 8, 2024
1 parent bada2da commit da21bdc
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 7 deletions.
5 changes: 5 additions & 0 deletions payjoin/src/send/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ pub struct RequestBuilder<'a> {
uri: PjUri<'a>,
disable_output_substitution: bool,
fee_contribution: Option<(bitcoin::Amount, Option<usize>)>,
/// Decreases the fee contribution instead of erroring.
///
/// If this option is true and a transaction with change amount lower than fee
/// contribution is provided then instead of returning error the fee contribution will
/// be just lowered in the request to match the change amount.
clamp_fee_contribution: bool,
min_fee_rate: FeeRate,
}
Expand Down
34 changes: 27 additions & 7 deletions payjoin/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,14 +402,9 @@ mod integration {
.assume_checked()
.check_pj_supported()
.unwrap();
let psbt = build_original_psbt(&sender, &pj_uri)?;
let psbt = build_sweep_psbt(&sender, &pj_uri)?;
let mut req_ctx = RequestBuilder::from_psbt_and_uri(psbt.clone(), pj_uri.clone())?
.build_with_additional_fee(
Amount::from_sat(10000),
None,
FeeRate::ZERO,
false,
)?;
.build_non_incentivizing()?;
let (Request { url, body, .. }, send_ctx) =
req_ctx.extract_v2(directory.to_owned())?;
let response = agent
Expand Down Expand Up @@ -826,6 +821,31 @@ mod integration {
Ok(Psbt::from_str(&psbt)?)
}

fn build_sweep_psbt(
sender: &bitcoincore_rpc::Client,
pj_uri: &PjUri,
) -> Result<Psbt, BoxError> {
let mut outputs = HashMap::with_capacity(1);
outputs.insert(pj_uri.address.to_string(), Amount::from_btc(50.0)?);
let options = bitcoincore_rpc::json::WalletCreateFundedPsbtOptions {
lock_unspent: Some(true),
fee_rate: Some(Amount::from_sat(2000)),
subtract_fee_from_outputs: vec![0],
..Default::default()
};
let psbt = sender
.wallet_create_funded_psbt(
&[], // inputs
&outputs,
None, // locktime
Some(options),
Some(true), // check that the sender properly clears keypaths
)?
.psbt;
let psbt = sender.wallet_process_psbt(&psbt, None, None, None)?.psbt;
Ok(Psbt::from_str(&psbt)?)
}

fn extract_pj_tx(
sender: &bitcoincore_rpc::Client,
psbt: Psbt,
Expand Down

0 comments on commit da21bdc

Please sign in to comment.