Розробка платформи виплат у криптовалюті

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка платформи виплат у криптовалюті
Складний
від 2 тижнів до 3 місяців
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1311
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1222
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    922
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1151
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    614
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    887

Розробка платформи оплаті в криптовалюті

Різниця між "додати кнопку оплаті криптовалютою" та "побудувати платіжну платформу" — принципіальна. У першому випадку інтегрується третій сервіс з його гарантіями та обмеженнями. У другому — будується власна інфраструктура: генерація адрес, мониторинг транзакцій, управління ключами, settlement, reconciliation. Ця сторінка — про другий варіант: коли обсяг, нормативні вимоги або бізнес-модель не дозволяють йти через посередника.

Чому будуть власну платформу

Типові причини:

  • Обсяг — при >$10M/місяць комісія 0.5–1% процесингу стає дорожче власної інфраструктури
  • Контроль над даними — фінансові дані не повинні йти до третіх осіб
  • Кастомна логіка — умовні платежі, escrow, рекурентні платежі, split платежів
  • White-label — платформа для інших бізнесів, власний процесинг обов'язковий
  • Нормативні вимоги — деякі юрисдикції вимагають ліцензії, несумісні з використанням іноземного процесора

Архітектура: ключові компоненти

Клієнт → Payment API → Invoice Service → Address Generator
                                       → Blockchain Monitor
                                       → Settlement Engine
                                       → Merchant Webhook

HD гаманці та генерація адрес

Основа платформи — ієрархічні детермінавні гаманці (BIP32/BIP44). Один master seed генерує необмежену кількість дочірніх адрес — по одній унікальній адресі на кожен інвойс:

m / purpose' / coin_type' / account' / change / index
m / 44'      / 60'        / 0'       / 0      / invoice_id
from hdwallet import HDWallet
from hdwallet.symbols import ETH

def generate_payment_address(merchant_id: int, invoice_id: int) -> str:
    """
    Детермінована генерація адреси: один інвойс = одна адреса
    merchant_id: account index (BIP44 рівень 3)
    invoice_id: address index (BIP44 рівень 5)
    """
    wallet = HDWallet(symbol=ETH)
    wallet.from_xprivate_key(MASTER_XPRIV)
    wallet.from_path(f"m/44'/60'/{merchant_id}'/0/{invoice_id}")
    return wallet.p2pkh_address()

Критично важливо: приватний ключ від master seed повинен зберігатися в HSM (Hardware Security Module) або мінімум у AWS KMS / HashiCorp Vault. Ніяких plaintext ключів у файлах конфігу або БД.

Для публічної генерації адрес (без доступу до приватного ключа) — xpub достатньо:

# Тільки xpub для watch-only адрес
wallet.from_xpublic_key(MERCHANT_XPUB)
wallet.from_path(f"m/0/{invoice_id}")  # відносне від xpub
address = wallet.p2pkh_address()

Мониторинг транзакцій

Два підходи до відслідковування вхідних платежів:

Polling через RPC — простий, працює везде:

import asyncio
from web3 import Web3

async def monitor_invoice(
    address: str,
    expected_amount: int,  # у wei
    invoice_id: str,
    timeout_seconds: int = 3600
):
    w3 = Web3(Web3.HTTPProvider(ETH_RPC_URL))
    start_block = w3.eth.block_number
    deadline = time.time() + timeout_seconds

    while time.time() < deadline:
        # Перевіряємо баланс адреси
        balance = w3.eth.get_balance(address, "latest")
        if balance >= expected_amount:
            # Чекаємо confirmations
            await wait_for_confirmations(address, expected_amount, confirmations=6)
            await mark_invoice_paid(invoice_id, balance)
            return

        await asyncio.sleep(15)  # приблизно на блок

    await mark_invoice_expired(invoice_id)

WebSocket subscriptions — для мінімальної затримки:

from web3 import AsyncWeb3
from web3.providers import WebsocketProviderV2

async def subscribe_to_address(address: str, callback):
    async with AsyncWeb3(WebsocketProviderV2("wss://eth-mainnet.g.alchemy.com/v2/KEY")) as w3:
        subscription_id = await w3.eth.subscribe(
            "logs",
            {"address": address}  # отримуємо усі logs для адреси
        )
        async for response in w3.socket.process_subscriptions():
            if response["subscription"] == subscription_id:
                await callback(response["result"])

Для ERC-20 платежів мониторинг складніший: потрібно слухати Transfer события токен-контракту з фільтром по to адресі, не ETH баланс.

Робота з кількома сітями та токенами

Production платформа підтримує мінімум: ETH/USDT/USDC на Ethereum, USDT/USDC на Polygon та Arbitrum (дешевше газу), BTC нативно. Архітектура мультисіті:

@dataclass
class NetworkConfig:
    chain_id: int
    rpc_url: str
    confirmations_required: int  # 1 для L2, 6 для ETH mainnet
    supported_tokens: dict[str, str]  # symbol -> contract address

NETWORKS = {
    "ethereum": NetworkConfig(
        chain_id=1,
        rpc_url=ETH_RPC,
        confirmations_required=6,
        supported_tokens={"USDT": "0xdAC17...", "USDC": "0xA0b86..."}
    ),
    "arbitrum": NetworkConfig(
        chain_id=42161,
        rpc_url=ARB_RPC,
        confirmations_required=1,
        supported_tokens={"USDT": "0xFd086...", "USDC": "0xFF970..."}
    ),
    # ...
}

Settlement: вивід коштів

Зібрані платежі потрібно агрегувати та вивести мерчанту. Два паттерни:

Sweeping — періодичний перевід зі усіх адрес на hot wallet:

async def sweep_address(from_address: str, to_address: str, token: str):
    private_key = await kms.get_key(derive_key_path(from_address))

    if token == "ETH":
        balance = w3.eth.get_balance(from_address)
        gas_estimate = 21000
        gas_price = w3.eth.gas_price
        amount = balance - (gas_estimate * gas_price)
        if amount <= 0:
            return

        tx = {
            "to": to_address,
            "value": amount,
            "gas": gas_estimate,
            "gasPrice": gas_price,
            "nonce": w3.eth.get_transaction_count(from_address),
            "chainId": 1
        }
    else:
        # ERC-20 sweep: спочатку ETH на газ, потім transfer токена
        await fund_gas(from_address)
        tx = build_erc20_transfer(token, from_address, to_address)

    signed = w3.eth.account.sign_transaction(tx, private_key)
    tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
    return tx_hash.hex()

Batch payments — для виплат мерчантам, використовуйте Multicall або спеціалізовані batch transfer контракти (наприклад, Disperse.app паттерн) — один газ на N переводів.

Робота з ERC-20: проблема газу

Слабке місце ERC-20 платежів: адреса отримання пуста (немає ETH для газу). Перед sweep потрібно відправити невелику кількість ETH для оплаті газу трансфера токена. Це створює dust проблему: ETH залишається після sweep.

Рішення — EIP-2612 Permit: токени з permit (USDC, DAI) дозволяють підписувати дозвіл на transfer без on-chain approve транзакції. Можна sweep токени в одній транзакції з підписом, без попереднього funding:

// USDC permit + transferFrom в одному виклику
function sweepWithPermit(
    address token,
    address from,
    address to,
    uint256 amount,
    uint256 deadline,
    uint8 v, bytes32 r, bytes32 s
) external {
    IERC20Permit(token).permit(from, address(this), amount, deadline, v, r, s);
    IERC20(token).transferFrom(from, to, amount);
}

Обмінні курси та ціноутворення

Інвойс створюється у фіатній валюті (USD/EUR), сума у крипті обчислюється динамічно. Для стейблкоїнів — курс 1:1 з невеликим буфером. Для волатильних активів (ETH, BTC):

def calculate_crypto_amount(fiat_amount: Decimal, currency: str, crypto: str) -> dict:
    # Агрегуємо ціну з кількох джерел
    prices = await asyncio.gather(
        fetch_binance_price(f"{crypto}USDT"),
        fetch_coinbase_price(f"{crypto}-USD"),
        fetch_chainlink_price(CHAINLINK_FEEDS[crypto])
    )
    median_price = statistics.median(prices)

    crypto_amount = fiat_amount / median_price
    # Додаємо буфер на випадок руху ціни (1-2%)
    crypto_amount_with_buffer = crypto_amount * Decimal("1.015")

    return {
        "amount": crypto_amount_with_buffer,
        "rate": median_price,
        "expires_at": datetime.now() + timedelta(minutes=15),
        "rate_locked": True
    }

Безпека та compliance

KYT (Know Your Transaction) — перевірка адрес на санкційні списки та зв'язки з mixers/dark markets. Провайдери: Chainalysis, Elliptic, TRM Labs. API інтегрується у воронку платежу:

async def check_address_risk(address: str) -> RiskScore:
    response = await chainalysis_client.post("/v2/address/identifications", json={"address": address})
    risk = response.json()
    if risk["risk"] in ["HIGH", "SEVERE"]:
        await flag_for_review(address)
    return RiskScore(level=risk["risk"], categories=risk["categories"])

Transaction limits — автоматичні ліміти за обсягом для AML: дневний ліміт на гаманець, поріг для ручної перевірки, обов'язкова верифікація для крупних транзакцій.

Reconciliation — щоденна сверка: сума виплачених мерчантам коштів + комісії платформи + залишки на sweep адресах повинні співпадати з сумою усіх підтверджених вхідних транзакцій. Будь-яке розбіжність — алерт.

Інфраструктура та надійність

Нода vs провайдер: для платіжної платформи з вимогами до надійності — власна нода або Alchemy/Infura з fallback на іншого провайдера. Single point of failure неприпустимий.

from web3 import Web3
from web3.middleware import ExceptionRetryMiddleware

providers = [
    Web3.HTTPProvider(ALCHEMY_URL),
    Web3.HTTPProvider(INFURA_URL),
    Web3.HTTPProvider(QUICKNODE_URL),
]

def get_w3_with_fallback():
    for provider in providers:
        w3 = Web3(provider)
        w3.middleware_onion.add(ExceptionRetryMiddleware, retries=3)
        if w3.is_connected():
            return w3
    raise RuntimeError("All providers unavailable")

Idempotency: всі операції повинні бути ідемпотентні — повторна обробка webhook або retry payment check не повинні створювати дублюючі виплати. Унікальний idempotency_key на кожну операцію.

Часові рамки

Фаза Зміст Тривалість
Архітектура та HD wallet Дизайн системи, генерація адрес, KMS інтеграція 1–2 тижні
Мониторинг транзакцій Polling/WebSocket мониторинг, confirmations 1–2 тижні
Settlement engine Sweep логіка, ERC-20 permit, batch payments 2–3 тижні
Merchant API REST API, webhooks, dashboard 2–3 тижні
Compliance KYT інтеграція, ліміти, reconciliation 1–2 тижні
Тестування Testnet, stress testing, security review 2–3 тижні

Мінімально жизнеспособна платформа з ETH/USDC на одній сіті: 6–8 тижнів. Повна мультисітева платформа з compliance: 3–5 місяців.