Разработка криптоплатёжного шлюза
Главная ошибка при проектировании криптоплатёжного шлюза — попытка натянуть модель традиционных платёжных систем на блокчейн. В fiat-платежах есть авторизация, захват, возврат, чарджбэк. В блокчейне — только подтверждённые транзакции и невозможность принудительного reversal. Всё остальное нужно строить вокруг этой фундаментальной особенности.
Архитектурные решения
Модель адресов для приёма платежей
Два подхода с принципиально разными trade-off:
Один адрес на заказ (HD wallet деривация)
Для каждого нового платежа деривируем уникальный адрес из master xpub ключа по пути m/44'/60'/0'/0/{orderId}. Клиент видит адрес, уникальный для его заказа — нет путаницы с суммами, нет конфликтов между одновременными платежами. Приватный ключ для сбора средств деривируется offline, только в момент вывода.
import { HDNodeWallet, Mnemonic } from "ethers";
function derivePaymentAddress(xpub: string, index: number): string {
const node = HDNodeWallet.fromExtendedKey(xpub);
return node.deriveChild(index).address;
}
Проблема: нужно мониторить тысячи адресов. Решение — webhook-подписки через Alchemy/Moralis/QuickNode на Activity для конкретных адресов, или собственная нода с eth_getLogs по диапазону блоков.
Shared deposit address с мемо/тегом
Один адрес, клиент указывает уникальный payment ID в data поля транзакции. Проще в инфраструктуре, но создаёт UX-проблему: пользователь должен не забыть указать мемо. В B2B это работает, в B2C — часто нет.
Мультивалютность
Минимальный production набор для 2024: ETH, USDT (ERC-20), USDC (ERC-20), BNB, USDT (BEP-20), BTC, TRC-20 USDT. Каждая сеть требует отдельного воркера для мониторинга.
Для ERC-20 токенов мониторинг через событие Transfer(address indexed from, address indexed to, uint256 value):
const transferTopic = ethers.id("Transfer(address,address,uint256)");
const logs = await provider.getLogs({
address: USDT_CONTRACT,
topics: [transferTopic, null, ethers.zeroPadValue(depositAddress, 32)],
fromBlock: lastCheckedBlock,
toBlock: "latest",
});
Воркер подтверждений
Критический компонент — сервис, отслеживающий статус транзакций. Логика:
PENDING → CONFIRMING (1 подтверждение) → CONFIRMED (N подтверждений) → CREDITED
Количество подтверждений зависит от суммы и сети:
| Сеть | Малые суммы (<$100) | Средние ($100–$10k) | Крупные (>$10k) |
|---|---|---|---|
| Ethereum | 2 блока | 6 блоков | 12 блоков |
| BSC | 15 блоков | 30 блоков | 60 блоков |
| Bitcoin | 1 подтверждение | 3 подтверждения | 6 подтверждений |
| Tron | 20 блоков | 40 блоков | 60 блоков |
Реорги — реальная проблема на BSC и EVM-сетях с быстрыми блоками. Воркер должен уметь обнаруживать реорг (blockhash транзакции изменился) и откатывать статус платежа.
Hot wallet и сбор средств
После подтверждения платежа деньги на deposit адресе нужно собрать в hot wallet. Для EVM-сетей это отдельная транзакция с газом, которую нужно профинансировать:
async function sweepDeposit(depositIndex: number, amount: BigInt) {
const depositKey = derivePrivateKey(masterKey, depositIndex);
const depositWallet = new ethers.Wallet(depositKey, provider);
// Сначала отправить ETH для газа
await hotWallet.sendTransaction({
to: depositWallet.address,
value: GAS_BUDGET, // ~0.001 ETH
});
// Затем собрать токены
const token = new ethers.Contract(TOKEN_ADDRESS, ERC20_ABI, depositWallet);
await token.transfer(hotWalletAddress, amount);
}
Для ERC-20 есть паттерн через permit (EIP-2612) — если токен его поддерживает, можно собирать без предварительной отправки ETH на газ через transferFrom с подписью.
Безопасность
Segregation of keys: master xpub (для деривации адресов) хранится в приложении. Приватные ключи деривируются только для sweep-операций, и только в изолированном signing сервисе. Hot wallet — отдельный HSM или KMS (AWS KMS, GCP Cloud HSM).
Double-spend protection: не кредитовать до достижения порога подтверждений. Не доверять pending транзакциям — мемпул можно заменить через RBF (Replace-by-Fee) в Bitcoin.
Rate limiting на deposit адреса: один адрес должен принимать один платёж. После получения первой транзакции — помечать адрес как "используется", новые транзакции на него обрабатывать отдельно с алертом.
Webhook подписи: все исходящие уведомления о платеже подписываем HMAC-SHA256 с секретом. Получатель верифицирует подпись — защита от подделки webhook.
Стек для production
- Backend: Node.js/TypeScript или Go для воркеров (высокая конкурентность)
- Queue: Redis + BullMQ или RabbitMQ для обработки событий
- DB: PostgreSQL для payments, отдельная таблица аудита (append-only)
- Мониторинг нод: Alchemy/QuickNode с failover на резервный провайдер
- Алерты: Grafana + PagerDuty на зависание воркеров, аномальные суммы, ошибки подтверждения
Срок разработки MVP с поддержкой 3–4 сетей и базовым дашбордом — 1–2 недели. Это минимальный срок при наличии готового блокчейн-инфраструктурного опыта.







