Torch Liquidation Bot
Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions using the SDK's bulk lo...
Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions using the SDK's bulk lo...
Real data. Real impact.
Growing
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Autonomous vault-based liquidation keeper for Torch Market lending on Solana.
Every migrated token on Torch has a built-in lending market. Holders lock tokens as collateral and borrow SOL from the community treasury (depth-adaptive LTV 25-50%, 2% weekly interest). When a loan's LTV crosses 65%, it becomes liquidatable. Anyone can liquidate it and collect a 10% bonus on the collateral value.
This bot scans every migrated token's lending market using the SDK's bulk loan scanner (
getAllLoanPositions) -- one RPC call per token returns all active positions pre-sorted by health. When it finds one that's underwater, it liquidates it through your vault.
This is not a read-only scanner. This is a fully operational keeper that generates its own keypair, verifies vault linkage, and executes liquidation transactions autonomously in a continuous loop.
┌──────────────────────────────────────────────────────────┐ │ LIQUIDATION LOOP │ │ │ │ 1. Discover migrated tokens (getTokens) │ │ 2. For each token, scan all loans (getAllLoanPositions) │ │ -- single RPC call, positions sorted by health │ │ -- liquidatable -> at_risk -> healthy │ │ 3. Skip tokens with no active loans │ │ 4. For each liquidatable position: │ │ -> buildLiquidateTransaction(vault=creator) │ │ -> sign with agent keypair │ │ -> submit and confirm │ │ -> break when health != 'liquidatable' (pre-sorted) │ │ 5. Sleep SCAN_INTERVAL_MS, repeat │ │ │ │ All SOL comes from vault. All collateral goes to vault. │ │ Agent wallet holds nothing. Vault is the boundary. │ └──────────────────────────────────────────────────────────┘
The bot generates a fresh
Keypair in-process on every startup. No private key file. No environment variable (unless you want to provide one). The keypair is disposable -- it signs transactions but holds nothing of value.
On first run, the bot checks if this keypair is linked to your vault. If not, it prints the exact SDK call you need to link it. Link it from your authority wallet, then restart.
Human (authority) Agent (controller, ~0.01 SOL gas) ├── createVault() ├── liquidate(vault) -> SOL from vault ├── depositVault(SOL) └── collateral tokens -> vault ATA ├── linkWallet(agent) ├── withdrawVault() <- auth only ├── withdrawTokens() <- auth only └── unlinkWallet() <- instant
| Guarantee | Mechanism |
|---|---|
| Full custody | Vault holds all SOL and tokens. Controller holds nothing. |
| Closed loop | SOL from vault pays debt, collateral tokens to vault. No leakage. |
| Authority separation | Creator (immutable) / Authority (transferable) / Controller (disposable) |
| Instant revocation | Authority unlinks controller in one tx |
| No extraction | Controllers cannot withdraw. Period. |
npm install torch-liquidation-bot
Or use the bundled source from ClawHub -- the Torch SDK is included in
lib/torchsdk/ and the bot source is in lib/kit/.
From your authority wallet:
import { Connection } from "@solana/web3.js"; import { buildCreateVaultTransaction, buildDepositVaultTransaction, } from "torchsdk";const connection = new Connection(process.env.SOLANA_RPC_URL);
// Create vault const { transaction: createTx } = await buildCreateVaultTransaction(connection, { creator: authorityPubkey, }); // sign and submit with authority wallet...
// Fund vault with SOL for liquidations const { transaction: depositTx } = await buildDepositVaultTransaction(connection, { depositor: authorityPubkey, vault_creator: authorityPubkey, amount_sol: 5_000_000_000, // 5 SOL }); // sign and submit with authority wallet...
VAULT_CREATOR=<your-vault-creator-pubkey> SOLANA_RPC_URL=<rpc-url> npx torch-liquidation-bot
On first run, the bot prints the agent keypair and instructions to link it. Link it from your authority wallet, then restart.
| Variable | Required | Default | Description |
|---|---|---|---|
| Yes | -- | Solana RPC endpoint (HTTPS). Fallback: |
| Yes | -- | Vault creator pubkey |
| No | -- | Disposable controller keypair (base58 or JSON byte array). If omitted, generates fresh keypair on startup (recommended) |
| No | | Milliseconds between scan cycles (min 5000) |
| No | | Max tokens scanned per cycle ( = unlimited) |
| No | | Pause liquidations when agent gas balance drops below this |
| No | | , , , |
| No | | (human-readable) or (structured, one record per line) |
| Function | Returns |
|---|---|
| Token list (filterable, sortable) |
| Full detail: price, treasury, status |
| Lending parameters and pool state |
| All loans sorted by liquidation risk |
| Loan: collateral, debt, LTV, health |
| Vault state |
| Reverse vault lookup |
| VersionedTransaction (sign with ) |
| On-chain confirmation via RPC |
import { getTokens, getAllLoanPositions, buildLiquidateTransaction } from 'torchsdk'const { tokens } = await getTokens(connection, { status: 'migrated', sort: 'volume', limit: 50 })
for (const token of tokens) { const { positions } = await getAllLoanPositions(connection, token.mint)
for (const pos of positions) { if (pos.health !== 'liquidatable') break // pre-sorted, done
const { transaction, message } = await buildLiquidateTransaction(connection, { mint: token.mint, liquidator: agentPubkey, borrower: pos.borrower, vault: vaultCreator, }) transaction.sign([agentKeypair]) await connection.sendRawTransaction(transaction.serialize())} }
MAX_LTV 25-50% (depth-adaptive: 25% <50 SOL, 35% 50-200, 45% 200-500, 50% 500+) LIQ_THRESHOLD 65% INTEREST 2% per epoch (~7 days) LIQ_BONUS 10% UTIL_CAP 80% MIN_BORROW 0.1 SOL MIN_POOL_SOL 5 SOL (below this: margin ops blocked) PROGRAM_ID 8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT
If
SOLANA_PRIVATE_KEY is provided: must be a fresh disposable keypair (~0.01 SOL gas). All capital lives in vault. If compromised: attacker gets dust, authority revokes in one tx. Key never leaves the runtime.
If not provided: the bot generates a fresh keypair on startup (recommended).
Rules:
| Service | Purpose | When Called |
|---|---|---|
CoinGecko () | SOL/USD price for display | Token queries via |
Creator-controlled metadata URI (typically ) | Token metadata JSON | / — 10s fetch timeout, failure is non-fatal |
No credentials sent. All requests are read-only GET. No private key material is ever transmitted.
Requires Surfpool running a mainnet fork:
surfpool start --network mainnet --no-tui pnpm test
lib/torchsdk/ | npm | source8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeTNo automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.