deleted: debug_digest_details.py deleted: debug_monero_auth.py renamed: CRYPTO_WATCHER_FLOW.md -> docs/CRYPTO_WATCHER_FLOW.md deleted: test_digest_auth_local.py deleted: test_dogecoin_client.py deleted: test_monero_auth.py deleted: test_monero_client.py deleted: test_requests_lib.py deleted: test_urllib_variants.py
12 KiB
12 KiB
Crypto Watcher Mechanism - Complete Flow Documentation
This document describes the complete flow of the crypto payment watcher system, including all paths for payment processing, duplicate detection, and refund handling.
flowchart TD
A[Crypto Watcher Starts] --> B[Load Active Crypto Processors]
B --> C[For Each Processor: Scan Wallet]
C --> D{New Transactions Found?}
D -->|No| E[Sleep 20 seconds]
D -->|Yes| F[Process Each Transaction]
F --> G[Match Transaction to Payment by Subaddress]
G --> H{Payment Found?}
H -->|No| I[Log: No matching payment]
H -->|Yes| J[Call process_payment]
J --> K{Payment Status?}
K -->|PENDING| L[First Payment Path]
K -->|RECEIVED/CONFIRMED| M[Duplicate Detection Path]
K -->|DOUBLEPAY_REFUND| N[Refund Processing Path]
subgraph FirstPayment [First Payment Path]
L1[Add transaction amount]
L2[Update tx_hashes with txid]
L3[Update confirmations]
L4{Amount >= Expected AND Confirmations >= Required?}
L5[Status = CONFIRMED]
L6[Status = RECEIVED]
L7[Finalize Invoice - Unlock Products]
L8[Continue Monitoring]
L1 --> L2
L2 --> L3
L3 --> L4
L4 -->|Yes| L5
L4 -->|No| L6
L5 --> L7
L6 --> L8
L7 --> L8
end
subgraph DuplicateDetection [Duplicate Detection Path]
M1{received_amount > 0 AND new_txids?}
M2[DUPLICATE PAYMENT DETECTED]
M3[Create Duplicate Payment Records]
M4[Set status = STATUS_DOUBLEPAY_REFUND]
M5[Store tx_hashes with duplicate txid]
M6[Update original payment confirmations only]
M7[Scanner will process refunds]
M1 -->|Yes| M2
M2 --> M3
M3 --> M4
M4 --> M5
M5 --> M6
M6 --> M7
end
subgraph RefundProcessing [Refund Processing Path]
N1{PaymentRescue available?}
N2[Status = STATUS_NO_REFUND]
N3[Calculate refund amount with 9% fee]
N4[Execute refund transaction]
N5{Refund successful?}
N6[Store refund_tx_hash]
N7[Log refund failure]
N8[Monitor refund confirmations]
N9[Status remains DOUBLEPAY_REFUND]
N10{Refund confirmed?}
N11[Status = STATUS_DOUBLEPAY_REFUND_COMPLETE]
N12[Continue monitoring]
N1 -->|No| N2
N1 -->|Yes| N3
N3 --> N4
N4 --> N5
N5 -->|Yes| N6
N5 -->|No| N7
N6 --> N8
N7 --> N9
N8 --> N10
N10 -->|Yes| N11
N10 -->|No| N12
end
L --> FirstPayment
M --> DuplicateDetection
N --> RefundProcessing
M1 -->|No| L1
E --> C
L8 --> E
M7 --> E
N2 --> E
N9 --> E
N11 --> E
N12 --> E
I --> E
Complete Payment Status State Machine
stateDiagram-v2
[*] --> PENDING : Payment created
%% Normal payment flow
PENDING --> RECEIVED : First transaction received
RECEIVED --> CONFIRMED : Sufficient confirmations + exact payment
RECEIVED --> CONFIRMED_OVERPAID : Sufficient confirmations + overpayment
%% Terminal success states
CONFIRMED --> [*] : Products unlocked
CONFIRMED_OVERPAID --> CONFIRMED_OVERPAID_REFUNDED : Excess refunded
CONFIRMED_OVERPAID_REFUNDED --> [*] : Refund confirmed
%% Expiration flow
PENDING --> EXPIRED : Quote expires (no payment)
RECEIVED --> EXPIRED : Quote expires (partial payment)
EXPIRED --> EXPIRED_REFUNDED : Late payment arrives + refund sent
EXPIRED_REFUNDED --> EXPIRED_REFUNDED_COMPLETE : Refund confirmed
EXPIRED_REFUNDED_COMPLETE --> [*]
EXPIRED --> [*] : No late payment
%% Underpayment flow
RECEIVED --> UNDERPAID_REFUNDED : Quote expires + insufficient funds
UNDERPAID_REFUNDED --> UNDERPAID_REFUNDED_COMPLETE : Refund confirmed
UNDERPAID_REFUNDED_COMPLETE --> [*]
%% Duplicate payment flow
CONFIRMED --> DOUBLEPAY_REFUND : Duplicate payment detected
CONFIRMED_OVERPAID --> DOUBLEPAY_REFUND : Duplicate payment detected
RECEIVED --> DOUBLEPAY_REFUND : Duplicate payment detected
DOUBLEPAY_REFUND --> DOUBLEPAY_REFUND_COMPLETE : Refund confirmed
DOUBLEPAY_REFUND_COMPLETE --> [*]
%% Out of stock flow
PENDING --> OUT_OF_STOCK_REFUNDED : Product out of stock + payment received
RECEIVED --> OUT_OF_STOCK_REFUNDED : Product out of stock
CONFIRMED --> OUT_OF_STOCK_REFUNDED : Product out of stock after payment
OUT_OF_STOCK_REFUNDED --> OUT_OF_STOCK_REFUNDED_COMPLETE : Refund confirmed
OUT_OF_STOCK_REFUNDED_COMPLETE --> [*]
%% No refund scenarios
EXPIRED --> NO_REFUND : No refund address configured
UNDERPAID_REFUNDED --> NO_REFUND : Refund failed
DOUBLEPAY_REFUND --> NO_REFUND : Refund failed
OUT_OF_STOCK_REFUNDED --> NO_REFUND : Refund failed
NO_REFUND --> NO_REFUND_COMPLETE : Manual resolution
NO_REFUND_COMPLETE --> [*]
%% Cancellation flow
PENDING --> CANCELLED : Payment cancelled by user/system
RECEIVED --> CANCELLED : Payment cancelled with refund
CANCELLED --> [*]
%% Status groupings for processing
state "Active Statuses (Monitored)" as ActiveGroup {
PENDING
RECEIVED
CONFIRMED
CONFIRMED_OVERPAID
NO_REFUND
}
state "Refund Pending (Confirmation Monitoring)" as RefundGroup {
EXPIRED_REFUNDED
UNDERPAID_REFUNDED
OUT_OF_STOCK_REFUNDED
DOUBLEPAY_REFUND
}
state "Terminal Statuses (No Processing)" as TerminalGroup {
EXPIRED
EXPIRED_REFUNDED_COMPLETE
UNDERPAID_REFUNDED_COMPLETE
CONFIRMED_OVERPAID_REFUNDED
CANCELLED
OUT_OF_STOCK_REFUNDED_COMPLETE
NO_REFUND_COMPLETE
DOUBLEPAY_REFUND_COMPLETE
}
Status Categories and Processing Rules
Active Statuses (Actively Monitored)
- PENDING: Waiting for first payment
- RECEIVED: Has funds, waiting for confirmations
- CONFIRMED: Payment complete, products unlocked
- CONFIRMED_OVERPAID: Overpaid, products unlocked, excess pending refund
- NO_REFUND: Failed refund scenarios, manual intervention needed
Refund Pending (Confirmation Monitoring)
- EXPIRED_REFUNDED: Late payment refunded with 9% fee
- UNDERPAID_REFUNDED: Partial payment refunded with 9% fee
- OUT_OF_STOCK_REFUNDED: Out of stock, full refund (no fee)
- DOUBLEPAY_REFUND: Duplicate payment refunded with 9% fee
Terminal Statuses (No Further Processing)
- EXPIRED: Quote expired, no payment received
- EXPIRED_REFUNDED_COMPLETE: Late payment refund confirmed
- UNDERPAID_REFUNDED_COMPLETE: Partial payment refund confirmed
- CONFIRMED_OVERPAID_REFUNDED: Overpayment excess refund confirmed
- CANCELLED: Payment cancelled by user/system
- OUT_OF_STOCK_REFUNDED_COMPLETE: Out of stock refund confirmed
- NO_REFUND_COMPLETE: Manual resolution complete
- DOUBLEPAY_REFUND_COMPLETE: Duplicate payment refund confirmed
Key Functions and Their Responsibilities
Main Processing Loop
crypto_watcher_main(): Entry point, coordinates scanning and processingprocess_payment(): Core payment processing logicscan_wallet_for_double_or_late_payments(): Scanner for missed/duplicate transactions
Duplicate Detection
_create_duplicate_payment(): Creates separate records for duplicate transactions_should_process_late_payment(): Determines if a transaction should be processed
Payment Processing Paths
1. Normal Payment Path
# New payment to fresh address
status: PENDING → RECEIVED → CONFIRMED
actions:
- Add amount to received_amount
- Update tx_hashes with transaction IDs
- Update confirmation count
- Finalize invoice when confirmed
2. Duplicate Payment Path (Main Loop)
# Additional payment to already-paid address
if (received_amount > 0 AND new_txids AND status != PENDING):
# Create separate duplicate records
for txid in new_txids:
duplicate = _create_duplicate_payment(original, tx, coin_type)
duplicate.status = STATUS_DOUBLEPAY_REFUND
duplicate.tx_hashes = json.dumps([txid])
# Update original payment confirmations only (no new amounts)
original.confirmations = calculate_from_legitimate_txs_only()
3. Scanner Duplicate Processing
# Scanner finds duplicate transactions
for tx in wallet_transfers:
payment = find_by_subaddress(tx)
if payment.received_amount > 0: # Duplicate
existing = find_duplicate_by_txid(tx.txid)
if not existing:
duplicate = _create_duplicate_payment(payment, tx, coin_type)
else:
duplicate = existing
# Process refund
process_payment(request, duplicate, [tx], client=refund_client)
4. Refund Processing Path
# For payments with STATUS_DOUBLEPAY_REFUND
if payment.status == STATUS_DOUBLEPAY_REFUND:
if payment_rescue and payment.refund_address:
refund_amount = received_amount * 0.91 # 9% fee
result = payment_rescue.execute_refund(payment, refund_amount)
if result.success:
payment.refund_tx_hash = result.tx_hash
# Monitor for refund confirmation
else:
# Log failure, retry later
else:
payment.status = STATUS_NO_REFUND
Infinite Duplicate Support
The system now supports unlimited duplicate payments to the same address:
- Payment #1: Normal processing → CONFIRMED
- Payment #2: Main loop creates duplicate record #1 → Scanner processes refund #1
- Payment #3: Main loop creates duplicate record #2 → Scanner processes refund #2
- Payment #4: Main loop creates duplicate record #3 → Scanner processes refund #3
- etc...
Each duplicate gets:
- Its own
CryptoPaymentrecord with unique ID - Status:
STATUS_DOUBLEPAY_REFUND - Individual refund processing
- Separate entry in crypto payments history
Error Handling and Edge Cases
Double Refund Prevention
- Scanner checks for existing duplicate records by transaction ID
- Only one duplicate record created per transaction
- Refund only processed once per duplicate
Confirmation Handling for Duplicates
- Original payment confirmations calculated from legitimate transactions only
- Duplicate transactions don't affect original payment confirmation count
- Original payment can move RECEIVED → CONFIRMED despite having duplicates
Missing Transaction Scenarios
- Scanner catches transactions missed by main loop
- Late payments to expired quotes handled separately
- Blockchain reorganizations handled through re-scanning
Database Schema Impact
CryptoPayment Table Fields Used
id: Unique payment identifierstatus: Payment status (see status flow above)received_amount: Amount received for this specific paymenttx_hashes: JSON array of transaction IDsrefund_tx_hash: Transaction ID of refund (for duplicates)refund_address: Where to send refundsubaddress_index: Unique address identifier
Query Patterns
-- Find payment by subaddress
SELECT * FROM mps_crypto_payment
WHERE coin_type = ? AND account_index = ? AND subaddress_index = ?
-- Find duplicate by transaction ID
SELECT * FROM mps_crypto_payment
WHERE status = 'doublepay-refund'
AND tx_hashes LIKE '%"transaction-id-here"%'
-- Get payment history
SELECT * FROM mps_crypto_payment
WHERE user_id = ?
ORDER BY created_timestamp DESC
This system ensures that every payment (original and all duplicates) is tracked, processed, and appears in the user's payment history while preventing financial loss through proper duplicate detection and single-refund-per-transaction guarantees.