Back to index page

31.08.2022: Payment gateway for this project is deactivated. No transactions are detected.

Crypto shop system

Shop   -   Login   -   Docs   -   Imprint


Improvement of my Crypto payment system

31.08.2022: Payment gateway for this project is deactivated. No transactions are detected.

25. Aug 2022

Project 1: Picture Map
Docs
Example

Project 2: Test shop system
Docs (This page)
Example
Hacker News discussion

Some thoughts at the beginning

In the middle of the year 2022 I built my first Crypto payment gateway supporting Litecoin, Dogecoin, Nano, Solana and Stellar. You can read about it here: Project 1. It worked but isn't convenient. The question I want to answer is how difficult can it be to implement an automatic Crypto payment system on your own website fully operated by yourself.

The new version is easier to use and the payment process is much faster (payment checking every minute). Some people would still say it's kind of slow in comparison to credit card payments. It is, but you don't have to share private informations (credit card informations or details about your bank account) to make a payment. And you don't need to pay or use a third party service to offer a payment option at all.

A new solution

The last solution in Project 1 was more complicated. For every order somebody made, a new address for coin deposit was created. This makes sense when using UTXO blockchains (Bit-, Lite- and Dogecoin) but not so much if you choose blockchains using the balance model (Ethereum, Solana and Stellar). I used a VPS for operating all the blockchain stuff. This means new created private keys are not that private. A successful payment was recognised when the provided address had a specific amount of coins in it.

The new solution works with a fixed address for each coin. So how do I differentiate payments? The best solution would be to read the memo field which can be set by the customer when an amount of coins is sent. But not every wallet supports this option (especially multi coin wallets - hopefully it will be implemented sometime). So I decided to make the amount unique. When a new order is created, a unique field in the database is set to a number between 01 and 99. This number represents the last two digits of the payment amount.

Update: The random number is a bad solution for this problem. A better implementation is to look for free numbers (0-99) in the database first and then proceed the payment process. In this case you would have a maximum of 100 transaction per 12 minutes (max. time I wait for an incoming transaction). This is only a temporarily solution. Ideal solution would be to use the memo field, which gives you infinite payments.

Example:

Price in USD: 10
Price in XLM: 90.74574856167987

Unique number: 77
New price in XLM: 90.7457477

The smallest unit depends on the coin. It's so small it doesn't affect the price (not yet). Right now the unique number is generated randomly. If the number is already in use (DB error trying to store the number) an error is shown and the customer is encouraged to try it again (need to be improved).

I only support two coins now: Stellar and Solana. These are the easiest to imlement, have almost no memory footprint and support instant transactions (really cheap). Both Lite- and Dogecoin need the whole blockchain download (pruning possible - reduces size to 3-5 GB otherwise it would be over 90 GB) to operate and take longer to transfer funds. They also use a lot of memory (up to 2GB per daemon). Nano is kind of dying and not a well known coin anymore.

I didn't include the Bitcoin Lightning network, because it's too complicated. I want to focus on the payment process but implementing Lightning means maintaining channels as well. You need the full blockchain on your VPS (pruning doesn't work here so it is 430 GB). It's kind of difficult and I read almost everyday about problems with Umbrel and co. I'm sorry, but I don't like the solution at all. I might try it anyway but not yet.

You can test my solution with the Stellar Solar wallet. It includes the testnet and the option to receive some testcoins with one click.

Implementation

PHP Webspace and VPS connection

app.diagrams.net

 

Cronjob on VPS

app.diagrams.net

 

Stellar transaction check

The script runs every minute. It checks if there was a change in the amount connected to the fixed address.

#!/usr/bin/python3
import urllib.request, json

adr = "GCUGO4DDCY57MZC33KWQRSU6SZCLV2F6O67WYDHTHIWQWB6BG63DB6N5"
url = "https://horizon-testnet.stellar.org/accounts/" + adr
resource = urllib.request.urlopen(url)
content =  resource.read().decode('ascii', 'ignore')
content = json.loads(content)
balance = content["balances"][0]["balance"]
print(balance)

#
# Code which loads last balance and compares it
#

If there was a change, transactions are checked and new ones added to the SQLite database. A link is called which confirms payment.

url = "https://horizon-testnet.stellar.org/accounts/" + adr + "/payments?limit=15&order=desc"
resource = urllib.request.urlopen(url)
content =  resource.read().decode('ascii', 'ignore')
content = json.loads(content)
 
for i in content["_embedded"]["records"]:
 if i["type"] == "payment":
  #
  print(i["id"], i["type"], i["amount"], i["created_at"])
  #
  # - Check if transaction id is already saved in DB
  # - If not save it to DB and call link:
  #   https://cryptogif.info/project2/paid.php?amount=" + i["amount"] + "&token=secret

That's it.

Solana transaction check

This one is more difficult and runs also every minute. It's a mess how I implemented it in a Python script (combination of Solana binary usage and JSON RPC calls). You need to download the Solana CLI utilities to speak with the cluster.

Parameters

#!/usr/bin/python3

sol_bin = "/home/asdf/.local/share/solana/install/releases/1.10.29/solana-release/bin/solana"
sol_address = "5BStpuW43vXCZPUxFLQo7QxWkiyWa3qRZ5gNxDYqyf6F"
sol_cluster = "https://api.devnet.solana.com/"
sol_balance = "curl " + sol_cluster + " -X POST -H \"Content-Type: application/json\" -d '{\"jsonrpc\":\"2.0\", \"id\":1, \"method\":\"getBalance\", \"params\":[\"" + sol_address + "\"]}'"
sol_transfer = sol_bin  + " transaction-history " + sol_address + " --url " + sol_cluster
sol_transaction1 = "curl " + sol_cluster + " -X POST -H \"Content-Type: application/json\" -d '{\"jsonrpc\":\"2.0\", \"id\":1, \"method\":\"getTransaction\", \"params\":[\"" 
sol_transaction2 = "\"]}'"

Checking the balance of an address

curl https://api.devnet.solana.com/ -X POST -H "Content-Type: application/json" -d \'{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["5BStpuW43vXCZPUxFLQo7QxWkiyWa3qRZ5gNxDYqyf6F"]}\'

If there is a change proceed with listing the transactions

solana transaction-history 5BStpuW43vXCZPUxFLQo7QxWkiyWa3qRZ5gNxDYqyf6F --url https://api.devnet.solana.com/

Example output:
4EePxMk9RnUg89UDNYoJF...
56Qy29SCVHJ1id9yo2Vq1...
2ZmvceL3Jzg6hiGS6oryq...
4kbWpJfu1oFkHPURgdwL7...
2FTACawC7y366seQ31rdh...
5 transactions found

Check if transaction is already listed in SQLite DB and if not, add it and get more information about the new transaction

curl https://api.devnet.solana.com/ -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getTransaction", "params":["3knJrqeEYu22ckaTnowLoLfF4GLbPNk6z8MSjBfjnmESiPnsvNNiGnErPqTaWiv23cYxZNGtPFdaFo4hDvHXAkR7"]}'

Parse the output and calculate the transferred amount with

amount = preBalances - (fee + postBalances)

Let the online PHP website know, that this balance was transferred.

Future development

I'm happy with the status of the project now. Improvements would be:

There are not many coins which are suitable for instant payment. But anyways it's kind of exhausting to implement as many as possible. Best way is to choose one and hope your costumer is ready to buy a bag of it to pay for your product. This might get easier if Multicoin wallets offer swapping coins for low fees.

Right now nobody is really interested in using Crypto for payment. I like to find real use cases and looking forward to buy real stuff with it, but most people just hodl, especially when markets are down.

While paying with Crypto is easy, the process to get Crypto is kind of difficult. You have to register on an exchange, make an KYC check and transfer real money to purchase some Crypto. That's not enough. You need a wallet software on your computer or mobile phone to receive and send funds. How can you know which one is good enough?

At the current state there is a lot of work involved to get used to it (for the buyer and the shop owner). As a shop owner, it's just easier to use a third party service. And customers have no need to use Crypto over credit card. If you don't buy stuff on some darknet marketplace you actually don't need Crypto for payment.

I hope to find some usecases in the future. I might buy a broken vending machine and adapt Crypto payment to it. If you have some other ideas let me know.