Настройка приймання платежів в Monero
Monero (XMR) — не просто ще один крипто-платіжний метод. Його протокол конфіденційності вбудований на рівні протоколу і не опціональний: кожна транзакція використовує stealth addresses, Ring Signatures та RingCT. Це робить прийняття XMR принципово іншим завданням порівняно з Bitcoin або USDT — стандартні підходи "дивись на адресу в блокчейні" тут не працюють.
Криптографічна основа: чому Monero складніше
Кожна Monero-адреса складається з двох пар ключів: (public spend key, private spend key) та (public view key, private view key). Публічна адреса кодує обидві публічні частини.
Stealth addresses: відправник ніколи не переводить безпосередньо на вашу публічну адресу. Він генерує одноразову stealth address з використанням вашого public view key і випадкового scalar. Тільки власник private view key може обчислити, що це вхідна транзакція саме для нього.
Ring Signatures: кожен input у транзакції підписаний кільцем, що складається з реальної UTXO та кількох decoys (за замовчуванням 15 в Monero з HF v15). Зовнішній спостерігач не може визначити, хто є істинним відправником.
RingCT (Ring Confidential Transactions): суми транзакцій приховані за допомогою Pedersen commitments. Тільки відправник і одержувач знають реальні суми.
Що це означає для приймання платежів
Ви не можете просто дивитись на блокчейн і бачити вхідні платежі — транзакції на вашій адресі видно тільки якщо у вас є private view key. Для моніторингу вхідних потрібно або запустити повний вузол з monero-wallet-rpc, або використовувати view key на сервері (що дозволяє бачити вхідні, але не витрачати).
Архітектура: monero-wallet-rpc
Стандартний інструмент для інтеграції — monero-wallet-rpc з офіційного Monero daemon. Він надає JSON-RPC інтерфейс для всіх операцій з гаманцем.
Розгортання вузла
Спочатку потрібен синхронізований monerod (Monero daemon). Розмір блокчейну ~180 GB (pruned ~60 GB), синхронізація з нуля — 12–48 годин залежно від обладнання.
# Запуск monerod з pruning
monerod --data-dir /var/lib/monero \
--prune-blockchain \
--db-sync-mode fast \
--rpc-bind-ip 127.0.0.1 \
--rpc-bind-port 18081 \
--no-igd \
--detach
# Запуск monero-wallet-rpc
monero-wallet-rpc \
--daemon-address 127.0.0.1:18081 \
--rpc-bind-port 18083 \
--wallet-file /etc/monero/payment-wallet \
--password-file /etc/monero/wallet.pass \
--rpc-login payment_server:$(cat /etc/monero/rpc.pass) \
--disable-rpc-login false \
--trusted-daemon \
--non-interactive
Для production — окремий гаманець для кожного оточення, wallet-rpc за nginx з TLS, аутентифікація через HTTP Basic.
Subaddresses: правильна архітектура для платежів
Monero підтримує subaddresses — похідні адреси від основного гаманця, які повністю незалежні на рівні блокчейну. Це ключова функція для payment processing.
Створюємо subaddress для кожного замовлення:
import requests
RPC_URL = "http://127.0.0.1:18083/json_rpc"
AUTH = ("payment_server", "rpc_password")
def create_payment_address(order_id: str) -> dict:
# Створюємо новий subaddress в account 0
response = requests.post(RPC_URL, auth=AUTH, json={
"jsonrpc": "2.0",
"id": "0",
"method": "create_address",
"params": {
"account_index": 0,
"label": f"order_{order_id}"
}
})
result = response.json()["result"]
return {
"address": result["address"],
"address_index": result["address_index"]
}
def check_incoming_transfers(min_amount_xmr: float) -> list:
response = requests.post(RPC_URL, auth=AUTH, json={
"jsonrpc": "2.0",
"id": "0",
"method": "get_transfers",
"params": {
"in": True,
"pending": False,
"min_height": 0 # можна указати останній перевірений блок
}
})
transfers = response.json()["result"].get("in", [])
return [t for t in transfers if t["amount"] / 1e12 >= min_amount_xmr]
Чому subaddresses краще ніж одна адреса з payment_id: Payment ID (старий метод) — застарілий. Integrated addresses існують для зворотної сумісності, але мають проблеми приватності: розкривають, що кілька транзакцій йдуть до одного одержувача. Subaddresses виглядають як незалежні адреси — краще для приватності та de facto стандарт з 2018 року.
Моніторинг підтверджень
Monero використовує концепцію unlocked balance — кошти стають доступними після 10 підтверджень (~20 хвилин при середньому blocktime 2 хвилини). Для платіжної системи:
def poll_payments(expected_payments: dict) -> None:
"""
expected_payments: {address_index: {"order_id": str, "amount_xmr": float}}
"""
response = requests.post(RPC_URL, auth=AUTH, json={
"jsonrpc": "2.0",
"id": "0",
"method": "get_transfers",
"params": {"in": True, "pending": True}
})
for transfer in response.json()["result"].get("in", []):
addr_idx = transfer["subaddr_index"]["minor"]
confirmations = transfer["confirmations"]
amount_xmr = transfer["amount"] / 1e12 # атомарна одиниця piconero = 1e-12 XMR
if addr_idx in expected_payments:
expected = expected_payments[addr_idx]
if amount_xmr >= expected["amount_xmr"] * 0.99: # допуск 1% на округлення
if confirmations >= 10:
mark_order_paid(expected["order_id"], amount_xmr)
else:
update_order_status(expected["order_id"], "pending_confirmations", confirmations)
Sweep і безпека
Приватний spend key має залишатись в ізольованому оточенні. Для автоматичних виплат — окремий hot wallet з мінімальним балансом. Основні кошти — в cold wallet, періодичний ручний sweep.
View-only wallet (тільки public spend key + private view key) можна безпечно тримати на сервері для моніторингу без ризику крадіжки коштів:
monero-wallet-cli --generate-from-view-key view-only-wallet \
--address <main_address> \
--viewkey <private_view_key>
Що входить в роботу
- Розгортання і синхронізація
monerod(full node або pruned) - Настройка
monero-wallet-rpcз аутентифікацією та TLS - Реалізація subaddress-based payment flow
- Polling сервіс для моніторингу вхідних транзакцій з логікою підтверджень
- Sweep автоматизація і розділення hot/cold storage
- Інтеграція з існуючою платіжною системою через webhook або callback







