Настройка приймання платежів у кількох криптовалютах
Завдання звучить просто: приймати BTC, ETH, USDT, USDC, SOL та ще кілька токенів. На практиці це означає підтримку мінімум трьох принципово різних протоколів (UTXO, EVM account-based, Solana), несумісних форматів адрес, різної логіки підтверджень, і все це потрібно зводити в єдиний платіжний статус для бізнес-логіки. Плюс обмінний курс змінюється поки користувач дивиться на рахунок.
Архітектурні варіанти
Варіант 1: Ready-made provider (NOWPayments, CoinPayments, BitPay). Швидко, але vendor lock-in, комісія 0.5-1% з кожної транзакції, обмежений контроль над UX та даними. Для MVP або малих обсягів — розумний вибір.
Варіант 2: Кастомна інтеграція — своя нода або RPC провайдер для кожної мережі, HD гаманець для дериації адрес, власний мониторинг. Повний контроль, нульові комісії провайдера, але операційне навантаження та більш тривала розробка.
Варіант 3: Гібридний — EVM мережі через один провайдер (Alchemy/Infura з підтримкою кількох мереж), BTC через окремену інтеграцію або Bitcore, Solana через Helius. Розумний баланс.
Для обсягів > $50k/місяць кастомна інтеграція окупається за 3-6 місяців тільки на saved provider fees.
HD Wallet дериація
BIP-44 визначає ієрархію: m / purpose' / coin_type' / account' / change / address_index. Для кожного нового платежу генерується нова адреса через інкремент address_index. Один master seed — адреси для всіх мереж.
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() # для BTC
# wallet.address() для ETH
Важливо: address_index повинен монотонно зростати та зберігатися в БД. Ніколи не переважайте адреси — це порушує privacy та ускладнює reconciliation.
Інтеграція по мережах
EVM мережі (Ethereum, Polygon, BSC, Arbitrum, Base)
Одна кодова база — кілька RPC endpoints. Мониторьте Transfer события ERC-20 + нативні ETH/MATIC переводи.
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 },
];
// Єдиний обробник для всіх EVM мереж
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 модель — нема «балансу», є набір unspent outputs. Адреса вважається оплаченою коли на неї приходять UTXO з потрібною сумою.
Варіанти інтеграції:
-
Electrum Protocol (ElectrumX/Fulcrum) —
blockchain.scripthash.subscribeдля підписки на зміни адреси. Набагато легше чим повна нода. - BlockCypher/Mempool.space API — без власної інфраструктури, але залежність від зовнішнього сервісу.
- Bitcoin Core + ZMQ — повна нода з ZeroMQ нотифікаціями про нові транзакції.
Для production рекомендую Fulcrum (швидка SPV-сумісна нода) + Bitcoin Core в pruned режимі.
Підтвердження Bitcoin: 1 підтвердження (~10 хвилин) — для невеликих сум, 3+ — стандарт, 6 — для крупних платежів.
TRON (USDT TRC-20)
TRON — окремий випадок тому що USDT TRC-20 займає величезну частку крипто-платежів у певних регіонах. API через TronGrid (HTTP) або власна нода. Адреси у Base58Check форматі (починаються з 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 використовує SPL Token стандарт. Кожен токен має свій Associated Token Account (ATA) для кожного гамана. Адреса для приймання USDC — не сам гаманець, а його ATA для USDC.
import { getAssociatedTokenAddress } from '@solana/spl-token';
const usdcMint = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
const paymentATA = await getAssociatedTokenAddress(usdcMint, paymentKeypair.publicKey);
// paymentATA.toBase58() — це адреса для приймання USDC на Solana
Solana фіналізація: при використанні commitment level finalized — ~32 слоти (~13 секунд).
Єдина система мониторингу
Незалежно від мережі, платіж проходить через один стан:
pending_payment → mempool_detected → confirmed (N conf) → settled
PostgreSQL схема:
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)
);
Курси та tolerance
Користувач бачить «оплатьте 0.001523 BTC» — курс зафіксований на 15-30 хвилин. За цей час курс може змінитися на 1-2%. Потрібен tolerance:
TOLERANCE_PERCENT = {
'BTC': 1.0, # ±1%
'ETH': 1.5,
'USDT': 0.1, # стейблкоін — малий 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)
Курси з мінімальною задержкою: CoinGecko API (безплатно, кеш 60 сек) або Binance WebSocket (реалтайм, для high-frequency).
Безпека
- Приватні ключі ніколи не на веб сервері. HD гаманець seed у HSM або мінімум у зашифрованому сховищі (AWS KMS, HashiCorp Vault).
- Sweep транзакції — автоматичний переміст поступивших засобів на холодний гаманець за розписанням або по порогу суми.
- Double-spend protection — для BTC та ETH не підтверджувати платіж по першому unconfirmed. Настроїти required_confirmations адекватно сумі.
- Адресна валідація — перед збереженням адреса проходить checksum валідацію (EIP-55 для ETH, Base58Check для BTC). Помилка в адресі = втрата засобів.
Процес впровадження
Аналітика (1-2 дні): які валюти потрібні, обсяги, географія (TRON популярен у СНГ/Азії), вимоги до підтверджень.
Інфраструктура (2-4 дні): RPC провайдери або власні ноди, HD wallet інтеграція, схема БД.
Мониторинг (3-4 дні): worker-и для кожної мережі, логіка підтверджень, webhook нотифікації.
Тестування (1-2 дні): testnet для EVM та Solana, Bitcoin testnet, edge cases (underpayment, overpayment, expired order, reorg).
Усього 1-2 тижні залежно від кількості мереж.







