Skip to content

BIP: Add payjoin proposal#3

Closed
NicolasDorier wants to merge 1 commit into
masterfrom
pj
Closed

BIP: Add payjoin proposal#3
NicolasDorier wants to merge 1 commit into
masterfrom
pj

Conversation

@NicolasDorier

Copy link
Copy Markdown
Owner

Ping @Kukks @junderw @lukechilds @lontivero @AdamISZ @ncoelho @nopara73

I am preparing the BIP to submit to the mailing list.

This is https://docs.btcpayserver.org/features/payjoin/payjoin-spec but without the btcpayserver specific parts, and more detailed on the protocol aspects.

@NicolasDorier

NicolasDorier commented May 9, 2020

Copy link
Copy Markdown
Owner Author

@Kukks I removed the "send transaction" and send PSBT by hex. While we support it in btcpayserver, supporting it in the BIP just make the protocol more complicated for receivers. Also, for "send a transaction" it can't work on a receiver without a full node, which is problematic.

@lukechilds

lukechilds commented May 9, 2020

Copy link
Copy Markdown

Does this BIP now require PSBT then?

The BTCPay spec implies the transactions can be sent as either a raw TX or PSBT: https://github.com/btcpayserver/btcpayserver-doc/blob/3bc213603419882a4780cb03ce1400fc6a4fae8b/Payjoin-spec.md#L21-L23

The way this BIP is worded sounds like the transactions MUST be communicated as a PSBT.

Is that an intentional change?

FWIW I support this change, I think it makes sense to require PSBT.

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
@NicolasDorier

Copy link
Copy Markdown
Owner Author

@lukechilds yes . While BTCPayServer support it, and will continue to support transmitting a transaction, I advise against it:

  1. A payjoin receiver that are not full node have no way to get the fees of the original transaction without introducing some third party
  2. Supporting two methods make the implementation of the receiver harder for everybody.

Comment thread bip-xxxx.mediawiki Outdated
@kristapsk

Copy link
Copy Markdown

I think some mention of BIP79 and @RHavar should be in this BIP too, as it is partially based on it.

@NicolasDorier

NicolasDorier commented May 10, 2020

Copy link
Copy Markdown
Owner Author

As per @Kukks advise, I removed the mandatory check for adding one input.
The receiver may just want to redirect the payment to a different address.

A typical usecase is the following is a receiver changing the payment's output address to match the spent UTXO's scriptPubKey type of the user.

#3 (comment)

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki
Comment thread bip-xxxx.mediawiki Outdated
We will designate these three heuristics as <code>common-input</code>, <code>change-scriptpubkey</code>, <code>change-round-amount</code>.

The problems we aim to solve are:
* For the receiver, there is a missed opportunity to consolidate their own UTXO or making payment in the sender's transaction.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* For the receiver, there is a missed opportunity to consolidate their own UTXO or making payment in the sender's transaction.
* For the receiver, there is a missed opportunity to consolidate their own UTXO or making payments in the sender's transaction.

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated

* 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a random thought, not sure if it's baseless.

What if we remove this requirement and just allow the payjoin endpoint to redirect the outputs of the proposed transaction?

It would allow settling payments scheduled by the receiver by using the sender's funds and not require any UTXOs at hand, and still poison heuristics even more. A 1 input tx could even be used to pay the receiver, and the receiver uses the same tx to pay scheduled payments. It is technically not a payjoin, but it is one in the world of meta as you've redirected funds from User A to Merchant A to MerchantSupplier A and MerchantSupplier B, with only 1 transaction.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great idea.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this too late. The idea sounds good but the sender should reject it because it gains no privacy.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lontivero it does. The receiver can make the change harder to detect.

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
@NicolasDorier

Copy link
Copy Markdown
Owner Author

This is a breaking change in the sender's implementation #3 (comment)

I think it is worth it though.

@RHavar

RHavar commented May 10, 2020

Copy link
Copy Markdown

Thanks for the shout-out! :D

Although, I don't really understand what you mean:

We decided to deviate from it as it was impossible for the receiver to bump the fees in the payjoin transaction.

BIP79 has explicit support for that: https://en.bitcoin.it/wiki/BIP_0079#Output_Adjustment

Unless I'm misunderstanding what you mean

@NicolasDorier

Copy link
Copy Markdown
Owner Author

@RHavar indeed I missed than from your specification. I enumerated different reasons in b531b4e .

@RHavar

RHavar commented May 11, 2020

Copy link
Copy Markdown

Ah cool, thanks for that. I'm not quite sure what this means

  • It was requiring at least one input to be contributed by the receiver.

as in BIP79 receivers are free to add no inputs, which is just broadcast the template transaction. It's actually the encouraged way to handle a few things (like if you think the person is suspicious and just trying to learn your inputs)

--

Anyway, great job with everything yall have done here. Looks really exciting and I hope it gets traction. Once you guys get a BIP, I'll try get BIP79 marked as obsolete in favor of yours.

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sender should not trust the receiver is honest.

What if the receiver replaces the change outputs' scriptPubKey by another already known address of the sender, forcing the sender to reuse addresses and damaging his privacy? Or Give it back some dust change even when the sender decided to spend the whole coin (to the same utxo scriptPubKey) or things like that.

Receiver could decide to split the change output in some way that only makes the sender to pay more fee.

The sender should not be forced to accept whatever the receiver proposes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the receiver replaces the change outputs' scriptPubKey by another already known address of the sender, forcing the sender to reuse addresses and damaging his privacy? Or Give it back some dust change even when the sender decided to spend the whole coin (to the same utxo scriptPubKey) or things like that.

We should tighten this. Indeed, the sender may want to do a batch payment for example.
However it is important that the receiver can change his payment output. For example, if the receiver has 2 wallets and the payer is using P2SH for paying a P2WPKH, then the receiver should be able to switch the payment output to P2SH for improved privacy.

Receiver could decide to split the change output in some way that only makes the sender to pay more fee.

I enumerated the checks that the sender need to do to make sure he does not pay too much fee. (It is capped to twice the fee)
Moreover, it is important for the receiver to also be able to batch his own payments.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the receiver replaces the change outputs' scriptPubKey by another already known address of the sender, forcing the sender to reuse addresses and damaging his privacy? Or Give it back some dust change even when the sender decided to spend the whole coin (to the same utxo scriptPubKey) or things like that.

Is there perhaps a misunderstanding here @lontivero ? I took this does NOT check section to mean only that the sender does not check the type or number of the receiver's outputs - the sender certainly does check his own output, insisting on an unchanged scriptPubKey, and of course checking that the output amounts follow the other rules described.

But, the language should be clearer. It is the receiver's outputs that don't need to be checked.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 50bda8e better?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably I misunderstood this @AdamISZ, what you say makes sense to me.
@NicolasDorier 50bda8e is more clear. I am not sure my point is really important because the sender can always reject a proposal from the receiver.

Comment thread bip-xxxx.mediawiki Outdated

If the sent amount in the payjoin proposal is above the amount sent in the original PSBT
* Check that the additional paid amount has been paid to fee.
* Check that the additional paid amount is not more than twice the original fee

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This limit sounds reasonable now but in January 2018 some people paid upto 30 us dollars for a transaction and if that situation repeats it could mean 60us dollars instead of 30. This should be a recommendation and not be hard parameter because the implementers can decide to change this anyway.

@lukechilds lukechilds May 11, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same thought. Why not require the receiver to bump any extra fees required from their own funds?

IMO, if the sender has already chosen a suitable fee rate and is expecting a certain amount of change, the receiver should not be changing this.

If the receiver wants to add inputs/outputs that's fine but they should cover all fees required and ensure they maintain an equivalent fee rate.

Allowing the receiver to change these values can lead to all sorts of strange UX issues that are problematic to solve on the wallet end.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be more reasonable here to state in terms of being cautious of fee increases?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think change:

  • Check that the sent amount in the payjoin proposal is less or equal to the sent amount of the original transaction.

If the sent amount in the payjoin proposal is above the amount sent in the original PSBT

  • Check that the additional paid amount has been paid to fee.
  • Check that the additional paid amount is not more than twice the original fee
  • Check that the additional paid amount has only been used to pay the receiver's additional inputs.

to just:

  • Check that the sent amount in the payjoin proposal is equal to the sent amount of the original transaction.

@lukechilds lukechilds May 11, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many wallets ask a user to confirm the details of a transaction before sending it. This normally includes fee rate and spending amount. It's pretty confusing if a user confirms this, does a PayJoin, and ends up broadcasting a TX that actually spends a different amount with a different fee rate.

Yes, the wallet could notify the user of these changes and prompt them for confirmation but that leads to other UX issues and weird edge cases.

If the wallet prompts the sender if they want to accept a different fee rate / change amount, the original non-payjoin TX could already be broadcast by the receiver before the sender confirms. This would be very confusing.

If we don't prompt the sender, they could lose unfair amounts of money or the TX could take an unreasonable length of time to confirm.

Maybe the sender wanted a specific fee rate, because they want the change UTXOs in a reasonable amount of time.
Maybe the sender wanted a specific amount of change.

The receiver doesn't know the sender's reasoning for choosing those values so IMO they shouldn't be changing them.

The receiver can add whatever inputs/outputs they want, and the sender shouldn't care, as long as their change/fee rate values aren't changed.

@NicolasDorier NicolasDorier May 11, 2020

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but with an additional check of percentage change as well.

This is the Check that the additional paid amount is not more than twice the original fee part. Basically it allows a 100% percent change max. This is not fool proof either as high fee can make it unacceptable.

Maybe we should just remove the percent change max, and let sender the freedom to deal as they want with it? If the fee is almost the same, the sender should not care about validating the payjoin. However, if the fee is very different, the sender's UI might want to show a proper confirmation step to the user.

Given how pain in the ass it is to implement, I guess a good temporary way for senders would be to enforce in software this max limit.

Another thing we can do is also to add an optional parameter that the sender can specify to the receiver "maxfeecontribution". For example "maxfeecontribution=1000" would tell to the receiver that the sender wants to pay up to 1000 satoshi of fee. Above this, the receiver could still pay from his own pocket.

I think this can be a good solution as it remove the need for sender wallet to ask one more question to the user. What do you think @lukechilds?
It could be a wallet setting: Don't accept more than 1USD of additional fee for payjoin or something like that.

@lukechilds lukechilds May 12, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another thing we can do is also to add an optional parameter that the sender can specify to the receiver "maxfeecontribution". For example "maxfeecontribution=1000" would tell to the receiver that the sender wants to pay up to 1000 satoshi of fee. Above this, the receiver could still pay from his own pocket.

Yeah, I think this is a reasonable solution.

It could just be a global setting in the wallet that defaults to some sane value. Then users can set a custom value if desired or override on a per payment basis.

It solves the UX issue of requiring a second user confirmation as you said. It also allows a wallet to show the max possible potential fee in the initial confirmation dialog to the user too.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the Check that the additional paid amount is not more than twice the original fee part. Basically it allows a 100% percent change max. This is not fool proof either as high fee can make it unacceptable.

Sorry if it wasn't clear. I meant percentage of the payment amount, not percentage of the existing fee. And this would be separate to what I am counting as a non-percentage "absolute" measure - the existing fee in satoshis (100% of fee as a number of sats).

@NicolasDorier NicolasDorier May 12, 2020

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote 38cfb3f @AdamISZ @lukechilds this would allow the sender to decide by himself what he considers reasonable. Does it solve all the issues?

This also let the receiver to adapt the size of his contributions based on the sender's preference. This also let the receiver eventually pay for the inputs if he wishes to.

@lukechilds lukechilds May 12, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's good.

Maybe reword to:

  • maxfeebumpcontribution=, an integer defining the maximum amount in satoshis that the sender is willing to contribute towards fees for the additional inputs. To be ignored if set to less than zero. (default: -1)

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki

* Common inputs heuristics.

Because payjoin is mixing the inputs of the sender and receiver, this heuristic becomes unreliable.

@lontivero lontivero May 11, 2020

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case the receiver does not add any inputs then the sender could use the original transaction instead of the proposed by the receiver because it is hard to believe the sender can improve his privacy in this way and there is a risk of the receiver is sending to an exchange, betting site or something like that.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sender can increase privacy even if inputs are not added, for example, if the receiver switched his output from P2SH to P2WSH to match the type of inputs.

Comment thread bip-xxxx.mediawiki Outdated

While we cannot prevent this type of attack entirely, we implemented the following mitigations:

* When the receiver detects an original transaction being broadcasted, or if the receiver detects that the original transaction has been double spent, then they will reuse the UTXO that was exposed for the next payjoin.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the receiver accept payjoin request with nLockTime in the future? It could be easy to scan the receiver utxo by sending transactions that can only be mined in 100 years.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can't because the receiver and the sender are broadcasting the original PSBT after 2 minutes whatever happen.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NicolasDorier you have answer this same question twice to me but I still don't get it. Do you say the receiver can broadcast a transaction that cannot be mined?

@NicolasDorier NicolasDorier May 12, 2020

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I misunderstood. I thought you were talking about an invalid payjoin tx (in which case, this is not a problem as the original transaction will be broadcasted).

In BTCPay Server, we verify that the transaction is broadcastable before doing payjoin.
For Wasabi wallet, the sender will not be able to automatically retry a payjoin transaction so he would only learn about a single utxo.

@NicolasDorier

Copy link
Copy Markdown
Owner Author

as in BIP79 receivers are free to add no inputs,

@RHavar but the bip mentioned The partial transaction contains at least one new (and signed) segwit input (owned by the receiver)

Comment thread bip-xxxx.mediawiki Outdated
@lontivero

Copy link
Copy Markdown

In case next year we have script version 1, should we avoid mixing different scripts versions as we do with script types? (fingerprint)

@RHavar

RHavar commented May 12, 2020

Copy link
Copy Markdown

@NicolasDorier That's correct, if the receiver doesn't add an additional input it's just the template transaction. So it still works fine if the receiver doesn't add an additional input, it's just falls back to a normal bitcoin transaction.

@NicolasDorier

Copy link
Copy Markdown
Owner Author

@lontivero the receiver on btcpayserver allow mixing of script from the sender. But if the sender does not mix, btcpayserver will not mix.

@NicolasDorier

Copy link
Copy Markdown
Owner Author

Adding a chapter about what the receiver should do.

@NicolasDorier

Copy link
Copy Markdown
Owner Author

@lontivero does af4f7bd make things clearer

Comment thread bip-xxxx.mediawiki Outdated
@NicolasDorier

Copy link
Copy Markdown
Owner Author

I added a note: if maxfeebumpcontribution is not specified, there should have an interactive confirmation of the payjoin with the sender.

Also, the sender may pay for the additional outputs, as it can be in his interest (spare change case for example)

@NicolasDorier

Copy link
Copy Markdown
Owner Author

Ping @lontivero this will be a change in the payjoin client we coded in C# about how the client should verify the additional fee.

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
@yahiheb

yahiheb commented May 13, 2020

Copy link
Copy Markdown

Add special thanks to yahiheb

@NicolasDorier Thank you. You and the other guys are doing the real work.

Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
Comment thread bip-xxxx.mediawiki Outdated
@NicolasDorier

NicolasDorier commented May 14, 2020

Copy link
Copy Markdown
Owner Author

@Kukks @junderw @lukechilds @lontivero @AdamISZ @ncoelho @nopara73 @RHavar @yahiheb when I have some of your ACKs and confident I addressed any suggestions, I will submit that to the mailing list to get a bip number and put the proposal as a draft in bitcoin/bips.

On my side I think this is ready. The optional parameters implemetation of the receiver will be released in the next release of BTCPayServer.
There is no breaking change, compared with the first btcpayserver payjoin spec. (outside a minor one in #3 (comment))

Comment thread bip-xxxx.mediawiki
@NicolasDorier

Copy link
Copy Markdown
Owner Author

Closing this, let's continue discussion on bitcoin#923

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants