summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dorier <nicolas.dorier@gmail.com>2020-05-17 04:46:35 +0900
committerbitcoindev <bitcoindev@gnusha.org>2020-05-16 19:46:51 +0000
commitd2d8e449da1e8bac5ac52ff452f122961a2a5924 (patch)
treedf92ec8affa167c356dd5a84642c3ea4a3be7fc3
parenta3aa3bc29120dfd9dad27dde197ecef35e7c2807 (diff)
downloadpi-bitcoindev-d2d8e449da1e8bac5ac52ff452f122961a2a5924.tar.gz
pi-bitcoindev-d2d8e449da1e8bac5ac52ff452f122961a2a5924.zip
[bitcoin-dev] BIP Number request for a simple payjoin proposal
-rw-r--r--1a/bf24659abef9f0b2ffb4999088cab1181cea821123
1 files changed, 1123 insertions, 0 deletions
diff --git a/1a/bf24659abef9f0b2ffb4999088cab1181cea82 b/1a/bf24659abef9f0b2ffb4999088cab1181cea82
new file mode 100644
index 000000000..fbdee0296
--- /dev/null
+++ b/1a/bf24659abef9f0b2ffb4999088cab1181cea82
@@ -0,0 +1,1123 @@
+Return-Path: <slashene@gmail.com>
+Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])
+ by lists.linuxfoundation.org (Postfix) with ESMTP id A7850C016F
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Sat, 16 May 2020 19:46:51 +0000 (UTC)
+Received: from localhost (localhost [127.0.0.1])
+ by hemlock.osuosl.org (Postfix) with ESMTP id C8A1C885C3
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Sat, 16 May 2020 19:46:50 +0000 (UTC)
+X-Virus-Scanned: amavisd-new at osuosl.org
+Received: from hemlock.osuosl.org ([127.0.0.1])
+ by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
+ with ESMTP id U9lyh8CAoEvD
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Sat, 16 May 2020 19:46:48 +0000 (UTC)
+X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6
+Received: from mail-oi1-f196.google.com (mail-oi1-f196.google.com
+ [209.85.167.196])
+ by hemlock.osuosl.org (Postfix) with ESMTPS id E84C78859B
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Sat, 16 May 2020 19:46:47 +0000 (UTC)
+Received: by mail-oi1-f196.google.com with SMTP id w4so1594247oia.1
+ for <bitcoin-dev@lists.linuxfoundation.org>;
+ Sat, 16 May 2020 12:46:47 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
+ h=mime-version:from:date:message-id:subject:to;
+ bh=vjjYuNfFYlE5i1C+9CT12Ges/37qM+Q8jtRzzQNltak=;
+ b=qaMHcgtEL5FiPkajP74dVVs8KTopj7LF1ZPZ/0kiJd/n7PUWWiX1XZYeswSnWKmKzP
+ 21JrMQffm7iiBvSW3XYAXVsxF0bx12TV1Zi60INxbGkBcAa+BmhVXQgCWyapKrYkyvJk
+ M1w+i5nzAXjc1EojlUk0wVF+SyInooSES39Pc9/BbR+5xF9zYEHenLOneHGEoUBYVWrx
+ 7bLmaRdUxNfnOeWL0W9f/6W05jZejW5XyedF9exp//A328t1vzgAUHEBkzGrw1ziZzOv
+ NhW4SHsrbgv0fJbaBz3APJw+AdthAGs0+No2+U8/dq4Lz6DFaG681zLmiqk1jMWX8bWo
+ hJFA==
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20161025;
+ h=x-gm-message-state:mime-version:from:date:message-id:subject:to;
+ bh=vjjYuNfFYlE5i1C+9CT12Ges/37qM+Q8jtRzzQNltak=;
+ b=Sl18WTyopSLUGzWioe+MAdmgBHQ1PQ+IJcOGy3bCB1jkgOw3LZS3IyKp7W8aVNrnKe
+ b31qyt9My+wMWSrwEvTqOscFhUCOy56BFzq9pHUJFZelxnESn2HSjwx54yENrBagHXye
+ lsrFfkFz9b2EBUpr9wH5fH0OW5x2QTBBwUet/xK1EQQdaxb0/v22pA84tnYbeauEJTwL
+ 6y+q+3i5ADrPRFn4NZGLL0Qg69zGtErJCL+tJKoXSwHSb1VwDdmJrFZvR8x4f5K4PtKN
+ d7vFHXQ+fTs1Iq+FvjSBaKsGyMLV96oVMeIB4hdhffO97pTHMse3Dypc1B7zsTBR65kO
+ vcfQ==
+X-Gm-Message-State: AOAM531Tq7m6iQ+idCH7x8pui68ekMvR/yZSE2/8QXhzqE9NniZKYF5r
+ W4uBfvpfabBah0x09yMcLzi2SCokHhoNvyHk7+fQUt7lHv0=
+X-Google-Smtp-Source: ABdhPJyhOp7BCcnSiNFX8+RwAB30YUBRqkIwLrVW1/F/98bKZXu6LBP243TwV63+1zwg9tdVxQFqVh94OYorSXFwRCI=
+X-Received: by 2002:aca:c4cf:: with SMTP id u198mr6250330oif.17.1589658406106;
+ Sat, 16 May 2020 12:46:46 -0700 (PDT)
+MIME-Version: 1.0
+From: Nicolas Dorier <nicolas.dorier@gmail.com>
+Date: Sun, 17 May 2020 04:46:35 +0900
+Message-ID: <CA+1nnrkq2zq_PFoUyNadE7KMncbv30M=Kr-Ek4nDfnJvgDHrfQ@mail.gmail.com>
+To: Bitcoin Dev <bitcoin-dev@lists.linuxfoundation.org>
+Content-Type: multipart/alternative; boundary="0000000000009c395605a5c930a9"
+X-Mailman-Approved-At: Sat, 16 May 2020 19:50:49 +0000
+Subject: [bitcoin-dev] BIP Number request for a simple payjoin proposal
+X-BeenThere: bitcoin-dev@lists.linuxfoundation.org
+X-Mailman-Version: 2.1.15
+Precedence: list
+List-Id: Bitcoin Protocol Discussion <bitcoin-dev.lists.linuxfoundation.org>
+List-Unsubscribe: <https://lists.linuxfoundation.org/mailman/options/bitcoin-dev>,
+ <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=unsubscribe>
+List-Archive: <http://lists.linuxfoundation.org/pipermail/bitcoin-dev/>
+List-Post: <mailto:bitcoin-dev@lists.linuxfoundation.org>
+List-Help: <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=help>
+List-Subscribe: <https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev>,
+ <mailto:bitcoin-dev-request@lists.linuxfoundation.org?subject=subscribe>
+X-List-Received-Date: Sat, 16 May 2020 19:46:51 -0000
+
+--0000000000009c395605a5c930a9
+Content-Type: text/plain; charset="UTF-8"
+
+I am requesting a BIP number to be allocated for this simple payjoin proposal.
+This proposal is already being implemented by several service and
+wallets and incorporate the feedback of the community at
+https://github.com/NicolasDorier/bips/pull/3
+
+I opened a pull request at: https://github.com/bitcoin/bips/pull/923
+
+I am not checking my mail very often, so I suggest give me feedback
+directly on the opened pull request.
+
+
+<pre>
+ BIP: ?
+ Layer: Applications
+ Title: A Simple Payjoin Proposal
+ Author: Nicolas Dorier <nicolas.dorier@gmail.com>
+ Comments-Summary: No comments yet.
+ Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-X
+ Status: Draft
+ Type: Standards Track
+ Created: 2019-05-01
+ License: BSD-2-Clause
+</pre>
+
+==Introduction==
+
+===Abstract===
+
+This document proposes a protocol for two parties
+to negotiate a coinjoin transaction during a payment between them.
+
+===Copyright===
+
+This BIP is licensed under the 2-clause BSD license.
+
+===Motivation===
+
+When two parties (later referred to as sender and receiver) want to transact,
+most of the time, the sender creates a transaction spending their own
+Unspent Transaction Outputs (UTXOs), signs
+it and broadcasts it on the network.
+
+This simple model gave birth to several heuristics impacting the
+privacy of the parties and of the network as a whole.
+
+* Common input ownership heuristic: In most transactions, all the
+inputs belong to the same party.
+* Change identification from scriptPubKey type: If all inputs are
+spending UTXOs of a certain scriptPubKey type, then the change output
+is likely to have the same scriptPubKey type, too.
+* Change identification from round amount: If an output in the
+transaction has a round amount, it is likely an output belonging to
+the receiver.
+
+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 UTXOs or making payment in the sender's transaction.
+* For the sender, there are privacy leaks regarding their wallet that
+happen when someone applies the heuristics detailed above to their
+transaction.
+
+Our proposal gives an opportunity for the receiver to consolidate
+their UTXOs while also batching their own payments, without creating a
+new transaction. (Saving fees in the process)
+For the sender, it allows them to invalidate the three heuristics
+above. With the receiver's involvement, the heuristics can even be
+poisoned. (ie, using the heuristics to intentionally mislead
+blockchain analysis)
+
+Note that the existence of this proposal is also improving the privacy
+of parties who are not using it by making the three heuristics
+unreliable to the network as a whole.
+
+=== Relation to BIP79 (Bustapay) ===
+
+Another implementation proposal has been written:
+[[https://github.com/bitcoin/bips/blob/master/bip-0079.mediawiki|BIP79
+Bustapay]].
+
+We decided to deviate from it for several reasons:
+* It was not using PSBT, so if the receiver wanted to bump the fee,
+they would need the full UTXO set.
+* The receiver was responsible to pay the additional fee, not the sender.
+* It was requiring at least one input to be contributed by the receiver.
+* Inability to change the payment output to match scriptPubKey type.
+* Lack of basic versioning negotiation if the protocol evolves.
+* No standardization of error condition for proper feedback to the sender.
+
+Other than that, our proposal is very similar.
+
+==Specification==
+
+===Protocol===
+
+In a payjoin payment, the following steps happen:
+
+* The receiver of the payment, presents a [[bip-021.mediawiki|BIP 21
+URI]] to the sender with a parameter <code>pj</code> describing an
+https (or http if it is a Tor hidden service) link to the payjoin
+endpoint.
+* The sender creates a signed, finalized PSBT with witness UTXO or
+previous transactions of the inputs. We call this PSBT the
+<code>original</code>.
+* The receiver replies back with a signed PSBT containing his own
+signed inputs/outputs and those of the sender. We call this PSBT
+<code>Payjoin proposal</code>.
+* The sender verifies the proposal, re-signs his inputs and broadcasts
+the transaction to the Bitcoin network. We call this transaction
+<code>Payjoin transaction</code>.
+<pre>
++----------+ +--------+ +-----------------+
+| Receiver | | Sender | | Bitcoin Network |
++----+-----+ +---+----+ +-------+---------+
+ | +-----------------+ | |
+ +-------+ BIP21 with ?pj= +------->+ |
+ | +-----------------+ | |
+ | | |
+ | +---------------+ | |
+ +<-------+ Original PSBT +---------+ |
+ | +---------------+ | |
+ | | |
+ | +------------------+ | |
+ | | Payjoin Proposal | | |
+ +-------+ PSBT +------>+ |
+ | +------------------+ | |
+ | | +--------------+ |
+ | |---+ Payjoin | |
+ | | | transaction +-->+
+ | | +--------------+ |
+ + + +
+</pre>
+The original PSBT is sent in the HTTP POST request body, base64
+serialized, with <code>text/plain</code> in the
+<code>Content-Type</code> HTTP header and <code>Content-Length</code>
+set correctly.
+The payjoin proposal PSBT is sent in the HTTP response body, base64
+serialized with HTTP code 200.
+
+To ensure compatibility with web-wallets and browser-based-tools, all
+responses (including errors) must contain the HTTP header
+<code>Access-Control-Allow-Origin: *</code>.
+
+The sender must ensure that the url refers to a scheme or protocol
+using authenticated encryption, for example TLS with certificate
+validation, or a .onion link to a hidden service whose public key
+identifier has already been communicated via a TLS connection. Senders
+MUST NOT accept a url representing an unencrypted or unauthenticated
+connection.
+
+===Receiver's well known errors===
+
+If for some reason the receiver is unable to create a payjoin
+proposal, it will reply with a HTTP code different than 200.
+The receiver is not constrained to specific set of errors, some are
+specified in this proposal.
+
+The errors have the following format:
+<pre>
+{
+ "errorCode": "leaking-data",
+ "message": "Key path information or GlobalXPubs should not be
+included in the original PSBT."
+}
+</pre>
+
+The well-known error codes are:
+{| class="wikitable"
+!Error code
+!Meaning
+|-
+|leaking-data
+|Key path information or GlobalXPubs should not be included in the
+original PSBT.
+|-
+|psbt-not-finalized
+|The original PSBT must be finalized.
+|-
+|unavailable
+|The payjoin endpoint is not available for now.
+|-
+|out-of-utxos
+|The receiver does not have any UTXO to contribute in a payjoin proposal.
+|-
+|not-enough-money
+|The receiver added some inputs but could not bump the fee of the
+payjoin proposal.
+|-
+|insane-psbt
+|Some consistency check on the PSBT failed.
+|-
+|version-unsupported
+|This version of payjoin is not supported.
+|-
+|need-utxo-information
+|The witness UTXO or non witness UTXO is missing
+|-
+|invalid-transaction
+|The original transaction is invalid for payjoin
+|}
+
+The receiver is allowed to return implementation specific errors which
+may assist the sender to diagnose any issue.
+
+However, it is important that error codes that are not well-known and
+that the message do not appear on the sender's software user
+interface.
+Such error codes or messages could be used maliciously to phish a non
+technical user.
+Instead those errors or messages can only appear in debug logs.
+
+It is advised to hard code the description of the error codes into the
+sender's software.
+
+===Receiver's original PSBT checklist===
+
+The receiver needs to do some check on the original PSBT before proceeding:
+
+* Non-interactive receivers (like a payment processor) need to check
+that the original PSBT is broadcastable. <code>*</code>
+* If the sender included inputs in the original PSBT owned by the
+receiver, the receiver must either return error
+<code>invalid-transaction</code> or make sure they do not sign those
+inputs in the payjoin proposal.
+* If the sender's inputs are all from the same scriptPubKey type, the
+receiver must match the same type. If the receiver can't match the
+type, they must return error <code>out-of-utxos</code>.
+
+<code>*</code>: Interactive receivers are not required to validate the
+original PSBT because they are not exposed to probing attacks.
+
+===Sender's payjoin proposal checklist===
+
+The sender should check the payjoin proposal before signing it to
+prevent a malicious receiver from stealing money.
+
+* Check that all the spent outpoints in the original PSBT still exist
+in the coinjoin PSBT.
+* Check that all the spent outpoints in the original PSBT do not have
+any partial signature.
+* If the sender is not using inputs with mixed types, 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 inputs added by the receiver are finalized.
+* Check that the transaction version, and nLockTime are unchanged.
+* Check that the sender's inputs' sequence numbers are unchanged.
+* If the sender's inputs' sequence numbers the homogenous, check that
+the receiver's contributed inputs match those.
+* Check that the sender's outputs have not been modified (but
+potentially shuffled), except for paying increased fee
+* If sender specified <code>feebumpindex=</code> (see later), the fee
+should have been subtracted from the output at the same index in the
+original PSBT.
+* Check that the sent amount in the payjoin proposal is less than 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 add paid to the fee.
+* Check that the estimated fee rate of the payjoin proposal is not
+more than the fee rate of the original PSBT. (fee estimation is hard,
+so we should allow ~2 satoshi per inputs as margin of error)
+* If <code>maxfeebumpcontribution=</code> was specified, check the
+additional paid amount is less than or equal to this amount.
+* If <code>maxfeebumpcontribution=</code> was not specified, the
+sender's software should ask an interactive confirmation to the user.
+
+The sender must be careful to only sign the inputs that were present
+in the original PSBT and nothing else.
+
+Note:
+* The sender should allow the payment output to be modified by the
+receiver (The receiver may substitute a P2WPKH payment to P2SH payment
+to increase privacy)
+* The sender must allow the receiver to add outputs.
+* The sender must allow the receiver to not add any input. Useful for
+the receiver to change the paymout output scriptPubKey type.
+* If no input has been added, the sender's wallet should accept the
+payjoin proposal, but should not mark the transaction as an actual
+payjoin in the user interface.
+
+Our method of checking the fee allows the receiver and the sender to
+batch payments in the payjoin transaction.
+It also allows the receiver to pay the fee for batching adding his own outputs.
+
+===Optional parameters===
+
+When the payjoin sender posts the original PSBT to the receiver, he
+can optionally specify the following HTTP query string parameters:
+
+* <code>v=</code>, the version number of the payjoin protocol that the
+sender is using. The current version is <code>1</code>.
+
+This can be used in the future so the receiver can reject a payjoin if
+the sender is using a version which is not supported via an error HTTP
+400, <code>version-unsupported</code>.
+If not specified, the receiver will assume the sender is <code>v=1</code>.
+
+If the receiver does not support the version of the sender, they
+should send an error with the list of supported versions:
+<pre>
+{
+ "errorCode": "version-unsupported",
+ "supported" : [ 2, 3, 4 ],
+ "message": "The version is not supported anymore"
+}
+</pre>
+
+* <code>feebumpindex=</code>, the preferred output from which to
+increase the fee for the added inputs. (default: <code>-1</code>)
+
+If the <code>feebumpindex</code> is out of bounds or pointing to the
+payment ouptut meant for the receiver, the receiver should ignore the
+parameter.
+
+* <code>maxfeebumpcontribution=</code>, an integer defining the
+maximum amount in satoshis that the sender is willing to contribute
+towards fees for the additional inputs.
+<code>maxfeebumpcontribution</code> must be ignored if set to less
+than zero. (default: -1)
+
+Note that if <code>maxfeebumpcontribution</code> is too low, the
+sender should create a transaction with RBF disabled, as the original
+transaction could replace the payjoin transaction.
+
+==Rationale==
+
+There is several consequences of our proposal:
+
+* The receiver can bump the fee of the original transaction.
+* The receiver can modify the outputs of the original PSBT.
+* The sender must provide the UTXO information (Witness or previous
+transaction) in the PSBT.
+
+===Respecting the minimum relay fee policy===
+
+To be properly relayed, a Bitcoin transaction needs to pay at least 1
+satoshi per virtual byte.
+When fees are low, the original transaction is already 1 satoshi per
+virtual byte, so if the receiver adds their own input, they need to
+make sure the fee is increased such that the rate does not drop below
+1 satoshi per virtual byte.
+
+===Preventing mempool replacement===
+
+A safe way to implement payjoin, is for both the sender and receiver
+to try broadcasting the original transaction at some fixed interval
+period regardless of the state of the payjoin.
+
+If the receiver was not properly adding fees to the payjoin
+transaction, the original transaction would end up replacing the
+payjoin transaction in the mempool.
+
+===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 transactions could easily be identifiable on the
+blockchain.
+
+Not only would those transactions 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 does not need to be a full node===
+
+Because the receiver needs to bump the fee to keep the same fee rate
+as the original PSBT, it needs the input's UTXO information to know
+what is the original fee rate. Without PSBT, light wallets like Wasabi
+Wallet would not be able to receive a payjoin transaction.
+
+The validation (policy and consensus) of the original transaction is
+optional: a receiver without a full node can decide to create the
+payjoin transaction and automatically broadcast the original
+transaction after a timeout of 1 minute, and only verify that it has
+been propagated in the network.
+
+However, non-interactive receivers (like a payment processor) need to
+verify the transaction to prevent UTXO probing attacks.
+
+This is not a concern for interactive receivers like Wasabi Wallet,
+because those receivers can just limit the number of original PSBT
+proposals of a specific address to one. With such wallets, the
+attacker has no way to generate new deposit addresses to probe the
+UTXOs.
+
+===Spare change donation===
+
+Small change inside wallets are detrimental to privacy. Mixers like
+Wasabi wallet, because of its protocol, eventually generate such
+[[https://docs.wasabiwallet.io/using-wasabi/ChangeCoins.html#first-round-coinjoin-change|small
+change]].
+
+A common way to protect your privacy is to donate those spare changes,
+to deposit them in an exchange or on your favorite merchant's store
+account. Those kind of transactions can easily be spotted on the
+blockchain: There is only one output.
+
+However, if you donate via payjoin, it will look like a normal transaction.
+
+On top of this the receiver can poison analysis by randomly faking a
+round amount of satoshi for the additional output.
+
+===Payment output substitution===
+
+The receiver is free to change the output paying to himself.
+For example, if the sender's scriptPubKey type is P2WPKH while the
+receiver's payment output in the original PSBT is P2SH, then the
+receiver can substitute the payment output to be P2WPKH to match the
+sender's scriptPubKey type.
+
+===Impacted heuristics===
+
+Our proposal of payjoin is breaking the following blockchain heuristics:
+
+* Common inputs heuristics.
+
+Because payjoin is mixing the inputs of the sender and receiver, this
+heuristic becomes unreliable.
+
+* Change identification from scriptPubKey type heuristics
+
+When Alice pays Bob, if Alice is using P2SH but Bob's deposit address
+is P2WPKH, the heuristic would assume that the P2SH output is the
+change address of Alice.
+This is now however a broken assumption, as the payjoin receiver has
+the freedom to mislead analytics by purposefully changing the
+invoice's address in the payjoin transaction.
+
+Alternatively, if the original address of Bob is P2WPKH and Alice's
+address is also P2WPKH, Bob can change the receiving address in the
+payjoin to P2SH. The heuristic would wrongfully identify the payjoin's
+receiving address as the change address of the transaction.
+
+See payment output substitution above.
+
+* Change identification from round change amount
+
+If Alice pays Bob, she might be tempted to pay him a round amount,
+like <code>1.23000000 BTC</code>. When this happens, blockchain
+analysis often identifies the output without the round amount as the
+change of the transaction.
+
+For this reason, during a [spare
+change](Payjoin-spec.md#spare-change-donation) situation, we randomly
+round the amount in the output added by the receiver to the payjoin
+transaction.
+
+==Attack vectors==
+
+===On the receiver side: UTXO probing attack===
+
+When the receiver creates a payjoin proposal, they expose one or more
+inputs belonging to them.
+
+An attacker could create multiple original transactions in order to
+learn the UTXOs of the receiver, while not broadcasting the payjoin
+proposal.
+
+While we cannot prevent this type of attack entirely, we implemented
+the following mitigations:
+
+* When the receiver detects an original transaction being broadcast,
+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.
+* While the exposed UTXO will be reused in priority to not leak other
+UTXOs, there is no strong guarantee about it. This prevents the
+attacker from detecting with certainty the next payjoin of the
+merchant to another peer.
+
+Note that probing attacks are only a problem for automated payment
+systems such as BTCPay Server. End-user wallets with payjoin
+capabilities are not affected, as the attacker can't create multiple
+invoices to force the receiver to expose their UTXOs.
+
+===On the sender side: Double payment risk for hardware wallets===
+
+For a successful payjoin to happen, the sender needs to sign two
+transactions double spending each other: The original transaction and
+the payjoin proposal.
+
+The sender's software wallet can verify that the payjoin proposal is
+legitimate by the sender's checklist.
+
+However, a hardware wallet can't verify that this is indeed the case.
+This means that the security guarantee of the hardware wallet is
+decreased. If the sender's software is compromised, the hardware
+wallet would sign two valid transactions, thus sending two payments.
+
+Without payjoin, the maximum amount of money that could be lost by a
+compromised software is equal to one payment (via address
+substitution).
+
+With payjoin, the maximum amount of money that can be lost is equal to
+two payments.
+
+==Implementations==
+
+* [[https://github.com/BlueWallet/BlueWallet|BlueWallet]] is in the
+process of implementing the protocol.
+* [[https://github.com/btcpayserver/btcpayserver|BTCPay Server]] has
+implemented sender and receiver side of this protocol.
+* [[https://github.com/zkSNACKs/WalletWasabi/|Wasabi Wallet]] has
+merged sender's support.
+* [[https://github.com/JoinMarket-Org/joinmarket-clientserver|Join
+Market]] is in the process of implementing the protocol.
+* [[https://github.com/junderw/payjoin-client-js|JavaScript sender
+implementation]].
+
+==Special thanks==
+
+Special thanks to Kukks for developing the initial support to BTCPay
+Server, to junderw, AdamISZ, lukechilds, ncoelho, nopara73, yahiheb
+for all the feedback we received since our first implementation.
+Thanks also to RHavar who wrote the
+[[https://github.com/bitcoin/bips/blob/master/bip-0079.mediawiki|BIP79
+Bustapay]] proposal, this gave a good starting point for our proposal.
+
+--0000000000009c395605a5c930a9
+Content-Type: text/html; charset="UTF-8"
+Content-Transfer-Encoding: quoted-printable
+
+<div dir=3D"ltr">
+<pre>I am requesting a BIP number to be allocated for this simple payjoin p=
+roposal.<br>This proposal is already being implemented by several service a=
+nd wallets and incorporate the feedback of the community at <a href=3D"http=
+s://github.com/NicolasDorier/bips/pull/3">https://github.com/NicolasDorier/=
+bips/pull/3</a><br><br>I opened a pull request at: <a href=3D"https://githu=
+b.com/bitcoin/bips/pull/923">https://github.com/bitcoin/bips/pull/923</a><b=
+r></pre><pre>I am not checking my mail very often, so I suggest give me fee=
+dback directly on the opened pull request.<br></pre><pre><br>&lt;pre&gt;
+ BIP: ?
+ Layer: Applications
+ Title: A Simple Payjoin Proposal
+ Author: Nicolas Dorier &lt;<a href=3D"mailto:nicolas.dorier@gmail.com">ni=
+colas.dorier@gmail.com</a>&gt;
+ Comments-Summary: No comments yet.
+ Comments-URI: <a href=3D"https://github.com/bitcoin/bips/wiki/Comments:BI=
+P-X">https://github.com/bitcoin/bips/wiki/Comments:BIP-X</a>
+ Status: Draft
+ Type: Standards Track
+ Created: 2019-05-01
+ License: BSD-2-Clause
+&lt;/pre&gt;
+
+=3D=3DIntroduction=3D=3D
+
+=3D=3D=3DAbstract=3D=3D=3D
+
+This document proposes a protocol for two parties
+to negotiate a coinjoin transaction during a payment between them.
+
+=3D=3D=3DCopyright=3D=3D=3D
+
+This BIP is licensed under the 2-clause BSD license.
+
+=3D=3D=3DMotivation=3D=3D=3D
+
+When two parties (later referred to as sender and receiver) want to transac=
+t,
+most of the time, the sender creates a transaction spending their own Unspe=
+nt Transaction Outputs (UTXOs), signs
+it and broadcasts it on the network.
+
+This simple model gave birth to several heuristics impacting the privacy of=
+ the parties and of the network as a whole.
+
+* Common input ownership heuristic: In most transactions, all the inputs be=
+long to the same party.
+* Change identification from scriptPubKey type: If all inputs are spending =
+UTXOs of a certain scriptPubKey type, then the change output is likely to h=
+ave the same scriptPubKey type, too.
+* Change identification from round amount: If an output in the transaction =
+has a round amount, it is likely an output belonging to the receiver.
+
+We will designate these three heuristics as &lt;code&gt;common-input&lt;/co=
+de&gt;, &lt;code&gt;change-scriptpubkey&lt;/code&gt;, &lt;code&gt;change-ro=
+und-amount&lt;/code&gt;.
+
+The problems we aim to solve are:
+* For the receiver, there is a missed opportunity to consolidate their own =
+UTXOs or making payment in the sender&#39;s transaction.
+* For the sender, there are privacy leaks regarding their wallet that happe=
+n when someone applies the heuristics detailed above to their transaction.
+
+Our proposal gives an opportunity for the receiver to consolidate their UTX=
+Os while also batching their own payments, without creating a new transacti=
+on. (Saving fees in the process)
+For the sender, it allows them to invalidate the three heuristics above. Wi=
+th the receiver&#39;s involvement, the heuristics can even be poisoned. (ie=
+, using the heuristics to intentionally mislead blockchain analysis)
+
+Note that the existence of this proposal is also improving the privacy of p=
+arties who are not using it by making the three heuristics unreliable to th=
+e network as a whole.
+
+=3D=3D=3D Relation to BIP79 (Bustapay) =3D=3D=3D
+
+Another implementation proposal has been written: [[<a href=3D"https://gith=
+ub.com/bitcoin/bips/blob/master/bip-0079.mediawiki|BIP79">https://github.co=
+m/bitcoin/bips/blob/master/bip-0079.mediawiki|BIP79</a> Bustapay]].
+
+We decided to deviate from it for several reasons:
+* It was not using PSBT, so if the receiver wanted to bump the fee, they wo=
+uld need the full UTXO set.
+* The receiver was responsible to pay the additional fee, not the sender.
+* It was requiring at least one input to be contributed by the receiver.
+* Inability to change the payment output to match scriptPubKey type.
+* Lack of basic versioning negotiation if the protocol evolves.
+* No standardization of error condition for proper feedback to the sender.
+
+Other than that, our proposal is very similar.
+
+=3D=3DSpecification=3D=3D
+
+=3D=3D=3DProtocol=3D=3D=3D
+
+In a payjoin payment, the following steps happen:
+
+* The receiver of the payment, presents a [[bip-021.mediawiki|BIP 21 URI]] =
+to the sender with a parameter &lt;code&gt;pj&lt;/code&gt; describing an ht=
+tps (or http if it is a Tor hidden service) link to the payjoin endpoint.
+* The sender creates a signed, finalized PSBT with witness UTXO or previous=
+ transactions of the inputs. We call this PSBT the &lt;code&gt;original&lt;=
+/code&gt;.
+* The receiver replies back with a signed PSBT containing his own signed in=
+puts/outputs and those of the sender. We call this PSBT &lt;code&gt;Payjoin=
+ proposal&lt;/code&gt;.
+* The sender verifies the proposal, re-signs his inputs and broadcasts the =
+transaction to the Bitcoin network. We call this transaction &lt;code&gt;Pa=
+yjoin transaction&lt;/code&gt;.
+&lt;pre&gt;
++----------+ +--------+ +-----------------+
+| Receiver | | Sender | | Bitcoin Network |
++----+-----+ +---+----+ +-------+---------+
+ | +-----------------+ | |
+ +-------+ BIP21 with ?pj=3D +-------&gt;+ |
+ | +-----------------+ | |
+ | | |
+ | +---------------+ | |
+ +&lt;-------+ Original PSBT +---------+ |
+ | +---------------+ | |
+ | | |
+ | +------------------+ | |
+ | | Payjoin Proposal | | |
+ +-------+ PSBT +------&gt;+ |
+ | +------------------+ | |
+ | | +--------------+ |
+ | |---+ Payjoin | |
+ | | | transaction +--&gt;+
+ | | +--------------+ |
+ + + +
+&lt;/pre&gt;
+The original PSBT is sent in the HTTP POST request body, base64 serialized,=
+ with &lt;code&gt;text/plain&lt;/code&gt; in the &lt;code&gt;Content-Type&l=
+t;/code&gt; HTTP header and &lt;code&gt;Content-Length&lt;/code&gt; set cor=
+rectly.
+The payjoin proposal PSBT is sent in the HTTP response body, base64 seriali=
+zed with HTTP code 200.
+
+To ensure compatibility with web-wallets and browser-based-tools, all respo=
+nses (including errors) must contain the HTTP header &lt;code&gt;Access-Con=
+trol-Allow-Origin: *&lt;/code&gt;.
+
+The sender must ensure that the url refers to a scheme or protocol using au=
+thenticated encryption, for example TLS with certificate validation, or a .=
+onion link to a hidden service whose public key identifier has already been=
+ communicated via a TLS connection. Senders MUST NOT accept a url represent=
+ing an unencrypted or unauthenticated connection.
+
+=3D=3D=3DReceiver&#39;s well known errors=3D=3D=3D
+
+If for some reason the receiver is unable to create a payjoin proposal, it =
+will reply with a HTTP code different than 200.
+The receiver is not constrained to specific set of errors, some are specifi=
+ed in this proposal.
+
+The errors have the following format:
+&lt;pre&gt;
+{
+ &quot;errorCode&quot;: &quot;leaking-data&quot;,
+ &quot;message&quot;: &quot;Key path information or GlobalXPubs should n=
+ot be included in the original PSBT.&quot;
+}
+&lt;/pre&gt;
+
+The well-known error codes are:
+{| class=3D&quot;wikitable&quot;
+!Error code
+!Meaning
+|-
+|leaking-data
+|Key path information or GlobalXPubs should not be included in the original=
+ PSBT.
+|-
+|psbt-not-finalized
+|The original PSBT must be finalized.
+|-
+|unavailable
+|The payjoin endpoint is not available for now.
+|-
+|out-of-utxos
+|The receiver does not have any UTXO to contribute in a payjoin proposal.
+|-
+|not-enough-money
+|The receiver added some inputs but could not bump the fee of the payjoin p=
+roposal.
+|-
+|insane-psbt
+|Some consistency check on the PSBT failed.
+|-
+|version-unsupported
+|This version of payjoin is not supported.
+|-
+|need-utxo-information
+|The witness UTXO or non witness UTXO is missing
+|-
+|invalid-transaction
+|The original transaction is invalid for payjoin
+|}
+
+The receiver is allowed to return implementation specific errors which may =
+assist the sender to diagnose any issue.
+
+However, it is important that error codes that are not well-known and that =
+the message do not appear on the sender&#39;s software user interface.
+Such error codes or messages could be used maliciously to phish a non techn=
+ical user.
+Instead those errors or messages can only appear in debug logs.
+
+It is advised to hard code the description of the error codes into the send=
+er&#39;s software.
+
+=3D=3D=3DReceiver&#39;s original PSBT checklist=3D=3D=3D
+
+The receiver needs to do some check on the original PSBT before proceeding:
+
+* Non-interactive receivers (like a payment processor) need to check that t=
+he original PSBT is broadcastable. &lt;code&gt;*&lt;/code&gt;
+* If the sender included inputs in the original PSBT owned by the receiver,=
+ the receiver must either return error &lt;code&gt;invalid-transaction&lt;/=
+code&gt; or make sure they do not sign those inputs in the payjoin proposal=
+.
+* If the sender&#39;s inputs are all from the same scriptPubKey type, the r=
+eceiver must match the same type. If the receiver can&#39;t match the type,=
+ they must return error &lt;code&gt;out-of-utxos&lt;/code&gt;.
+
+&lt;code&gt;*&lt;/code&gt;: Interactive receivers are not required to valid=
+ate the original PSBT because they are not exposed to probing attacks.
+
+=3D=3D=3DSender&#39;s payjoin proposal checklist=3D=3D=3D
+
+The sender should check the payjoin proposal before signing it to prevent a=
+ malicious receiver from stealing money.
+
+* Check that all the spent outpoints in the original PSBT still exist in th=
+e coinjoin PSBT.
+* Check that all the spent outpoints in the original PSBT do not have any p=
+artial signature.
+* If the sender is not using inputs with mixed types, check that the receiv=
+er inputs type match the inputs type of the sender. (ie. both using P2SH-P2=
+WPKH or both using P2WPKH)
+* Check that any inputs added by the receiver are finalized.
+* Check that the transaction version, and nLockTime are unchanged.
+* Check that the sender&#39;s inputs&#39; sequence numbers are unchanged.
+* If the sender&#39;s inputs&#39; sequence numbers the homogenous, check th=
+at the receiver&#39;s contributed inputs match those.
+* Check that the sender&#39;s outputs have not been modified (but potential=
+ly shuffled), except for paying increased fee
+* If sender specified &lt;code&gt;feebumpindex=3D&lt;/code&gt; (see later),=
+ the fee should have been subtracted from the output at the same index in t=
+he original PSBT.
+* Check that the sent amount in the payjoin proposal is less than 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 add paid to the fee.
+* Check that the estimated fee rate of the payjoin proposal is not more tha=
+n the fee rate of the original PSBT. (fee estimation is hard, so we should =
+allow ~2 satoshi per inputs as margin of error)
+* If &lt;code&gt;maxfeebumpcontribution=3D&lt;/code&gt; was specified, chec=
+k the additional paid amount is less than or equal to this amount.
+* If &lt;code&gt;maxfeebumpcontribution=3D&lt;/code&gt; was not specified, =
+the sender&#39;s software should ask an interactive confirmation to the use=
+r.
+
+The sender must be careful to only sign the inputs that were present in the=
+ original PSBT and nothing else.
+
+Note:
+* The sender should allow the payment output to be modified by the receiver=
+ (The receiver may substitute a P2WPKH payment to P2SH payment to increase =
+privacy)
+* The sender must allow the receiver to add outputs.
+* The sender must allow the receiver to not add any input. Useful for the r=
+eceiver to change the paymout output scriptPubKey type.
+* If no input has been added, the sender&#39;s wallet should accept the pay=
+join proposal, but should not mark the transaction as an actual payjoin in =
+the user interface.
+
+Our method of checking the fee allows the receiver and the sender to batch =
+payments in the payjoin transaction.
+It also allows the receiver to pay the fee for batching adding his own outp=
+uts.
+
+=3D=3D=3DOptional parameters=3D=3D=3D
+
+When the payjoin sender posts the original PSBT to the receiver, he can opt=
+ionally specify the following HTTP query string parameters:
+
+* &lt;code&gt;v=3D&lt;/code&gt;, the version number of the payjoin protocol=
+ that the sender is using. The current version is &lt;code&gt;1&lt;/code&gt=
+;.
+
+This can be used in the future so the receiver can reject a payjoin if the =
+sender is using a version which is not supported via an error HTTP 400, &lt=
+;code&gt;version-unsupported&lt;/code&gt;.
+If not specified, the receiver will assume the sender is &lt;code&gt;v=3D1&=
+lt;/code&gt;.
+
+If the receiver does not support the version of the sender, they should sen=
+d an error with the list of supported versions:
+&lt;pre&gt;
+{
+ &quot;errorCode&quot;: &quot;version-unsupported&quot;,
+ &quot;supported&quot; : [ 2, 3, 4 ],
+ &quot;message&quot;: &quot;The version is not supported anymore&quot;
+}
+&lt;/pre&gt;
+
+* &lt;code&gt;feebumpindex=3D&lt;/code&gt;, the preferred output from which=
+ to increase the fee for the added inputs. (default: &lt;code&gt;-1&lt;/cod=
+e&gt;)
+
+If the &lt;code&gt;feebumpindex&lt;/code&gt; is out of bounds or pointing t=
+o the payment ouptut meant for the receiver, the receiver should ignore the=
+ parameter.
+
+* &lt;code&gt;maxfeebumpcontribution=3D&lt;/code&gt;, an integer defining t=
+he maximum amount in satoshis that the sender is willing to contribute towa=
+rds fees for the additional inputs. &lt;code&gt;maxfeebumpcontribution&lt;/=
+code&gt; must be ignored if set to less than zero. (default: -1)
+
+Note that if &lt;code&gt;maxfeebumpcontribution&lt;/code&gt; is too low, th=
+e sender should create a transaction with RBF disabled, as the original tra=
+nsaction could replace the payjoin transaction.
+
+=3D=3DRationale=3D=3D
+
+There is several consequences of our proposal:
+
+* The receiver can bump the fee of the original transaction.
+* The receiver can modify the outputs of the original PSBT.
+* The sender must provide the UTXO information (Witness or previous transac=
+tion) in the PSBT.
+
+=3D=3D=3DRespecting the minimum relay fee policy=3D=3D=3D
+
+To be properly relayed, a Bitcoin transaction needs to pay at least 1 satos=
+hi per virtual byte.
+When fees are low, the original transaction is already 1 satoshi per virtua=
+l byte, so if the receiver adds their own input, they need to make sure the=
+ fee is increased such that the rate does not drop below 1 satoshi per virt=
+ual byte.
+
+=3D=3D=3DPreventing mempool replacement=3D=3D=3D
+
+A safe way to implement payjoin, is for both the sender and receiver to try=
+ broadcasting the original transaction at some fixed interval period regard=
+less of the state of the payjoin.
+
+If the receiver was not properly adding fees to the payjoin transaction, th=
+e original transaction would end up replacing the payjoin transaction in th=
+e mempool.
+
+=3D=3D=3DDefeating heuristics based on the fee calculation=3D=3D=3D
+
+Most wallets are creating a round fee rate (like 2 sat/b).
+If the payjoin transaction&#39;s fee was not increased by the added size, t=
+hen those payjoin transactions could easily be identifiable on the blockcha=
+in.
+
+Not only would those transactions stand out by not having a round fee (like=
+ 1.87 sat/b), but any suspicion of payjoin could be confirmed by checking i=
+f removing one input would create a round fee rate.
+
+=3D=3D=3DReceiver does not need to be a full node=3D=3D=3D
+
+Because the receiver needs to bump the fee to keep the same fee rate as the=
+ original PSBT, it needs the input&#39;s UTXO information to know what is t=
+he original fee rate. Without PSBT, light wallets like Wasabi Wallet would =
+not be able to receive a payjoin transaction.
+
+The validation (policy and consensus) of the original transaction is option=
+al: a receiver without a full node can decide to create the payjoin transac=
+tion and automatically broadcast the original transaction after a timeout o=
+f 1 minute, and only verify that it has been propagated in the network.
+
+However, non-interactive receivers (like a payment processor) need to verif=
+y the transaction to prevent UTXO probing attacks.=20
+
+This is not a concern for interactive receivers like Wasabi Wallet, because=
+ those receivers can just limit the number of original PSBT proposals of a =
+specific address to one. With such wallets, the attacker has no way to gene=
+rate new deposit addresses to probe the UTXOs.
+
+=3D=3D=3DSpare change donation=3D=3D=3D
+
+Small change inside wallets are detrimental to privacy. Mixers like Wasabi =
+wallet, because of its protocol, eventually generate such [[<a href=3D"http=
+s://docs.wasabiwallet.io/using-wasabi/ChangeCoins.html#first-round-coinjoin=
+-change|small">https://docs.wasabiwallet.io/using-wasabi/ChangeCoins.html#f=
+irst-round-coinjoin-change|small</a> change]].
+
+A common way to protect your privacy is to donate those spare changes, to d=
+eposit them in an exchange or on your favorite merchant&#39;s store account=
+. Those kind of transactions can easily be spotted on the blockchain: There=
+ is only one output.
+
+However, if you donate via payjoin, it will look like a normal transaction.
+
+On top of this the receiver can poison analysis by randomly faking a round =
+amount of satoshi for the additional output.
+
+=3D=3D=3DPayment output substitution=3D=3D=3D
+
+The receiver is free to change the output paying to himself.
+For example, if the sender&#39;s scriptPubKey type is P2WPKH while the rece=
+iver&#39;s payment output in the original PSBT is P2SH, then the receiver c=
+an substitute the payment output to be P2WPKH to match the sender&#39;s scr=
+iptPubKey type.
+
+=3D=3D=3DImpacted heuristics=3D=3D=3D
+
+Our proposal of payjoin is breaking the following blockchain heuristics:
+
+* Common inputs heuristics.
+
+Because payjoin is mixing the inputs of the sender and receiver, this heuri=
+stic becomes unreliable.
+
+* Change identification from scriptPubKey type heuristics
+
+When Alice pays Bob, if Alice is using P2SH but Bob&#39;s deposit address i=
+s P2WPKH, the heuristic would assume that the P2SH output is the change add=
+ress of Alice.
+This is now however a broken assumption, as the payjoin receiver has the fr=
+eedom to mislead analytics by purposefully changing the invoice&#39;s addre=
+ss in the payjoin transaction.
+
+Alternatively, if the original address of Bob is P2WPKH and Alice&#39;s add=
+ress is also P2WPKH, Bob can change the receiving address in the payjoin to=
+ P2SH. The heuristic would wrongfully identify the payjoin&#39;s receiving =
+address as the change address of the transaction.
+
+See payment output substitution above.
+
+* Change identification from round change amount
+
+If Alice pays Bob, she might be tempted to pay him a round amount, like &lt=
+;code&gt;1.23000000 BTC&lt;/code&gt;. When this happens, blockchain analysi=
+s often identifies the output without the round amount as the change of the=
+ transaction.
+
+For this reason, during a [spare change](Payjoin-spec.md#spare-change-donat=
+ion) situation, we randomly round the amount in the output added by the rec=
+eiver to the payjoin transaction.
+
+=3D=3DAttack vectors=3D=3D
+
+=3D=3D=3DOn the receiver side: UTXO probing attack=3D=3D=3D
+
+When the receiver creates a payjoin proposal, they expose one or more input=
+s belonging to them.
+
+An attacker could create multiple original transactions in order to learn t=
+he UTXOs of the receiver, while not broadcasting the payjoin proposal.
+
+While we cannot prevent this type of attack entirely, we implemented the fo=
+llowing mitigations:
+
+* When the receiver detects an original transaction being broadcast, or if =
+the receiver detects that the original transaction has been double spent, t=
+hen they will reuse the UTXO that was exposed for the next payjoin.
+* While the exposed UTXO will be reused in priority to not leak other UTXOs=
+, there is no strong guarantee about it. This prevents the attacker from de=
+tecting with certainty the next payjoin of the merchant to another peer.
+
+Note that probing attacks are only a problem for automated payment systems =
+such as BTCPay Server. End-user wallets with payjoin capabilities are not a=
+ffected, as the attacker can&#39;t create multiple invoices to force the re=
+ceiver to expose their UTXOs.
+
+=3D=3D=3DOn the sender side: Double payment risk for hardware wallets=3D=3D=
+=3D
+
+For a successful payjoin to happen, the sender needs to sign two transactio=
+ns double spending each other: The original transaction and the payjoin pro=
+posal.
+
+The sender&#39;s software wallet can verify that the payjoin proposal is le=
+gitimate by the sender&#39;s checklist.
+
+However, a hardware wallet can&#39;t verify that this is indeed the case. T=
+his means that the security guarantee of the hardware wallet is decreased. =
+If the sender&#39;s software is compromised, the hardware wallet would sign=
+ two valid transactions, thus sending two payments.
+
+Without payjoin, the maximum amount of money that could be lost by a compro=
+mised software is equal to one payment (via address substitution).
+
+With payjoin, the maximum amount of money that can be lost is equal to two =
+payments.
+
+=3D=3DImplementations=3D=3D
+
+* [[<a href=3D"https://github.com/BlueWallet/BlueWallet|BlueWallet">https:/=
+/github.com/BlueWallet/BlueWallet|BlueWallet</a>]] is in the process of imp=
+lementing the protocol.
+* [[<a href=3D"https://github.com/btcpayserver/btcpayserver|BTCPay">https:/=
+/github.com/btcpayserver/btcpayserver|BTCPay</a> Server]] has implemented s=
+ender and receiver side of this protocol.
+* [[<a href=3D"https://github.com/zkSNACKs/WalletWasabi/|Wasabi">https://gi=
+thub.com/zkSNACKs/WalletWasabi/|Wasabi</a> Wallet]] has merged sender&#39;s=
+ support.
+* [[<a href=3D"https://github.com/JoinMarket-Org/joinmarket-clientserver|Jo=
+in">https://github.com/JoinMarket-Org/joinmarket-clientserver|Join</a> Mark=
+et]] is in the process of implementing the protocol.
+* [[<a href=3D"https://github.com/junderw/payjoin-client-js|JavaScript">htt=
+ps://github.com/junderw/payjoin-client-js|JavaScript</a> sender implementat=
+ion]].
+
+=3D=3DSpecial thanks=3D=3D
+
+Special thanks to Kukks for developing the initial support to BTCPay Server=
+, to junderw, AdamISZ, lukechilds, ncoelho, nopara73, yahiheb for all the f=
+eedback we received since our first implementation.
+Thanks also to RHavar who wrote the [[<a href=3D"https://github.com/bitcoin=
+/bips/blob/master/bip-0079.mediawiki|BIP79">https://github.com/bitcoin/bips=
+/blob/master/bip-0079.mediawiki|BIP79</a> Bustapay]] proposal, this gave a =
+good starting point for our proposal.
+</pre>
+
+</div>
+
+--0000000000009c395605a5c930a9--
+