npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

torch-liquidation-bot

v4.0.2

Published

autonomous vault-based liquidation keeper for Torch Market lending on Solana using torchsdk

Readme

torch-liquidation-bot v4.0.2 (Vault Mode)

Vault-based liquidation bot for Torch Market on Solana. Generates an agent keypair in-process — no user wallet required. All operations route through a Torch Vault.

v3.0.0+ Breaking Change: The bot now operates through the torchsdk v3.7.22 vault model. It generates a disposable agent keypair at startup, scans for underwater loan positions using the SDK's bulk loan scanner (getAllLoanPositions), and executes liquidations. The user never provides a wallet — only a vault creator pubkey and an RPC endpoint.

Install

npm install [email protected]

Quick Start

# 1. start the bot — it prints its agent wallet on startup
VAULT_CREATOR=<your-vault-creator-pubkey> SOLANA_RPC_URL=<rpc> npx torch-liquidation-bot

# 2. link the printed agent wallet to your vault (one-time, from your authority wallet)
#    the bot will print the exact instructions if the wallet is not yet linked

# 3. restart the bot — it will begin scanning and liquidating

What It Does

Every migrated token on Torch has a built-in lending market. Borrowers lock tokens as collateral and borrow SOL. When a position's LTV exceeds the liquidation threshold, anyone can liquidate it and earn the liquidation bonus.

This bot:

  1. Generates a disposable Keypair in-process (no private key leaves the process)
  2. Verifies the vault exists and the agent wallet is linked
  3. Scans migrated tokens with getAllLoanPositions() — one RPC call per token, positions pre-sorted liquidatable-first
  4. Executes buildLiquidateTransaction() for each liquidatable position
  5. Confirms the transaction via confirmTransaction()
  6. Repeats on a configurable interval

All value flows through the vault. The agent wallet is a stateless controller.

Configuration

| Variable | Required | Default | Description | |----------|----------|---------|-------------| | SOLANA_RPC_URL | yes | -- | Solana RPC endpoint (fallback: RPC_URL) | | VAULT_CREATOR | yes | -- | Vault creator pubkey (identifies which vault to use) | | SOLANA_PRIVATE_KEY | no | -- | Disposable controller keypair (base58 or JSON byte array). If omitted, generates fresh keypair on startup | | SCAN_INTERVAL_MS | no | 30000 | Milliseconds between scan cycles (min 5000) | | LOG_LEVEL | no | info | debug, info, warn, error |

Vault Setup

The bot uses the torchsdk v3.7.22 vault model:

User (hardware wallet) → Creates vault, deposits SOL
                       → Links bot's agent wallet
Bot  (disposable)      → Scans for liquidatable positions
                       → Executes liquidations using vault funds
                       → All proceeds return to vault
User                   → Withdraws from vault (authority only)

The agent wallet needs minimal SOL for gas (~0.01 SOL). All liquidation value flows through the vault.

Programmatic Usage

import { Connection, Keypair } from '@solana/web3.js'
import {
  getTokens,
  getAllLoanPositions,
  getVault,
  getVaultForWallet,
  buildLiquidateTransaction,
  confirmTransaction,
} from 'torchsdk'

const connection = new Connection('<rpc>', 'confirmed')
const agent = Keypair.generate()

// verify vault and link
const vaultCreator = '<vault-creator-pubkey>'
const vault = await getVault(connection, vaultCreator)
const link = await getVaultForWallet(connection, agent.publicKey.toBase58())

// scan and liquidate
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 } = await buildLiquidateTransaction(connection, {
      mint: token.mint,
      liquidator: agent.publicKey.toBase58(),
      borrower: pos.borrower,
      vault: vaultCreator,
    })
    transaction.sign(agent)
    const sig = await connection.sendRawTransaction(transaction.serialize())
    await confirmTransaction(connection, sig, agent.publicKey.toBase58())
  }
}

Architecture

src/
├── types.ts    — BotConfig interface
├── config.ts   — loadConfig() (SOLANA_RPC_URL, VAULT_CREATOR, SOLANA_PRIVATE_KEY, SCAN_INTERVAL_MS, LOG_LEVEL)
├── utils.ts    — sol(), bpsToPercent(), withTimeout(), createLogger()
└── index.ts    — vault-based liquidation loop

Lending Parameters

| Parameter | Value | |-----------|-------| | Max LTV | 50% | | Liquidation threshold | 65% LTV | | Interest rate | 2% per epoch (~7 days) | | Liquidation bonus | 10% of collateral | | Min borrow | 0.1 SOL |

Testing

Requires Surfpool running a mainnet fork:

surfpool start --network mainnet --no-tui
pnpm test

Security

  • Agent keypair generated in-process with Keypair.generate() (or loaded from optional SOLANA_PRIVATE_KEY)
  • Vault model: agent is a stateless controller, all value stays in the vault
  • Authority can unlink the agent wallet instantly via buildUnlinkWalletTransaction()
  • All SDK calls wrapped with 30-second timeout — a hanging RPC cannot stall the bot indefinitely
  • Minimal dependencies: @solana/web3.js + torchsdk -- both pinned to exact versions
  • No post-install hooks, no remote code fetching
  • disable-model-invocation: true -- agents cannot invoke this skill autonomously

External Runtime Dependencies

The SDK makes outbound HTTPS requests to two external services at runtime (the bot does not contact SAID Protocol):

| Service | Purpose | When Called | |---------|---------|------------| | CoinGecko (api.coingecko.com) | SOL/USD price for display | Token queries via getTokens() | | Irys Gateway (gateway.irys.xyz) | Token metadata fallback (name, symbol, image) | getTokens() when on-chain metadata URI points to Irys |

confirmTransaction() does NOT contact SAID — it only calls connection.getParsedTransaction() (Solana RPC). The SDK exports a verifySaid() function that contacts api.saidprotocol.com, but the bot never calls it.

No credentials are sent to any external service. All requests are read-only GET. No private key material is ever transmitted.

Links

License

MIT