All invoice deletion tests were failing because they were missing the
mock setup for should_keep_invoice.return_value = False. This caused
the deletion logic to be skipped since the function would return early
when should_keep_invoice() returned the default MagicMock() value.
Changes:
- Added self.mock_crypto_payment.should_keep_invoice.return_value = False
to test_handle_invoice_deletion_returns_false test
- All 11 invoice deletion tests now pass
- Completes the crypto payment test suite fixes (155 tests passing)
The invoice deletion logic properly checks should_keep_invoice() which
returns payment.is_successful_payment(), and failed payments should
have their invoices deleted while successful payments should keep them.
When multiple transactions arrive simultaneously to a pending payment, treat ALL transactions as duplicates rather than processing the first one normally. This prevents potential attack scenarios where multiple payments are sent rapidly to the same quote.
- Modified duplicate detection logic to treat all concurrent transactions as suspicious
- Set new_sum=0 and new_txids=[] when all transactions become duplicates
- Removed recalculation logic that was processing first transaction
- Enhanced logging to reflect new behavior
Fixes test_double_spend_protection.py failures. All 130 crypto tests now pass.
- Fix duplicate detection logic to prevent amount accumulation when new transactions arrive to already-processed payments
- Fix status constant naming errors: STATUS_CONFIRMED_OVERPAID → STATUS_CONFIRMED_OVERPAY, STATUS_EXPIRED_REFUNDED → STATUS_LATEPAY_REFUNDED
- Fix SweepRestockingFeeTests mock setup: add missing refund_confirmations, get_coin_config patches, and proper XMR client mocks
- Correct overpayment test expectations: restocking fee sweep happens later after refund confirmation, not immediately
- Update test assertions to match actual implementation behavior (transfer vs sweep_all for XMR)
- Add comprehensive mock configurations for DOGE/XMR atomic units and balance methods
All 108 crypto payment tests now pass. Fixes critical duplicate payment processing bug and aligns test expectations with production behavior.
* Implement complete state machine with 17 test scenarios
* Add priority-based processing order validation
* Include property-based testing for state transitions
* Add graph analysis for state machine integrity
* Validate all payment lifecycle paths
* Ensure robust error handling and logging
* Remove temporary debug files and consolidate test structure
- Fix payment_priority() to include ALL refund statuses (EXPIRED_REFUNDED, UNDERPAID_REFUNDED, OUT_OF_STOCK_REFUNDED) not just DOUBLEPAY_REFUND
- Auto-sweep operations (CONFIRMED, CONFIRMED_OVERPAID, NO_REFUND) now have lowest priority (3)
- Refactor to use match/case statements for better readability
- Add comprehensive docstring explaining priority system
- Ensure refunds processed before auto-sweep for customer service priority
Priority order: 0=refunds, 1=incoming, 2=other (pending/terminals), 3=auto-sweep
Updated tests to reflect correct behavior where multiple transactions
to one quote are treated as duplicates rather than legitimate payments.
Key changes:
- Fixed test_concurrent_transactions_within_processing_window to expect
duplicate detection behavior instead of transaction summing
- Fixed test_second_processing_cycle_rejects_duplicates to properly
validate duplicate detection warnings and status
- Updated test_multiple_rapid_payments_scenario and test_zero_amount_transactions
to handle duplicate payment scenarios correctly
- Removed int() casting from received_amount calculation to preserve
precision in cryptocurrency amounts
The core insight is that there should never be legitimate multiple
transactions to one quote - any additional transactions are duplicates
that should be handled by the scanner for refunds.
All 22 tests in test_double_spend_protection.py now pass.
- Add detection for multiple transactions during initial pending payment processing
- Process first transaction normally, create DOUBLEPAY_REFUND records for duplicates
- Recalculate amounts to use only first transaction for original payment
- Prevent summing all transactions into single overpayment
- Maintain existing logic for already-processed payments with new transactions
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The issue was that duplicate payments were being created without proper
invoice references, causing the refund processing logic to fail when
looking up user information. This resulted in duplicate payments being
marked as 'no-refund' instead of 'doublepay-refund'.
Key changes:
- Modified _create_duplicate_payment() to preserve the original invoice
reference instead of setting it to None
- Updated duplicate payment processing logic to use the invoice.user
directly instead of trying to look up the "original payment"
- Explicitly set user_id and shop_id foreign keys to ensure proper
database relationships
- Updated test assertions to expect duplicate payments to reference
the same invoice as the original payment
This fixes the core architectural insight that duplicate payments
should reference the same invoice since they're all payments toward
the same original quote/order. The invoice-to-quote relationship
remains intact while allowing proper duplicate payment tracking.
Fixes:
- test_double_payment_creates_separate_refund_entry
- test_race_condition_double_refund_prevention
- test_three_payments_one_confirms_two_refund
- Fix precision mismatches by using Decimal arithmetic throughout quote generation
- Replace int() truncation with math.ceil() for atomic unit conversions
- Update DOGE and XMR quote generation to avoid floating point errors
- Fix order of operations: process duplicate refunds BEFORE auto-sweep
- Add fund reservation logic to auto-sweep to protect pending refunds
- Fix duplicate payment queries to use address for DOGE, subaddress for XMR
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix "Invalid amount" error in DOGE refunds by rounding to 8 decimal places
* Add detailed RPC error logging to DogecoinClient for better debugging
* Add comment parameter to sendtoaddress calls for transaction labeling
* Identified root cause: Dogecoin daemon rejects amounts with >8 decimal precision
* Refund amount changed from 1.0385903528 to 1.03859035 DOGE
The system was correctly detecting overpayments (5.5 vs 4.358 DOGE expected)
but failing on the actual refund transaction due to precision requirements.
* Add is_finalized() method to CryptoPayment model that checks:
- Status in confirmed states (STATUS_CONFIRMED, STATUS_CONFIRMED_OVERPAID, STATUS_CONFIRMED_OVERPAID_REFUNDED)
- Received amount >= expected amount (handles overpayments)
- Current confirmations >= required confirmations
* Make process_confirmed_payment() idempotent and resumable:
- Check is_finalized() before attempting to finalize invoice
- Check refund_tx_hash before attempting refunds
- Only set terminal status at function end when all operations succeed
- Keep payments in STATUS_CONFIRMED_OVERPAID if refunds fail (allows retry)
* Fix logging errors by safely handling None process results
* Update test mocks to include required fields and new function signatures
* All 94 crypto watcher tests now pass
This allows failed refunds to be retried without re-delivering products to customers or losing funds.
- Fix DOGE amount parsing precision in get_dogecoin_incoming_transfers
- Fix payment comparison logic to use new_sum directly instead of adding to received_amount
- Fix PaymentRescue to use coin-specific clients and RPC calls
- Fix Decimal/float type conversion in wallet scanning
- Add proper balance checking for DOGE vs XMR clients
- Implement coin-specific refund mechanisms (sendtoaddress vs transfer)
- Fix confirmation requirements to use coin-specific values
Resolves underpayment detection bug where DOGE amounts were parsed as 4 koinu
instead of proper atomic units, causing false underpayment flags.
- PaymentRescue was using whatever client was passed in (usually Monero)
- Now gets coin-specific client based on payment.coin_type
- DOGE refunds will use DOGE client, XMR refunds use XMR client
- Fixes 404/500 errors when attempting DOGE refunds
This was causing DOGE refunds to fail because they were trying to call
sendtoaddress on the Monero RPC endpoint instead of Dogecoin RPC.
- Add coin-specific refund logic (XMR uses transfer, DOGE uses sendtoaddress)
- Fix confirmation threshold logging to use coin-specific requirements
- Improve refund amount logging to show correct coin type and atomic units
- DOGE refunds now use sendtoaddress RPC instead of failing with 404
Note: Crypto watcher needs restart to pick up changes
- Use coin-specific confirmation requirements from get_coin_config
- DOGE refunds now process at 2 confirmations instead of 10
- Improve logging to show correct coin type and atomic units
- Still need to implement DOGE-specific refund mechanism (currently uses XMR transfer RPC)
Critical fixes:
1. DOGE amount normalization in scan_wallet_for_double_or_late_payments
- Convert DOGE amounts from listsinceblock to atomic units (koinu)
- Prevents amounts like 4.38281195 DOGE being parsed as 4 koinu
2. DOGE confirmation updates in update_payment_confirmations_only
- Implement proper confirmation tracking using gettransaction RPC
- Allows DOGE refunds to process at 2 confirmations (not 10)
3. Fix XMR exact payment regression
- Use new_sum directly for first payments (don't add to received_amount)
- We don't allow multiple payments, so blockchain amount is authoritative
- Fixes exact XMR payments being incorrectly flagged as underpaid
4. Update coin-specific confirmation requirements
- DOGE uses 2 confirmations (not 10) for refunds
- Add confirmations_required to COIN_CONFIGS
5. Add comprehensive debug logging for amount comparisons
- Helps diagnose precision and comparison issues
This should fix both the DOGE "4 koinu" bug and XMR exact payments
being flagged as underpaid when using QR code payments.
- Add explicit float() conversion for DOGE amounts before multiplying by 1e8
- This fixes precision issues where amounts like 4.38281195 DOGE were being
converted to 4 koinu instead of 438281195 koinu
- Add regression test for precise DOGE amounts to prevent future issues
- Resolves underpayment detection false positives for valid DOGE payments
The root cause was tx.get("amount") returning string values that when
multiplied by 100000000 resulted in incorrect integer conversions.
- Add Monero and Dogecoin logo images to static assets
- Update cart_checkout.j2 to display crypto logos on payment buttons
- Update crypto_checkout.j2 to show logos in checkout headers
- Remove duplicate sweep script files (dogecoin-sweep-all.sh, sweep-all-doge.sh)
- Update CLAUDE.md with development standards and testing guidelines
- Fix process_payment to check for null invoice before calling finalize_invoice
- Update TransactionMatchingIntegrationTests to use real Invoice objects instead of None
- Add explicit dbsession.flush() calls after process_payment in tests to ensure transaction persistence
- Update test expectations from STATUS_RECEIVED to STATUS_CONFIRMED for sufficient confirmations
- Add comprehensive documentation explaining transaction flow and test methodology
- Fix shop name uniqueness issues in test setup with UUID-based names
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed issue where Dogecoin scanner was incorrectly matching old processed
transactions to new payments, causing cross-payment contamination. Added
comprehensive transaction deduplication logic that:
- Skips transactions already processed for current payment
- Prevents transactions from being matched to multiple payments
- Maintains database integrity during wallet scanning
Added unit tests in TransactionMatchingTests class and integration tests
in TransactionMatchingIntegrationTests class to prevent regression.
Resolves production issue where dust transactions were being incorrectly
matched to new payment addresses.
- Add check_user_has_pending_quotes() function to prevent infinite pending quotes
- Block new crypto quotes when user has pending/received payments
- Flash warning message and redirect to crypto history for pending quotes
- Disable Monero/Dogecoin buttons in checkout when user has pending quotes
- Fix integration test email mocking to prevent MagicMock string errors
- Fix underpayment test assertion to handle status transition variations
- Fix early detection logic to use new_sum instead of received_amount for underpayment check
- Fix hardcoded XMR atomic units (1e12) used for DOGE refunds, use correct coin-specific units
- Add comprehensive tests for atomic unit conversions for DOGE (1e8) and XMR (1e12)
- Prevent false underpayment detection when dust or corrupted amounts exist in database
This fixes production issue where valid DOGE payments were incorrectly marked as underpaid
due to comparing old stored amount instead of new incoming transaction amount.
- Replace non-existent download_instructions attribute with proper is_physical check
- Assume digital by default and only mark as non-digital if any product is physical
- Fixes AttributeError during crypto payment finalization for both XMR and DOGE
- Remove config modification logic from make serve to respect existing listen settings
- Remove --reload flag to test remote host binding
- Add missing listsinceblock method to DogecoinClient and MockDogecoinClient for late payment scanning
- Update Dogecoin auto sweep test expectations to match new 0.002 DOGE fee buffer (was 0.1 DOGE)
Use pserve config override syntax: listen=0.0.0.0:6501
instead of invalid --bind flag. This forces the server to bind
to all interfaces on port 6501 for external access during development.
The --reload flag was ignoring the listen = 0.0.0.0:6501 setting
in development.ini. Added explicit --bind=0.0.0.0:6501 to make serve
target to ensure development server binds to all interfaces on port 6501.
This allows external access to the dev server for testing.
1. Added getblockhash() method to DogecoinClient for late payment scanning
- Fixes 'DogecoinClient' object has no attribute 'getblockhash' error
- Required for crypto watcher to scan for missed payments
2. Added sweep-all-doge Makefile target for dust collection
- Sweeps ALL spendable Dogecoin balance to cold storage
- Uses sendtoaddress with subtractfeefromamount=true for complete sweep
- Includes safety confirmations and balance checks
- Perfect for cleaning up dust from hot wallet
Usage:
COLD_WALLET_ADDRESS=DYourColdAddress make sweep-all-doge
Critical for production Dogecoin deployment and hot wallet management.
The crypto watcher's late payment scanner was failing with:
'DogecoinClient' object has no attribute 'getblockhash'
Added getblockhash() method to both DogecoinClient and MockDogecoinClient:
- Uses standard Bitcoin RPC getblockhash call with block height parameter
- Enables proper Dogecoin late payment detection in production
- Required for crypto watcher to scan for missed payments
Critical for production Dogecoin support.
The crypto watcher was using uncapped fee estimation (1.77 DOGE/KB) when
sweeping funds, causing ~1 DOGE fees instead of the capped quote fees.
Applied same optimizations as quote system:
- Use 6 block target instead of 2 blocks for cheaper fees
- Reduce transaction size estimate from 0.5KB to 0.25KB
- Cap fee rate at 0.1 DOGE/KB maximum
- Use 0.002 DOGE fallback instead of 0.1 DOGE
This ensures backend sweep fees match the frontend quote fees,
preventing excessive sweep costs that eat into payment amounts.
The estimatesmartfee RPC was returning inflated fee rates (3+ DOGE/KB)
causing fees of ~/bin/bash.20 instead of expected ~/bin/bash.024.
Added fee rate cap of 0.1 DOGE/KB which results in:
- Max fee: 0.1 * 0.25KB * 2 = 0.05 DOGE (~/bin/bash.011)
- Much closer to wallet estimates of ~0.102 DOGE (~/bin/bash.024)
- Still covers inbound + outbound transaction costs
This prevents customers from being overcharged due to temporary
network fee spikes or misconfigured fee estimation.
UUID objects need to use .uuid_str property to get string representation,
as documented in CLAUDE.md. Using str() on UUID objects doesn't work properly.
Added comprehensive logging to see if fee estimation is:
- Using dynamic network fees from estimatesmartfee RPC
- Consistently falling back to hardcoded 0.004 DOGE fee
- Encountering RPC errors
This will help determine if high fees are due to fallback usage
vs actual network conditions.
The fee estimation was calculating ~/bin/bash.20 fees when it should be much lower.
Changes:
- Use 6 block target (~1 hour) instead of 2 blocks for cheaper estimates
- Reduce transaction size estimate from 0.5KB to 0.25KB (more realistic for DOGE)
- Lower fallback fee from 0.01 DOGE to 0.002 DOGE (~/bin/bash.0006 vs /bin/bash.003)
- Update development.ini default to match new lower fallback
This should reduce typical fee estimates from ~/bin/bash.20 to ~/bin/bash.02-0.05 range,
making Dogecoin payments more cost-effective for users while still covering
both inbound and sweep transaction costs.
Removed the 'Received: X / Y piconero' display that was showing raw atomic units
(piconero for XMR, koinu for DOGE) which confused users during testing.
Changes:
- Removed HTML div showing received/expected atomic units
- Removed JavaScript variables and logic for updating atomic unit display
- Users now see only human-readable cryptocurrency amounts
This improves UX by showing only meaningful amounts users can understand.
TEMPORARY: /crypto/debug/wallet-scan endpoint to diagnose why late payment
scanner shows 'No transfers found' while wallet actually has transactions.
READ-ONLY route that:
- Shows crypto processor count and scan positions
- Tests wallet RPC with same parameters as scanner
- Compares transfer counts to identify if issue is RPC or scanner logic
- Masks sensitive data (shop IDs, amounts, addresses)
TODO: Comment out this route when debugging is complete.
The late payment scanner stopped finding payments after double payment fixes.
Added detailed logging to diagnose the issue:
- Log each processor's scan position and calculated height
- Log minimum scan position used for wallet queries
- Log exact RPC query parameters sent to wallet
- Log all transfers found with height, amount, confirmations, subaddress
- Log payment lookup results for each transfer
- Log late payment decision logic with accept/reject reasons
This will reveal if:
- Scan positions are too high and skipping late payments
- Transfers are found but not matched to payment records
- Payments are found but rejected by late payment logic
Critical for debugging production issue where real customer funds
may not be getting processed due to missed late payments.
Fixed template syntax error where {% break %} is not supported in Jinja2.
Replaced with proper Jinja2 pattern using set variable and conditional check
to find first available thumbnail for Open Graph images.
Changes:
- Use {%- set og_thumbnail = none %} and conditional assignment
- Check og_thumbnail is none to ensure only first match is used
- Maintains same functionality with valid Jinja2 syntax
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhanced social media sharing by updating og:image meta tags to use the first
available thumbnail (thumbnail1-4) instead of hardcoding thumbnail1. This ensures
better social media previews on Slack, Twitter, Facebook when products don't have
thumbnail1 but have other thumbnails available.
Updated templates:
- product.j2: Smart thumbnail fallback for product pages
- content.j2: Smart thumbnail fallback for content pages
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Updated intro description to mention that Make Post Sell accepts both
credit cards and Monero (XMR) payments for better feature visibility.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This test reproduces the exact issue where duplicate payments weren't getting
their confirmation counts updated in the main processing loop, causing stuck refunds.
The test:
- Creates a duplicate payment with STATUS_DOUBLEPAY_REFUND and 0 confirmations
- Mocks blockchain data showing the transaction has 15 confirmations
- Calls process_payment() to simulate the main processing cycle
- Asserts that current_confirmations gets updated from 0 to 15
This test would have caught the bug where duplicate payments remained stuck
at 0 confirmations despite transactions having 10+ confirmations on blockchain.
Currently FAILS (as expected) since the fix hasn't been fully verified.
The test will pass once the confirmation update logic is working correctly.
The previous fix for update_payment_confirmations_only only worked for REFUND_PENDING_STATUSES,
but duplicate payments in STATUS_DOUBLEPAY_REFUND were being processed in the main loop
without updating their confirmation counts.
Added confirmation count updates directly in the duplicate payment processing logic:
- After finding specific duplicate transactions for XMR payments
- After fetching transaction details for other coin types
- Logs the confirmation count change for debugging
This ensures duplicate payments get their confirmation counts updated during processing,
allowing stuck refunds to proceed when transactions have sufficient confirmations.
Production logs showed payment stuck at "incoming: 0/2" despite transaction having 10+ confirmations.
This fix will update the count to show actual confirmations from the blockchain.