Розробка криптоплатіжного шлюзу
Головна помилка при проектуванні криптоплатіжного шлюзу — спроба натягнути модель традиційних платіжних систем на блокчейн. У 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 за діапазоном блоків.
Спільна адреса депозиту з memo/тегом
Одна адреса, клієнт вказує унікальний payment ID у data полі транзакції. Простіше в інфраструктурі, але створює UX-проблему: користувач має не забути вказати memo. У 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 та збір коштів
Після підтвердження платежу кошти на адресі депозиту потрібно зібрати в 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 транзакціям — mempool можна замінити через RBF (Replace-by-Fee) у Bitcoin.
Rate limiting на адреси депозиту: одна адреса має приймати один платіж. Після отримання першої транзакції — помічати адресу як "використовується", нові транзакції на неї обробляти окремо з алертом.
Webhook підписи: все вихідні сповіщення про платіж підписуємо HMAC-SHA256 з секретом. Отримувач верифікує підпис — захист від підробки webhook.
Production стек
- Backend: Node.js/TypeScript або Go для воркерів (висока конкурентність)
- Queue: Redis + BullMQ або RabbitMQ для обробки подій
- DB: PostgreSQL для платежів, окрема таблиця аудиту (append-only)
- Моніторинг нод: Alchemy/QuickNode з failover на резервний провайдер
- Алерти: Grafana + PagerDuty на зависання воркерів, аномальні суми, помилки підтвердження
Час розробки MVP з підтримкою 3–4 мереж і базового дашборду — 1–2 тижні. Це мінімальний термін при наявності готового блокчейн-інфраструктурного досвіду.







