Skip to content

UncapLabs/liquidation

Repository files navigation

Uncap Liquidation Bot

Automated liquidation bot for the Uncap Protocol on Starknet. Runs as a Cloudflare Worker on a per-minute cron schedule, monitoring and liquidating undercollateralized troves.

Versions

There are two versions of the bot, each on its own branch:

v1 (main branch) — this branch

  • Collateral: WWBTC (115% MCR)
  • JIT liquidation: Supported via LiquidationsKeeper (2-hop swap: WBTC -> USDC -> USDU)
  • Fallback: Redistribution when JIT fails (configurable)
  • Account config: Single LIQUIDATOR_ADDRESS / LIQUIDATOR_PRIVATE_KEY
  • Cloudflare Worker name: liquidation

v2 (add_collaterals branch)

  • Collaterals: WWBTC, TBTC, SOLVBTC
  • JIT liquidation: Supported via a new LiquidationsKeeper contract with multi-hop swap routes
    • WWBTC: WBTC -> USDC -> USDU (2 hops)
    • TBTC: TBTC -> WBTC -> USDC -> USDU (3 hops)
    • SOLVBTC: SOLVBTC -> WBTC -> USDC -> USDU (3 hops)
  • Fallback: Redistribution when JIT fails (configurable)
  • Account config: Network-specific credentials (LIQUIDATOR_ADDRESS_MAINNET / _SEPOLIA)
  • Cloudflare Worker name: liquidation-v2
v1 (main) v2 (add_collaterals)
Collaterals WWBTC WWBTC, TBTC, SOLVBTC
JIT swap hops 2 2 or 3 (depends on collateral)
LiquidationsKeeper contract v1 v2 (takes troveManager, stabilityPool, swap route)
Unwrapping WWBTC -> WBTC WWBTC -> WBTC (TBTC/SOLVBTC don't need unwrapping)
Account config Single key pair Network-specific key pairs

How It Works

Every minute the Cloudflare Worker cron trigger fires and the bot runs through these steps:

  1. Discover — queries a GraphQL indexer for trove candidates that look close to liquidation
  2. Price — fetches fresh on-chain prices from the PriceFeed contract
  3. Validate — reads latest on-chain debt/collateral for at-risk troves and computes their collateral ratio (CR)
  4. Batch — groups liquidatable troves (CR < MCR) by collateral type, packs them into batches of max 20 using a greedy algorithm that maximizes Stability Pool usage
  5. Execute — submits each batch using the best available liquidation strategy (see below)
  6. Unwrap — converts wrapped collateral rewards back to underlying tokens (WWBTC -> WBTC)

Liquidation Strategy

The bot picks the best strategy for each batch using a three-tier hierarchy:

Tier 1: Stability Pool

Used when the Stability Pool (SP) has enough USDU to cover the entire batch debt.

TroveManager.batch_liquidate_troves(troveIds)
  -> SP USDU pays off debt
  -> SP depositors receive collateral at ~5% discount

Tier 2: JIT (Just-In-Time)

Used when the SP doesn't have enough USDU. The bot flash-borrows the deficit and temporarily tops up the SP.

LiquidationsKeeper.liquidate(jitAmount, troveIds, usduUsdcPoolKey, usdcWbtcPoolKey)
  -> Flash borrow USDU deficit via Ekubo
  -> Deposit into SP temporarily
  -> Liquidate using full SP balance
  -> Swap WBTC back to USDU via Ekubo (WBTC -> USDC -> USDU)
  -> Repay flash loan
  -> Profit stays in the LiquidationsKeeper contract

Tier 3: Redistribution (fallback)

Used when JIT fails and ENABLE_REDISTRIBUTIONS is set to true.

TroveManager.batch_liquidate_troves(troveIds)
  -> Uses whatever SP USDU is available
  -> Remaining debt + collateral is redistributed to active borrowers

Decision Tree

Is SP sufficient for full batch debt?
├── YES -> Tier 1: Stability Pool liquidation
└── NO  -> Tier 2: JIT liquidation
          ├── Success -> Done (profit in keeper contract)
          └── Fail
              ├── ENABLE_REDISTRIBUTIONS=true  -> Tier 3: Redistribution
              └── ENABLE_REDISTRIBUTIONS=false -> Skip batch

Setup

Prerequisites

Install

pnpm install

Configure environment

Copy the example file and fill in your values:

cp .dev.vars.example .dev.vars
Variable Description
GRAPHQL_ENDPOINT URL of the GraphQL indexer
NETWORK sepolia or mainnet
NODE_URL Starknet RPC endpoint (e.g. Alchemy URL with API key)
LIQUIDATOR_ADDRESS Your Starknet account address
LIQUIDATOR_PRIVATE_KEY Your Starknet private key
ENABLE_REDISTRIBUTIONS true / false — fallback to redistribution if JIT fails

Running Locally

Start the worker in dev mode:

pnpm dev

In another terminal, trigger the cron manually:

curl "http://localhost:8787/__scheduled?cron=*+*+*+*+*"

Deploying to Cloudflare

1. Set secrets

Store secrets in Cloudflare (they're injected as env vars at runtime). You only need to do this once, or when rotating keys.

wrangler secret put GRAPHQL_ENDPOINT
wrangler secret put NETWORK
wrangler secret put NODE_URL
wrangler secret put LIQUIDATOR_ADDRESS
wrangler secret put LIQUIDATOR_PRIVATE_KEY
wrangler secret put ENABLE_REDISTRIBUTIONS

2. Deploy

pnpm deploy

This runs wrangler deploy, which uploads the worker and activates the cron trigger (* * * * * — every minute).

3. Monitor

Cloudflare Observability is enabled in wrangler.jsonc. View logs in the Cloudflare dashboard under Workers & Pages -> your worker -> Logs.

Architecture

Cron Trigger (every 1 min)
    |
    v
Indexer Service         -- GraphQL query for liquidatable candidates
    |
    v
Price Service           -- Fetch fresh on-chain prices per collateral
    |
    v
Validator Service       -- On-chain validation, filter by CR < MCR
    |
    v
Calculator Service      -- Greedy batch packing (SP batches + JIT batches)
    |
    v
Executor Service        -- Submit transactions (SP / JIT / redistribution)
    |
    v
Unwrap Rewards          -- WWBTC -> WBTC (if applicable)
Component File Role
Worker entry src/worker.ts Cloudflare Worker cron handler
Orchestrator src/run-liquidations.ts Coordinates all steps
Indexer src/services/indexer.ts GraphQL candidate discovery
Prices src/services/prices.ts On-chain price fetching
Validator src/services/validator.ts On-chain trove validation
Calculator src/services/calculator.ts Greedy batch packing algorithm
Executor src/services/executor.ts Transaction execution + unwrapping
Collaterals src/collaterals.ts Collateral config, MCR, contract addresses
Pool config src/pool-config.ts Ekubo DEX pool parameters for JIT swaps

GraphQL Codegen

If you modify GraphQL queries in src/graphql/documents.ts, regenerate types:

pnpm codegen

Safety Features

  • Fresh on-chain data — always validates prices, debt, and collateral before executing
  • Risk buffer — only fetches on-chain data for troves within 10% of MCR (saves RPC calls)
  • Error isolation — a failed batch does not stop the rest of the run
  • JIT fallback — configurable fallback to redistribution if JIT fails
  • Automatic unwrapping — WWBTC rewards are unwrapped to WBTC

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published