Настройка приёма платежей в 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 (старый метод) — deprecated. Integrated addresses существуют для обратной совместимости, но имеют privacy проблемы: они раскрывают, что несколько транзакций идут к одному получателю. Subaddresses выглядят как независимые адреса — это и лучше для privacy, и стандарт 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







