> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mycryptoserver.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sweep

> How funds are moved from deposit addresses to your payout wallet

After a payment is confirmed, My Crypto Server **sweeps** the funds from the deposit address to your configured payout wallet. This keeps deposit addresses clean and moves money to where you actually want it.

## What triggers a sweep

Sweeps are triggered automatically after finality is confirmed. Three callers can initiate a sweep:

1. **Inline finalize** — the `paymentVerify` Inngest workflow triggers sweep immediately after marking the session `paid`.
2. **Manual retry** — the dashboard's Payouts page lets you retry failed sweeps.
3. **Hourly cron** — the `reconcileAlchemy` job also catches any sessions that slipped through.

All three callers use the same atomic claim mechanism — only one will ever succeed at a time.

## The sweep state machine

```
                ┌── atomic claim (UPDATE…RETURNING) ──┐
                │  only one caller wins → "sweeping"  │
                └──────────────────────────────────────┘
pending ──►  sweeping ──(token only)──► gas_funded ──► broadcasting ──► swept
               │                                             │
               └── failed (notify merchant)                  │ hash persisted
                                                             │ before confirm
skipped (dust / no balance / misconfigured address)
```

### Stage descriptions

| Stage          | Meaning                                                         |
| -------------- | --------------------------------------------------------------- |
| `pending`      | Sweep not yet started                                           |
| `sweeping`     | Claimed by a worker — being processed                           |
| `gas_funded`   | For ERC-20 tokens: gas wallet has topped up the deposit address |
| `broadcasting` | Transaction signed and submitted to the chain                   |
| `swept`        | Confirmed — funds landed in the payout wallet                   |
| `failed`       | An error occurred — merchant is notified                        |
| `skipped`      | Intentionally skipped (see below)                               |

## Atomic claim: no double-sweeps

The sweep uses an `UPDATE … RETURNING` query that only succeeds if the payout row's stage is `pending`, `failed`, or `skipped` — or if it's been in `sweeping`, `gas_funded`, or `broadcasting` for more than 10 minutes (treated as a crashed worker). If the claim returns no rows, another worker owns it and this caller exits.

This is the single mechanism that prevents two callers from broadcasting competing transactions.

## Crash safety: hash persisted before confirm

The transaction hash is written to the database the instant the transaction is broadcast, before waiting for the receipt. If the process crashes between broadcast and confirm, the hash is already recorded. When sweep is retried, it detects `balance == 0` + `sweepTxHash is set` and marks the payout `swept` without re-broadcasting.

## When sweeps are skipped

| Reason          | Description                                                                              |
| --------------- | ---------------------------------------------------------------------------------------- |
| `dust`          | USD value is below your configured `sweepMinUsd` threshold                               |
| `no_balance`    | Deposit address balance is 0 and no hash was recorded                                    |
| `misconfigured` | Payout address for this chain is not set. A `payout_misconfigured` notification is sent. |
| `provider_paid` | Session was paid via a hosted provider (e.g. Binance Pay) — no on-chain funds to sweep   |

Manual retries bypass the dust filter — if you click Retry on a low-value payout, it sweeps regardless of `sweepMinUsd`.

## Token sweeps

For ERC-20 tokens, the deposit address typically has no native gas (ETH) to pay for the transfer. The sweep handles this automatically:

1. The gas wallet sends a small ETH top-up to the deposit address (`gas_funded` stage).
2. The deposit address uses that ETH to call the ERC-20 `transfer()` function to the payout wallet.

## Payout address configuration

Configure your payout address in the dashboard under **Settings → Wallet**. You need one address per chain kind (EVM, Solana, Bitcoin, Tron). EVM addresses are run through checksum validation before any transfer — a corrupted address throws rather than sending funds to a wrong address.
