new file: docs/CRYPTO_PERFORMANCE.rst modified: docs/DOGECOIN.md modified: docs/MONERO.rst
592 lines
No EOL
19 KiB
ReStructuredText
592 lines
No EOL
19 KiB
ReStructuredText
=====================================
|
|
Monero (XMR) Integration Guide
|
|
=====================================
|
|
|
|
**Privacy-First Cryptocurrency Payment Processing**
|
|
|
|
Overview
|
|
========
|
|
|
|
Make Post Sell's Monero integration provides a comprehensive multi-tenant cryptocurrency payment system that enables any shop to accept XMR payments with complete financial isolation, automatic fund management, and privacy-focused transaction processing.
|
|
|
|
**Monero Advantages:**
|
|
|
|
- ✅ **Built-in privacy** - All transactions are private by default
|
|
- ✅ **Subaddress system** - Perfect payment isolation per customer
|
|
- ✅ **Remote node support** - No blockchain storage requirements
|
|
- ✅ **Mature infrastructure** - Comprehensive RPC API and wallet tools
|
|
- ✅ **Multi-tenant ready** - Account-based financial isolation
|
|
|
|
Architecture
|
|
============
|
|
|
|
Multi-Tenant Account System
|
|
---------------------------
|
|
|
|
Make Post Sell implements a sophisticated account-based isolation system where each shop gets its own dedicated Monero account within a single wallet:
|
|
|
|
**Account Structure:**
|
|
::
|
|
|
|
Wallet: make_post_sell_master
|
|
├── Account 0: Shop A (Digital Downloads)
|
|
│ ├── Subaddress 0: Primary (sweep destination)
|
|
│ ├── Subaddress 1: Payment #abc123
|
|
│ └── Subaddress 2: Payment #def456
|
|
├── Account 1: Shop B (Physical Goods)
|
|
│ ├── Subaddress 0: Primary (sweep destination)
|
|
│ ├── Subaddress 1: Payment #ghi789
|
|
│ └── Subaddress 2: Payment #jkl012
|
|
└── Account N: Shop N...
|
|
|
|
**Benefits:**
|
|
- Complete financial isolation between shops
|
|
- Simplified wallet management (single RPC service)
|
|
- Automatic account creation when shops enable Monero
|
|
- Subaddress generation for unique payment addresses
|
|
|
|
Payment Flow
|
|
============
|
|
|
|
Monero-Specific Processing
|
|
--------------------------
|
|
|
|
**1. Shop Onboarding**
|
|
::
|
|
|
|
# When shop enables Monero payments:
|
|
|
|
# Create dedicated account
|
|
account_label = f"mps-shop-{shop.uuid_str}"
|
|
result = client._call("create_account", {"label": account_label})
|
|
account_index = result.get("account_index")
|
|
|
|
# Tag account for identification
|
|
client._call("tag_accounts", {
|
|
"tag": shop.name,
|
|
"accounts": [account_index]
|
|
})
|
|
|
|
# Store account index for future use
|
|
processor.wallet_label = str(account_index)
|
|
|
|
**2. Payment Address Generation**
|
|
::
|
|
|
|
# Create unique subaddress for each payment
|
|
address, subaddr_index = client.create_subaddress(
|
|
account_index=shop.account_index,
|
|
label=f"payment-{payment.id}"
|
|
)
|
|
|
|
# Store subaddress details
|
|
payment.address = address
|
|
payment.subaddress_index = subaddr_index
|
|
payment.account_index = shop.account_index
|
|
|
|
**3. Payment Monitoring**
|
|
::
|
|
|
|
# Scan specific subaddresses for incoming transfers
|
|
transfers = client.get_transfers_for_subaddr(
|
|
account_index=payment.account_index,
|
|
subaddr_indices=[payment.subaddress_index]
|
|
)
|
|
|
|
# Process incoming transfers
|
|
for transfer in transfers.get('in', []):
|
|
if transfer['subaddr_index']['minor'] == payment.subaddress_index:
|
|
process_incoming_transfer(payment, transfer)
|
|
|
|
**4. Confirmation Processing**
|
|
::
|
|
|
|
# Check confirmations against requirements
|
|
wallet_height = client.get_height()
|
|
confirmations = wallet_height - transfer['height']
|
|
|
|
if confirmations >= payment.confirmations_required:
|
|
payment.status = CryptoPayment.STATUS_CONFIRMED
|
|
finalize_payment(payment)
|
|
|
|
# Trigger auto-sweep
|
|
auto_sweep_payment(payment, confirmed_amount)
|
|
|
|
Installation and Setup
|
|
======================
|
|
|
|
System Requirements
|
|
-------------------
|
|
|
|
**Resource Usage (Production Measurements):**
|
|
- **With Remote Node**: ~512MB RAM, ~11MB active memory usage
|
|
- **With Local Node**: ~2GB RAM for monerod + wallet RPC
|
|
- **Disk Space**: None for remote node, ~150GB for full local blockchain
|
|
- **Network**: Stable internet connection for RPC communication
|
|
|
|
Monero Node Requirements
|
|
------------------------
|
|
|
|
**Option 1: Remote Node (Recommended for Development)**
|
|
::
|
|
|
|
# No blockchain download required
|
|
# Uses public Monero nodes for blockchain data
|
|
# Wallet-only operation mode
|
|
|
|
# Start wallet RPC with remote node
|
|
monero-wallet-rpc \
|
|
--wallet-file=data/mps-wallet \
|
|
--password-file=data/wallet-password.txt \
|
|
--rpc-bind-ip=127.0.0.1 \
|
|
--rpc-bind-port=18083 \
|
|
--daemon-address=opennode.xmr-tw.org:18089 \
|
|
--trusted-daemon \
|
|
--log-level=1
|
|
|
|
**Option 2: Local Node (Production)**
|
|
::
|
|
|
|
# Full blockchain synchronization (~150GB)
|
|
# Maximum privacy and reliability
|
|
# Independent operation
|
|
|
|
# Start local Monero daemon
|
|
monerod \
|
|
--data-dir=data/monero-blockchain \
|
|
--rpc-bind-ip=127.0.0.1 \
|
|
--rpc-bind-port=18081 \
|
|
--log-level=1
|
|
|
|
# Start wallet RPC with local daemon
|
|
monero-wallet-rpc \
|
|
--wallet-file=data/mps-wallet \
|
|
--password-file=data/wallet-password.txt \
|
|
--rpc-bind-ip=127.0.0.1 \
|
|
--rpc-bind-port=18083 \
|
|
--daemon-address=127.0.0.1:18081 \
|
|
--trusted-daemon \
|
|
--log-level=1
|
|
|
|
Wallet Creation
|
|
---------------
|
|
|
|
**Initial Wallet Setup:**
|
|
::
|
|
|
|
# Create new wallet (first time only)
|
|
monero-wallet-cli \
|
|
--generate-new-wallet=data/mps-wallet \
|
|
--password-file=data/wallet-password.txt
|
|
|
|
# IMPORTANT: Save the 25-word mnemonic seed!
|
|
# This is your only recovery method for the wallet
|
|
|
|
**Configuration Setup:**
|
|
::
|
|
|
|
# Enable Monero payments in configuration
|
|
app.payments.monero.enabled = False # Default from development.ini
|
|
|
|
# Wallet RPC connection (development.ini defaults)
|
|
monero.rpc_url = http://127.0.0.1:18083/json_rpc
|
|
monero.rpc_user = test_user # Default from development.ini
|
|
monero.rpc_pass = test_pass # Default from development.ini
|
|
monero.account_index = 0 # Default account index
|
|
|
|
# Confirmation thresholds based on risk
|
|
# Note: Payment tier thresholds ($10 and $100) are shop settings
|
|
monero.confirmations.petty = 2 # Under $10 (default from development.ini)
|
|
monero.confirmations.mid = 10 # $10-$100 (default from development.ini)
|
|
monero.confirmations.high = 20 # Over $100 (default from development.ini)
|
|
|
|
# Quote and rate settings
|
|
monero.quote_expiry_seconds = 900 # 15 minutes (default from development.ini)
|
|
monero.rate_source_url = https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=usd
|
|
|
|
Shop-Specific Settings
|
|
----------------------
|
|
|
|
Each shop can configure payment risk thresholds through the web interface:
|
|
|
|
- **Mid Tier Threshold**: Default $10.00 (stored as 1000 cents)
|
|
- **High Tier Threshold**: Default $100.00 (stored as 10000 cents)
|
|
- **Quote Expiry**: Default 3600 seconds (60 minutes)
|
|
|
|
These thresholds determine which confirmation requirements apply to each payment:
|
|
|
|
- Payments under the mid threshold use ``monero.confirmations.petty`` (2 confirmations)
|
|
- Payments between mid and high use ``monero.confirmations.mid`` (10 confirmations)
|
|
- Payments over the high threshold use ``monero.confirmations.high`` (20 confirmations)
|
|
|
|
**Important**: The $0.64 minimum payment threshold is hardcoded and cannot be changed.
|
|
This prevents processing payments that would cost more in fees than their value.
|
|
|
|
Development Environment
|
|
=======================
|
|
|
|
Quick Start for Developers
|
|
---------------------------
|
|
|
|
**1. Start Monero Wallet (Remote Node)**
|
|
::
|
|
|
|
# Quick development setup with remote node
|
|
make monero-wallet-remote
|
|
|
|
# Or with authentication for testing
|
|
make monero-wallet-remote-auth
|
|
|
|
**2. Start Payment Processing**
|
|
::
|
|
|
|
# Start crypto watcher service
|
|
make crypto-watcher
|
|
|
|
# Or run once for testing
|
|
make crypto-watcher-once
|
|
|
|
**3. Start Web Application**
|
|
::
|
|
|
|
# Start development server
|
|
make serve
|
|
|
|
**Testing and Validation**
|
|
::
|
|
|
|
# Run Monero-specific tests
|
|
py.test make_post_sell/tests/test_crypto_watcher.py -k "xmr or monero"
|
|
|
|
# Test wallet connectivity
|
|
curl -u "test_user:test_pass" -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_balance","params":{}}'
|
|
|
|
Production Deployment
|
|
=====================
|
|
|
|
Security Configuration
|
|
-----------------------
|
|
|
|
**Wallet Security:**
|
|
::
|
|
|
|
# Production wallet RPC with authentication
|
|
monero-wallet-rpc \
|
|
--wallet-file=/secure/path/mps-wallet \
|
|
--password-file=/secure/path/wallet-password.txt \
|
|
--rpc-bind-ip=127.0.0.1 \
|
|
--rpc-bind-port=18083 \
|
|
--rpc-login=secure_user:very_secure_password \
|
|
--daemon-address=your.trusted.node:18089 \
|
|
--trusted-daemon \
|
|
--log-level=1
|
|
|
|
**Network Security:**
|
|
::
|
|
|
|
# Firewall rules (iptables example)
|
|
# Only allow local connections to wallet RPC
|
|
iptables -A INPUT -p tcp --dport 18083 -s 127.0.0.1 -j ACCEPT
|
|
iptables -A INPUT -p tcp --dport 18083 -j REJECT
|
|
|
|
# If using local daemon, secure it similarly
|
|
iptables -A INPUT -p tcp --dport 18081 -s 127.0.0.1 -j ACCEPT
|
|
iptables -A INPUT -p tcp --dport 18081 -j REJECT
|
|
|
|
**File Permissions:**
|
|
::
|
|
|
|
# Secure wallet files and directories
|
|
chmod 700 /secure/path/
|
|
chmod 600 /secure/path/mps-wallet*
|
|
chmod 600 /secure/path/wallet-password.txt
|
|
|
|
# Run wallet RPC as dedicated user
|
|
useradd -r -s /bin/false monero-wallet
|
|
chown monero-wallet:monero-wallet /secure/path/mps-wallet*
|
|
|
|
Cold Storage Integration
|
|
------------------------
|
|
|
|
**Shop Configuration:**
|
|
Each shop must configure their own cold wallet address for automatic sweep destinations:
|
|
|
|
::
|
|
|
|
# Shop settings form validation
|
|
def validate_monero_address(address):
|
|
# Standard address validation
|
|
if len(address) == 95 and address.startswith('4'):
|
|
return True
|
|
# Integrated address validation
|
|
if len(address) == 106 and address.startswith('4'):
|
|
return True
|
|
return False
|
|
|
|
**Auto-Sweep Configuration:**
|
|
::
|
|
|
|
# Automatic sweep after payment confirmation
|
|
def auto_sweep_payment(payment, confirmed_amount):
|
|
fee_reserve = Decimal('0.001') # Keep for future transactions
|
|
sweep_amount = confirmed_amount - fee_reserve
|
|
|
|
if sweep_amount > 0:
|
|
# Sweep to shop's configured cold wallet
|
|
result = client._call("transfer", {
|
|
"destinations": [{
|
|
"amount": int(sweep_amount * ATOMIC_UNITS),
|
|
"address": payment.shop.cold_wallet_address
|
|
}],
|
|
"account_index": payment.account_index,
|
|
"priority": 1
|
|
})
|
|
|
|
log.sweep_operation(payment, "Auto-sweep successful",
|
|
result['tx_hash'], sweep_amount)
|
|
|
|
Monitoring and Maintenance
|
|
==========================
|
|
|
|
Wallet Health Monitoring
|
|
-------------------------
|
|
|
|
**Key Metrics:**
|
|
::
|
|
|
|
# Wallet synchronization status
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_height"}' | \
|
|
python3 -c "import sys,json; print(f\"Height: {json.load(sys.stdin)['result']['height']}\")"
|
|
|
|
# Account balances across all shops
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_balance","params":{"all_accounts":true}}'
|
|
|
|
**Automated Health Checks:**
|
|
::
|
|
|
|
#!/bin/bash
|
|
# wallet_health_check.sh
|
|
|
|
# Check wallet RPC connectivity
|
|
if ! curl -s --max-time 5 http://127.0.0.1:18083/json_rpc > /dev/null; then
|
|
echo "CRITICAL: Wallet RPC not responding"
|
|
exit 2
|
|
fi
|
|
|
|
# Check wallet synchronization
|
|
height=$(curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_height"}' | \
|
|
python3 -c "import sys,json; print(json.load(sys.stdin)['result']['height'])")
|
|
|
|
if [ "$height" -lt 1 ]; then
|
|
echo "WARNING: Wallet not synchronized"
|
|
exit 1
|
|
fi
|
|
|
|
echo "OK: Wallet healthy, height: $height"
|
|
|
|
Log Analysis
|
|
------------
|
|
|
|
**Monero-Specific Log Patterns:**
|
|
::
|
|
|
|
# Monitor Monero payment processing
|
|
grep "XMR.*confirmed" logs/crypto_watcher.log
|
|
|
|
# Check auto-sweep operations
|
|
grep "XMR.*swept to cold storage" logs/crypto_watcher.log
|
|
|
|
# Monitor wallet connectivity
|
|
grep "Monero RPC" logs/crypto_watcher.log
|
|
|
|
# Account creation tracking
|
|
grep "account.*created.*shop" logs/crypto_watcher.log
|
|
|
|
**Performance Monitoring:**
|
|
::
|
|
|
|
# Payment processing time analysis
|
|
grep "Payment.*XMR.*state transition" logs/crypto_watcher.log | \
|
|
awk '{print $1, $2, $NF}' | \
|
|
sort
|
|
|
|
**Error Analysis:**
|
|
::
|
|
|
|
# Common Monero error patterns
|
|
grep -E "(wallet.*locked|daemon.*not.*reachable|insufficient.*balance)" logs/crypto_watcher.log
|
|
|
|
# RPC communication errors
|
|
grep "Monero RPC connection error" logs/crypto_watcher.log
|
|
|
|
Troubleshooting
|
|
===============
|
|
|
|
Common Issues
|
|
-------------
|
|
|
|
**Wallet Synchronization Problems:**
|
|
::
|
|
|
|
# Check daemon connectivity
|
|
curl -s -X POST http://127.0.0.1:18081/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_info"}'
|
|
|
|
# Force wallet refresh
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"refresh"}'
|
|
|
|
**Account/Subaddress Issues:**
|
|
::
|
|
|
|
# List all accounts
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_accounts"}'
|
|
|
|
# Get subaddresses for specific account
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_address","params":{"account_index":1}}'
|
|
|
|
**Payment Tracking Issues:**
|
|
::
|
|
|
|
# Check transfers for specific account/subaddress
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_transfers","params":{"in":true,"account_index":1,"subaddr_indices":[1]}}'
|
|
|
|
**Recovery Procedures:**
|
|
::
|
|
|
|
# Wallet recovery from mnemonic seed
|
|
monero-wallet-cli \
|
|
--restore-deterministic-wallet \
|
|
--wallet-file=data/mps-wallet-restored \
|
|
--password-file=data/wallet-password.txt
|
|
|
|
# Account recreation (if accounts are lost)
|
|
# Note: Account indices must match original setup
|
|
for shop in shops_with_xmr:
|
|
curl -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"create_account\",\"params\":{\"label\":\"mps-shop-${shop.uuid}\"}}"
|
|
|
|
Emergency Procedures
|
|
--------------------
|
|
|
|
**Emergency Fund Sweep:**
|
|
::
|
|
|
|
# If server compromise is suspected
|
|
# Sweep ALL accounts to emergency cold storage
|
|
|
|
EMERGENCY_ADDRESS="your_emergency_cold_wallet_address"
|
|
|
|
# Get all accounts
|
|
accounts=$(curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_accounts"}' | \
|
|
python3 -c "import sys,json; accounts=json.load(sys.stdin)['result']['subaddress_accounts']; print(','.join(str(acc['account_index']) for acc in accounts))")
|
|
|
|
# Sweep each account
|
|
for account in $(echo $accounts | tr ',' ' '); do
|
|
curl -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"sweep_all\",\"params\":{\"address\":\"$EMERGENCY_ADDRESS\",\"account_index\":$account}}"
|
|
done
|
|
|
|
**Wallet Backup and Recovery:**
|
|
::
|
|
|
|
# Regular backup procedures
|
|
# 1. Backup wallet files
|
|
cp data/mps-wallet* /secure/backup/location/
|
|
|
|
# 2. Backup account configuration
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"get_accounts"}' > account_backup.json
|
|
|
|
# 3. Export key images (for recovery)
|
|
curl -s -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"export_key_images"}' > key_images_backup.json
|
|
|
|
Advanced Configuration
|
|
======================
|
|
|
|
Performance Tuning
|
|
-------------------
|
|
|
|
**Wallet RPC Optimization:**
|
|
::
|
|
|
|
# Increase RPC timeout for large operations
|
|
monero-wallet-rpc \
|
|
--wallet-file=data/mps-wallet \
|
|
--rpc-bind-port=18083 \
|
|
--daemon-address=remote.node:18089 \
|
|
--trusted-daemon \
|
|
--max-concurrency=4 \
|
|
--log-level=1
|
|
|
|
**Memory Management:**
|
|
::
|
|
|
|
# For high-volume shops, optimize memory usage
|
|
# Reduce transaction history retention
|
|
curl -X POST http://127.0.0.1:18083/json_rpc \
|
|
-d '{"jsonrpc":"2.0","id":"0","method":"set_tx_notes","params":{"txids":["old_tx_id"],"notes":[""]}}'
|
|
|
|
**Database Optimization:**
|
|
::
|
|
|
|
# Index optimization for crypto payment queries
|
|
CREATE INDEX idx_crypto_payment_account_subaddr ON mps_crypto_payment(account_index, subaddress_index);
|
|
CREATE INDEX idx_crypto_payment_status_coin ON mps_crypto_payment(status, coin_type);
|
|
CREATE INDEX idx_crypto_payment_shop_created ON mps_crypto_payment(shop_id, created_at);
|
|
|
|
Multi-Node Setup
|
|
----------------
|
|
|
|
**Load Balancing Multiple Nodes:**
|
|
::
|
|
|
|
# Primary node configuration
|
|
monero-wallet-rpc \
|
|
--wallet-file=data/mps-wallet-primary \
|
|
--rpc-bind-port=18083 \
|
|
--daemon-address=node1.example.com:18089
|
|
|
|
# Backup node configuration
|
|
monero-wallet-rpc \
|
|
--wallet-file=data/mps-wallet-backup \
|
|
--rpc-bind-port=18084 \
|
|
--daemon-address=node2.example.com:18089
|
|
|
|
**Failover Configuration:**
|
|
::
|
|
|
|
# Application configuration for failover
|
|
monero.rpc_url.primary = http://localhost:18083
|
|
monero.rpc_url.backup = http://localhost:18084
|
|
monero.failover_timeout = 10
|
|
monero.retry_attempts = 3
|
|
|
|
Conclusion
|
|
==========
|
|
|
|
Monero integration in Make Post Sell provides a robust, privacy-focused payment solution that scales from single-shop installations to large multi-tenant deployments. The account-based isolation system ensures complete financial separation while maintaining operational efficiency through shared infrastructure.
|
|
|
|
The comprehensive monitoring, automatic fund management, and recovery procedures make this a production-ready solution for businesses requiring privacy-focused cryptocurrency payments with enterprise-grade reliability.
|
|
|
|
**Key Benefits for Monero:**
|
|
|
|
- **Privacy-first design** - All transactions are private by default
|
|
- **Perfect isolation** - Subaddress system ensures payment separation
|
|
- **Scalable architecture** - Single wallet serving unlimited shops
|
|
- **Remote node support** - No blockchain storage requirements
|
|
- **Comprehensive monitoring** - Full payment lifecycle tracking
|
|
- **Automatic fund management** - Immediate sweep to cold storage
|
|
- **Production-tested** - Extensive test coverage and real-world validation
|
|
|
|
For general cryptocurrency system information, see ``docs/CRYPTO.rst``. For Dogecoin-specific setup, see ``docs/DOGECOIN.md``. |