Multi-Cryptocurrency Payment Acceptance Setup

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Multi-Cryptocurrency Payment Acceptance Setup
Medium
~1-2 weeks
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1215
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1043
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Setting Up Multi-Cryptocurrency Payment Acceptance

The task sounds simple: accept BTC, ETH, USDT, USDC, SOL and several more tokens. In practice this means supporting at least three fundamentally different protocols (UTXO, EVM account-based, Solana), incompatible address formats, different confirmation logics, and you need to consolidate all this into a single payment status for business logic. Plus exchange rates change while the user is looking at the invoice.

Architectural Options

Option 1: Ready-made provider (NOWPayments, CoinPayments, BitPay). Quick, but vendor lock-in, commission 0.5-1% on each transaction, limited control over UX and data. For MVP or small volumes — reasonable choice.

Option 2: Custom integration — your own node or RPC provider for each network, HD wallet for address derivation, own monitoring. Full control, zero provider commissions, but operational burden and longer development.

Option 3: Hybrid — EVM networks through one provider (Alchemy/Infura supporting multiple networks), BTC through separate integration or Bitcore, Solana through Helius. Reasonable balance.

For volumes > $50k/month custom integration pays off in 3-6 months just on saved provider fees.

HD Wallet Derivation

BIP-44 defines hierarchy: m / purpose' / coin_type' / account' / change / address_index. For each new payment a new address is generated via incrementing address_index. One master seed — addresses for all networks.

from hdwallet import HDWallet

def derive_address(master_seed: str, coin_type: int, index: int) -> str:
    wallet = HDWallet()
    wallet.from_mnemonic(master_seed)
    # BTC: coin_type=0, ETH: coin_type=60, SOL: coin_type=501
    wallet.from_path(f"m/44'/{coin_type}'/0'/0/{index}")
    return wallet.p2pkh_address()  # for BTC
    # wallet.address() for ETH

Important: address_index must monotonically increase and be stored in DB. Never reuse addresses — it violates privacy and complicates reconciliation.

Network Integration

EVM Networks (Ethereum, Polygon, BSC, Arbitrum, Base)

One codebase — multiple RPC endpoints. Monitor Transfer events from ERC-20 + native ETH/MATIC transfers.

import { createPublicClient, http, parseAbi } from 'viem';
import { mainnet, polygon, arbitrum } from 'viem/chains';

const chains = [
  { chain: mainnet, rpc: process.env.ETH_RPC, tokens: ETH_TOKENS },
  { chain: polygon, rpc: process.env.POLY_RPC, tokens: POLY_TOKENS },
  { chain: arbitrum, rpc: process.env.ARB_RPC, tokens: ARB_TOKENS },
];

// Single handler for all EVM networks
async function watchEVMPayment(client, tokenAddress, recipientAddress, orderId) {
    return client.watchContractEvent({
        address: tokenAddress,
        abi: ERC20_ABI,
        eventName: 'Transfer',
        args: { to: recipientAddress },
        onLogs: (logs) => handlePayment(logs, orderId),
    });
}

Bitcoin

Bitcoin UTXO model — no "balance", there's a set of unspent outputs. An address is considered paid when it receives UTXO with required amount.

Integration options:

  • Electrum Protocol (ElectrumX/Fulcrum) — blockchain.scripthash.subscribe to subscribe to address changes. Much easier than full node.
  • BlockCypher/Mempool.space API — without own infrastructure, but depends on external service.
  • Bitcoin Core + ZMQ — full node with ZeroMQ notifications about new transactions.

For production I recommend Fulcrum (fast SPV-compatible node) + Bitcoin Core in pruned mode.

Bitcoin confirmations: 1 confirmation (~10 minutes) — for small amounts, 3+ — standard, 6 — for large payments.

TRON (USDT TRC-20)

TRON is separate case because USDT TRC-20 occupies huge share of crypto payments in certain regions. API via TronGrid (HTTP) or own node. Addresses in Base58Check format (start with T).

import tronpy

client = tronpy.Tron(network='mainnet')

def check_trc20_payment(address: str, contract: str, min_amount: int) -> list:
    txns = client.get_token_trc20_transfers(
        contract_address=contract,
        to_address=address,
        min_timestamp=int((time.time() - 3600) * 1000)
    )
    return [tx for tx in txns if tx['value'] >= min_amount]

Solana

Solana uses SPL Token standard. Each token has its Associated Token Account (ATA) for each wallet. Address for receiving USDC — not the wallet itself, but its ATA for USDC.

import { getAssociatedTokenAddress } from '@solana/spl-token';

const usdcMint = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
const paymentATA = await getAssociatedTokenAddress(usdcMint, paymentKeypair.publicKey);
// paymentATA.toBase58() — this is the address for receiving USDC on Solana

Solana finality: when using commitment level finalized — ~32 slots (~13 seconds).

Unified Monitoring System

Regardless of network, payment goes through one state:

pending_payment → mempool_detected → confirmed (N conf) → settled

PostgreSQL schema:

CREATE TABLE payment_orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    order_id VARCHAR(100) UNIQUE NOT NULL,
    currency VARCHAR(20) NOT NULL,     -- 'BTC', 'ETH', 'USDT_ERC20', 'USDT_TRC20'
    network VARCHAR(20) NOT NULL,      -- 'bitcoin', 'ethereum', 'tron'
    payment_address VARCHAR(200) NOT NULL,
    expected_amount NUMERIC(30, 8) NOT NULL,
    received_amount NUMERIC(30, 8) DEFAULT 0,
    tx_hash VARCHAR(200),
    confirmations INTEGER DEFAULT 0,
    required_confirmations INTEGER NOT NULL,
    status VARCHAR(30) DEFAULT 'pending',
    expires_at TIMESTAMPTZ NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    INDEX idx_payment_address (payment_address),
    INDEX idx_status_expires (status, expires_at)
);

Rates and Tolerance

User sees "pay 0.001523 BTC" — rate is locked for 15-30 minutes. In this time rate can change by 1-2%. You need tolerance:

TOLERANCE_PERCENT = {
    'BTC': 1.0,    # ±1%
    'ETH': 1.5,
    'USDT': 0.1,   # stablecoin — small tolerance
    'USDC': 0.1,
}

def is_payment_sufficient(currency: str, expected: Decimal, received: Decimal) -> bool:
    tolerance = TOLERANCE_PERCENT.get(currency, 1.0) / 100
    return received >= expected * (1 - tolerance)

Rates with minimal delay: CoinGecko API (free, 60 sec cache) or Binance WebSocket (real-time, for high-frequency).

Security

  • Private keys never on web server. HD wallet seed in HSM or minimum in encrypted storage (AWS KMS, HashiCorp Vault).
  • Sweep transactions — automatic transfer of received funds to cold wallet by schedule or amount threshold.
  • Double-spend protection — for BTC and ETH don't confirm payment on first unconfirmed. Set required_confirmations appropriately to amount.
  • Address validation — before saving address passes checksum validation (EIP-55 for ETH, Base58Check for BTC). Address error = lost funds.

Implementation Process

Analytics (1-2 days): which currencies are needed, volumes, geography (TRON popular in CIS/Asia), confirmation requirements.

Infrastructure (2-4 days): RPC providers or own nodes, HD wallet integration, DB schema.

Monitoring (3-4 days): workers for each network, confirmation logic, webhook notifications.

Testing (1-2 days): testnet for EVM and Solana, Bitcoin testnet, edge cases (underpayment, overpayment, expired order, reorg).

Total 1-2 weeks depending on number of networks.