# Crypto Payments State Machine This document visualizes the complete state machine for cryptocurrency payments in the make-post-sell system, including semantic state groups, business logic rules, and implementation details. ## State Machine Diagram ```mermaid stateDiagram-v2 [*] --> pending [*] --> doublepay-refunded : Duplicate payment detected [*] --> latepay-refunded: Late payment detected %% Main payment flow pending --> received : Payment detected in mempool pending --> expired : Payment timeout (never received) pending --> cancelled : User cancellation %% From received state - multiple possible outcomes %% NOTE: received payments CANNOT expire (detected in mempool, confirmations tracking) received --> confirmed : Sufficient payment + confirmations received --> confirmed-overpay : Overpayment detected received --> underpaid-refunded : Underpayment detected received --> out-of-stock-refunded : Product unavailable %% Successful payment paths confirmed --> confirmed-complete : Swept to cold storage confirmed-complete --> [*] : ✓ Terminal Success %% Overpayment refund flow confirmed-overpay --> confirmed-overpay-refunded : Initiate refund confirmed-overpay-refunded --> confirmed-overpay-refunded-complete : Refund confirmed confirmed-overpay-refunded --> confirmed-overpay-not-refunded : No refund wallet configured confirmed-overpay-refunded-complete --> [*] : ✓ Terminal Success confirmed-overpay-not-refunded --> [*] : ✓ Terminal Success (Not Refunded) %% Expired payment handling (terminal - late payments create new objects) expired --> [*] : ✓ Terminal Failed (Expired) %% Late payment objects (created separately for payments after expiration) latepay-refunded --> latepay-refunded-complete : Refund confirmed latepay-refunded --> latepay-not-refunded : No refund wallet configured latepay-refunded-complete --> [*] : ✓ Terminal Failed (Refund Complete) latepay-not-refunded --> [*] : ✓ Terminal Failed (Not Refunded) %% Underpayment refund flow underpaid-refunded --> underpaid-refunded-complete : Refund confirmed underpaid-refunded --> underpaid-not-refunded : No refund wallet configured underpaid-refunded-complete --> [*] : ✓ Terminal Failed (Refund Complete) underpaid-not-refunded --> [*] : ✓ Terminal Failed (Not Refunded) %% Out of stock refund flow out-of-stock-refunded --> out-of-stock-refunded-complete : Refund confirmed out-of-stock-refunded --> out-of-stock-not-refunded : No refund wallet configured out-of-stock-refunded-complete --> [*] : ✓ Terminal Failed (Refund Complete) out-of-stock-not-refunded --> [*] : ✓ Terminal Failed (Not Refunded) %% Double payment refund flow doublepay-refunded --> doublepay-refunded-complete : Refund confirmed doublepay-refunded --> doublepay-not-refunded : No refund wallet configured doublepay-refunded-complete --> [*] : ✓ Terminal Failed (Refund Complete) doublepay-not-refunded --> [*] : ✓ Terminal Failed (Not Refunded) %% User cancellation (always terminal, only from pending) cancelled --> [*] : ✓ Terminal Failed (Cancelled) %% Style the states by semantic category classDef successState fill:#d4edda,stroke:#155724,color:#155724 classDef initialWaitingState fill:#e7f3ff,stroke:#0056b3,color:#0056b3 classDef refundState fill:#fff3cd,stroke:#856404,color:#856404 classDef failedState fill:#f8d7da,stroke:#721c24,color:#721c24 classDef processingState fill:#cce5ff,stroke:#004085,color:#004085 %% Successful payments (customer received product) class confirmed,confirmed-complete,confirmed-overpay-refunded-complete,confirmed-overpay-not-refunded successState %% Initial/waiting states (entry points that don't come from 'received') class pending,latepay-refunded,doublepay-refunded initialWaitingState %% Active refund processing states class confirmed-overpay-refunded,underpaid-refunded,out-of-stock-refunded refundState %% Failed payments (customer did not receive product) class expired,cancelled,latepay-refunded-complete,latepay-not-refunded,underpaid-refunded-complete,underpaid-not-refunded,out-of-stock-refunded-complete,out-of-stock-not-refunded,doublepay-refunded-complete,doublepay-not-refunded failedState %% Processing states class received,confirmed-overpay processingState ``` ## Semantic State Groups The state machine uses semantic groups to categorize states by business logic purpose. These groups determine invoice handling, priority processing, and system behavior. ### 🔵 **Initial/Waiting States** (Light Blue) Entry point states that don't transition from `received` - they represent the start of payment flows: - **`pending`** - Initial state for new payment requests - **`latepay-refunded`** - Initial state for late payment objects (payments received after expiration) - **`doublepay-refunded`** - Initial state for duplicate payment objects (separate payment instances) **Business Logic**: These states represent separate payment flows and are processed with Priority 0-2 depending on their nature. ### 🟢 **Successful Payment States** (Green) Customer received their product - invoices are preserved: - **`confirmed`** - Normal successful payment (exact amount, confirmed) - **`confirmed-complete`** - Confirmed payment that has been swept to cold storage - **`confirmed-overpay-refunded-complete`** - Overpaid, customer got product + refund - **`confirmed-overpay-not-refunded`** - Overpaid, customer got product, no refund wallet configured **Business Logic**: `is_successful_payment() = True`, `should_keep_invoice() = True` ### 🔴 **Failed Payment States** (Red) Customer did not receive product - invoices are deleted: - **`expired`** - Payment window expired before any blockchain detection - **`cancelled`** - User cancelled payment (only from pending) - **`*-refunded-complete`** - Failed payments with completed refunds - **`*-not-refunded`** - Failed payments with no refund wallet configured **Business Logic**: `is_failed_payment() = True`, `should_keep_invoice() = False` ### 🟡 **Refund Processing States** (Yellow) Active refund workflows - intermediate states: - **`confirmed-overpay-refunded`** - Overpayment refund in progress (customer got product) - **`underpaid-refunded`** - Underpayment refund in progress - **`out-of-stock-refunded`** - Out of stock refund in progress - **Note**: `latepay-refunded` and `doublepay-refunded` are Initial/Waiting states, not regular refund processing **Business Logic**: Priority 0 processing (highest), actively monitored for confirmation ### 🔵 **Processing States** (Blue) Active payment processing states: - **`received`** - Payment detected on blockchain, being processed - **`confirmed-overpay`** - Overpayment confirmed, deciding refund action **Business Logic**: Priority 1-3 processing, confirmation monitoring ## Critical State Machine Rules ### **Rule 1: Blockchain Detection is Irreversible** - ❌ **INVALID**: `received → expired` - ✅ **VALID**: `pending → expired` **Rationale**: Once a payment is detected on the blockchain (`received`), it cannot "expire" - it already exists. Only payments that never arrive can expire. ### **Rule 2: Past-Tense Naming Convention** All status constants use past-tense naming for consistency: - ✅ `STATUS_DOUBLEPAY_REFUNDED` (correct) - ❌ `STATUS_DOUBLEPAY_REFUND` (incorrect - not past tense) ### **Rule 3: Entry Points vs Transitions** Some states are entry points for new payment objects, not transitions from existing payments: - `pending` - Entry point for new payments - `latepay-refunded` - Entry point for late payment objects (created after expiration) - `doublepay-refunded` - Entry point for duplicate payment objects ### **Rule 4: Invoice Preservation Logic** ```python should_keep_invoice() = is_successful_payment() ``` - **Keep**: Successful payments (customer got product) - **Delete**: Failed payments (customer did not get product) ## Priority-Based Processing System The crypto watcher processes payments by priority to ensure proper fund flow and customer service: ### **Priority 0 (Highest): Customer Refunds** - `doublepay-refunded`, `latepay-refunded`, `underpaid-refunded`, `out-of-stock-refunded` - **Rationale**: Customer service is highest priority ### **Priority 1: New Incoming Payments** - `received` - **Rationale**: Process new money quickly for customer experience ### **Priority 2: Other Processing** - `pending`, monitoring states, intermediate states - **Rationale**: General processing tasks ### **Priority 3: Auto-Sweep to Shop Owner** - `confirmed`, `confirmed-overpay` - **Rationale**: Move confirmed funds to shop owner ### **Priority 4 (Lowest): Restocking Fee Sweeps** - `*-refunded-complete` states - **Rationale**: Most dangerous operation, requires high confirmations, done last ## Business Logic Flows ### **Normal Payment Flow** ``` pending → received → confirmed → confirmed-complete ✅ ``` Customer pays exact amount, gets product, invoice kept, funds swept to cold storage. ### **Overpayment Flow** ``` pending → received → confirmed-overpay → confirmed-overpay-refunded → confirmed-overpay-refunded-complete ✅ ``` Customer overpays, gets product, gets refund, invoice kept. ### **Late Payment Flow** ``` Original: pending → expired ❌ New object: latepay-refunded → latepay-refunded-complete ❌ ``` Original payment expires. Late payment creates new object, gets refunded, invoice deleted. ### **Underpayment Flow** ``` pending → received → underpaid-refunded → underpaid-refunded-complete ❌ ``` Customer pays too little, gets refund, no product, invoice deleted. ### **Duplicate Payment Flow** ``` Original: pending → received → confirmed ✅ Duplicate: doublepay-refunded → doublepay-refunded-complete ❌ ``` First payment succeeds, duplicate creates separate object and gets refunded. ### **Out of Stock Flow** ``` pending → received → out-of-stock-refunded → out-of-stock-refunded-complete ❌ ``` Product unavailable, customer gets refund, no product, invoice deleted. ### **Cancellation Flow** ``` pending → cancelled ❌ ``` User cancels before payment detected, invoice deleted. ## Terminal States Analysis **Successful Terminals** (keep invoice): - `confirmed` - Normal success (awaiting sweep) - `confirmed-complete` - Normal success + swept to cold storage - `confirmed-overpay-refunded-complete` - Overpaid + refunded - `confirmed-overpay-not-refunded` - Overpaid, no refund wallet **Failed Terminals** (delete invoice): - `expired` - Never paid - `cancelled` - User cancelled - `*-refunded-complete` - Failed + refunded - `*-not-refunded` - Failed, no refund wallet ## State Transition Validation All transitions are validated via `CryptoPayment.is_valid_transition()`: ```python VALID_TRANSITIONS = { STATUS_PENDING: [STATUS_RECEIVED, STATUS_EXPIRED, STATUS_CANCELLED], STATUS_RECEIVED: [ STATUS_CONFIRMED, STATUS_CONFIRMED_OVERPAY, # NOTE: STATUS_EXPIRED removed - received payments cannot expire STATUS_UNDERPAID_REFUNDED, STATUS_DOUBLEPAY_REFUNDED, STATUS_OUT_OF_STOCK_REFUNDED, ], STATUS_CONFIRMED: [STATUS_CONFIRMED_COMPLETE], # Can transition to complete after sweep STATUS_CONFIRMED_COMPLETE: [], # Terminal - confirmed and swept # ... additional transitions } ``` **Property Testing**: The complete test suite validates: - ✅ All valid transitions work correctly - ❌ Invalid transitions are properly rejected - 🔄 Priority system assignments are consistent - 📊 Graph analysis confirms no orphaned states or cycles - 🧪 Property-based testing validates invariants - 🛣️ All payment lifecycles reach valid terminal states ## Implementation Details ### **Core Files** - **Model**: `make_post_sell/models/crypto_payment.py` - Line 55: `INITIAL_WAITING_STATUSES` - New semantic group - Line 62: `SUCCESSFUL_PAYMENT_STATUSES` - Keep invoices - Line 70: `FAILED_PAYMENT_STATUSES` - Delete invoices - Line 386: `VALID_TRANSITIONS` - State transition rules - Line 488: `is_successful_payment()` - Business logic helper - Line 522: `is_initial_waiting_state()` - New helper method - **Tests**: `make_post_sell/tests/test_crypto_payment_transitions.py` - 21 comprehensive test methods - Property-based validation - Graph analysis and reachability testing - Priority system validation - **Watcher**: `make_post_sell/lib/crypto_watcher.py` - Priority-based processing engine - State transition enforcement - Invoice deletion logic - **Views**: `make_post_sell/views/crypto.py` - Status display logic - User-facing state information ### **Database Schema** - Payments stored with `status` column containing string constants - `invoice_id` nullable for proper invoice handling - `created_timestamp` and `updated_timestamp` for audit trails ### **Testing Coverage** - **155 total crypto payment tests** all passing - Unit tests for individual state transitions - Integration tests for payment flows - Property-based tests for state machine invariants - Functional tests for end-to-end payment processing ## Debugging and Monitoring ### **Log Messages** All state transitions generate structured logs: ``` Payment {id} state transition: {old_status} → {new_status} (context: {context}) ``` ### **Invalid Transition Handling** ```python if not payment.is_valid_transition(new_status): logger.error(f"Invalid state transition for payment {payment.id}: {payment.status} → {new_status}") return False ``` ### **Common Issues** 1. **Invalid `received → expired`**: Check if payment was properly detected on blockchain 2. **Priority conflicts**: Verify processing order matches business requirements 3. **Invoice handling**: Ensure successful payments keep invoices, failed payments delete them 4. **Naming inconsistency**: All status constants must use past-tense naming This state machine provides a robust, well-tested foundation for cryptocurrency payment processing with clear semantic boundaries and validated state transitions.