A couple of weeks ago I took a deep dive into the Bitcoin Payment Protocol, aka BIP-70. The reason behind doing that was that I tried to make a payment to a BitPay merchant using the Android version of Electron Cash and it actually failed, which required a few e-mails back and forth to BitPay support so I could get my precious money back. For a new user the UX of a failed payment is absolutely catastrophic and simply can not happen.
I am a big fan of BIP-70 since it enables some handshaking between a customer and a merchant that, according to BitPays data, drastically lowers the rate of faulty transactions. A faulty transaction will reflect poorly on a merchant and will raise the bar for that specific merchant to keep Bitcoin as a payment method.
There are however a few points in the standard that should be extended, clarified and changed so every wallet and merchant operates consistently. In this text I use the word “merchant” when in reality it might most often be a third-party payment processor like BitPay or Coinbase Commerce.
The merchant shall transmit the transaction to the P2P network
This is how the protocol works on a high level. Picture from the actual BIP-70 specification
My main concern is that the Wallet App sends the transaction to the P2P network before receiving a PaymentACK from the Merchant Server. This makes no sense at all since the wallet has no way of knowing if the merchant accepts the Payment before the PaymentACK is received. If a merchant thinks the Payment is invalid it would already be too late and the wallet would’ve broadcasted the transaction and thus lost control of the money and a very user unfriendly process of getting a refund needs to be initiated by a disappointed customer that most likely hasn’t done anything wrong. BitPay has gone so far as to reject a Payment if the transaction is broadcasted to the network before it is ACKed.
Related to this I am of the firm believe that it isn’t the customer that has the responsibility to broadcast the transaction after the merchant has acknowledged it. That should fall on the responsibility of the merchant. The “transaction” arrow in the picture above should be removed completely since the “transactions” arrow at the bottom renders it redundant.
More explicit PaymentRequests
Currently a merchant may NACK a payment for a variety of reasons that the Wallet App would find out about too late in the process. Some of the reasons might be:
- Too low mining fee. Currently modus operandi on the BCH network is to use a 1 satoshi/byte and it should just work. For the future I predict that the BCH network will start to see lower fees than that and during a transition period it might be hard to get a sub 1 sat/b confirmed in the next block due to all miners not accepting that level. On the BTC network this is absolutely crucial since it is non-trivial to estimate a reasonable fee for a next-block confirmation. The merchant should be the one that decides the lower level and the customer either accepts or cancels the payment from his or her wallet.
- Transaction contain unconfirmed input(s). Being able to spend unconfirmed coins is a really neat feature but some might consider it dangerous. The merchant should decide if it should be possible or if the transaction inputs should have 1, 6, 10 or whatever number of confirmations on the blockchain. The wallet app would automatically construct the transaction of inputs according to this parameter.
Both of these should explicitly be set as parameters in the PaymentDetails for a smoother experience.
In BIP-70 the PaymentProtocol is communicated over HTTP(S) and this assumes that any merchant will have a server online which arguably works fine for web merchants. I would like to have the entire function contained within one application that doesn’t require trusting a third party (the web server in this case). Imagine a scenario where a brick-and-mortar shop has installed a simple point-of-sales system on a generic smartphone and still would like the benefits of the protocol. The merchant would enter the amount and possibly a memo and generate a QR-code that the customer scans. This QR-code currently decodes to a URL where the actual PaymentDetails is fetched and then the customer sends the Payment back to the web server and the merchant gets an ACK/NACK in the application and hands over the goods.
I would rather have the QR-code being a trigger for starting communicating via for instance bluetooth instead and ideally the QR-code could be complemented with NFC. I would like to experiment and figure out if the current Android and iOS APIs would allow this to happen with reasonable complexity. If the units needs to be paired and verified it might be to cumbersome to even attempt at deploying such a solution. If anyone can point me to any previous work on this I would be grateful.
BitPay has proposed a new standard called jsonPaymentProtocol. It solves some of my concerns, namely the transmission of the transaction and the minimum fee, but not the flexability of spending unconfirmed coins to which I opened a pull request some time ago. Besides not touching on the ability to use another transport medium then HTTP(S) I am a little concerned about the signature verifications. In BIP-70 the signature verification relies on X.509 PKI and in a nutshell relies on the fact that the merchant has a signed key by any Certificate Authority (CA) that is trusted by your Operating System, which is basically the same scheme as web browsers use to determine if a HTTPS site is trusted or not. History has shown that this is not a perfect system but I don’t think the alternative is feasible for large scale. In jsonPaymentProtcol this has changed to a model where a wallet has to make the decision by somehow knowing a public key from every merchant. The specification even lists three different methods, each with its own pros and cons, and I think this will be problem for merchants that want to move away from the major payment processors. It probably works great for BitPay since every wallet would make sure that their key would work but it would be highly problematic for a random merchant to launch his own implementation of the specification. In BIP-70 he or she would get the key signed by a CA (remember, Let’s Encrypt is free!) and then be good to go whereas in jsonPaymentProtocol the key would need to be communicated to wallet developers and basically non functional until some action has been taken.
If we are to gain mass adoption the payments needs to go really smoothly from a user perspective. I hope that someone reads all this and comes with more suggestions, ideas or critique.