Unique payment ID via payment protocol

We have an update on the payment ID discussions which have been increasing over the past weeks. The main point of discussion has been whether additional data should be included in the block payload - various options and opinions have been discussed in the New state block design topic.

The general stance from the Nano Foundation is that adding this additional, open data field to the block comes with trade-offs we think may not make it worth doing, some of these concerns are noted here. As an alternative, we have suggested a separate payment management setup, including a block and/or block hash handoff, which may provide the benefits needed without adding complexity to the protocol and ledger. Below are some details about how this might work for further discussion.

The problem

Each block already has a unique ID associated with it, which is the block hash, but when a typical transaction occurs with a merchant there is often only a one-way communication - the merchant telling the customer how much Nano to send and to what address. With this setup the merchant can't know for sure that a specific payment to the address was for a specific purchase - if the amounts conflict with another recent transaction it can become an issue.

To get around this most payment processors use a pool of unique accounts and assign one per expected purchase, then after validating payment they forward that on to a central wallet to manage. This is cumbersome and increases ledger size due to extra forwarding transactions.

Potential solution

The payment protocol approach is aiming to allow connecting a block published to the network with a specific payment expected by a merchant. It does so by standardizing the communication for sending the hash of the payment block or the fully signed block to the merchant for tracking purposes. Each of these approaches has benefits worth discussing.

Block hash and signed block handoff

In both handoff scenarios, the main component is a standard for a merchant to provide the wallet with a URL that accepts details of the payment to be made - we will call this the payment response URL. By providing the URL to the wallet the merchant can also include a unique payment ID as a parameter to include in the response, thus allowing direct ties between the block and the payment.

In the block hash approach, the response would include just the hash of the block prepared, not the block contents. The wallet would then publish the block contents to the network themselves, which the merchant can easily watch for confirmation on to complete the transaction on their side.

In the signed block handoff approach, the response would include the entire contents of the signed block, ready for the merchant to validate, connect with the payment on their end and publish to the network themselves. Here is a diagram outlining this process in more detail.

There are pros and cons to both methods, so including them both is likely useful. The block hash approach will likely be the preferred method when:

  • The customer wallet has an internet connection/ability to publish the block themselves

  • Has the ability to provide the necessary work with the block (or the merchant doesn't offer this option)

It is preferred because it doesn't rely on the merchant having to publish the block as the other approach requires, which removes the ability of the merchant to hold onto the signed block for malicious purposes. This malicious behavior only makes sense if the merchant believes they can deny providing the goods of the transaction while holding the block, and then subsequently publish the block to receive payment anyway. This scenario can be avoided by the wallet watching for the block being published to their node and providing a "cancel" option, which is essentially publishing another block themselves (change representative, without balance change, etc.) to prevent the merchant block from being allowed. This issue doesn't seem to be a high risk one, but is notable.

There are other situations where the signed block handoff would be necessary, primarily when:

  • The customer wallet doesn't have an internet connection so must use NFC or QR code scanning to communicate (e.g. in a busy stadium with poor cellular reception)

  • The customer doesn't have work ready for the block and the merchant offers to cover it

In these scenarios, the customer doesn't have a choice in letting the merchant publish the block on their behalf because they don't meet the necessary requirements to do so themselves (or perhaps the alternative is just too cumbersome, such as the merchant providing the work back to the user with an extra communication step).

Note that the ability for a receiver (merchant) to cover the work for a sender is possible, although requires on-demand work generation currently. Some potential changes being considered that would allow pre-computed work on the receiver side to cover sender work have been mentioned here.

What if the wallet used doesn't support these methods?

There is a generic fallback mechanism that can be used if the wallet doesn't support this protocol, and it likely is only needed in edge cases. If the merchant is expecting a payment of a specific amount and there is only one payment that arrives for that amount, then it is easy to associate those together. If there are conflicting payment amounts, then a small set of digits can be requested from the payment block so the merchant can choose the right block to associate with the payment. This is included in the diagram linked above.

Other payment standards

There are other payment protocols that attempt to standardize the communication between merchants and customers, most notably the W3C Payment Request API. The above process should be able to fit within a protocol such as this, as they are flexible enough to define a payment type with unique data fields to be passed along (including block hash, full block contents, etc.).

Prototype of payment process

Thanks to community developer Hector Chu, we now have a basic prototype of the signed block handoff process available. We are temporarily hosted the server side of the payment process but this is now down, keeping the below for future reference. This doesn't support QR code generation and scanning at this point, so some manual entry is required. But it does show how this process can work. Here is how to test:

  1. Download the Gonano-gui v0.1.7 wallet from here: Release Gonano v0.1.7 · hectorchu/gonano-gui · GitHub

  2. Setup an account on the wallet and deposit 0.00001 Nano there (NOTE: this was done on the main network to make it more accessible to the community; please manage your funds wisely)

  3. The server side is now down so this can't be completed but leaving for reference

  4. Click the Buy button next to either the Apple or Banana; note that a new entry appears at the top of the table with a unique payment ID

  5. In the Gonano wallet, click Send and enter the following details:

  6. Recipient = the wallet address at the top of the payment page

  7. Amount = the amount for the item selected

  8. Payment URL = right-click and copy the "Payment Link" on the payment page (this URL should contain the unique payment ID of the item you intend to buy)

  9. Click OK and if everything was correct you should get a notification in the wallet and see the hash appear next to the proper item on the payment page

If you try sending the incorrect amount an error will appear in the wallet noting the issue and no payment will be made. As mentioned earlier this is a manual process that would be replaced with QR code scanning or NFC negotiation to make it seamless. By validating the payment details before publishing on the merchant side, this also avoids the complication of incorrect payments requiring refunds or additional top-up to complete.

Evaluating this option

All the details above were pulled together to generate discussion about whether this is a viable route for the Nano ecosystem. Given the separate protocol, this does require receivers of payments to run a service for managing these payment communications and wallets to support the process as well. However given the lightweight nature of the process, this is likely to be straight forward for Point of Sale backends and online checkout systems alike. And ultimately it helps wallets by eventually opening up an option for merchants to cover work they would otherwise have to do themselves.

There was consideration for including a payment protocol as part of the node itself, but that comes with drawbacks of additional complexity in the node, requiring additional ports opened on the node server and means setting up multiple instances of the payment services requires multiple nodes. The separation of concerns between the node and the payment protocol seems worthwhile.

We are interested in additional thoughts around this approach as it impacts the New state block design conversations as well as various services across the Nano network. We are especially looking forward to comments from developers of payment processors and wallets, so will be directly asking for their feedback in various channels. Thanks in advance for everyone's time, testing and consideration, we are excited to make some progress in this critical payments area.

15 Likes

I admire the efforts to solve this problem, as I think it's an important one.

I'm one of the devs of Nanowire, and the forwarding-to-master-account approach was a big frustration for us. With our platform, users depositing funds into our service aren't buying an item of fixed value, they're depositing any amount they would like. This would also apply to exchanges and other similar services (such as a Mechanical Turk type service that uses Nano - which I think would be a great use-case for Nano payments due to the micropayment nature of it).

If the merchant is expecting a payment of a specific amount and there is only one payment that arrives for that amount, then it is easy to associate those together.

This would be a problem for us due to the above. We never know what amount is coming through to us, and I think this will be a fairly common scenario. The only solution you've provided as a work around that I think -could- work for us (since we would want to move away from the unique address per user approach) would be the "last 6 digits of the block hash". Are you suggesting we would prompt the user in some fashion to enter these last 6 digits into a form field to associate their payment? I'm trying to understand how this would work in practice. If that is the case, I think this is quite a cumbersome/clunky fallback scenario from a UX/UI perspective.

  • What is stopping people from monitoring the network to steal funds by copy-pasting other peoples "last 6 digits" into our platform?
  • If this is a separate hash that I'm currently unaware of and is only visible to the user, what is the life expectancy of this hash?
  • What happens if the user closes their wallet later to discover that the payment has not been received, now wallets would need a way to show these last 6 digits at all times as a recovery mechanism? This then falls back to wallet integrations required, which is the problem trying to be solved to begin with. If it's a publicly visible hash then I'm concerned about the stealing funds part again.

In addition to the above, what happens if our node is offline? All users are now required to settle payments via this recovery mechanism?

The benefit of having the payment ID as an optional field in the blockchain itself would be that none of this 'recovery' process is required as you can always scan the blockchain for the field, regardless of whether you're online or not at the time of payment. There's the concern of wallets not supporting this field yet, however I think wallets would be very quick to add support for this as it would be a very simple adjustment so I don't see that as a big problem - and in the mean time it could be stated that only wallets supporting the payment ID are supported. Of course there's always the possibility that a user forgets to include the payment identifier or accidently removes it from their transaction, and would require a support ticket to resolve the problem, but I think that's outside of the scope of this.

Also worth noting that having a payment ID string to paste into desktop wallets is a little bit cleaner than a URL - only marginally, but still.

Also does this have any security implications due to using a URL? DNS poisoning for example? And what happens if the the particular client is unable to resolve that URL at all, now isn't there some further communication issues? It at least complicates the integration for wallets, unless you're only allowing an IP address, but that has problems of it's own.

It seems this could easily work for the case where an amount isn't known, or needed, simply by not performing this check during processing.

In your case, I think the best solution is instead for you to offer an account for the costumer to deposit, the costumer gives you his account from which his deposits will be coming from.

That's how real finance works. If you want to send funds to your brokerage house, they don't create a bank account for you to deposit. They check if the money came from an account with your name.

So we just have to verify that an account belong to a user once, and from then on every deposit made from that account is his.

So to exemplify, the costumer registers with you, you ask him for his account from which he will be making deposits. He inputs it and then you ask for a deposit with a random amount you created to prove that he owns that account (deposit 0.000000004856451531354 Nano). If it checks out, now you know that that account really belongs to him and he can now deposit forever directly into your main wallet without telling you before and you will always be able to identify his deposits as his.

That setup seems like it can be done right now and without any data field in the transactions. This is for a payment that has no pre-setup.

All of these methods involve a shared-secret generated by the receiver and told to the sender. Whether that's in a data field, through an account setup process, or with this proposal, in the payment request QR code that the wallet can automatically understand requiring no user intervention.

2 Likes

The UX is our primary focus so we definitely want to make sure that's center. The user should never have to enter information manually and the intent is that everything gets handled automatically. Some work needs to be done on the fallback method but this prototype is to example the handoff scheme by itself and then we can work on the fallback route.

In the case of DNS poisoning obviously the first port of call is for the URL to use DNSsec or the like. In the worst case someone observes the block and publishes it themselves, this would mess up accounting and need manual intervention.

In cases of failure, I'd think the send-to list in the payment request URI would include several fallbacks like:

  1. Send over NFC
  2. Send to this URL
  3. Generate a QR code of block contents
  4. ...

Why not create a new type of address - a merchant address? That way if you're sending to a merchant address it needs to have a payment ID or else it will be rejected. I think this can be accomplished using the change representative transaction or something similar. Or maybe this can be accomplished from the way the wallet is generated - when deriving the public key add another piece of info (such as a single bit).
The prefix could also be different, instead of nano_1xxx or nano_3xxx we could change it to nano_0xxx or something.
Goals for this:

  • Find out a way to differentiate between normal addresses and merchant addresses
  • Implement client-side verification to make sure the transaction has a payment ID (most wallets would be doing this)
  • Implement server-side verification. Ideally this wouldn't be too hard. just checking for a field and comparing it to the address.

Some notes:

  • Sending a payment ID to a normal address would be fine.
  • This would be hard to implement.
  • Payment IDs would need to be standardized (maybe receiverAddressHash+senderAddressHash+amount+epochTime)
  • Might pose a security risk

If the merchant is already providing a payment id to the sender, why would we want a new address type?

This is an interesting discussion. I do find it surprising that NF doesn't want to add a small id field; the rep field and/or small amount digits are already being abused for this purpose, with a detrimental overall effect, not to mention separate accounts for each customer/transaction. I do have a few points to raise; perhaps more experienced devs can see solutions which I can not.

How can transactions be done atomically using block hashes as a post-confirmation transaction id? If someone can monitor the merchant's account for incoming transactions, they could steal user funds by submitting block hashes faster than the user's wallet - this would seem to come down to whoever has the fastest ping from their node to the merchant's server, and the end user is disadvantaged in such a scenario because of the round trip from their wallet node to their device. As such this doesn't seem to be a viable transaction id alternative, even when two way communication is possible.

The payment protocol approach requires either a merchant server or third party server being available to conduct the transaction. This appears to remove the resiliency benefit of utilizing the peer to peer technology that is Nano's advantage over today's major payment processors. In a transaction cost/speed race to the bottom, a centralized service will generally win over a decentralized one, especially if the centralized service is well established; as soon as Visa feels threatened, Visa's fees would drop to rival Nano's P2PoW fees.

In sum, an on-chain payment id remains a simpler and more resilient means of enabling secure payments over one-way communication than a payment protocol that is dissociated from the core Nano transaction.

4 Likes

People may be exploiting undefined behavior by sticking data in the balance or rep fields but it's still undefined behavior. We don't want to over-specify the protocol because that works us in to a corner in the future when our only focus is on value transfer.

The hash would be submitted and acknowledged before the block itself would be published, this guarantees atomicity.

I don't understand a situation where the merchant and buyer wouldn't interact beforehand but also needs to know where a payment came from. The reason for not putting payment ids in a protocol is because it's a communication between two people and doesn't need to be agreed upon by the network, account balances do, however.

To test simplicity and resiliency, can you write an interaction sequence that's simpler than this.

3 Likes

I'm thinking of a payment at the grocery store or a stadium. I think we can both agree that the friendliest UX is if the user scans a QR code or taps an NFC-enabled device, exchanging one data in one direction, and maybe taps a confirmation popup or goes through a fingerprint/face scan, then the transaction is complete, in under two seconds.
This can be done with a payment protocol by directing the user to an endpoint that isn't directly a Nano protocol endpoint with the qr/nfc. But if it isn't a protocol endpoint, whatever interaction takes place there will be less resilient than the network proper, and likely a centralized service. A single point of failure in the user experience, which on-chain data transfer of an automatically generated transaction id integrated in the qr/nfc could avoid.

Nano's advantage over Visa in tech terms is its resiliency as a peer to peer network, yes? This advantage is negated in a situation where the transaction is conducted through a third party payment protocol service.

There are two communications, the first is the payment request as you describe, and the second reaches out to the network and publishes the block. This replaces the call from the wallet, possibly to your wallet provider or a direct network publish requiring protocol code to be put in to the wallet, with hitting a URL, functionality that already exists.

I don't follow this, being resilient to a purpose, value transfer, doesn't mean it serves all purposes, arbitrary data transfer. The network has no way to validate what's in a data field but it does know how to validate the amount field.

Likely in what way? As described this is run by the merchant themselves, connected to their accounting system.

It transfers value faster in a decentralized way.

It's not a third party, it's run by the merchant.

2 Likes

I don't know how to do fancy quotes, but I'll try to address this in the same way.

I don't follow this, being resilient to a purpose, value transfer, doesn't mean it serves all purposes, arbitrary data transfer. The network has no way to validate what's in a data field but it does know how to validate the amount field.

I mean the transaction itself, from start to finish. Can the user complete their payment near-instantly and without any hassle? If the answer is no, such as if a third party payment processor is down, but the nano network overall is still functioning, that's a needless failure: resiliency is needlessly reduced even though the core transaction could have taken place. The user's wallet could have a fallback node, the merchant could use a different node, but if payment service fails the merchant can't accept Nano within their framework until its fixed.

As described this is run by the merchant themselves, connected to their accounting system.

Merchants want plug and play solutions. They are unlikely to run their own nodes for the most part, and are no more likely to run their own payment processor if it isn't integrated in the node. They are much more likely to use a service to complete the payment for them, as we've seen with.. well, every merchant that's come into discord asking for a Nano-compatible payment processor. (If the payment processor is integrated into the node, my objections no longer apply)

3 Likes

It's pretty slick, you can just select the text and a quote button comes up.

Unless you feel this system precludes the merchant themselves from running it, I think we should restrict calling it a third party service since it's not. It's a part of the merchant's payment system. This system likely includes many components that all need to work together to deliver what the user requested.

For instance, in the case of the stadium, there is a problem connecting to the network, too many cell signals in one place or cement walls. This is a situation where handing the block off via nfc, btle, or a QR code is more resilient than the wallet's internet connection.

But merchants by definition are already running web services, code, databases, that store all the orders they have being processed and in history. This is all using normal standard software all merchants have access to and understand.

I think they're much more likely to put their payment records in a database than inspecting blocks in the payment network.

3 Likes

Ah, very nice!

Online merchants likely are, though they've generally indicated in discord that they would still prefer to integrate a payment processor. But in person at a convenience store, or especially in emerging markets where Nano has the most potential to really take off as a day to day currency in the medium term, merchants aren't likely to have their own software beyond a cash register or cell phone wallet app.

1 Like

If they're choosing to opt-in to a third-party payment provider service, this payment provider would be the one running the handoff if they choose to use this method instead of account-per-transaction as they do now.

In an emerging market with an in-person transaction using a phone wallet app, why do they need a payment id at all since there is a physical association with the transaction: the person standing in front of you.

3 Likes

The need for a payment processor is reduced if confidence on who you are transacting with can be achieved without a block handoff protocol, which can presently be achieved by abusing the rep field or small amount bits. Or could be achieved in the future with a transaction id field. But introducing additional complexity in the block handoff protocol increases the need to opt-in to a third party payment provided. I would also argue that directly sending blocks to a public node is not involving a third party to the same degree; as in the case of an outage the transaction can be sent to any other public node and still be completed, and you only need to send signed blocks to a third party rather than trust them to handle your entire payment process.

Five tellers at the grocery store? Process cleanliness? Verifiable proof? Atomic transactions?

This seems like a deal breaker to me. I could wreak havoc on exchanges or platforms by automatically doing this, if I'm not mistaken.

1 Like

I think we have to go back to a listing of interactions before we can say one method more or less complex than the other.

Can you list out the steps to do an atomic payment with a transaction ID so we can compre it to the steps here? I think this should include steps the merchant does to create and correlate the transaction ID with a block on the network.