Настройка приймання платежів в Ethereum
Прийняття ETH звучить просто: користувач відправляє транзакцію, гроші прийшли. На практиці питання "як я дізнаюся, що платіж прийшов і від кого" вирішується кількома способами, і більшість швидких реалізацій мають race conditions або проблеми з безпекою.
Архітектура: не робіть один адрес для всіх
Найнадійніша схема—унікальна адреса на кожне замовлення/користувача. Це усуває проблему атрибуції: не потрібно зіставляти суми з замовленнями, немає колізій коли два користувачі платять одну суму.
Реалізація через HD wallet (BIP-44): один master private key, адреси деривуються детерміністично за індексом. Користувач отримує адресу m/44'/60'/0'/0/{order_id}, кошти з неї переводяться на гарячий гаманець після підтвердження.
import { HDNodeWallet } from 'ethers'
const masterWallet = HDNodeWallet.fromPhrase(process.env.MNEMONIC)
function getDepositAddress(orderId: number): string {
return masterWallet.deriveChild(orderId).address
}
Master мнемоніка—в HSM або як мінімум в зашифрованому вигляді в змінних оточення, ніколи в коді.
Моніторинг вхідних транзакцій
Поганий способ—поллити eth_getBalance кожні N секунд. Повільно, дорого за RPC-запитами, пропускає транзакції при перезапуску.
Правильний способ—підписка на события через WebSocket RPC:
provider.on({ address: depositAddress }, (log) => {
// Обробка вхідного перевода
})
Або через eth_subscribe newPendingTransactions—отримуємо сповіщення до підтвердження, але статус pending не можна вважати остаточним.
Для надійного production рішення—Alchemy Notify або QuickNode Streams: вебхуки на активність адрес, працюють навіть якщо ваш backend перезапустився.
Підтвердження та finality
На Ethereum після Merge finality настає через ~2 епохи (~12.8 хвилин). Для платежів:
| Сума | Рекомендовані підтвердження |
|---|---|
| < $100 | 1–3 блока (~15–45 сек) |
| $100–$10k | 6–12 блоків (~1.5–2.5 хв) |
| > $10k | 32–64 блока (до finality) |
Ніколи не зараховуйте кошти за pending транзакцію—транзакція може бути замінена через EIP-1559 replacement або витиснута з mempool.
Робота з ERC-20 токенами
Якщо потрібно приймати USDC/USDT поверх ETH—логіка ускладнюється: подія Transfer замість нативної транзакції. Необхідно слухати логи за ABI токена:
const filter = {
address: USDC_CONTRACT,
topics: [
ethers.id('Transfer(address,address,uint256)'),
null,
ethers.zeroPadValue(depositAddress, 32)
]
}
provider.on(filter, handleUsdcDeposit)
Окремо зазначимо: USDT на Ethereum має нестандартний approve (повертає void, а не bool)—це ламає стандартний ERC-20 інтерфейс. Використовуйте SafeERC20 від OpenZeppelin або обробляйте обидва випадки.
Що налаштовується
За 2–3 дні реалізуємо: генерацію унікальних адрес депозиту через HD wallet, вебхук-моніторинг через Alchemy/QuickNode або self-hosted listener, логіку підтвердження з налаштовуваним порогом, автоматичну пересилку коштів на основний гаманець (sweeping), базовий API для інтеграції з вашим бекендом. Інфраструктура: будь-який EVM-сумісний бекенд (Node.js, Python, Go).







