> For the complete documentation index, see [llms.txt](https://docs.fast.poker/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fast.poker/for-operators-dealer-service/config.md).

# Configuration

The packaged Dealer Service has two local configuration surfaces:

* `.env` next to the binary for first-run values: dashboard host and port, dashboard login, RPC endpoints, `DEALER_HOME`, `CRANK_DATA_DIR`, and the dealer keypair path.
* `data/crank-config.json` for hot-reloadable crank behavior.

The binary can print the machine-readable crank schema with:

```bash
./dealer config-options
./dealer config-options --json
```

The crank config is hot-reloaded every 5 seconds. Only a subset of fields take effect hot; the rest require a restart.

## File location

Packaged binary layout:

```
dealer
.env
data/
  keypair.json
  auth.json
  api-token
  crank-config.json
  crank-control.json
  crank-heartbeat.json
  crank-metrics.json
  .crank.pid
```

`./dealer init` writes `.env` and can create or import `data/keypair.json`. The crank writes `data/crank-config.json` with defaults if the file does not exist. Set `DEALER_HOME=/path/to/state` to use a different state directory.

## `.env` (first-run values)

`.env` holds the values the binary needs before the crank starts. `./dealer init` writes it for you; edit it directly to change them. Never commit `.env` or any keypair file.

Required:

| Key                  | Purpose                                         |
| -------------------- | ----------------------------------------------- |
| `L1_RPC`             | Your Solana L1 RPC endpoint.                    |
| `TEE_RPC`            | The MagicBlock / TEE endpoint.                  |
| `CRANK_KEYPAIR_PATH` | Absolute path to the operator (dealer) keypair. |

Optional:

| Key                                            | Purpose                                                    |
| ---------------------------------------------- | ---------------------------------------------------------- |
| `L1_PAYER_KEYPAIR`                             | Separate L1 fee payer; defaults to the operator keypair.   |
| `DEALER_PORT` / `DEALER_HOST`                  | Dashboard bind address (default `127.0.0.1:3847`).         |
| `DEALER_HOME`                                  | Move all runtime state out of `data/`.                     |
| `CRANK_DATA_DIR`                               | Override just the crank state directory (default `data/`). |
| `LASERSTREAM_API_KEY` / `LASERSTREAM_ENDPOINT` | Optional Yellowstone/LaserStream gRPC streaming.           |

Program IDs are baked into the binary; operators supply only their own RPC and keypairs.

## Core schema

```json
{
  "l1_rpc": "https://your-solana-rpc.example",
  "tee_rpc": "https://your-magicblock-tee-rpc.example",
  "crank_keypair_path": "",
  "l1_payer_keypair_path": "",
  "table_filter_mode": "none",
  "table_whitelist": [],
  "table_blacklist": [],
  "table_no_start": [],
  "sng_pool_filter_mode": "none",
  "sng_pool_whitelist": [],
  "sng_pool_blacklist": [],
  "accepted_mints": [],
  "laserstream_enabled": false,
  "laserstream_api_key": "",
  "laserstream_endpoint": "",
  "removal_sweep_interval": 30000,
  "rake_sweep_interval": 60000,
  "timeout_ms": 30000,
  "cash_reward_snapshot_min_rake_base_units": 1000000,
  "crank_sng": true,
  "crank_cash": true,
  "process_cashouts": true,
  "auto_kick": true,
  "timeout_enabled": true,
  "verbose_logging": true,
  "rake_sweep": false,
  "auction_sweep": true,
  "create_sng_tables": true,
  "game_types": {
    "cash": true,
    "sng_2max": true,
    "sng_6max": true,
    "sng_9max": true
  },
  "auto_forward": {
    "enabled": false,
    "threshold_sol": 1,
    "destination": "",
    "reserve_sol": 0.1
  },
  "limits": {
    "max_concurrent_tables": 0
  },
  "funding": {
    "allow_runtime_keypair_generation": false,
    "l1_payer_warn_sol": 0.1,
    "l1_payer_sng_setup_floor_sol": 0.12,
    "tee_payer_l1_floor_sol": 0.02,
    "tee_payer_er_floor_sol": 0.01,
    "tee_payer_startup_topup_sol": 0.05,
    "tee_payer_warn_sol": 0.02,
    "tee_payer_refill_threshold_sol": 0.01,
    "tee_payer_refill_sol": 0.05,
    "funder_enabled": false,
    "funder_target_sol": 0.25,
    "funder_refill_threshold_sol": 0.05,
    "funder_warn_sol": 0.1,
    "escrow_topup_sol": 0.05
  },
  "dealing": {
    "sol": { "enabled": true, "require_tips": false },
    "spl": { "enabled": true, "require_tips": false }
  }
}
```

## Field reference

### `l1_rpc` and `tee_rpc` (string)

RPC endpoints for Solana L1 and the configured MagicBlock / TEE environment.

Restart required to change.

### `crank_keypair_path` and `l1_payer_keypair_path` (string)

`crank_keypair_path` is the dealer/operator wallet. `l1_payer_keypair_path` is an optional separate fee payer for L1 transactions. If omitted, the dealer uses the operator wallet created or imported by `./dealer init`.

Restart required to change.

### `table_filter_mode` (string)

How tables are picked up by discovery.

| Value         | Behavior                                            |
| ------------- | --------------------------------------------------- |
| `"none"`      | Track every active table found on L1                |
| `"whitelist"` | Track only tables in `table_whitelist`              |
| `"blacklist"` | Track every table EXCEPT those in `table_blacklist` |

Restart required to change. Note: changing this at runtime does not untrack tables the dealer is already managing. To fully isolate, stop the dealer, change the mode, restart.

### `table_whitelist` (string\[])

List of Table PDA pubkeys. Used only when `table_filter_mode` is `"whitelist"`.

Restart required to take effect.

### `table_blacklist` (string\[])

List of Table PDA pubkeys. Used only when `table_filter_mode` is `"blacklist"`.

Restart required to take effect.

### `table_no_start` (string\[])

List of cash table pubkeys where the dealer may perform maintenance and cashout work, but will not start new hands.

Restart required to take effect.

### `sng_pool_filter_mode`, `sng_pool_whitelist`, `sng_pool_blacklist`

SNG pool filters use `gameType:tier` pairs. Use `"none"` to accept every pool, `"whitelist"` to operate only selected pools, or `"blacklist"` to skip selected pools.

Restart required to take effect.

### `accepted_mints` (string\[])

Optional token-mint filter. Empty means the dealer accepts all supported table denominations.

Restart required to take effect.

### `laserstream_enabled` (boolean)

Set to `true` to use Helius LaserStream gRPC for real-time L1 Table account updates. Reduces reliance on `getProgramAccounts` polling, useful at scale.

Requires `laserstream_api_key`. Restart required to change.

### `laserstream_api_key` and `laserstream_endpoint` (string)

Helius API key and LaserStream endpoint. Keep API keys out of public repos; the dealer expects them in `crank-config.json`.

### `removal_sweep_interval` (number, default 30000)

How often the dealer sweeps for inactive cash seats.

Restart required to change.

### `rake_sweep_interval` (number, default 60000)

How often the dealer sweeps rake and operator rewards when `rake_sweep` is enabled.

Restart required to change.

### `timeout_ms` (number, default 30000)

How long the dealer waits before submitting the timeout path. The on-chain program enforces a 15 second minimum.

Restart required to change.

### `cash_reward_snapshot_min_rake_base_units` (number, default 1000000)

Minimum cash-table rake delta, in lamports or token base units, before the dealer sends an ER reward snapshot commit.

Restart required to change.

### Runtime toggles

Each top-level toggle is re-read from `crank-config.json`.

| Toggle              | Default | Effect when false                                                 |
| ------------------- | ------- | ----------------------------------------------------------------- |
| `crank_sng`         | `true`  | Sit-and-Go tables are ignored                                     |
| `crank_cash`        | `true`  | Cash tables are ignored                                           |
| `process_cashouts`  | `true`  | Cashout pipeline does not advance `Leaving` seats                 |
| `auto_kick`         | `true`  | `SittingOut > 5min` seats are not removed                         |
| `timeout_enabled`   | `true`  | `handle_timeout` is never submitted, idle players never auto-fold |
| `verbose_logging`   | `true`  | Detailed crank diagnostics are reduced                            |
| `rake_sweep`        | `false` | Periodic rake/reward sweep is not run automatically               |
| `auction_sweep`     | `true`  | Listing-auction sweeps are not run automatically                  |
| `create_sng_tables` | `true`  | Dealer will not create replacement SNG tables for eligible pools  |

Flipping `crank_sng` or `crank_cash` to false is the recommended way to wind down a dealer before stopping it.

### `game_types`

Granular switches for `cash`, `sng_2max`, `sng_6max`, and `sng_9max`.

Restart required to change.

### `limits`

Operator runtime limits. `limits.max_concurrent_tables = 0` means no explicit table-count limit.

Restart required to change.

### `funding`

MagicBlock fee-payer and escrow funding thresholds. These values control warning levels, top-up thresholds, and whether the funder subsystem is enabled.

Restart required to change.

### `dealing`

Per-currency dealing preferences for SOL and SPL-token tables. `require_tips` can restrict dealing to tipped tables for that currency.

Restart required to change.

### `credit_to` (string)

Wallet to credit all crank reward weight to. The signer/payer pays gas; this wallet earns and never needs to load on the server. Empty = credit the operator signer itself. The credited wallet must hold a dealer license or the weight earns nothing. Full how-to: [Reward routing (credit\_to)](/for-operators-dealer-service/credit-to-routing.md).

Hot-reloaded.

### `fleet` (object)

Multi-instance topology. Absent or `enabled: false` = single box (role `all`).

| Field                               | Meaning                                 |
| ----------------------------------- | --------------------------------------- |
| `enabled`                           | Run as a fleet.                         |
| `servicers`                         | Number of dealing instances (1-16).     |
| `discovery` / `settler` / `sweeper` | Run those roles as dedicated instances. |

Also `fleet_mode` (`auto` = lone box deals all; `strict` = fail-closed when not a servicer) and `fleet_stale_ms` (ignore a shard map older than this). Each TEE-committing instance needs its own funded `tee-payer-keypair.json`. Full guide: [Fleet and sharding setup](/for-operators-dealer-service/fleet-setup.md). Restart to change.

### `rpc_governor` (object)

Opt-in per-channel RPC rate limiter (token-bucket RPS + in-flight cap). Default off. Per channel `l1` / `tee`: `enabled`, `max_rps` (0 = off), `max_inflight` (0 = off), `max_queue`, `max_wait_ms` (fail-open guard), `ws_exempt`; plus top-level `backoff_on_failure`. Fail-open by design, so it never stalls dealing. Per-instance, so divide your target RPS by the instance count. Panic switch: `CRANK_RPC_GOVERNOR=0`. Full reference: [RPC governor](/for-operators-dealer-service/rpc-governor.md).

Hot-reloaded.

### `alt_reclaim` (object)

Automatic dead-ALT (address lookup table) rent-reclaim sweep. `enabled` (default true), `interval_ms` (sweep cadence), `min_age_hours` (only reclaim tables idle this long, default 24), `max_ops_per_sweep` (cap close/deactivate txs per pass), `recipient` (empty = the authority wallet). Fail-open; never touches live or the global ALT.

Hot-reloaded.

### `streaming` (object)

L1 account streaming over Yellowstone gRPC, decoupled from the polling `l1_rpc`. `enabled`, `provider` (`helius` / `triton` / `quicknode` / `custom`, a hint for endpoint/auth format), `endpoint`, `auth_token`. This is the current way to configure gRPC streaming; the `laserstream_*` keys are still read as a fallback.

Restart required to change.

### `tee_blockhash_cache` (object)

Cache the TEE blockhash to remove the `getLatestBlockhash` round-trip from each send. `enabled` (default false), `ttl_ms`, `refresh_ms`. A dedup guard never reuses a blockhash twice. Restart to (de)activate the background refresher.

### `priority_fee` (object)

L1 priority-fee policy. `enabled`, `override_microlamports`, `refresh_ms`, `fallback_microlamports`, `max_microlamports`, `priority_level` (one of `Min`, `Low`, `Medium`, `High`, `VeryHigh`, `UnsafeMax`).

Hot-reloaded.

### `subscriptions` (object)

Optional WebSocket subscriptions to cut RPC polling. `signature_subscribe` confirms sends over WS with a poll fallback. Hot-reloaded.

### `confirmation_poll_ms` (number, default 500)

How often the crank polls for transaction confirmation when not using a subscription. Lower = faster confirms, more RPC load. Hot-reloaded.

### `closeout` (object)

SNG prize-closeout tuning: CAU seat-undelegate batch size (capped at 4) and L1 relay poll attempts + backoff. Hot-reloaded.

This tunes transport/retry behavior only. It does not disable `SngSettlementRecord`, Flat Bounty payout gates, jackpot-entry closure, or clean-table assertions.

### Governed SNG settings are not dealer config

The dealer reads and passes global `EmissionCtrl` plus the matching 83-byte `PoolIdle` for each format/tier. Demand target/floor, retain rates, idle caps, and pool caps are authority-governed on chain; they are not fields in `crank-config.json`. Jackpot base denominators are likewise read from `JackpotGlobal`.

Every 6-max/9-max table uses canonical Flat Bounty ruleset 1. Operators cannot select a legacy bounty, shield, tiebreak, retention, or burn mode in local configuration.

### Cross-instance coordination

There is no coordination broker. When you run more than one dealer instance (a fleet), instances coordinate purely through a local **shard map** file plus a per-instance stand-down guard, so no two instances crank the same table. There is no network service and nothing to configure here. On-chain program checks remain the source of correctness, so the coordination layer only avoids wasted duplicate work, never acting as a custody or gameplay authority.

See [Fleet and sharding setup](/for-operators-dealer-service/fleet-setup.md) for how a fleet is sized and run.

## What does NOT hot-reload

* All `*_keypair_path` fields
* `l1_rpc`, `tee_rpc`, and LaserStream endpoint settings
* `table_filter_mode`, `table_whitelist`, `table_blacklist`, `table_no_start`
* SNG pool filters and accepted mint filters
* Game-type, limit, funding, and dealing settings
* Interval values (`removal_sweep_interval`, `rake_sweep_interval`, `timeout_ms`)
* `laserstream_*` settings

If you change one of these, write `data/crank-control.json` with `{"action":"restart"}` or run `./dealer service restart` for a managed service.

## Auto-forward (advanced)

Optional. Forwards SOL above a reserve to a destination wallet automatically. Disabled by default.

| Field                        | Purpose                                            |
| ---------------------------- | -------------------------------------------------- |
| `auto_forward.enabled`       | Master switch                                      |
| `auto_forward.threshold_sol` | Forward when wallet balance is above this amount   |
| `auto_forward.destination`   | Destination pubkey                                 |
| `auto_forward.reserve_sol`   | SOL kept in the dealer wallet for transaction fees |

Leaving this off is the right default. Turn it on only if you understand the funds flow.
