DCA distribution fails when ATM cash exceeds total tracked client balances #1

Closed
opened 2025-12-31 22:25:56 +00:00 by padreug · 1 comment
Owner

Problem

When the physical cash in the ATM machine exceeds the sum of all tracked client balances in satmachineadmin, DCA distributions fail for all clients.

Example from logs (2025-12-31)

Transaction: 2000 GTQ → 317,700 sats
Total tracked client balances: ~700 GTQ

Distribution calculation (proportional share):
├── Client 5XweGGWg: 690/700 = 98.57% → 1971.45 GTQ allocated
├── Client YqrSBUUV:   7.54/700 = 1.08% →   21.55 GTQ allocated  
├── Client j8swYGRT:   2.38/700 = 0.34% →    6.80 GTQ allocated
└── Client EjQ8Nqvj:   0.07/700 = 0.01% →    0.20 GTQ allocated

Result: All 4 client payments refused because each allocation exceeds their actual balance.

Root Cause

In transaction_processor.py:calculate_distribution_amounts():

  1. Line 769-770: Proportion is calculated as client_balance / total_confirmed_deposits
  2. Line 814: Fiat equivalent is calculated from the full transaction amount
  3. Line 894-896: Safety check correctly catches mismatch and refuses payment

The proportion calculation assumes total_confirmed_deposits >= transaction_fiat_amount, which is false when there are "orphan funds" in the machine.

Orphan Funds Sources

  • Direct cash deposits to ATM not registered in satmachineadmin
  • Testing transactions
  • Balances from deleted/migrated clients
  • Manual adjustments not reflected in the system

Current Behavior

  • Small transactions (100 GTQ) succeed because proportional allocations stay under individual balances
  • Large transactions (2000 GTQ) fail completely - no distributions occur
  • Commission is still extracted and sent to commission wallet
  • Source wallet is credited but sats remain there instead of going to clients

Proposed Solutions

# In calculate_distribution_amounts():
if total_confirmed_deposits < fiat_amount:
    logger.warning(f"Sync issue detected: tracked balances ({total_confirmed_deposits}) < transaction ({fiat_amount})")
    # Cap each client's allocation to their remaining balance
    # Track orphan amount separately
    orphan_fiat = fiat_amount - total_confirmed_deposits

Each client receives sats equivalent to their full remaining balance, orphan funds go to a designated wallet or stay in source.

Option 2: Proportional scaling

Scale down all allocations proportionally so total distributed equals total tracked balances, not transaction amount.

Option 3: Require manual reconciliation

Refuse to process transactions when out of sync, alert admin for manual intervention.

Acceptance Criteria

  • Large transactions process successfully when sync mismatch exists
  • Clients receive sats proportional to their actual remaining balances
  • Orphan funds are tracked/logged for reconciliation
  • No client receives more sats than their fiat balance entitles them to
## Problem When the physical cash in the ATM machine exceeds the sum of all tracked client balances in satmachineadmin, DCA distributions fail for all clients. ### Example from logs (2025-12-31) ``` Transaction: 2000 GTQ → 317,700 sats Total tracked client balances: ~700 GTQ Distribution calculation (proportional share): ├── Client 5XweGGWg: 690/700 = 98.57% → 1971.45 GTQ allocated ├── Client YqrSBUUV: 7.54/700 = 1.08% → 21.55 GTQ allocated ├── Client j8swYGRT: 2.38/700 = 0.34% → 6.80 GTQ allocated └── Client EjQ8Nqvj: 0.07/700 = 0.01% → 0.20 GTQ allocated ``` **Result**: All 4 client payments refused because each allocation exceeds their actual balance. ### Root Cause In `transaction_processor.py:calculate_distribution_amounts()`: 1. **Line 769-770**: Proportion is calculated as `client_balance / total_confirmed_deposits` 2. **Line 814**: Fiat equivalent is calculated from the full transaction amount 3. **Line 894-896**: Safety check correctly catches mismatch and refuses payment The proportion calculation assumes `total_confirmed_deposits >= transaction_fiat_amount`, which is false when there are "orphan funds" in the machine. ### Orphan Funds Sources - Direct cash deposits to ATM not registered in satmachineadmin - Testing transactions - Balances from deleted/migrated clients - Manual adjustments not reflected in the system ### Current Behavior - Small transactions (100 GTQ) succeed because proportional allocations stay under individual balances - Large transactions (2000 GTQ) fail completely - no distributions occur - Commission is still extracted and sent to commission wallet - Source wallet is credited but sats remain there instead of going to clients ## Proposed Solutions ### Option 1: Cap allocations to remaining balance (Recommended) ```python # In calculate_distribution_amounts(): if total_confirmed_deposits < fiat_amount: logger.warning(f"Sync issue detected: tracked balances ({total_confirmed_deposits}) < transaction ({fiat_amount})") # Cap each client's allocation to their remaining balance # Track orphan amount separately orphan_fiat = fiat_amount - total_confirmed_deposits ``` Each client receives sats equivalent to their **full remaining balance**, orphan funds go to a designated wallet or stay in source. ### Option 2: Proportional scaling Scale down all allocations proportionally so total distributed equals total tracked balances, not transaction amount. ### Option 3: Require manual reconciliation Refuse to process transactions when out of sync, alert admin for manual intervention. ## Acceptance Criteria - [ ] Large transactions process successfully when sync mismatch exists - [ ] Clients receive sats proportional to their actual remaining balances - [ ] Orphan funds are tracked/logged for reconciliation - [ ] No client receives more sats than their fiat balance entitles them to
Author
Owner

Fixed in commit 545a028 on main.

The sync mismatch detection now caps each client's allocation to their remaining fiat balance equivalent in sats. Orphan sats are tracked and logged for reconciliation.

Fixed in commit 545a028 on main. The sync mismatch detection now caps each client's allocation to their remaining fiat balance equivalent in sats. Orphan sats are tracked and logged for reconciliation.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: aiolabs/satmachineadmin#1
No description provided.