Developing Decentralized Crypto Payment Gateway

Welcome to a detailed guide about setting up payments on the websites using cryptocurrency. First of all I will explain some basics to you and then we will create our own payment gateway for WooCommerce (it is a eCommerce platform for WordPress).

This is the tutorial for developers. If you’re interested in a cryptocurrency payment gateway plugin for WooCommerce, I have one.

The Difference Between Decentralized and Centralized Cryptocurrency Gateways

That’s the number one thing anyone has to understand. And this thing becomes very clear, when we look at the example.

Let’s assume you have a website, and you configured you website payments using Stripe or PayPal. It is kind of usual, right? But what, if Stripe starts to accept crypto? At that moment it becomes a centralized cryptocurrency payment processor. Why centralized? Because all the power is its hands. Either it doesn’t have your country support or it may not like your account and bans you, in both these cases you can not use it and sometimes even can lose your money – we have all the cons of centralized system here.

When we’re speaking of a decentralized payment processor, it is just a software that interacts with the blockchain, that’s all. Once you have it, nobody can take it from you. And yes, no KYC.

Creating a Crypto Payment Gateway for WooCommerce

In this part of the tutorial we are going to create a crypto currency payment method for WooCommerce. If you’re using a different eCommerce platform, it may still be useful for you because the idea is always the same.

I highly recommend you to check the initial payment gateway tutorial, because below I assume that you know everything described in it, and as always remind you that me and my team are at your service, if you need some help with development, contact us.

The Basics

Before we dive deep into the coding part, let’s deconstruct the whole idea of cryptocurrency payment methods into step by step process.

How it actually happens:

  1. A customer adds some products to the cart and proceeds to the checkout page.
  2. (Optional) Your website generates unique wallet addresses for each customer.
  3. A wallet address or QR code will be shown to the customer.
  4. The customer transfers the crypto with that specific amount to the wallet provided.
  5. (Optional) You may display a field below the wallet address where the customers will be asked to fill the Transaction ID (TxID).
  6. Your website performs a search in the blockchain and checks if that specific transaction has been really made and it was a success.
  7. Depending on the result make the order failed or completed or perform another search within a couple of seconds.

What token and network to choose?

There are plenty of coins and networks you could use. It is up to you to decide what coin you would like to accept on your website. Some coins and networks could be a little bit more difficult to integrate, some – easier. Some coins are more widely used than the others. And of course nobody stops you from integrating as many of them as possible.

In order to understand it more clearly we can make an analogy with PayPal again. For example you accept payments with PayPal on your website. If your potential customers have a PayPal account, it would be easier for them to pay, right? The same applies here, if for example you accept payments with USDT on ERC-20 network, for me it will be easier to pay if I have a wallet in that network.

Another thing to keep in mind is the amount of commission per transaction in a network you’re going to use. For example the commission for ERC-20 network is much higher than in TRC-20 network.

When I tested crypto payment on my website, I used the only USDT token, because for me it was easier to connect it to actual product prices and also I allowed my customers to choose a network from TRC-20, ERC-20 and BEP-20. For each network you have to code the whole integration.

The importance of using unique wallet addresses and why Transaction ID may not be enough

Let’s imagine a situation again. Somebody makes a purchase on your website, and once he or she sends the funds to your wallet, the transaction becomes visible in the blockchain. You can go to usdt.tokenview.com (if the website accepts USDT for payments which is more common) and input your wallet address there.

search for a wallet address in usdt explorer

If you click on a specific transaction, there will be its transaction information. As I said, everything is super-transparent.

So, everyone can see the transaction ID (hash), the time when it had been made, the amount and a wallet address it was send to.

This information can be used to trick your website and create false orders for example. Even if you’re asking for transaction ID for confirmation, because is is also publicly available.

It may also lead to problems if you expect huge amount of order via a short period of time.

So, what to do? Actually there are two ways, that can improve the situation:

  • You can create a lot of wallets, like 10 or even 20 ones, and rotate them in your website checkout.
  • You can use a HD (Hierarchical Deterministic) wallet that allows you to have as many addresses linked to it as you want.

Crypto payment gateway plugin options

When creating a fiat payment gateway we usually need to provide API public and secret keys, for now just a wallet address will be enough.

Our form_fields() array will look like this:

public function init_form_fields(){

	$this->form_fields = array(
		'enabled' => array(
			'title'       => 'Enable/Disable',
			'label'       => 'Enable Crypto Misha Gateway',
			'type'        => 'checkbox',
			'description' => '',
			'default'     => 'no'
		),
		'title' => array(
			'title'       => 'Title',
			'type'        => 'text',
			'description' => 'This controls the title which the user sees during checkout.',
			'default'     => 'Crypto',
			'desc_tip'    => true,
		),
		'description' => array(
			'title'       => 'Description',
			'type'        => 'textarea',
			'description' => 'This controls the description which the user sees during checkout.',
			'default'     => 'Pay with cryptocurrency via our super-cool payment gateway.',
		),
		'address' => array(
			'title'       => 'Wallet address',
			'type'        => 'text'
		),
	);
}

Our payment gateway settings page should look like:

Generate and display QR code

In this part of the tutorial we are going to work with payment_fields() and validate_fields() methods, both these methods was described a little bit more in details here.

Our goal is pretty straightforward – to display a QR code of the wallet address and I suppose we’re also going to display an input field for entering a transaction ID. To generate a QR code from a wallet address I am going to use Qrious, so don’t forget to enqueue it in advance.

<?php

public function payment_fields() {

	?>
		<p>Please send <?php echo $this->get_order_total() ?> USDT TRC-20 by using the QR code or address: <strong><?php echo $this->address ?></strong></p>
		<canvas id="qr"></canvas>
		<p>Once you've done that, please enter transaction ID below:</p>
		<p class="form-row form-row-wide">
			<input type="text" name="txid" placeholder="Transaction ID" / >
		</p>
		<script>
		(function() {
			const qr = new QRious({
				element: document.getElementById( 'qr' ),
				value: '<?php echo $this->address ?>',
				size: 250
			});
		})();
		</script>
	<?php
}

If you’ve done everything correctly:

cryptocurrency payment method in WooCommerce
In case you’re wondering what WordPress theme I am using here – it is free Storefront.

The last thing I recommend to do in this step – is to check if transaction ID is not empty and if it hasn’t been used for any existing orders yet. You might also want to add some validation to make sure if it is really a hash was entered, but it is optional because we validate it in the next step anyway.

public function validate_fields(){
	
	// if transaction ID is not provided
	if( empty( $_POST[ 'txid' ] ) ) {
		wc_add_notice(  'Transaction ID is required!', 'error' );
		return false;
	}
	
	// if transaction ID is already used in an existing order
	if( get_posts( array( 'post_type' => 'shop_order', 'meta_key' => 'txid', 'meta_value' => $_POST[ 'txid' ], 'post_status' => 'any' ) ) ) {
		wc_add_notice( 'Transaction ID is not correct.', 'error' );
		return false;
	}
	return true;
 
}

This code snippet allows to display an error message like below in case a transaction ID has not been provided by a customer.

Transaction ID is required

Check the transaction in the blockchain

The most interesting part.

Here we are going to connect to the blockchain and check if there is a specific transaction. Some moments I recommend you to keep in mind:

  • I decided to show you an example with TRON network, I like it because of its low transaction fees and because it has a free API.
  • Never forget to check if an order with this specific transaction ID is already exists on your WooCommerce store.
  • It would be great if you’re going to use an HD wallet instead of Transaction IDs.
public function process_payment( $order_id ) {

	// let's conntect to TRON API
	$remote = wp_remote_get(
		add_query_arg(
			array(
				'hash' => $_POST[ 'txid' ],
			),
			'https://apilist.tronscan.org/api/transaction-info'
		)
	);

	// check if API connection was successfully established
	if(
		is_wp_error( $remote )
		|| 'OK' !== wp_remote_retrieve_response_message( $remote )
		|| ( ! $remote = json_decode( wp_remote_retrieve_body( $remote ) ) )
	) {
		wc_add_notice( 'Connection error.', 'error' );
		return false;
	}

	// check wallet address
	if( $this->address !== $remote->toAddress ) {
		wc_add_notice( 'Transaction ID is not correct.', 'error' );
		return false;
	}

	// check transaction status
	if( 'SUCCESS' !== $remote->contractRet ) {
		wc_add_notice( 'Your payment didn\'t go through. Please try again.', 'error' );
		return false;
	}

	// let's do some stuff with the order
	$order = wc_get_order( $order_id );
	$order->payment_complete();
	$order->reduce_order_stock();
	$order->add_meta_data( 'txid', $_POST[ 'txid' ], true );
	$order->save();

	// Empty cart
	WC()->cart->empty_cart();

	// redirect to the thank you page
	return array(
		'result' => 'success',
		'redirect' => $this->get_return_url( $order )
	);

}

That’s pretty much it!

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X