Настройка приёма платежей в нескольких криптовалютах
Задача звучит просто: принимать 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 endpoint'ов. Мониторинг 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 mode.
Подтверждения 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 дня): какие валюты нужны, объёмы, geography (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 недели в зависимости от количества сетей.







