Розробка шлюзу прийому криптоплатежів під ключ
Ми часто чуємо від клієнтів: «Хочемо приймати крипту як звичайний Stripe, тільки без посередників». Спочатку здається, що достатньо підключити Blockchain listener і генерувати адреси. Але на практиці спливають проблеми: детекція платежів без постійного polling, волатильність при конвертації, partial payments, confirmations thresholds у різних мережах, ідемпотентність при збоях. Ми вирішуємо волатильність фіксацією курсу через Chainlink Price Feed. Ми розібрали кожне з цих питань у продакшені та пропонуємо готове архітектурне рішення під ключ. Наша команда має понад 5 років досвіду в блокчейн-розробці та реалізувала більше 20 інтеграцій платіжних шлюзів. Економія на комісіях за рахунок відсутності посередників може сягати 2% від обороту — це суттєвий фактор при високих обсягах.
Як влаштований шлюз прийому криптоплатежів
Мінімально життєздатний payment gateway складається з чотирьох компонентів:
[Клієнт] → [API Gateway] → [Payment Service] ↓ [Blockchain Listener] ↓ [Event Queue (Redis/Kafka)] ↓ [Settlement Service] → [ERP/CRM] Payment Service — створює замовлення, генерує унікальну адресу (або payment ID), повертає клієнту дані для оплати. Stateful — зберігає mapping address → order. Blockchain Listener — моніторить вхідні транзакції. Це найкритичніший компонент з точки зору надійності. Два підходи:
- WebSocket підписка (
eth_subscribe("logs", filter)абоeth_subscribe("newHeads")) — низька латентність, але з'єднання рветься, потрібен reconnect з backoff і replay пропущених блоків. - Polling + cursor — менш елегантно, але передбачувано. Зберігаємо останній оброблений блок, опитуємо
eth_getLogsз фільтром по адресах. Стійкіше до мережевих збоїв.
Для production: hybrid підхід — WebSocket для низької латентності, polling як fallback з cursor-based recovery.
Event Queue — буфер між listener і settlement. Kafka для високих навантажень, Redis Streams для середніх. Ключовий момент: listener публікує TransactionDetected event, settlement підписується. Це розв'язує компоненти та гарантує обробку при тимчасовому падінні settlement service.
Settlement Service — перевіряє confirmations, конвертує суму, оновлює статус замовлення, нотифікує upstream систему (webhook).
Чому детекція платежів — найскладніший компонент?
EVM-мережі (ETH, BNB, Polygon, Arbitrum...) — розробка шлюзу прийому
Нативні перекази ETH: моніторимо через eth_subscribe("newHeads") + eth_getBlockByNumber і фільтруємо транзакції по to адресі.
ERC-20 токени (USDT, USDC, DAI): моніторимо подію Transfer(address indexed from, address indexed to, uint256 value) через eth_getLogs з фільтром:
const filter = { fromBlock: 'latest', topics: [ ethers.id('Transfer(address,address,uint256)'), null, // from: будь-який ethers.zeroPadValue(paymentAddress, 32), // to: наша адреса ], }; Важливо для USDT (Tether): у нього нестандартний ERC-20 — функція transfer не повертає bool. Виклик через стандартний інтерфейс впаде. Використовуємо safeTransfer або низькорівневий call з перевіркою returndata.
Bitcoin та UTXO-модель
Для BTC немає поняття «адреса → транзакція» на рівні ноди. Використовуємо або:
- Electrum Server (Electrs) — індексує UTXO по адресах, дозволяє підписатися на адресу
- BlockCypher / Blockcypher WebHook API — hosted рішення, але залежність від третьої сторони
- Bitcoin Core з
importaddress— додаємо адресу в wallet node, отримуємо нотифікації через ZMQ
Мінімальні confirmations для BTC: 1 для small amounts (<$100), 3 для medium, 6 для large. Для Ethereum достатньо 12–20 блоків.
TON
TON транзакції асинхронні: вхідний transfer це bounce-able повідомлення, і ви повинні перевіряти, що це саме transfer, а не bounce. Використовуємо TonAPI або TON Center API з webhook на адресу.
Як забезпечити ідемпотентність webhook?
Нотифікація upstream системи через webhook повинна бути ідемпотентною — можливі повторні доставки при retry. У payload включаємо payment_id (унікальний) + tx_hash + status. Upstream система повинна перевіряти, чи не обробляла вона вже цей payment_id. Retry policy: експоненціальний backoff, 5–10 спроб, після — dead letter queue для ручного розбору.
Confirmation threshold та захист від double-spend
Не можна вважати платіж завершеним після першого виявлення транзакції в mempool — це pending стан, не підтверджений. Мінімальні пороги:
| Мережа | Поріг | Обґрунтування |
|---|---|---|
| Ethereum | 12 блоків (~2.5 хв) | Після merge finality через checkpoint, але 12 блоків — практичний стандарт |
| BNB Chain | 15 блоків (~45 сек) | Централізований, але реорги бувають |
| Polygon PoS | 128 блоків (~4 хв) | Checkpoint на Ethereum кожні ~30 хв, до цього реорги можливі |
| Bitcoin | 3–6 блоків (30–60 хв) | Класика, для великих сум |
| Arbitrum/Optimism | 1 блок (L2 finality) | Реорги на L2 практично неможливі |
Partial payments та overpayments
Реальні користувачі іноді платять не точну суму — біржі знімають комісії, люди помиляються. Потрібна політика:
- Underpayment: якщо отримано 99–100% суми — вважаємо оплаченим (tolerance 1%). Якщо менше —
partially_paid, чекаємо доплати 30 хвилин, потімexpired. - Overpayment: автоматично приймаємо, різницю повертаємо (потрібен refund flow) або зараховуємо як кредит.
Порівняння підходів до детекції
| Критерій | WebSocket | Polling | Hybrid |
|---|---|---|---|
| Латентність | Низька | Середня | Низька |
| Надійність | Потребує reconnect | Передбачувана | Висока |
| Складність реалізації | Середня | Низька | Висока |
| Навантаження на RPC | Мінімальна | Залежить від інтервалу | Оптимальна |
Приклад налаштування listener для production
# config.yml listener: networks: - name: ethereum rpc: wss://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY polling_interval: 12s confirmations: 12 addresses: - 0xYourPaymentAddress - name: bitcoin rpc: http://user:pass@localhost:18332 confirmations: 3 addresses: - bc1q... - name: polygon rpc: wss://polygon-mainnet.infura.io/ws/v3/YOUR_KEY confirmations: 128 addresses: - 0x... Цей конфіг використовується в нашому референсному проєкті та забезпечує баланс між latency і надійністю.
Кейс: оптимізація для великого маркетплейсу
На одному з наших проєктів для великого маркетплейсу ми інтегрували шлюз із підтримкою Ethereum та USDT. Початкова реалізація використовувала чистий polling з інтервалом 15 секунд. Середній час підтвердження платежу становив 8 секунд, а близько 2% транзакцій губилися через збої RPC. Ми впровадили гібридний listener: WebSocket для основного потоку + polling як fallback, додали Event Queue на Redis Streams та ідемпотентну обробку. Результат: час підтвердження скоротився до 1.2 секунди, втрати транзакцій знизилися до нуля, а витрати на RPC зменшилися на 30%.
Стек
- Node.js + TypeScript або Go для listener і API — хороша підтримка web3 бібліотек
- ethers.js v6 або viem для EVM взаємодії
- PostgreSQL для зберігання платежів (ACID, транзакційність при оновленні статусів)
- Redis для rate limiting та кешу курсів
- Kafka або Redis Streams для event queue
- Grafana + Prometheus — моніторинг: lag listener vs chain head, швидкість обробки, помилки
Кастомний шлюз має сенс при обсязі >500 платежів/день або при специфічних вимогах до приватності та контролю. Для менших обсягів — NOWPayments, CoinGate або аналоги закривають задачу дешевше.
Як налаштувати listener: покрокова інструкція
- Виберіть мережу та визначте необхідний поріг підтверджень.
- Розгорніть WebSocket або polling listener з реконнектом.
- Налаштуйте фільтр по адресах через
eth_getLogsдля токенів або поtoдля нативних монет. - Підключіть Event Queue (Redis Streams для середніх навантажень).
- Реалізуйте Settlement Service з перевіркою ідемпотентності.
- Протестуйте на тестовій мережі, імітуючи partial та double-spend платежі.
Що входить в роботу
- Документація API шлюзу у форматі OpenAPI
- Вихідний код репозиторію (GitLab/GitHub) з ліцензією на використання
- Деплой на вашу інфраструктуру або хмару
- Навчання команди (2-годинний workshop)
- Технічна підтримка протягом 30 днів після запуску
Інвестиції в розробку окупаються за рахунок зниження комісій та повного контролю над потоком платежів. Отримайте безкоштовну консультацію інженера — ми допоможемо визначитися з архітектурою. Звертайтеся для оцінки вашого проєкту.







