Skip to content

Settler

The Settler is a dedicated service that handles thesis settlements for Kaizen Core. Instead of running settlement logic in the block production loop, settlements are offloaded to this service which monitors theses and submits settlement transactions.

Why Settler?

ApproachBlock ProductionSettlement LatencyScalability
In-block (old)Blocked during settlementCoupled to block timeLimited
Settler (current)UnblockedIndependentPer-pair parallelizable

Benefits:

  • Block producer only processes transactions
  • Streams events for breach detection
  • Can run separate settlers per trading pair
  • One pair's issues don't affect others

Architecture

Settler Architecture

Running

# Build
cargo build --release -p kaizen-settler
 
# All pairs (single settler)
./target/release/settler --write-node 127.0.0.1:9000
 
# Specific pair only
./target/release/settler --pairs BTC/USDT
 
# Multiple pairs
./target/release/settler --pairs BTC/USDT,ETH/USDT
 
# Multiple settlers for different pairs
./target/release/settler --pairs BTC/USDT &
./target/release/settler --pairs ETH/USDT &
./target/release/settler --pairs SOL/USDT &

CLI Options

OptionDescriptionDefault
-w, --write-node <addr>Write node sync address127.0.0.1:9000
-r, --rpc-url <url>Kaizen Core RPC URLhttp://127.0.0.1:8545
-k, --private-key <key>Settler private key (hex, without 0x)From env
-p, --pairs <pairs>Comma-separated pairs (e.g., BTC/USDT,ETH/USDT). Empty for allEmpty (all)
--check-interval <ms>Settlement check interval100
--batch-size <n>Max settlements per batch100
--deadline-buffer <ms>Buffer added to challenge deadline before UserWins settlement200
--metrics-port <port>Metrics HTTP server port (0 to disable)9090
--data-dir <path>Data directory for persistent stateFrom env
--json-logsOutput logs in JSON formatfalse

Environment Variables

VariableDescription
SETTLER_PRIVATE_KEYSettler private key (hex, without 0x)
SETTLER_PAIRSComma-separated pairs to handle (empty = all)
SETTLER_DATA_DIRData directory for persistent state

Per-Pair Deployment

Run separate settler instances for each trading pair:

# Terminal 1: BTC/USDT settler
SETTLER_PAIRS=BTC/USDT ./target/release/settler
 
# Terminal 2: ETH/USDT settler
SETTLER_PAIRS=ETH/USDT ./target/release/settler
 
# Terminal 3: SOL/USDT settler
SETTLER_PAIRS=SOL/USDT ./target/release/settler

Advantages:

  • BTC settler crash doesn't affect ETH settlements
  • High-volume pairs can get dedicated resources
  • Separate logs per pair
  • Update one pair's settler without downtime

Settlement Flow

Settler Flow

Settlement Types

User Wins

When the observation period ends without any price breach:

SystemSettleTx {
    thesis_id: 42,
    settlement_type: SystemSettlementType::UserWins,
}
  • Submitted after thesis.challenge_deadline passes
  • User receives full payout
  • No breach evidence required

Solver Wins

When a price breach is detected during the observation period:

SystemSettleTx {
    thesis_id: 42,
    settlement_type: SystemSettlementType::SolverWins {
        breach_timestamp: 1700000500000,
        breach_price: 94500000000, // Below lower bound
    },
}
  • Submitted immediately upon breach detection
  • Solver receives full payout
  • Breach evidence (timestamp + price) is verified by Core

Breach Detection

The settler maintains a price cache and checks each active thesis against historical prices using parallel iteration:

// Parallel breach detection with rayon
let decisions: Vec<SettlementDecision> = theses
    .par_iter()
    .filter_map(|thesis| {
        if let Some((breach_ts, breach_price)) = find_breach(thesis, &state, now) {
            return Some(SettlementDecision::SolverWins { ... });
        }
        if now >= thesis.challenge_deadline {
            return Some(SettlementDecision::UserWins { ... });
        }
        None
    })
    .collect();

Key Points:

  • Price data is cached for the observation period (5 minutes)
  • Binary search for price lookup (O(log n))
  • Checks at 100ms intervals (matches oracle granularity)
  • Early exit on first breach

Core Integration

SystemSettle Transaction

The settler submits SystemSettle transactions which are processed by Kaizen Core:

pub struct SystemSettleTx {
    pub thesis_id: u64,
    pub settlement_type: SystemSettlementType,
}
 
pub enum SystemSettlementType {
    UserWins,
    SolverWins {
        breach_timestamp: u64,
        breach_price: u64,
    },
}

Permission Model

The settler uses a special Settler permission:

PermissionWhoWhat
UserAnyoneTrade, transfer
AdminOperatorsConfiguration
RelayerBridgeDeposits/withdrawals
FeederOraclePrice feeds
SettlerSettlerSettlement only

The settler address must be configured in Core's global config.

Breach Verification

When processing SolverWins, Core verifies:

  1. Thesis exists and is active
  2. Breach timestamp is within observation period
  3. Breach price exists in oracle history
  4. Breach price is outside price range

This prevents invalid settlement claims.

Token Addresses

Default token address mappings:

SymbolAddress
BTC0x0000000000000000000000000000000000000001
ETH0x0000000000000000000000000000000000000002
SOL0x0000000000000000000000000000000000000003
USDT0x0000000000000000000000000000000000000100

Error Handling

ErrorAction
Node disconnectedRetry connection, resume from last state
Settlement rejectedLog error, continue with next thesis
Invalid breachLog warning, skip thesis

Deployment

Docker

# All pairs
docker run -d \
  --name kaizen-settler \
  -e SETTLER_PRIVATE_KEY=... \
  kaizen/settler:latest \
  --write-node kaizen-node:9000
 
# Specific pair
docker run -d \
  --name kaizen-settler-btc \
  -e SETTLER_PRIVATE_KEY=... \
  -e SETTLER_PAIRS=BTC/USDT \
  kaizen/settler:latest \
  --write-node kaizen-node:9000

Docker Compose

services:
  settler-btc:
    image: kaizen/settler:latest
    command: --write-node kaizen-node:9000
    environment:
      - SETTLER_PRIVATE_KEY=${SETTLER_PRIVATE_KEY}
      - SETTLER_PAIRS=BTC/USDT
    depends_on:
      - kaizen-node
    restart: unless-stopped
 
  settler-eth:
    image: kaizen/settler:latest
    command: --write-node kaizen-node:9000
    environment:
      - SETTLER_PRIVATE_KEY=${SETTLER_PRIVATE_KEY}
      - SETTLER_PAIRS=ETH/USDT
    depends_on:
      - kaizen-node
    restart: unless-stopped
 
  settler-sol:
    image: kaizen/settler:latest
    command: --write-node kaizen-node:9000
    environment:
      - SETTLER_PRIVATE_KEY=${SETTLER_PRIVATE_KEY}
      - SETTLER_PAIRS=SOL/USDT
    depends_on:
      - kaizen-node
    restart: unless-stopped