Skip to main content

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.

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.
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.

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 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

1

Clone the repository

git clone https://github.com/geodeag/geode-settler.git
cd geode-settler
2

Install dependencies

npm install
The settler has only three dependencies: express, ethers, and cors.
3

Configure environment

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
4

Start the settler

npm start
The settler will print its configuration, start the settlement loop, and listen for intents on port 3003.

Configuration

VariableRequiredDefaultDescription
SETTLER_PRIVATE_KEYPrivate key for the settler wallet. Must have ETH for gas.
HOOK_ADDRESS⚠️Deployed GeodeHook address. Without this, auto-settlement is disabled.
RPC_URLNohttp://localhost:8545JSON-RPC endpoint
SETTLE_INTERVAL_MSNo2000How often to check for pending intents (ms)
PORTNo3003HTTP API port
INDEXER_URLNohttps://indexer.geode.agIndexer API for auto pool discovery
INDEXER_SYNC_INTERVAL_MSNo30000How often to re-sync pools from the indexer (ms)
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.

Automatic Pool Discovery

The settler automatically discovers all launched tokens by syncing with the Geode 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
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.

API Reference

Submit Intent

POST /intents
Content-Type: application/json
Submit a signed Permit2 intent for batch settlement.
{
  "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..."
  }
}
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.

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:

Settlement Fees

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.

Gas Reimbursement

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.

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:
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 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
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.

Source Code

The settler is open-source under the MIT license: