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

# Settler Bot

> Run a permissionless settlement service for Geode — earn fees by batching and executing signed intents on-chain.

## What is a Settler?

A settler is an off-chain service that collects signed trade intents from users, batches them by pool, and calls `geodeSettleBatch()` on the GeodeHook contract. In return, the settler earns settlement fees and gas reimbursement from the protocol.

<Info>
  **Settlement is permissionless** — anyone can run a settler. The first valid batch submitted for a given settlement window wins the fees. This creates competitive dynamics that ensure intents are settled promptly.
</Info>

## Architecture

```
User signs intent (Permit2)         Settler Bot
        │                     ┌─────────────────────┐
        └──── POST /intents ──►  Intent Queue        │
                              │  (per pool)          │
                              │       │              │
  Indexer (indexer.geode.ag)  │  every 2 seconds     │
        │                     │       │              │
        └──── GET /tokens ───►│  Auto-discover pools │
              (every 30s)     │       ▼              │
                              │  geodeSettleBatch()  │
                              │       │              │
                              │  ┌────┴────┐         │
                              │  ▼         ▼         │
                              │ Fees    Gas Reimb    │
                              │ (0.1%)  (from surplus)│
                              └─────────────────────┘
```

The settler operates a lightweight HTTP API that:

1. **Syncs** with the [Indexer](/indexer) to auto-discover all launched token pools
2. **Receives** signed Permit2 intents from the frontend or any client
3. **Validates** intent fields (addresses, amounts, deadlines)
4. **Queues** intents as buys or sells per pool
5. **Settles** by calling `geodeSettleBatch()` on-chain every settlement cycle
6. **Earns** settlement fees + gas reimbursement

## Quick Start

<Steps>
  <Step title="Clone the repository">
    ```bash theme={null}
    git clone https://github.com/Geode-vAMM/geode-settler.git
    cd geode-settler
    ```
  </Step>

  <Step title="Install dependencies">
    ```bash theme={null}
    npm install
    ```

    The settler has only three dependencies: `express`, `ethers`, and `cors`.
  </Step>

  <Step title="Configure environment">
    ```bash theme={null}
    cp .env.example .env
    ```

    Edit `.env` and set:

    * `SETTLER_PRIVATE_KEY` — your settler wallet's private key
    * `HOOK_ADDRESS` — the deployed GeodeHook contract address
    * `RPC_URL` — your Ethereum JSON-RPC endpoint
  </Step>

  <Step title="Start the settler">
    ```bash theme={null}
    npm start
    ```

    The settler will print its configuration, start the settlement loop, and listen for intents on port 3003.
  </Step>
</Steps>

## Configuration

| Variable                   | Required | Default                    | Description                                                            |
| -------------------------- | -------- | -------------------------- | ---------------------------------------------------------------------- |
| `SETTLER_PRIVATE_KEY`      | ✅        | —                          | Private key for the settler wallet. Must have ETH for gas.             |
| `HOOK_ADDRESS`             | ⚠️       | —                          | Deployed GeodeHook address. Without this, auto-settlement is disabled. |
| `RPC_URL`                  | No       | `http://localhost:8545`    | JSON-RPC endpoint                                                      |
| `SETTLE_INTERVAL_MS`       | No       | `2000`                     | How often to check for pending intents (ms)                            |
| `PORT`                     | No       | `3003`                     | HTTP API port                                                          |
| `INDEXER_URL`              | No       | `https://indexer.geode.ag` | Indexer API for auto pool discovery                                    |
| `INDEXER_SYNC_INTERVAL_MS` | No       | `30000`                    | How often to re-sync pools from the indexer (ms)                       |

<Warning>
  **Never commit your `.env` file.** The settler's private key controls a wallet that holds ETH. Use environment variables or a secrets manager in production.
</Warning>

## Automatic Pool Discovery

The settler automatically discovers all launched tokens by syncing with the [Geode Indexer](/indexer):

1. **On startup** — fetches all tokens from `INDEXER_URL/tokens` and registers their pools
2. **Every 30 seconds** — re-syncs to discover newly launched tokens
3. **No manual registration needed** — any coin launched via the Launchpad is automatically available for settlement

<Info>
  The settler reconstructs pool keys from token data (sorting WETH and the token address to determine `currency0`/`currency1`). If you're running your own indexer, set `INDEXER_URL` to point to it.
</Info>

## API Reference

### Submit Intent

```
POST /intents
Content-Type: application/json
```

Submit a signed Permit2 intent for batch settlement.

```json theme={null}
{
  "intent": {
    "poolId": "0x...",
    "owner": "0x...",
    "tokenIn": "0x...",
    "tokenOut": "0x...",
    "amountIn": "1000000000000000000",
    "minAmountOut": "990000000000000000",
    "deadline": 1715200000,
    "nonce": 1
  },
  "signature": "0x...",
  "poolKey": {
    "currency0": "0x...",
    "currency1": "0x...",
    "fee": 3000,
    "tickSpacing": 60,
    "hooks": "0x..."
  }
}
```

<Note>
  The `poolKey` is required on the first intent for a new pool — the settler uses it to auto-register the pool. Subsequent intents for the same `poolId` can omit it.
</Note>

### View Pending Intents

```
GET /intents/:poolId
```

Returns the current buy/sell queue for a pool. Useful for frontends to check if a user's intent is still pending.

### Force Settlement

```
POST /settle/:poolId
```

Trigger immediate settlement for a pool (bypasses the interval timer). Returns the transaction hash and gas used.

### Register Pool

```
POST /pools/register
```

Manually register a pool for the settler to watch.

### List Pools

```
GET /pools
```

Returns all registered pools with their pending intent counts and on-chain settlement status.

### Health Check

```
GET /health
```

Returns settler status, connected hook address, pool count, and uptime.

### Statistics

```
GET /stats
```

Returns cumulative settlement statistics (total settlements, intents processed, errors).

## Economics

Settlers earn revenue from two sources:

<CardGroup cols={2}>
  <Card title="Settlement Fees" icon="coins">
    **0.1% of each filled intent's input amount.** Deducted before routing — the settler takes the unrouted fee deposit directly from the PoolManager. For a batch with 10 ETH total buy volume, the settler earns \~0.01 ETH in fees.
  </Card>

  <Card title="Gas Reimbursement" icon="gas-pump">
    **Gas cost × 1.5, capped at 0.01 ETH per batch.** Drawn from the pool's accumulated direct-swap fee surplus. This ensures settlers are made whole on gas even for small batches.
  </Card>
</CardGroup>

### Settler Profitability

A settler is profitable when:

```
settlement_fees + gas_reimbursement > gas_cost
```

Since gas reimbursement covers 1.5× the actual gas cost (up to the cap), **settlers are profitable from the first batch** — even before considering settlement fees. The settlement fees are pure profit on top of the gas subsidy.

### Wash Trade Resistance

Settlement fees are deducted from **both sides** of every trade. A wash trader pays 0.1% on the buy side AND 0.1% on the sell side, making wash trading strictly net-negative. The settler cannot inflate their revenue through self-trading.

## Permit2 Integration

The settler's `permit2.js` module provides utilities for working with Geode's Permit2 integration:

```javascript theme={null}
import {
  buildPermit2TypedData,  // Build EIP-712 message for signing
  signIntent,             // Sign an intent with a local wallet
  validateIntent,         // Validate intent fields
  computeWitnessHash,     // Compute the GeodeWitness hash
  PERMIT2_TYPES,          // EIP-712 type definitions
} from './permit2.js';
```

The witness type appended to the standard Permit2 `PermitWitnessTransferFrom`:

```
GeodeWitness(bytes32 poolId, address tokenOut, uint256 minAmountOut)
```

See the [Intents documentation](/intents) for the full EIP-712 signing flow.

## Running Multiple Settlers

Multiple settlers can operate on the same network simultaneously:

* Each settler maintains its own intent queue independently
* The first settler to submit a valid batch for a given block window earns the fees
* Settlers compete on latency and intent coverage — omitting valid intents leaves fees for competitors
* The protocol enforces one settlement per batch interval per pool

<Note>
  **For integrators**: You can build custom settlers with different strategies — e.g., settling only high-value batches, or running a private intent relay for specific pools. The `geodeSettleBatch()` function is permissionless and accepts any valid set of signed intents.
</Note>

## Source Code

The settler is open-source under the MIT license:

* **GitHub**: [Geode-vAMM/geode-settler](https://github.com/Geode-vAMM/geode-settler)
* **Dependencies**: `express`, `ethers v6`, `cors`
* **Runtime**: Node.js ≥ 18
