The current model has the client connecting to the block explorer, listening for transactions and sending a POST /paid request to the server when a transaction is received. This is non-ideal for several reasons:
Clients are unreliable and sometimes neglect to call the endpoint
Socket.IO in the browser to the Insight instance uses significant client network resources
There are glitches with Socket.IO on some browsers currently with the default block explorer
Specifying a block explorer when creating PayButtons adds additional complexity
The size of pay.js could be reduced if we could get rid of Socket.IO and axios
The server be the one to determine when the invoice is paid, not the client
If the server were to listen for transactions, it would be able to process payments instantaneously and we could get rid of the pendingPayments queue. Broken payments would be far less likely and we wouldn't need to send thousands of API requests to a block explorer every 12 hours
Proposal
We should set up a WebSocket (not Socket.IO) server on the Gateway API server. PayButton requests POST /pay and then gets an address back from the server. The PayButton connects to the WebSocket server.
The server adds the new invoice address to its internal list of addresses to watch for. Any transactions concerning any watched address (which can be thousands of addresses) are processed. The server has no need to query address balances every 12 hours, because any transactions are handled live.
The PayButton listens for several things from the server: paid, overpaid and underpaid. The PayButton responds accordingly. PayButton no longer connects with Socket.IO to a block explorer, saving on payload size and client bandwidth.
Merchants on the gateway.cash site can connect to the socket and see new payments come in live from the server.
Confidentiality can be added to the WebSocket server by requiring merchants to "subscribe" to their API key's channel so that they can only see their transactions. PayButton clients should receive a socketKey with their paymentAddress which they will use when connecting to the socket in order to see their relevant transactions.
On the backend, the API server is always connected to a block explorer via Socket.IO and is listening for addresses it is concerned with. After the appropriate action is performed (processing the payment, notifying customer of overpaid funds etc), the server sends alerts to the WebSocket channels. Merchant API keys serve as channels for the specific merchant, and socketKeys should be stored in the payments table.
Occasionally, broken payments will still happen so we might consider querying past address balances at startup or maybe very slowly over the course of a week, from various explorers so as to be good citizens.
The current model has the client connecting to the block explorer, listening for transactions and sending a POST /paid request to the server when a transaction is received. This is non-ideal for several reasons:
pay.js
could be reduced if we could get rid of Socket.IO andaxios
Proposal
We should set up a WebSocket (not Socket.IO) server on the Gateway API server. PayButton requests
POST /pay
and then gets an address back from the server. The PayButton connects to the WebSocket server.The server adds the new invoice address to its internal list of addresses to watch for. Any transactions concerning any watched address (which can be thousands of addresses) are processed. The server has no need to query address balances every 12 hours, because any transactions are handled live.
The PayButton listens for several things from the server:
paid
,overpaid
andunderpaid
. The PayButton responds accordingly. PayButton no longer connects with Socket.IO to a block explorer, saving on payload size and client bandwidth.Merchants on the gateway.cash site can connect to the socket and see new payments come in live from the server.
Confidentiality can be added to the WebSocket server by requiring merchants to "subscribe" to their API key's channel so that they can only see their transactions. PayButton clients should receive a
socketKey
with theirpaymentAddress
which they will use when connecting to the socket in order to see their relevant transactions.On the backend, the API server is always connected to a block explorer via Socket.IO and is listening for addresses it is concerned with. After the appropriate action is performed (processing the payment, notifying customer of overpaid funds etc), the server sends alerts to the WebSocket channels. Merchant API keys serve as channels for the specific merchant, and
socketKey
s should be stored in the payments table.Occasionally, broken payments will still happen so we might consider querying past address balances at startup or maybe very slowly over the course of a week, from various explorers so as to be good citizens.
I'd love to hear some feedback on this