activepieces
AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents
Xpersona Agent
Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions (LTV > 65%) using the S...
clawhub skill install kn7a0ff82yxwmqsge7kh9kdgqn80hpbf:torchliquidationbotOverall rank
#62
Adoption
2K downloads
Trust
Unknown
Freshness
Feb 28, 2026
Freshness
Last checked Feb 28, 2026
Best For
Torch Liquidation Bot is best for general automation workflows where OpenClaw compatibility matters.
Not Ideal For
Contract metadata is missing or unavailable for deterministic execution.
Evidence Sources Checked
CLAWHUB, CLAWHUB, runtime-metrics, public facts pack
Key links, install path, reliability highlights, and the shortest practical read before diving into the crawl record.
Overview
Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions (LTV > 65%) using the S... Capability contract not published. No trust telemetry is available yet. 2K downloads reported by the source. Last updated 4/15/2026.
Trust score
Unknown
Compatibility
OpenClaw
Freshness
Feb 28, 2026
Vendor
Clawhub
Artifacts
0
Benchmarks
0
Last release
4.0.4
Install & run
clawhub skill install kn7a0ff82yxwmqsge7kh9kdgqn80hpbf:torchliquidationbotInstall using `clawhub skill install kn7a0ff82yxwmqsge7kh9kdgqn80hpbf:torchliquidationbot` in an isolated environment before connecting it to live workloads.
No published capability contract is available yet, so validate auth and request/response behavior manually.
Review the upstream CLAWHUB listing at https://clawhub.ai/mrsirg97-rgb/torchliquidationbot before using production credentials.
Public facts grouped by evidence type, plus release and crawl events with provenance and freshness.
Public facts
Vendor
Clawhub
Protocol compatibility
OpenClaw
Latest release
4.0.4
Adoption signal
2K downloads
Handshake status
UNKNOWN
Parameters, dependencies, examples, extracted files, editorial overview, and the complete README when available.
Captured outputs
Extracted files
5
Examples
6
Snippets
0
Languages
Unknown
text
┌──────────────────────────────────────────────────────────┐ │ LIQUIDATION LOOP │ │ │ │ 1. Discover migrated tokens (getTokens) │ │ 2. For each token, scan all loans (getAllLoanPositions) │ │ — single RPC call, returns 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. │ └──────────────────────────────────────────────────────────┘
text
--- ACTION REQUIRED ---
agent wallet is NOT linked to the vault.
link it by running (from your authority wallet):
buildLinkWalletTransaction(connection, {
authority: "<your-authority-pubkey>",
vault_creator: "<your-vault-creator>",
wallet_to_link: "<agent-pubkey>"
})
then restart the bot.
-----------------------bash
npm install [email protected]
typescript
import { Connection } from "@solana/web3.js";
import {
buildCreateVaultTransaction,
buildDepositVaultTransaction,
} from "./lib/torchsdk/index.js";
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...bash
VAULT_CREATOR=<your-vault-creator-pubkey> SOLANA_RPC_URL=<rpc-url> npx torch-liquidation-bot
text
packages/bot/src/ ├── index.ts — entry point: keypair generation, vault verification, scan loop ├── config.ts — loadConfig(): validates SOLANA_RPC_URL, VAULT_CREATOR, SOLANA_PRIVATE_KEY, SCAN_INTERVAL_MS, LOG_LEVEL ├── types.ts — BotConfig, LogLevel interfaces └── utils.ts — sol(), bpsToPercent(), withTimeout(), createLogger()
SKILL.md
---
name: torch-liquidation-bot
version: "4.0.4"
description: Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions (LTV > 65%) using the SDK's built-in bulk loan scanner (getAllLoanPositions), builds and executes liquidation transactions through a Torch Vault, and collects a 10% collateral bonus. The agent keypair is generated in-process -- disposable, holds nothing of value. All SOL and collateral tokens route through the vault. The human principal creates the vault, funds it, links the agent, and retains full control. Built on torchsdk v3.7.22 and the Torch Market protocol.
license: MIT
disable-model-invocation: true
requires:
env:
- name: SOLANA_RPC_URL
required: true
- name: VAULT_CREATOR
required: true
- name: SOLANA_PRIVATE_KEY
required: false
metadata:
clawdbot:
requires:
env:
- name: SOLANA_RPC_URL
required: true
- name: VAULT_CREATOR
required: true
- name: SOLANA_PRIVATE_KEY
required: false
openclaw:
requires:
env:
- name: SOLANA_RPC_URL
required: true
- name: VAULT_CREATOR
required: true
- name: SOLANA_PRIVATE_KEY
required: false
install:
- id: npm-torch-liquidation-bot
kind: npm
package: torch-liquidation-bot@^4.0.2
flags: []
label: "Install Torch Liquidation Bot (npm, optional -- SDK is bundled in lib/torchsdk/ and bot source is bundled under lib/kit on clawhub)"
author: torch-market
version: "4.0.4"
clawhub: https://clawhub.ai/mrsirg97-rgb/torch-liquidation-bot
kit-source: https://github.com/mrsirg97-rgb/torch-liquidation-kit
website: https://torch.market
program-id: 8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT
keywords:
- solana
- defi
- liquidation
- liquidation-bot
- liquidation-keeper
- collateral-lending
- vault-custody
- ai-agents
- agent-wallet
- agent-safety
- treasury-lending
- bonding-curve
- fair-launch
- token-2022
- raydium
- community-treasury
- protocol-rewards
- solana-agent-kit
- escrow
- anchor
- pda
- on-chain
- autonomous-agent
- keeper-bot
- torch-market
categories:
- solana-protocols
- defi-primitives
- lending-markets
- agent-infrastructure
- custody-solutions
- liquidation-keepers
compatibility: >-
REQUIRED: SOLANA_RPC_URL (HTTPS Solana RPC endpoint)
REQUIRED: VAULT_CREATOR (vault creator pubkey).
OPTIONAL: SOLANA_PRIVATE_KEY -- the bot generates a fresh disposable keypair in-process if not provided. The agent wallet holds nothing of value (~0.01 SOL for gas). All liquidation proceeds (collateral tokens) route to the vault. The vault can be created and funded entirely by the human principal.
This skill sets disable-model-invocation: true -- it must not be invoked autonomously withou_meta.json
{
"ownerId": "kn7a0ff82yxwmqsge7kh9kdgqn80hpbf",
"slug": "torchliquidationbot",
"version": "4.0.4",
"publishedAt": 1772291810792
}audit.md
# Torch Liquidation Bot — Security Audit **Audit Date:** February 27, 2026 **Auditor:** Claude Opus 4.6 (Anthropic) **Bot Version:** 4.0.2 **Kit Version:** 2.0.0 **SDK Version:** torchsdk 3.7.22 **On-Chain Program:** `8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT` (V3.7.7, 27 instructions) **Language:** TypeScript **Test Result:** 9 passed, 0 failed (Surfpool mainnet fork) --- ## Table of Contents 1. [Executive Summary](#executive-summary) 2. [Scope](#scope) 3. [Methodology](#methodology) 4. [What Changed (v3.0.2 → v4.0.0)](#what-changed-v302--v400) 5. [Keypair Safety Review](#keypair-safety-review) 6. [Vault Integration Review](#vault-integration-review) 7. [Scan Loop Security](#scan-loop-security) 8. [Configuration Validation](#configuration-validation) 9. [Dependency Analysis](#dependency-analysis) 10. [Threat Model](#threat-model) 11. [Findings](#findings) 12. [Resolved Findings from v3.0.2](#resolved-findings-from-v302) 13. [Conclusion](#conclusion) --- ## Executive Summary This audit covers the Torch Liquidation Bot v4.0.0, an autonomous keeper that scans Torch Market lending positions and liquidates underwater loans through a Torch Vault. The bot was reviewed for key safety, vault integration correctness, error handling, and dependency surface. The major change in v4.0.0 is the replacement of the N+1 scan pattern (`getLendingInfo` → `getHolders` → per-holder `getLoanPosition`) with a single `getAllLoanPositions()` call per token. This reduces RPC calls from 2 + N per token to 1 per token, eliminates the 20-holder discovery ceiling from the previous version, and leverages the SDK's pre-sorted output to break early once all liquidatable positions are processed. The bot remains **vault-first** (all value routes through the vault PDA), **disposable-key** (agent keypair generated in-process, holds nothing), and **single-purpose** (scan and liquidate only — no trading, borrowing, or token creation). ### Overall Assessment | Category | Rating | Notes | |----------|--------|-------| | Key Safety | **PASS** | In-process `Keypair.generate()`, no key files, no key logging | | Vault Integration | **PASS** | `vault` param correctly passed to `buildLiquidateTransaction` | | Error Handling | **PASS** | Cycle-level catch, per-token try/catch, per-liquidation try/catch, 30s RPC timeout | | Config Validation | **PASS** | Required env vars checked, scan interval floored at 5000ms | | Dependencies | **MINIMAL** | 2 runtime deps, both pinned exact | | Supply Chain | **LOW RISK** | No post-install hooks, no remote code fetching | ### Finding Summary | Severity | Count | |----------|-------| | Critical | 0 | | High | 0 | | Medium | 0 | | Low | 0 (1 resolved) | | Informational | 2 | --- ## Scope ### Files Reviewed | File | Lines | Role | |------|-------|------| | `packages/bot/src/index.ts` | 192 | Entry point: keypair load/generate, vault check, scan loop | | `packages/bot/src/config.ts` | 36 | Environment variable validation | | `packages/bot/sr
design.md
# Torch Liquidation Bot — Design Document > Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Version 4.0.2. ## Overview The Torch Liquidation Bot is a single-purpose keeper that scans Torch Market lending positions and liquidates underwater loans through a Torch Vault. It generates a disposable agent keypair in-process, verifies vault linkage, and runs a continuous scan-liquidate loop. All SOL and collateral tokens route through the vault — the agent wallet holds nothing of value. The bot is built on `[email protected]` and targets the Torch Market on-chain program (`8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT`). It uses the SDK's bulk loan scanner (`getAllLoanPositions`) to discover liquidatable positions and the vault-routed `buildLiquidateTransaction` to execute them. ## Architecture ``` ┌──────────────────────────────────────────────────────────┐ │ LIQUIDATION BOT │ │ │ │ main() │ │ ├── loadConfig() → validate env vars │ │ ├── Keypair.generate() → disposable agent keypair │ │ ├── getVault() → verify vault exists │ │ ├── getVaultForWallet() → verify agent linked to vault │ │ └── while (true) │ │ └── scanAndLiquidate() │ │ ├── getTokens({ status: 'migrated' }) │ │ ├── getAllLoanPositions(mint) │ │ │ → returns positions sorted by health │ │ │ → break at first non-liquidatable │ │ ├── buildLiquidateTransaction(vault=creator) │ │ ├── transaction.sign(agentKeypair) │ │ ├── connection.sendRawTransaction() │ │ └── confirmTransaction() │ └──────────────────────────┬───────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ torchsdk v3.7.22 │ │ │ │ Read-only queries: │ │ getTokens, getAllLoanPositions │ │ getVault, getVaultForWallet │ │ │ │ Transaction builder: │ │ buildLiquidateTransaction (vault-routed) │ │ │ │ Confirmation: │ │ confirmTransaction (on-chain via RPC) │ └──────────────────────────┬───────────────────────────────┘ │ ▼ ┌───────────────────────────────────────
verification.md
# Formal Verification Report ## TL;DR We used [Kani](https://model-checking.github.io/kani/), a formal verification tool from AWS, to mathematically prove that torch.market's core math is correct -- not just tested, but **proven for every possible input**. This covers all fee calculations, bonding curve pricing, lending formulas, and reward distribution. No SOL can be created from nothing, no tokens can be minted from thin air, and no fees can exceed their stated rates. This is **not** a security audit. It proves the arithmetic is correct, but does not cover access control, account validation, or economic attacks. See [What Is NOT Verified](#what-is-not-verified) for full scope limitations. **43 proof harnesses. All passing. Zero failures.** --- ## Overview torch_market's core arithmetic has been formally verified using [Kani](https://model-checking.github.io/kani/), a Rust model checker backed by the CBMC bounded model checker. Kani exhaustively proves properties hold for **all** valid inputs within constrained ranges -- not just sampled test cases. **Tool:** Kani Rust Verifier 0.67.0 / CBMC 6.8.0 **Target:** `torch_market` v3.7.8 **Harnesses:** 43 proof harnesses, all passing **Source:** `programs/torch_market/src/kani_proofs.rs` ## What Is Formally Verified The proofs cover the **pure arithmetic layer** -- every fee calculation, bonding curve formula, lending math function, and reward distribution used by the on-chain program. Each proof harness uses symbolic (unconstrained) inputs bounded to realistic protocol ranges, and Kani exhaustively checks all possible values within those bounds. ### Buy Flow (Harnesses 1-8) | Harness | Property | Input Range | |---------|----------|-------------| | `verify_buy_fee_conservation` | `protocol_fee + treasury_fee + after_fees == sol_amount` | 0.001-200 SOL | | `verify_protocol_fee_split` | `dev_share + protocol_portion == protocol_fee_total` | 0.001-200 SOL | | `verify_treasury_rate_bounds` | `rate in [500, 2000]` (5-20%) flat across all tiers | 0-target SOL reserves | | `verify_treasury_rate_monotonic` | More reserves -> lower treasury rate | 0-target SOL (two symbolic) | | `verify_sol_distribution_conservation` | `curve + treasury + creator + dev + protocol == sol_amount` (zero SOL created or lost, V34 5-way sum) | 0.001-10 SOL per trade, 0-target SOL reserves | | `verify_curve_tokens_bounded_legacy` | `tokens_out < virtual_token_reserves` (can't mint from thin air) | Legacy pool state space (IVT=107.3T) | | `verify_curve_tokens_bounded_v25` | Same property for V27 per-tier reserves | V27 pool state space (IVT=756.25M tokens) | | `verify_token_split_conservation` | `tokens_to_buyer + tokens_to_treasury == tokens_out` | 0 to TOTAL_SUPPLY | ### Sell Flow (Harnesses 9-10) | Harness | Property | Input Range | |---------|----------|-------------| | `verify_sell_sol_bounded_legacy` | `sol_out < virtual_sol_reserves` (can't drain more SOL than exists) | Legacy pool state, max wallet cap | | `verif
Editorial read
Docs source
CLAWHUB
Editorial quality
thin
Skill: Torch Liquidation Bot Owner: mrsirg97-rgb Summary: Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions (LTV > 65%) using the S... Tags: latest:4.0.4 Version history: v4.0.4 | 2026-02-28T15:16:50.792Z | user No user-facing changes detected in this release. Version bump only. - Version number updated to 4.0.4. - No changes to files
Skill: Torch Liquidation Bot
Owner: mrsirg97-rgb
Summary: Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions (LTV > 65%) using the S...
Tags: latest:4.0.4
Version history:
v4.0.4 | 2026-02-28T15:16:50.792Z | user
No user-facing changes detected in this release. Version bump only.
v4.0.3 | 2026-02-27T21:52:12.295Z | user
No functional or user-facing changes; version number updated.
v4.0.2 | 2026-02-27T21:45:57.758Z | user
v4.0.1 | 2026-02-27T21:28:43.047Z | user
torchliquidationbot v4.0.1
v4.0.0 | 2026-02-27T21:21:46.427Z | user
Version 4.0.0 introduces major efficiency and scanning improvements:
getAllLoanPositions), performing a single RPC call per token to retrieve and sort all loan positions by health.SOLANA_PRIVATE_KEY (agent keypair remains disposable by default).verification.md) added.v3.0.2 | 2026-02-13T15:34:23.366Z | user
v3.0.1 | 2026-02-13T14:54:43.105Z | user
v3.0.0 | 2026-02-13T14:28:25.299Z | user
Major Update: liquidator bot upgraded from read-only scanner to full autonomous liquidation keeper with vault-based custody and agent safety.
SOLANA_RPC_URL and VAULT_CREATOR (vault owner); agent wallet is generated automatically unless a private key is provided.lib/kit/), leveraging the newest torchsdk v3.2.3.v2.1.2 | 2026-02-11T17:50:34.690Z | user
@coral-xyz/anchor and @solana/spl-token remain as transitive dependencies in the bundled torchsdk.v2.1.1 | 2026-02-11T17:45:06.077Z | user
v2.1.0 | 2026-02-11T17:32:07.636Z | user
v2.0.9 | 2026-02-11T17:23:53.528Z | user
v2.0.9: Source-bundled release — all bot source included in skill package
v2.0.8 | 2026-02-11T01:12:18.780Z | user
v2.0.7 | 2026-02-10T19:21:28.530Z | user
RPC_URL is now explicitly declared as a required environment variable.disable-model-invocation moved to top-level frontmatter for stronger enforcement in the registry.v2.0.6 | 2026-02-10T18:51:56.865Z | user
Version 2.0.6
v2.0.5 | 2026-02-10T18:33:38.352Z | user
v2.0.4 | 2026-02-10T17:00:09.543Z | user
v2.0.3 | 2026-02-10T16:51:06.903Z | user
v2.0.2 | 2026-02-10T16:41:14.962Z | user
@solana/web3.js, torchsdk).v2.0.0 | 2026-02-10T16:09:41.176Z | user
v2.0.0 is a breaking change: Now fully read-only — all wallet-dependent bot features removed. npm package has also been updated to reflect these changes.
v1.0.9 | 2026-02-10T15:44:52.099Z | user
Version 1.0.9
v1.0.8 | 2026-02-10T15:37:57.285Z | user
Version 1.0.8
v1.0.7 | 2026-02-10T15:33:41.762Z | user
Version 1.0.7
v1.0.6 | 2026-02-10T15:06:58.870Z | user
torch-liquidation-bot 1.0.6
v1.0.5 | 2026-02-10T14:04:04.900Z | user
Torch Liquidation Bot 1.0.5
v1.0.4 | 2026-02-09T03:36:06.575Z | user
Summary: v1.0.4 makes "info" mode the default and fully read-only; wallet is now only needed for bot or watch modes.
v1.0.3 | 2026-02-09T03:29:01.009Z | user
Version 1.0.3
v1.0.2 | 2026-02-09T02:28:43.044Z | user
v1.0.0 | 2026-02-09T02:16:50.015Z | user
Initial release of torch-liquidation-bot.
Archive index:
Archive v4.0.4: 22 files, 96042 bytes
Files: agent.json (6139b), audit.md (21316b), design.md (12278b), lib/kit/config.js (1577b), lib/kit/index.js (7088b), lib/kit/types.js (182b), lib/kit/utils.js (1987b), lib/torchsdk/constants.js (6651b), lib/torchsdk/ephemeral.js (1330b), lib/torchsdk/gateway.js (1581b), lib/torchsdk/index.js (7875b), lib/torchsdk/program.js (13486b), lib/torchsdk/quotes.js (3751b), lib/torchsdk/said.js (3617b), lib/torchsdk/tokens.js (35336b), lib/torchsdk/torch_market.json (224847b), lib/torchsdk/transactions.js (66086b), lib/torchsdk/types.js (144b), SKILL.md (19734b), verification.md (18057b), whitepaper.md (50580b), _meta.json (138b)
File v4.0.4:SKILL.md
You're here because you want to run a liquidation keeper on Torch Market -- and you want to do it safely.
Every migrated token on Torch has a built-in lending market. Holders lock tokens as collateral and borrow SOL from the community treasury (up to 50% LTV, 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.
That's where this bot comes in.
It 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. The collateral tokens go to your vault ATA. The SOL cost comes from your vault. The agent wallet that signs the transaction holds nothing.
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, returns 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:
--- ACTION REQUIRED ---
agent wallet is NOT linked to the vault.
link it by running (from your authority wallet):
buildLinkWalletTransaction(connection, {
authority: "<your-authority-pubkey>",
vault_creator: "<your-vault-creator>",
wallet_to_link: "<agent-pubkey>"
})
then restart the bot.
-----------------------
Link it from your authority wallet (hardware wallet, multisig, whatever you use). The agent never needs the authority's key. The authority never needs the agent's key. They share a vault, not keys.
This is the same Torch Vault from the full Torch Market protocol. It holds all assets -- SOL and tokens. The agent is a disposable controller.
When the bot liquidates a position:
The human principal retains full control:
withdrawVault() — pull SOL at any timewithdrawTokens(mint) — pull collateral tokens at any timeunlinkWallet(agent) — revoke agent access instantlyIf the agent keypair is compromised, the attacker gets dust and vault access that you revoke in one transaction.
npm install [email protected]
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 "./lib/torchsdk/index.js";
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 |
|----------|----------|---------|-------------|
| SOLANA_RPC_URL | Yes | -- | Solana RPC endpoint (HTTPS). Fallback: RPC_URL |
| VAULT_CREATOR | Yes | -- | Vault creator pubkey |
| SOLANA_PRIVATE_KEY | No | -- | Disposable controller keypair (base58 or JSON byte array). If omitted, generates fresh keypair on startup (recommended) |
| SCAN_INTERVAL_MS | No | 30000 | Milliseconds between scan cycles (min 5000) |
| LOG_LEVEL | No | info | debug, info, warn, error |
packages/bot/src/
├── index.ts — entry point: keypair generation, vault verification, scan loop
├── config.ts — loadConfig(): validates SOLANA_RPC_URL, VAULT_CREATOR, SOLANA_PRIVATE_KEY, SCAN_INTERVAL_MS, LOG_LEVEL
├── types.ts — BotConfig, LogLevel interfaces
└── utils.ts — sol(), bpsToPercent(), withTimeout(), createLogger()
The bot is ~192 lines of TypeScript. It does one thing: find underwater loans and liquidate them through the vault.
| Package | Version | Purpose |
|---------|---------|---------|
| @solana/web3.js | 1.98.4 | Solana RPC, keypair, transaction |
| torchsdk | 3.7.22 | Token queries, bulk loan scanning, liquidation builder, vault queries |
Two runtime dependencies. Both pinned to exact versions. No ^ or ~ ranges.
The same seven guarantees from the Torch Market vault apply here:
| Property | Guarantee | |----------|-----------| | Full custody | Vault holds all SOL and all collateral tokens. Agent wallet holds nothing. | | Closed loop | Liquidation SOL comes from vault, collateral tokens go to vault. No leakage to agent. | | Authority separation | Creator (immutable PDA seed) vs Authority (transferable admin) vs Controller (disposable signer). | | One link per wallet | Agent can only belong to one vault. PDA uniqueness enforces this on-chain. | | Permissionless deposits | Anyone can top up the vault. Hardware wallet deposits, agent liquidates. | | Instant revocation | Authority can unlink the agent at any time. One transaction. | | Authority-only withdrawals | Only the vault authority can withdraw SOL or tokens. The agent cannot extract value. |
| Direction | Flow | |-----------|------| | SOL out | Vault → Borrower's treasury debt (covers the loan) | | Tokens in | Borrower's collateral → Vault ATA (at 10% discount) | | Net | Vault receives collateral worth 110% of SOL spent |
The bot is profitable by design — every successful liquidation returns more value than it costs. The profit accumulates in the vault. The authority withdraws when ready.
| Parameter | Value | |-----------|-------| | Max LTV | 50% | | Liquidation Threshold | 65% | | Interest Rate | 2% per epoch (~weekly) | | Liquidation Bonus | 10% | | Utilization Cap | 70% of treasury | | Min Borrow | 0.1 SOL |
Collateral value is calculated from Raydium pool reserves. The 0.03% Token-2022 transfer fee (3 bps, immutable per mint) applies on collateral deposits and withdrawals.
A loan becomes liquidatable when its LTV exceeds 65%. This happens when:
The bot checks position.health === 'liquidatable' — the SDK calculates LTV from on-chain Raydium reserves and the loan's accrued debt.
The bot uses a focused subset of the Torch SDK:
| Function | Purpose |
|----------|---------|
| getTokens(connection, { status: 'migrated' }) | Discover all tokens with active lending markets |
| getAllLoanPositions(connection, mint) | Bulk scan all active loans for a token — returns positions pre-sorted by health (liquidatable first), fetches pool price once |
| getVault(connection, creator) | Verify vault exists on startup |
| getVaultForWallet(connection, wallet) | Verify agent is linked to vault |
| buildLiquidateTransaction(connection, params) | Build the liquidation transaction (vault-routed) |
| confirmTransaction(connection, sig, wallet) | Confirm transaction on-chain via RPC (verifies signer, checks Torch instructions) |
import { getTokens, getAllLoanPositions, buildLiquidateTransaction } from 'torchsdk'
// 1. Discover migrated tokens
const { tokens } = await getTokens(connection, { status: 'migrated', sort: 'volume', limit: 50 })
for (const token of tokens) {
// 2. Bulk scan — one RPC call per token, positions sorted liquidatable-first
const { positions } = await getAllLoanPositions(connection, token.mint)
for (const pos of positions) {
if (pos.health !== 'liquidatable') break // pre-sorted, done
// 3. Build and execute through vault
const { transaction, message } = await buildLiquidateTransaction(connection, {
mint: token.mint, // token with the underwater loan
liquidator: agentPubkey, // agent wallet (signer)
borrower: pos.borrower, // borrower being liquidated
vault: vaultCreator, // vault creator pubkey (SOL from vault, tokens to vault)
})
transaction.sign(agentKeypair)
await connection.sendRawTransaction(transaction.serialize())
}
}
=== torch liquidation bot ===
agent wallet: 7xK9...
vault creator: 4yN2...
scan interval: 30000ms
[09:15:32] INFO vault found — authority=8cpW...
[09:15:32] INFO agent wallet linked to vault — starting scan loop
[09:15:32] INFO treasury: 5.0000 SOL
[09:15:33] INFO LIQUIDATABLE | SDKTEST | borrower=3AyZ... | LTV=72.50% | owed=0.5000 SOL
[09:15:34] INFO LIQUIDATED | SDKTEST | borrower=3AyZ... | sig=4vK9... | collateral received at 10% discount
The vault is the security boundary, not the key.
The agent keypair is generated fresh on every startup with Keypair.generate(). It holds ~0.01 SOL for gas fees. If the key is compromised, the attacker gets:
The agent never needs the authority's private key. The authority never needs the agent's private key. They share a vault, not keys.
All SDK calls are wrapped with a 30-second timeout (withTimeout in utils.ts). A hanging or unresponsive RPC endpoint cannot stall the bot indefinitely — the call rejects, the error is caught by the scan loop, and the bot continues to the next token or cycle.
| Variable | Required | Purpose |
|----------|----------|---------|
| SOLANA_RPC_URL / RPC_URL | Yes | Solana RPC endpoint (HTTPS) |
| VAULT_CREATOR | Yes | Vault creator pubkey — identifies which vault the bot operates through |
| SOLANA_PRIVATE_KEY | No | Optional — if omitted, the bot generates a fresh keypair on startup (recommended) |
The SDK contains functions that make outbound HTTPS requests to external services. The bot's runtime path contacts two of them:
| Service | Purpose | When Called | Bot Uses? |
|---------|---------|------------|-----------|
| CoinGecko (api.coingecko.com) | SOL/USD price for display | Token queries with USD pricing | Yes — via getTokens(), getToken() |
| Irys Gateway (gateway.irys.xyz) | Token metadata fallback (name, symbol, image) | getToken() when on-chain metadata URI points to Irys | Yes — via getTokens() |
| SAID Protocol (api.saidprotocol.com) | Agent identity verification and trust tier lookup | verifySaid() only | No — the bot does not call verifySaid() |
confirmTransaction() does NOT contact SAID. Despite living in the SDK's said.js module, it only calls connection.getParsedTransaction() (Solana RPC) to verify the transaction succeeded on-chain and determine the event type. No data is sent to any external service.
No credentials are sent to CoinGecko or Irys. All requests are read-only GET. If either service is unreachable, the SDK degrades gracefully. No private key material is ever transmitted to any external endpoint.
Requires Surfpool running a mainnet fork:
surfpool start --network mainnet --no-tui
pnpm test
Test result: 9 passed, 0 failed (Surfpool mainnet fork).
| Test | What It Validates | |------|-------------------| | Connection | RPC reachable | | getTokens | Discovers migrated tokens | | getLendingInfo | Reads lending state for all tokens | | getAllLoanPositions | Bulk scans active loans, verifies sort order (liquidatable first) | | getToken | Token metadata, price, status | | getVaultForWallet | Vault link returns null for unlinked wallet | | In-process keypair | No external key required |
VAULT_NOT_FOUND: No vault exists for this creatorWALLET_NOT_LINKED: Agent wallet is not linked to the vaultNOT_LIQUIDATABLE: Position LTV below liquidation thresholdNO_ACTIVE_LOAN: No open loan for this wallet/tokenINVALID_MINT: Token not foundlib/torchsdk/ -- included in this skill8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeTThis bot exists because Torch lending markets need keepers. When loans go underwater and nobody liquidates them, the treasury takes the loss. Active liquidation keepers protect treasury health and earn a profit doing it. The vault makes it safe — all value stays in the escrow, all risk is bounded, and the human principal keeps the keys.
File v4.0.4:_meta.json
{ "ownerId": "kn7a0ff82yxwmqsge7kh9kdgqn80hpbf", "slug": "torchliquidationbot", "version": "4.0.4", "publishedAt": 1772291810792 }
File v4.0.4:audit.md
Audit Date: February 27, 2026
Auditor: Claude Opus 4.6 (Anthropic)
Bot Version: 4.0.2
Kit Version: 2.0.0
SDK Version: torchsdk 3.7.22
On-Chain Program: 8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT (V3.7.7, 27 instructions)
Language: TypeScript
Test Result: 9 passed, 0 failed (Surfpool mainnet fork)
This audit covers the Torch Liquidation Bot v4.0.0, an autonomous keeper that scans Torch Market lending positions and liquidates underwater loans through a Torch Vault. The bot was reviewed for key safety, vault integration correctness, error handling, and dependency surface.
The major change in v4.0.0 is the replacement of the N+1 scan pattern (getLendingInfo → getHolders → per-holder getLoanPosition) with a single getAllLoanPositions() call per token. This reduces RPC calls from 2 + N per token to 1 per token, eliminates the 20-holder discovery ceiling from the previous version, and leverages the SDK's pre-sorted output to break early once all liquidatable positions are processed.
The bot remains vault-first (all value routes through the vault PDA), disposable-key (agent keypair generated in-process, holds nothing), and single-purpose (scan and liquidate only — no trading, borrowing, or token creation).
| Category | Rating | Notes |
|----------|--------|-------|
| Key Safety | PASS | In-process Keypair.generate(), no key files, no key logging |
| Vault Integration | PASS | vault param correctly passed to buildLiquidateTransaction |
| Error Handling | PASS | Cycle-level catch, per-token try/catch, per-liquidation try/catch, 30s RPC timeout |
| Config Validation | PASS | Required env vars checked, scan interval floored at 5000ms |
| Dependencies | MINIMAL | 2 runtime deps, both pinned exact |
| Supply Chain | LOW RISK | No post-install hooks, no remote code fetching |
| Severity | Count | |----------|-------| | Critical | 0 | | High | 0 | | Medium | 0 | | Low | 0 (1 resolved) | | Informational | 2 |
| File | Lines | Role |
|------|-------|------|
| packages/bot/src/index.ts | 192 | Entry point: keypair load/generate, vault check, scan loop |
| packages/bot/src/config.ts | 36 | Environment variable validation |
| packages/bot/src/types.ts | 13 | BotConfig and LogLevel interfaces |
| packages/bot/src/utils.ts | 58 | Formatting helpers, logger, base58 decoder, RPC timeout |
| packages/bot/tests/test_e2e.ts | 248 | E2E test suite |
| packages/bot/package.json | 37 | Dependencies and scripts |
| packages/bot/tsconfig.json | 20 | TypeScript configuration |
| Total | ~604 | |
The bot relies on [email protected] for all on-chain interaction. The SDK was independently audited (see Torch SDK Audit). This audit focuses on the bot's usage of the SDK, not the SDK internals.
Key SDK changes since v3.2.3:
getAllLoanPositions() added in v3.7.17 — bulk loan scanning via getProgramAccountsbuildAutoBuybackTransaction deletedThe core scan loop was rewritten to use getAllLoanPositions():
Before (v3.0.2):
getTokens → for each token:
getLendingInfo → skip if no active loans
getHolders → get up to 20 holders
getLoanPosition → check each holder individually
buildLiquidateTransaction → if liquidatable
After (v4.0.0):
getTokens → for each token:
getAllLoanPositions → all active loans, sorted by health
break → stop at first non-liquidatable (pre-sorted)
buildLiquidateTransaction → for each liquidatable
Removed: getLendingInfo, getHolders, getLoanPosition, type LendingInfo, type LoanPositionInfo
Added: getAllLoanPositions, type LoanPositionWithKey
| Metric | v3.0.2 | v4.0.0 |
|--------|--------|--------|
| RPC calls per token | 2 + N (lending + holders + per-holder position) | 1 (getAllLoanPositions) |
| Max discoverable borrowers | 20 (getTokenLargestAccounts limit) | Unlimited (scans all LoanPosition PDAs) |
| Source lines (index.ts) | 210 | 187 |
| SDK imports | 10 | 7 |
| Error isolation levels | 4 (cycle, token, holder, liquidation) | 3 (cycle, token, liquidation) |
The reduction from 4 to 3 error isolation levels is correct — the holder level is no longer needed because getAllLoanPositions returns positions directly.
Unchanged from v3.0.2. The keypair is created in main() via one of two paths:
Keypair.generate() — fresh Ed25519 keypair from system entropySOLANA_PRIVATE_KEY env var — loaded as JSON byte array or base58, decoded via Keypair.fromSecretKey()// index.ts:137-153 — load or generate agent keypair
let agentKeypair: Keypair
if (config.privateKey) {
// try JSON byte array, then base58
agentKeypair = Keypair.fromSecretKey(...)
} else {
agentKeypair = Keypair.generate()
}
The keypair is:
SOLANA_PRIVATE_KEY)agentKeypair is local to main(), not in the public APIagentKeypair.publicKey.toBase58())The keypair is used in exactly two places:
transaction.sign(agentKeypair) at index.ts:86) — local signing onlyThe keypair holds ~0.01 SOL for gas. If the process memory is dumped, the attacker gets:
Verdict: Key safety is correct. No key material leaks from the process. Unchanged from v3.0.2.
Unchanged from v3.0.2:
const vault = await getVault(connection, config.vaultCreator) // index.ts:142
if (!vault) throw new Error(...)
const link = await getVaultForWallet(connection, agentKeypair.publicKey.toBase58()) // index.ts:149
if (!link) { /* print instructions, exit */ }
The bot verifies both vault existence and agent linkage before entering the scan loop. If either fails, the process exits with clear instructions.
const { transaction, message } = await buildLiquidateTransaction(connection, {
mint: token.mint,
liquidator: agentKeypair.publicKey.toBase58(),
borrower: position.borrower, // now from getAllLoanPositions result
vault: vaultCreator, // index.ts:83
})
The vault parameter is correctly passed. The borrower field now comes from LoanPositionWithKey.borrower (returned by getAllLoanPositions) instead of holder.address (from getHolders). Both are base58 public key strings — the type is unchanged.
Per the SDK audit, the vault param causes:
vaultCreator (["torch_vault", creator])liquidator (["vault_wallet", wallet])Verdict: Vault integration is correct. All value routes through the vault PDA.
Cycle level — never crashes the loop (unchanged):
while (true) {
try {
await scanAndLiquidate(connection, log, config.vaultCreator, agentKeypair)
} catch (err: any) {
log('error', `scan cycle error: ${err.message}`)
}
await new Promise(resolve => setTimeout(resolve, config.scanIntervalMs))
}
Token level — skip tokens where getAllLoanPositions fails:
for (const token of tokens) {
let positions: LoanPositionWithKey[]
try {
const result = await getAllLoanPositions(connection, token.mint)
positions = result.positions
} catch {
continue // lending not enabled for this token
}
if (positions.length === 0) continue
Liquidation level — each liquidation attempt is individually caught:
try {
const { transaction, message } = await buildLiquidateTransaction(...)
transaction.sign(agentKeypair)
const signature = await connection.sendRawTransaction(transaction.serialize())
await confirmTransaction(...)
log('info', `LIQUIDATED | ...`)
} catch (err: any) {
log('warn', `LIQUIDATION FAILED | ...`)
}
// index.ts:67-68
for (const position of positions) {
if (position.health !== 'liquidatable') break
This is correct because getAllLoanPositions returns positions sorted by health: liquidatable → at_risk → healthy. Once the first non-liquidatable position is encountered, all remaining positions are also non-liquidatable. The E2E test (test_e2e.ts:159-174) independently validates this sort order.
Verdict: Error handling is robust. The bot degrades gracefully at every level. The break optimization is correct and validated by tests.
Unchanged from v3.0.2.
| Variable | Validation | Failure Mode |
|----------|-----------|--------------|
| SOLANA_RPC_URL | Must be set (fallback: RPC_URL) | Throws on startup |
| VAULT_CREATOR | Must be set | Throws on startup |
| SCAN_INTERVAL_MS | Must be >= 5000 | Throws on startup |
| LOG_LEVEL | Must be debug\|info\|warn\|error | Throws on startup |
| Variable | Default |
|----------|---------|
| SCAN_INTERVAL_MS | 30000 |
| LOG_LEVEL | info |
SOLANA_RPC_URL is used only for Solana RPC calls — never logged, transmitted externally, or storedVAULT_CREATOR is a public key (not sensitive)SOLANA_PRIVATE_KEY is optional — if provided, it is read once at startup and used to derive the keypair via Keypair.fromSecretKey(). The raw string is never logged or transmitted. If omitted, the bot generates a fresh keypair with Keypair.generate() (recommended).Verdict: Configuration is properly validated. Sensitive SOLANA_PRIVATE_KEY is handled safely when provided.
| Package | Version | Pinning | Post-Install | Risk |
|---------|---------|---------|-------------|------|
| @solana/web3.js | 1.98.4 | Exact | None | Low — standard Solana |
| torchsdk | 3.7.22 | Exact | None | Low — audited separately |
| Package | Version | Purpose |
|---------|---------|---------|
| @types/node | 20.19.33 | TypeScript types |
| prettier | 3.8.1 | Code formatting |
| typescript | 5.9.3 | Compilation |
^ or ~ version ranges — all dependencies pinned to exact versions"scripts" contains only build, clean, test, formatimport(), no eval(), no fetch-and-executepnpm-lock.yaml pins transitive dependenciesThe SDK contains functions that make outbound HTTPS requests. The bot's runtime path contacts two external services:
| Service | Purpose | When Called | Bot Uses? |
|---------|---------|------------|-----------|
| CoinGecko (api.coingecko.com) | SOL/USD price for display | Token queries via getTokens() | Yes |
| Irys Gateway (gateway.irys.xyz) | Token metadata fallback | getTokens() when metadata URI points to Irys | Yes |
| SAID Protocol (api.saidprotocol.com) | Agent identity verification | verifySaid() only | No — bot does not call verifySaid() |
Important: confirmTransaction() does NOT contact SAID Protocol. Despite residing in the SDK's said.js module, it only calls connection.getParsedTransaction() (Solana RPC) to verify the transaction succeeded on-chain. No transaction data or agent identifiers are sent to any external reputation service.
Data transmitted to external services:
No credentials are sent. If either service is unreachable, the SDK degrades gracefully. No private key material is ever transmitted to any external endpoint.
Verdict: Minimal and locked dependency surface. No supply chain concerns. External network calls are read-only, non-critical, and transmit no sensitive data.
Attack: Attacker obtains the agent's private key from process memory.
Impact: Attacker can sign transactions as the agent.
Mitigation: The agent keypair holds ~0.01 SOL. The vault's value is controlled by the authority, who can unlink the compromised wallet in one transaction. The attacker cannot call withdrawVault or withdrawTokens.
Residual risk: Attacker could execute vault-routed trades until unlinked. Limited by vault SOL balance.
Attack: RPC returns fabricated loan positions to trick the bot into unprofitable liquidations. Impact: The bot liquidates positions that aren't actually underwater, losing vault SOL. Mitigation: The on-chain program validates all liquidation preconditions. A fabricated RPC response would produce a transaction that fails on-chain. Residual risk: None — on-chain validation is the actual security boundary.
Attack: A compromised or malicious RPC returns positions with health: 'liquidatable' for loans that are actually healthy.
Impact: Bot builds liquidation transactions that fail on-chain (program checks LTV).
Mitigation: Same as above — on-chain program enforces liquidation threshold. The health field from getAllLoanPositions is a client-side convenience; the program independently verifies collateral value vs debt. A failed liquidation costs only the transaction fee (~0.000005 SOL).
Residual risk: Wasted gas on failed transactions. No vault SOL lost on failed liquidations.
Attack: Overwhelming the bot with slow/failed RPC responses.
Impact: Bot can't discover or liquidate positions.
Mitigation: SCAN_INTERVAL_MS floor of 5000ms. Each scan cycle is independent. Bot recovers on next cycle.
Residual risk: Missed liquidation opportunities during outage.
Attack: MEV bot observes the liquidation transaction in mempool and front-runs it.
Impact: Bot's transaction fails (NOT_LIQUIDATABLE — position already liquidated).
Mitigation: The bot catches the error and moves to the next position. No vault SOL is lost on a failed liquidation.
Residual risk: Reduced liquidation success rate in competitive MEV environments.
Severity: Low
File: utils.ts:12-21, index.ts (all SDK call sites)
Description: SDK calls (getTokens, getAllLoanPositions, buildLiquidateTransaction, confirmTransaction, getVault, getVaultForWallet) previously had no explicit timeout. A hanging RPC endpoint could block the scan loop indefinitely.
Resolution: All 6 SDK calls are now wrapped with withTimeout(promise, label) which races against a 30-second deadline via Promise.race. Timeouts in the scan loop are caught by existing try/catch layers — the bot logs the timeout and continues. Startup timeouts surface as a FATAL error (correct behavior — if RPC is unreachable at startup, the bot should not silently hang).
Status: Resolved in v4.0.1.
Severity: Informational Description: The bot checks all tokens and all positions on every cycle. If a liquidation fails (e.g., insufficient vault SOL), the same position will be retried on every cycle. Impact: Repeated log noise for positions that can't be liquidated. No security impact.
Severity: Informational
Description: getAllLoanPositions internally calls getProgramAccounts with discriminator + mint filters to find all LoanPosition accounts. Some RPC providers rate-limit or restrict getProgramAccounts. The bot falls back gracefully (the catch block skips the token), but tokens may be silently skipped if the RPC provider blocks this call.
Impact: Missed liquidation opportunities on restrictive RPC providers. No security impact. The previous getHolders approach (getTokenLargestAccounts) had the same class of issue.
Recommendation: Use an RPC provider that supports getProgramAccounts without restrictions (Helius, Triton, QuickNode, or a private validator).
Status: Resolved in v3.0.2. Optional SOLANA_PRIVATE_KEY env var allows persisting the agent wallet. Still resolved in v4.0.0.
Status: Resolved in v4.0.0. The bot no longer calls getHolders / getTokenLargestAccounts. getAllLoanPositions scans all LoanPosition PDAs directly via getProgramAccounts with no holder count ceiling.
Status: Still present, still informational. For a bot with 30-second cycle intervals, this is irrelevant.
Status: Resolved in v4.0.0. The bot no longer calls getHolders / getTokenLargestAccounts. The E2E test no longer depends on this Surfpool-limited RPC method.
The Torch Liquidation Bot v4.0.2 is a cleaner, more efficient keeper with correct vault integration and robust error handling. Key findings:
Keypair.generate() by default, optional SOLANA_PRIVATE_KEY for persistence. No key logging, no key transmission. Unchanged from v3.0.2.vault param passed to buildLiquidateTransaction, SOL from vault, collateral to vault ATA. Unchanged from v3.0.2.getAllLoanPositions replaces the N+1 holder scan. One RPC call per token, no 20-holder ceiling, pre-sorted results with early break. Two v3.0.2 findings (I-1, I-4) are resolved by this change.The bot is safe for production use as an autonomous liquidation keeper operating through a Torch Vault.
This audit was performed by Claude Opus 4.6 (Anthropic) on February 27, 2026. All source files were read in full and cross-referenced against the torchsdk v3.7.22 audit. The E2E test suite (9 passed, 0 failed) validates the bot against a Surfpool mainnet fork, including sort order verification for getAllLoanPositions.
Auditor: Claude Opus 4.6
Date: 2026-02-27
Bot Version: 4.0.2
Kit Version: 2.0.0
SDK Version: torchsdk 3.7.22
On-Chain Version: V3.7.7 (Program ID: 8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT, 27 instructions)
File v4.0.4:design.md
Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Version 4.0.2.
The Torch Liquidation Bot is a single-purpose keeper that scans Torch Market lending positions and liquidates underwater loans through a Torch Vault. It generates a disposable agent keypair in-process, verifies vault linkage, and runs a continuous scan-liquidate loop. All SOL and collateral tokens route through the vault — the agent wallet holds nothing of value.
The bot is built on [email protected] and targets the Torch Market on-chain program (8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT). It uses the SDK's bulk loan scanner (getAllLoanPositions) to discover liquidatable positions and the vault-routed buildLiquidateTransaction to execute them.
┌──────────────────────────────────────────────────────────┐
│ LIQUIDATION BOT │
│ │
│ main() │
│ ├── loadConfig() → validate env vars │
│ ├── Keypair.generate() → disposable agent keypair │
│ ├── getVault() → verify vault exists │
│ ├── getVaultForWallet() → verify agent linked to vault │
│ └── while (true) │
│ └── scanAndLiquidate() │
│ ├── getTokens({ status: 'migrated' }) │
│ ├── getAllLoanPositions(mint) │
│ │ → returns positions sorted by health │
│ │ → break at first non-liquidatable │
│ ├── buildLiquidateTransaction(vault=creator) │
│ ├── transaction.sign(agentKeypair) │
│ ├── connection.sendRawTransaction() │
│ └── confirmTransaction() │
└──────────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ torchsdk v3.7.22 │
│ │
│ Read-only queries: │
│ getTokens, getAllLoanPositions │
│ getVault, getVaultForWallet │
│ │
│ Transaction builder: │
│ buildLiquidateTransaction (vault-routed) │
│ │
│ Confirmation: │
│ confirmTransaction (on-chain via RPC) │
└──────────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ Solana RPC (mainnet / validator) │
│ │
│ getProgramAccounts getAccountInfo sendTransaction │
└──────────────────────────────────────────────────────────┘
packages/bot/src/
├── index.ts Entry point — keypair generation, vault verification, scan loop
├── config.ts loadConfig() — validates SOLANA_RPC_URL, VAULT_CREATOR, SOLANA_PRIVATE_KEY, SCAN_INTERVAL_MS, LOG_LEVEL
├── types.ts BotConfig, LogLevel interfaces
└── utils.ts sol(), bpsToPercent(), createLogger()
index.ts ──→ config.ts ──→ types.ts
──→ utils.ts ──→ types.ts
──→ torchsdk (external)
──→ @solana/web3.js (external)
No circular dependencies. index.ts is the single entry point. config.ts handles environment validation. utils.ts provides formatting helpers. All on-chain interaction goes through torchsdk.
The bot does one thing: find underwater loans and liquidate them through the vault. No trading, no borrowing, no token creation. One loop, one responsibility.
Every liquidation routes through the Torch Vault. SOL comes from the vault. Collateral tokens go to the vault ATA. The agent wallet never holds value. This is enforced by passing vault: vaultCreator to buildLiquidateTransaction.
By default, the agent keypair is generated fresh on every startup with Keypair.generate(). Optionally, SOLANA_PRIVATE_KEY can be provided (base58 or JSON byte array) to persist the agent wallet across restarts. In both cases, the keypair exists only in runtime memory and is never logged or transmitted.
Before entering the scan loop, the bot verifies:
getVault(connection, vaultCreator) — vault exists on-chaingetVaultForWallet(connection, agentPubkey) — agent is linked to the vaultIf either check fails, the bot exits with clear instructions. It never enters the scan loop with an invalid vault or unlinked wallet.
The scan loop catches all errors at the cycle level. A failed RPC call or a failed liquidation never crashes the bot — it logs the error and moves to the next cycle. Individual token iterations use try/catch to skip tokens where getAllLoanPositions fails.
Two runtime dependencies (@solana/web3.js, torchsdk), both pinned to exact versions. ~187 lines of TypeScript. Four source files. No database, no API server, no indexer, no websockets.
for each migrated token:
positions = getAllLoanPositions(mint)
skip if positions is empty
for each position (pre-sorted: liquidatable → at_risk → healthy):
break if health !== 'liquidatable'
→ buildLiquidateTransaction(vault=creator)
→ sign with agent keypair
→ submit and confirm
→ log result
getTokens(connection, { status: 'migrated', sort: 'volume', limit: 50 }) returns the top 50 migrated tokens by volume. Only migrated tokens have active lending markets.
getAllLoanPositions(connection, mint) scans all LoanPosition PDAs for a token via getProgramAccounts with discriminator + mint filters. Returns all active positions (borrowed_amount > 0) pre-sorted by health: liquidatable → at_risk → healthy. Fetches the Raydium pool price once per call (not per position).
The SDK computes a health field for each position: 'healthy', 'at_risk', 'liquidatable', or 'none'. The bot only acts on 'liquidatable' — positions where LTV exceeds the 65% threshold. Because positions are pre-sorted, the bot breaks at the first non-liquidatable position.
const { transaction, message } = await buildLiquidateTransaction(connection, {
mint: token.mint,
liquidator: agentKeypair.publicKey.toBase58(),
borrower: position.borrower,
vault: vaultCreator,
})
When vault is provided:
vaultCreator (["torch_vault", creator])liquidator (["vault_wallet", wallet])| Property | Implementation |
|----------|---------------|
| Full custody | vault param routes all value through vault PDA |
| No extraction | Agent cannot call withdrawVault or withdrawTokens |
| Instant revocation | Authority calls unlinkWallet — bot's next tx fails with WALLET_NOT_LINKED |
| Closed loop | SOL out → vault, tokens in → vault ATA |
interface BotConfig {
rpcUrl: string // SOLANA_RPC_URL env var, fallback RPC_URL (required)
vaultCreator: string // VAULT_CREATOR env var (required)
privateKey: string | null // SOLANA_PRIVATE_KEY env var (optional)
scanIntervalMs: number // SCAN_INTERVAL_MS env var (default 30000, min 5000)
logLevel: LogLevel // LOG_LEVEL env var (default 'info')
}
SOLANA_RPC_URL must be set, fallback RPC_URL (throws on missing)VAULT_CREATOR must be set (throws on missing)SCAN_INTERVAL_MS must be >= 5000 (prevents RPC rate limiting)LOG_LEVEL must be one of debug, info, warn, errorThe bot uses a structured logger with level filtering:
[HH:MM:SS.mmm] LEVEL message
| Level | Purpose |
|-------|---------|
| debug | Scan cycle boundaries, token counts, skipped tokens |
| info | Vault status, liquidatable positions found, successful liquidations |
| warn | Failed liquidation attempts |
| error | Scan cycle errors |
Tests run against a Surfpool mainnet fork:
| Test | What It Validates | |------|-------------------| | Connection | RPC reachable, Solana version | | getTokens | Discovers migrated tokens via discriminator filter | | getLendingInfo | Reads lending state (rates, thresholds, active loans) | | getAllLoanPositions | Bulk scans active loans, verifies sort order (liquidatable first) | | getToken | Token metadata, price, status | | getVaultForWallet | Returns null for unlinked wallet | | In-process keypair | Keypair.generate() works, no external key |
Result: 9 passed, 0 failed.
| Package | Version | Purpose |
|---------|---------|---------|
| @solana/web3.js | 1.98.4 | Connection, Keypair, Transaction, sendRawTransaction |
| torchsdk | 3.7.22 | Token queries, bulk loan scanning, vault queries, liquidation builder, confirmation |
| Dev Package | Version | Purpose |
|-------------|---------|---------|
| @types/node | 20.19.33 | TypeScript node types |
| prettier | 3.8.1 | Code formatting |
| typescript | 5.9.3 | Compilation |
| Version | Changes |
|---------|---------|
| 1.0.0 | Initial read-only lending scanner. No wallet, no transactions, no state changes. |
| 2.0.0 | Added vault queries (getVault, getVaultForWallet). Still read-only. |
| 3.0.0 | Fully operational vault-based liquidation keeper. In-process keypair generation. Vault-routed buildLiquidateTransaction. Continuous scan-liquidate loop. Startup vault and link verification. Updated to [email protected]. Kit version 1.0.0. |
| 3.0.2 | Optional SOLANA_PRIVATE_KEY support (base58 or JSON byte array) for persistent agent wallet. Inline base58 decoder (no bs58 dependency). SOLANA_RPC_URL as primary env var with RPC_URL fallback. VAULT_CREATOR added to manifest requires.env. ClawHub audit consistency fixes. |
| 4.0.0 | Bulk loan scanning via getAllLoanPositions. Replaces N+1 scan pattern (getLendingInfo → getHolders → per-holder getLoanPosition) with single RPC call per token. Positions pre-sorted by health with early break. Updated to [email protected] (V33 buyback removal, 70% utilization cap). Kit version 2.0.0. |
| 4.0.1 | RPC timeout via withTimeout. Address L-1 Vulnerability with Denial-of-Service.
| 4.0.2 | Torchsdk Version Bump update to latest sdk v3.7.23
File v4.0.4:verification.md
We used Kani, a formal verification tool from AWS, to mathematically prove that torch.market's core math is correct -- not just tested, but proven for every possible input. This covers all fee calculations, bonding curve pricing, lending formulas, and reward distribution. No SOL can be created from nothing, no tokens can be minted from thin air, and no fees can exceed their stated rates.
This is not a security audit. It proves the arithmetic is correct, but does not cover access control, account validation, or economic attacks. See What Is NOT Verified for full scope limitations.
43 proof harnesses. All passing. Zero failures.
torch_market's core arithmetic has been formally verified using Kani, a Rust model checker backed by the CBMC bounded model checker. Kani exhaustively proves properties hold for all valid inputs within constrained ranges -- not just sampled test cases.
Tool: Kani Rust Verifier 0.67.0 / CBMC 6.8.0
Target: torch_market v3.7.8
Harnesses: 43 proof harnesses, all passing
Source: programs/torch_market/src/kani_proofs.rs
The proofs cover the pure arithmetic layer -- every fee calculation, bonding curve formula, lending math function, and reward distribution used by the on-chain program. Each proof harness uses symbolic (unconstrained) inputs bounded to realistic protocol ranges, and Kani exhaustively checks all possible values within those bounds.
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_buy_fee_conservation | protocol_fee + treasury_fee + after_fees == sol_amount | 0.001-200 SOL |
| verify_protocol_fee_split | dev_share + protocol_portion == protocol_fee_total | 0.001-200 SOL |
| verify_treasury_rate_bounds | rate in [500, 2000] (5-20%) flat across all tiers | 0-target SOL reserves |
| verify_treasury_rate_monotonic | More reserves -> lower treasury rate | 0-target SOL (two symbolic) |
| verify_sol_distribution_conservation | curve + treasury + creator + dev + protocol == sol_amount (zero SOL created or lost, V34 5-way sum) | 0.001-10 SOL per trade, 0-target SOL reserves |
| verify_curve_tokens_bounded_legacy | tokens_out < virtual_token_reserves (can't mint from thin air) | Legacy pool state space (IVT=107.3T) |
| verify_curve_tokens_bounded_v25 | Same property for V27 per-tier reserves | V27 pool state space (IVT=756.25M tokens) |
| verify_token_split_conservation | tokens_to_buyer + tokens_to_treasury == tokens_out | 0 to TOTAL_SUPPLY |
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_sell_sol_bounded_legacy | sol_out < virtual_sol_reserves (can't drain more SOL than exists) | Legacy pool state, max wallet cap |
| verify_sell_sol_bounded_v25 | Same property for V27 per-tier reserves | V27 pool state (IVS=3BT/8), max wallet cap |
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_transfer_fee_bounds | floor <= fee <= floor + 1 (ceiling division correct) | 0.001 SOL - 100 tokens |
| verify_transfer_fee_no_underflow | amount - fee never underflows | 0 to TOTAL_SUPPLY |
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_collateral_value_bounded_small | collateral_value <= pool_sol when collateral <= pool_tokens | 50 SOL / 50B token pool |
| verify_collateral_value_bounded_large | Same property at different pool scale | 500 SOL / 200T token pool |
| verify_ltv_zero_collateral | Zero collateral returns u64::MAX (instant liquidation) | All u64 debt values |
| verify_ltv_zero_debt | Zero debt returns 0 LTV | All u64 collateral values |
| verify_interest_no_overflow | Interest calculation doesn't overflow; interest <= principal | Up to 1000 SOL, 2%/epoch, 1 epoch |
| verify_liquidation_bonus_increases_seizure | Liquidation bonus increases collateral seized | 100 SOL pool, up to 50 SOL debt |
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_user_share_bounded | user_share <= distributable (no user can drain reward pool) | 500 SOL epoch, 50 SOL distributable |
| verify_min_claim_enforcement | [V32] Claims passing MIN_CLAIM_AMOUNT check are genuinely >= 0.1 SOL; claim never exceeds distributable | 10-10,000 SOL total volume, up to 1,000 SOL distributable |
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_ratio_fits_u64 | Pool ratio (sol * 1e9) / tokens fits in u64 | Up to 1000 SOL, tokens >= 1 token |
| verify_sell_threshold_fits_u64 | [V30] Sell threshold baseline_ratio * 12000 / 10000 fits in u64 | Same bounds as ratio proof, with 1.2x multiplier |
| verify_double_transfer_fee_positive | Token amount remains positive after two consecutive transfer fees | 1 token to TOTAL_SUPPLY |
These harnesses verify the V26 permissionless migration: SOL wrapping conservation, price-matched pool creation, and token burn accounting. Updated for V31 per-tier virtual reserves and zero-burn migration.
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_sol_wrapping_conservation | [V26] bc_debited == wsol_credited, total lamports conserved (bonding curve SOL → payer WSOL) | 0 to 200 SOL reserves, rent up to 10M lamports |
| verify_price_matched_pool_spark | [V31] Pool ratio matches curve ratio (truncation error < 1 unit) | Spark tier (50 SOL), 3 representative token values |
| verify_price_matched_pool_flame | [V31] Pool ratio matches curve ratio (truncation error < 1 unit) | Flame tier (100 SOL), 3 representative token values |
| verify_price_matched_pool_torch | [V31] Pool ratio matches curve ratio (truncation error < 1 unit) | Torch tier (200 SOL), 3 representative token values |
| verify_excess_token_burn_conservation | [V31] pool_tokens + burned_tokens == vault_total (no tokens created or lost) | Spark tier, vault up to CURVE_SUPPLY |
These harnesses verify the V31 token distribution model where IVS = 3*bonding_target/8, IVT = 756.25M tokens, CURVE_SUPPLY = 700M (70%), and TREASURY_LOCK_TOKENS = 300M (30%). V31 tunes the curve/lock split so that vault_remaining == tokens_for_pool at graduation — proving zero excess burn and full 1B supply preservation.
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_v31_full_supply_conservation_spark | wallets + vote_vault + pool + burned + treasury_lock == TOTAL_SUPPLY | Spark tier (50 SOL), exact graduation state |
| verify_v31_full_supply_conservation_flame | Same conservation for Flame tier | Flame tier (100 SOL), exact graduation state |
| verify_v31_full_supply_conservation_torch | Same conservation for Torch tier | Torch tier (200 SOL), exact graduation state |
| verify_v31_pool_tokens_positive_and_bounded | Pool tokens > 0 and <= real_token_reserves at graduation | All tiers, exact graduation state |
| verify_v31_zero_excess_burn_spark | excess_burned == 0 at graduation (zero-burn migration) | Spark tier, exact graduation state |
| verify_v31_zero_excess_burn_flame | excess_burned == 0 at graduation (zero-burn migration) | Flame tier, exact graduation state |
| verify_v31_zero_excess_burn_torch | excess_burned == 0 at graduation (zero-burn migration) | Torch tier, exact graduation state |
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_sell_fee_always_zero | SELL_FEE_BPS == 0 and computed fee == 0 for all valid sol_out | 0.001-200 SOL |
These harnesses verify the V34 creator revenue arithmetic: bonding SOL share rate bounds, monotonicity, safety of the treasury-creator subtraction, and post-migration fee share conservation.
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_creator_rate_bounds | creator_rate in [20, 100] bps (0.2%-1%) for all bonding progress | 0-target SOL reserves |
| verify_creator_rate_monotonic | More reserves → higher creator rate | 0-target SOL (two symbolic) |
| verify_creator_rate_less_than_treasury_rate | creator_rate < treasury_rate at all points (subtraction safety) | 0-target SOL reserves |
| verify_creator_fee_share_bounded | 15% share ≤ total, creator + treasury == total (conservation) | 0.001-200 SOL fee swap proceeds |
These harnesses verify end-to-end lending correctness: borrow → (optional interest accrual) → repay, proving treasury SOL conservation, correct interest-first repayment ordering, and loan zeroing.
| Harness | Property | Input Range |
|---------|----------|-------------|
| verify_lending_lifecycle_conservation | After borrow + full repay (same slot): treasury SOL exactly restored, loan zeroed, principal_paid == sol_borrowed | 100 SOL / 50T token pool, up to 50 SOL borrow |
| verify_lending_partial_repay_accounting | After partial repay: remaining_debt == total_owed - repaid, interest paid first, borrowed never increases | Up to 50 SOL, interest < 10% of principal |
| verify_lending_lifecycle_with_interest | After borrow + 1 epoch interest + full repay: treasury gains exactly the interest, principal fully returned | Up to 50 SOL, 2%/epoch, 1 epoch max |
Kani translates Rust code into a mathematical model and uses a SAT/SMT solver (CaDiCaL via CBMC) to exhaustively check whether any input can violate the asserted properties. Unlike fuzz testing which samples random inputs, Kani explores every possible execution path within the constrained input space.
A passing harness means: "there exists no input in the constrained range that violates this property."
Each harness constrains symbolic inputs to realistic protocol bounds:
MIN_SOL_AMOUNT (0.001 SOL) to BONDING_TARGET_LAMPORTS (200 SOL)TOTAL_SUPPLY (1 billion tokens, 6 decimals)INITIAL_VIRTUAL_SOL (30 SOL) to INITIAL_VIRTUAL_SOL + BONDING_TARGET_LAMPORTS (230 SOL)3*bonding_target/8 initial virtual SOL (18.75-75 SOL), INITIAL_VIRTUAL_TOKENS_V27 (756.25M tokens)INITIAL_VIRTUAL_TOKENS (107.3T raw units, legacy) or INITIAL_VIRTUAL_TOKENS_V27 (756.25T raw units, V31)CURVE_SUPPLY (700M tokens) for V31 bonding curve + pool allocationDEFAULT_INTEREST_RATE_BPS (2% per epoch)Some harnesses use concrete pool states instead of fully symbolic parameters. This is a deliberate constraint design choice driven by SAT solver tractability:
kani::any()) allow Kani to prove properties for all values in a range. This is the strongest form of proof but creates exponentially larger SAT formulas when multiple symbolic u64 values flow through u128 intermediate arithmetic.pool_sol = 100_000_000_000), eliminating those variables from the SAT formula entirely. Properties are verified exactly at those values rather than universally.virtual_tokens spanning 47 bits (which the solver cannot handle), three concrete values are tested at key pool states: bonding completion, midpoint, and maximum. This reduces solve time from intractable to sub-100ms while covering the important points.The concrete values are chosen to represent realistic protocol conditions: post-migration pool states for lending, bonding completion states for migration, and protocol-default rates for the sell cycle.
Eight harnesses were dropped during verification because they prove structurally guaranteed properties or were superseded:
| Dropped Harness | Reason |
|-----------------|--------|
| verify_curve_monotonic_fresh/half/full | Monotonicity of vt * sol / (vs + sol) is guaranteed by the formula structure for any fixed positive vt, vs. Integer floor division preserves monotonicity. |
| verify_no_round_trip_fresh/half/full | Round-trip loss (buy then sell <= original) is inherent in AMM constant-product formulas with integer truncation. Floor division always rounds down. |
| verify_ltv_100_percent | (v * 10000) / v == 10000 is a mathematical tautology. SAT solvers cannot efficiently prove symbolic u128 division cancellation. |
| verify_buyback_respects_reserve | Buyback reserve/amount constraints are enforced by handler-level checks, not arithmetic. Property is structural given the config validation. |
These properties remain true by construction. The remaining 43 harnesses cover every non-tautological safety property.
Kani proofs verify isolated pure functions extracted from the handlers. They do not cover:
| Category | Examples | Why Not Covered |
|----------|----------|-----------------|
| Access control | Who can call migrate_to_dex, update_dev_wallet | Enforced by Anchor #[derive(Accounts)] constraints, not arithmetic |
| Account validation | Fake PDAs, wrong mints, account substitution | Requires on-chain runtime context |
| State machine transitions | Can you sell before buying? Migrate before bonding completes? | Requires multi-instruction sequencing |
| CPI safety | Reentrancy via Raydium CPIs, privilege escalation | Cross-program invocation is outside arithmetic scope |
| Economic attacks | Sandwich attacks, oracle manipulation, flash loans | Require multi-transaction economic modeling |
| Anchor framework correctness | init-if-needed edge cases, PDA derivation | Framework-level concerns |
| Concurrency | Parallel transaction ordering, front-running | Solana runtime behavior |
The arithmetic layer is formally verified. Audit effort should focus on:
# Install Kani
cargo install --locked kani-verifier
cargo kani setup
# Run all harnesses
cd torch_market/programs/torch_market
cargo kani
# Run a specific harness
cargo kani --harness verify_buy_fee_conservation
All 43 harnesses pass. Most complete in under 1 second; the slowest (verify_transfer_fee_bounds, verify_treasury_rate_monotonic) take 30-55 seconds due to larger SAT formula complexity.
| Constant | Value | Description |
|----------|-------|-------------|
| TOTAL_SUPPLY | 1,000,000,000,000,000 | 1 billion tokens (6 decimals) |
| BONDING_TARGET_SPARK | 50,000,000,000 | 50 SOL bonding target (Spark tier) |
| BONDING_TARGET_FLAME | 100,000,000,000 | 100 SOL bonding target (Flame tier) |
| BONDING_TARGET_TORCH | 200,000,000,000 | 200 SOL bonding target (Torch tier, default) |
| INITIAL_VIRTUAL_SOL | 30,000,000,000 | 30 SOL initial virtual reserves (legacy) |
| INITIAL_VIRTUAL_TOKENS | 107,300,000,000,000 | Initial virtual token reserves (legacy) |
| INITIAL_VIRTUAL_TOKENS_V27 | 756,250,000,000,000 | 756.25M tokens initial virtual reserves (V27) |
| TREASURY_LOCK_TOKENS | 300,000,000,000,000 | 300M tokens locked in treasury (30% of supply) |
| CURVE_SUPPLY | 700,000,000,000,000 | 700M tokens for curve + pool (70% of supply) |
| V27 IVS | 3 * bonding_target / 8 | 18.75 SOL (Spark), 37.5 SOL (Flame), 75 SOL (Torch) |
| PROTOCOL_FEE_BPS | 100 | 1% protocol fee |
| TREASURY_FEE_BPS | 100 | 1% token treasury fee |
| TREASURY_SOL_MIN_BPS | 500 | 5% min treasury SOL rate (flat, all tiers) |
| TREASURY_SOL_MAX_BPS | 2000 | 20% max treasury SOL rate (flat, all tiers) |
| DEV_WALLET_SHARE_BPS | 1000 | [V32] 10% of protocol fee to dev (was 25%) |
| BURN_RATE_BPS | 1000 | 10% token burn on buy |
| TRANSFER_FEE_BPS | 4 | [V34] 0.04% Token-2022 transfer fee (was 3 bps, old tokens retain 3) |
| DEFAULT_INTEREST_RATE_BPS | 200 | 2% lending interest per epoch |
| DEFAULT_LIQUIDATION_BONUS_BPS | 1000 | 10% liquidation bonus |
| DEFAULT_LENDING_UTILIZATION_CAP_BPS | 7000 | [V33] 70% max treasury SOL lendable (was 50%) |
| RATIO_PRECISION | 1,000,000,000 | 1e9 ratio scale factor |
| DEFAULT_SELL_THRESHOLD_BPS | 12,000 | 120% -- sell triggers at 20% above baseline |
| DEFAULT_SELL_PERCENT_BPS | 1,500 | 15% of held tokens sold per call |
| SELL_ALL_TOKEN_THRESHOLD | 1,000,000,000,000 | 1M tokens -- sell 100% below this |
| MIN_EPOCH_VOLUME_ELIGIBILITY | 2,000,000,000 | [V32] 2 SOL min epoch volume for rewards (was 10 SOL) |
| MIN_CLAIM_AMOUNT | 100,000,000 | [V32] 0.1 SOL min claim amount |
| CREATOR_SOL_MIN_BPS | 20 | [V34] 0.2% creator SOL share at bonding start |
| CREATOR_SOL_MAX_BPS | 100 | [V34] 1% creator SOL share at bonding completion |
| CREATOR_FEE_SHARE_BPS | 1,500 | [V34] 15% creator share of fee swap proceeds |
| MIN_SOL_AMOUNT | 1,000,000 | 0.001 SOL minimum |
File v4.0.4:whitepaper.md
a programmable economic substrate
Brightside Solutions, 2026
torch.market | developer docs | audit | @torch_market
torch.market is a programmable economic substrate built on Solana. Every token launched on the protocol is its own self-sustaining economy — complete with a pricing engine, a central bank, a lending market, community governance, and optional privacy — all enclosed within a single non-extractive system where every action feeds a positive-sum feedback loop.
The protocol treats Solana not as a blockchain, but as a distributed computing substrate coupled with storage. On-chain accounts form a directed graph of economic relationships. PDA seeds define the edges. Handlers define the legal traversals. The result is a composable economic graph where anyone can launch a token and receive a complete, self-reinforcing financial ecosystem out of the box.
Unlike traditional launchpads that extract value from participants, torch.market is non-extractive by topology — there is no edge in the graph that removes value from the system. Fees become lending yield. Lending yield becomes community liquidity. Failed tokens become protocol rewards. Every outflow is an inflow somewhere else. This is not a zero-sum game by design.
The architecture works as follows:
Every token on torch.market instantiates a complete economic ecosystem. The on-chain accounts form a directed acyclic graph where each node is an autonomous economic actor:
Per-Token Economy:
Mint ──── Bonding Curve ──── Treasury
│ │ │
│ Token Vault Lending ──── Yield / Rewards
│ │ │
│ User Positions Lending ──── Collateral Vault
│ │ │
│ Votes Stars ──── Creator Payout
│ │
│ Migration ──── Raydium DEX Pool
│
└── Token-2022 Extensions
├── Transfer Fee (0.04%)
└── Confidential Transfer (optional)
Protocol Layer:
Protocol Treasury ◄── Fees + Reclaims
│
└── Epoch Rewards ──── Active Traders
Vault Layer (optional resolver):
TorchVault ◄── VaultWalletLink (identity)
│
└── Routes to: buy, sell, star, borrow, repay, swap
Each node maintains its own invariants. Each edge is structurally enforced by PDA derivation — the relationships between accounts are guaranteed by the runtime, not by application logic. A treasury can only exist for a bonding curve, which can only exist for a mint. The topology is the security model.
The Torch Vault acts as a protocol-native graph resolver — a middleware layer that sits between any caller and any action, resolving identity, SOL source, and token destination without knowing or caring what action is being performed. Two PDAs turn every economic flow in the protocol into a custody-aware operation.
Because the graph is complete — every meaningful economic flow is already a valid traversal — new capabilities emerge from the existing structure. Optional privacy is a single extension on the mint node. Vault custody is an optional dimension on every traversal. No refactoring needed. The graph just gets deeper.
Every token is launched with a token treasury, which is a wallet that acts as an automatic market maker and depreciates token supply.
The token treasury is the core mechanic of torch.market. Everyone talks supply control, but in torch.market, the protocol is the supply control. During bonding, the fee structure is as follows:
User spends 1 SOL
│
├── 1% → Protocol Fee (pre-bonding only)
│ ├── 90% → Protocol Treasury
│ └── 10% → Dev Wallet
│
├── 1% → Token Treasury Fee (lifetime)
│
└── 98% → Remainder
├── V2.3 Dynamic → 3-Way Split (V34)
│ ├── Token Treasury (19.8%→4% at start→end)
│ ├── Creator Wallet (0.2%→1% at start→end)
│ └── Total: 20% at start → 5% at completion
└── V2.3 Dynamic → Bonding Curve
└── 80% at start → 95% at completion
├── 90% → User (tokens)
└── 10% → Community Treasury (vote vault)
Dynamic Treasury Rate: The treasury SOL split uses inverse decay based on bonding progress. Early buyers contribute more to treasury (stronger early funding), late buyers get more tokens per SOL. The rate is flat across all tiers (Spark 50, Flame 100, Torch 200 SOL).
| 0 SOL | 50% of target | 100% of target | |-------|---------------|----------------| | 20% | 12.5% | 5% |
This creates a different mindset to how newly minted tokens are created. Users are not just paying into themselves, but paying into the long term growth of their communities.
The token treasury creates a positive-sum dynamic where every participant's actions strengthen the entire ecosystem:
Each user casts a vote prelaunch to determine what happens to 10% of their tokens.
Once a token reaches its bonding target (50, 100, or 200 SOL depending on tier), the community votes to decide what happens to the tokens held in the community treasury (vote vault). The voters can decide to:
Providing a group proposal solidifies project community before the DEX launch and gives all wallets a say:
1 wallet = 1 vote
The vote outcome is binding and executed automatically during migration.
Any given wallet is restricted to at most 2% of the entire supply of the token.
By restricting wallets to a hard limit on the total amount of tokens that they own before launch, this ensures better fairness for all wallets purchasing on the bond. Individual wallets can no longer control the entire supply of a given token at once, limiting the chance of price manipulation and dumping on incoming buyers.
New buyers may also be more likely to purchase a token seeing that it is "safer" from whale manipulation. A downside to this is that a single user may control more than 1 wallet, which could be considered a sybil attack against the protocol. However, this is partially mitigated by:
The token treasury pays the migration fee to DEX. Anyone can trigger it.
One of the main issues with current launchpads is that somebody has to pay the migration fee for the token to be migrated to a decentralized exchange. Because the treasury wallet is fully funded by the time the token bonds at its target (50/100/200 SOL), it is given the authority to pay the Raydium pool creation fee (0.15 SOL).
Migration is permissionless — any wallet can trigger the migration for any bonding-complete token. The triggering wallet pays a small rent fee (~0.02 SOL) for the WSOL account, while the treasury covers the 0.15 SOL Raydium pool creation fee. This means no single party can block a token from graduating to DEX.
The migration is executed as a two-step atomic process within a single transaction:
When your token bonds, anyone can complete the migration. The community is not dependent on the creator or any centralized operator.
Once a token migrates to Raydium, the treasury continues growing through the 0.04% transfer fee and lending yield.
All torch.market tokens use Solana's Token-2022 standard with a built-in 0.04% transfer fee (4 basis points). This fee is collected on every transfer — wallet to wallet, DEX trades, everything.
User transfers 100,000 tokens
│
└── 0.04% (4 tokens) → Withheld in mint
│
└── Harvested → Token Treasury
│
swap_fees_to_sol
│
┌────┴────┐
│ │
▼ ▼
Treasury Creator
(85%) (15%)
The transfer fee is not extracted from the sender or receiver as a separate charge — it's automatically withheld from the transferred amount at the Solana runtime level. The rate is immutable once set at token creation. Pre-V34 tokens retain their original 3 bps (0.03%) rate.
The accumulated transfer fees create a perpetual treasury growth engine:
harvest_fees to collect withheld tokens from transfers into the token treasury's token account.swap_fees_to_sol to sell the harvested tokens back to SOL via Raydium. Proceeds are split 85% to treasury SOL balance, 15% to creator wallet. The SDK bundles harvest + swap in one atomic transaction via buildSwapFeesToSolTransaction.The treasury accumulates SOL through fee harvesting and lending interest, creating a self-sustaining growth loop.
| Phase | SOL Source | Token Destination | |-------|-----------|-------------------| | Bonding | 1% fee + 20%→5% of buys (dynamic, 3-way: treasury + creator + curve) | Community treasury (vote vault) | | DEX | 0.04% transfer fee → sell to SOL (85% treasury, 15% creator) | Treasury SOL → lending pool + epoch rewards |
After migration, the token treasury holds SOL accumulated from fee harvesting. Holders can borrow SOL against their tokens, turning idle treasury capital into productive liquidity while earning yield for the treasury.
Token prices are derived from the Raydium pool reserves. The protocol reads the pool's SOL and token balances on-chain and computes the spot price. No external oracles are required — pricing is fully on-chain and permissionless.
Interest paid by borrowers flows back into the token treasury, compounding its SOL balance. Community members borrow SOL → buy tokens → generate volume → generate transfer fees → fees harvested and sold to SOL → treasury grows → more SOL available for lending. The treasury becomes a self-reinforcing liquidity engine.
Immutable Parameters: All lending parameters (LTV, liquidation threshold, interest rate, bonus, utilization cap) are set at pool creation and are immutable on-chain. No admin key can change them after deployment.
The protocol level fees don't just go to the development team, they're redistributed to active platform users.
During the bonding phase, 1% of every buy goes to the protocol. This is split:
The Protocol Treasury accumulates SOL and distributes it to active traders every 7 days (1 epoch).
user_reward = (user_volume / total_volume) × distributable_amount
If the protocol treasury has 500 SOL after an epoch:
If total eligible volume was 50,000 SOL and you traded 5,000 SOL:
This mechanism rewards the most active participants on the platform and creates an incentive loop: more trading → more fees → more rewards → more trading.
Not every token succeeds. torch.market has mechanisms to handle failed tokens and even give them a second chance.
If a token fails to reach its bonding target (50/100/200 SOL depending on tier) and becomes inactive for 7 days, anyone can trigger a reclaim:
Conditions for reclaim:
✓ Bonding not complete (target not reached)
✓ No trading activity for 7+ days
✓ At least 0.01 SOL in reserves (not dust)
When reclaimed:
The reclaimed SOL joins the protocol treasury and is distributed to active traders in the next epoch. Failed tokens become rewards for successful traders.
A reclaimed token can be revived if the community believes in it. Anyone can contribute SOL to a reclaimed token:
Revival threshold (V27): 3BT/8 (18.75 SOL Spark, 37.5 SOL Flame, 75 SOL Torch)
Legacy tokens: BT/8 (6.25 SOL Spark, 12.5 SOL Flame, 25 SOL Torch)
Contributors are patrons — they do NOT receive tokens for their contribution. They're simply signaling belief that the token deserves another chance. Once the revival threshold is reached:
reclaimed flag is removedThis creates a natural market for "distressed" tokens. If a token had real community support but just needed more time, revival gives it that chance.
Every token on torch.market has a message board. Messages are stored on-chain using the SPL Memo program, making them permanent and censorship-resistant.
Messages can be bundled with trades. When a user buys or sells a token, they can attach a message to the transaction. This ties commentary directly to economic action — every message comes from someone with skin in the game.
Users can also post standalone messages without trading. These are recorded via the SPL Memo program and associated with the token's message board. Standalone messages still require a wallet signature, ensuring accountability.
torch.market integrates the SAID protocol — an on-chain identity layer for agents and humans. SAID provides verifiable trust without requiring personal information.
Each verified wallet receives a trust tier based on on-chain activity and verification depth:
| Tier | Color | |------|-------| | High | Emerald / Green | | Medium | Blue | | Low | Yellow |
Reputation is earned through on-chain activity on the platform:
torch.market is designed for both humans and AI agents. There is no API server between the agent and the protocol. Solana is the compute layer. The Torch SDK builds transactions locally from the on-chain program's Anchor IDL and reads all state directly from Solana RPC. No middleman, no API keys, no trust assumptions beyond the on-chain program itself.
Every protocol action — buy, sell, lend, govern, message — is an instruction on the Solana program. The SDK constructs these instructions locally using the Anchor IDL, serializes them into unsigned transactions, and submits them to any Solana RPC endpoint. The agent signs with its own keypair. No server processes the request. No intermediary touches the transaction. The path is:
Agent → SDK (local, Anchor IDL) → Solana RPC → On-chain program
This is a direct consequence of treating Solana as a computing substrate. The program is the API. The accounts are the database. The RPC is the network layer. There is nothing else to trust, nothing else to go down, nothing else to rate-limit.
Agents discover torch.market through a standard discovery chain:
llms.txt → Human/AI-readable overview
└── agent.json → Structured metadata, capabilities, actions
└── skill.md → Machine-readable SDK reference
└── openapi.json → Full OpenAPI specification
For agents built on the Solana Agent Kit, a dedicated plugin is available:
npm install solana-agent-kit-torch-market
The plugin wraps the SDK with typed actions (buy, sell, create, vote, lend, message) and handles transaction signing automatically. Humans and agents use the same on-chain program — there is no separate "bot mode."
The on-chain program is a directed graph of economic relationships. PDA seeds define the edges, handlers define the legal traversals. The topology enforces correctness — relationships between accounts are guaranteed by the Solana runtime, not by application logic.
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ TORCH MARKET PROTOCOL v3.7.8 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ PROTOCOL LAYER │ │
│ │ ┌─────────────────┐ ┌──────────────────────────────────────┐ │ │
│ │ │ GlobalConfig │ │ ProtocolTreasury │ │ │
│ │ │ (authority, │ │ (1% fees + reclaimed SOL, │ │ │
│ │ │ settings) │ │ no floor, epoch rewards) │ │ │
│ │ └─────────────────┘ └──────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ PER-TOKEN LAYER │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Token │ │ Bonding │ │ Treasury │ │ │
│ │ │ (Mint) │───▶│ Curve │───▶│ (lending, │ │ │
│ │ │ Token-2022 │ │ (pricing, │ │ stars, │ │ │
│ │ │ 0.04% xfer │ │ voting) │ │ lending) │ │ │
│ │ └──────────────┘ └──────┬───────┘ └──────────────┘ │ │
│ │ │ │ │
│ │ ┌───────────────────┼───────────────────┐ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Token Vault │ │ Treasury's │ │ Raydium │ │ │
│ │ │ (tradeable │ │ Token Acct │ │ CPMM Pool │ │ │
│ │ │ supply) │ │ (vote vault)│ │ (post-grad) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ USER LAYER │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ UserPosition │ │ UserStats │ │ StarRecord │ │ │
│ │ │ (per-token │ │ (platform-wide │ │ (per-token │ │ │
│ │ │ holdings, │ │ volume, │ │ appreciation) │ │ │
│ │ │ vote) │ │ rewards) │ │ │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────────┐ │
│ │ VAULT LAYER (V3.1.0 — Full Custody) │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ TorchVault │ │VaultWalletLink │ │ Vault ATAs │ │ │
│ │ │ (per-creator │◀─│ (per-wallet │ │ (per-mint │ │ │
│ │ │ SOL + token │ │ reverse │ │ token accts │ │ │
│ │ │ full custody) │ │ pointer) │ │ owned by PDA) │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ INSTRUCTION HANDLERS (27 total) │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ admin │ │ token │ │ market │ │treasury│ │ dex │ │rewards │ │reclaim │ │
│ │ │ │ │ │ │ │/lending│ │migrate │ │ │ │/revival│ │
│ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │
│ ┌────────┐ ┌────────┐ │
│ │ vault │ │ swap │ │
│ │ │ │(V3.1.1)│ │
│ └────────┘ └────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────┘
The protocol uses 12 on-chain account types, all deterministic PDAs:
| Account | PDA Seeds | Purpose |
|---------|-----------|---------|
| GlobalConfig | ["global_config"] | Protocol-wide settings (authority, fees, pause flag) |
| BondingCurve | ["bonding_curve", mint] | Per-token pricing state, reserves, votes, bonding target |
| Treasury | ["treasury", mint] | Per-token treasury (SOL for lending, star balance, fee accumulation) |
| TreasuryLock | ["treasury_lock", mint] | [V31] Holds 300M locked tokens (30% of supply) |
| UserPosition | ["user_position", bc, user] | Per-user per-token holdings and vote |
| UserStats | ["user_stats", user] | Platform-wide volume and reward tracking |
| ProtocolTreasury | ["protocol_treasury_v11"] | Single treasury: fees + reclaims, no floor, epoch rewards (V32) |
| StarRecord | ["star_record", user, mint] | Prevents double-starring |
| LoanPosition | ["loan", mint, user] | Per-user per-token lending position |
| TorchVault | ["torch_vault", creator] | Per-creator full-custody SOL + token escrow |
| VaultWalletLink | ["vault_wallet", wallet] | Reverse pointer: wallet → vault (one link per wallet) |
The V3.7.8 program exposes 27 instructions across 9 handler domains:
| Domain | Instructions |
|--------|-------------|
| Admin | initialize, initialize_protocol_treasury, update_dev_wallet |
| Token | create_token |
| Market | buy, sell |
| Treasury | harvest_fees, swap_fees_to_sol |
| Migration | fund_migration_wsol, migrate_to_dex |
| Rewards | advance_protocol_epoch, claim_protocol_rewards, star_token |
| Reclaim/Revival | reclaim_failed_token, contribute_revival |
| Vault | create_vault, deposit_vault, withdraw_vault, link_wallet, unlink_wallet, transfer_authority, withdraw_tokens |
| Swap | fund_vault_wsol, vault_swap |
| Lending | borrow, repay, liquidate |
Note (V3.7.0):
update_authoritywas removed. Minimal admin surface: onlyinitializeandupdate_dev_walletrequire authority.Note (V3.7.5): V31 zero-burn migration. CURVE_SUPPLY 750M→700M, TREASURY_LOCK 250M→300M. Transfer fee 0.1%→0.03%. Vote return → treasury lock.
Note (V3.7.6): V32 protocol treasury rebalance. Reserve floor removed (0 SOL). Volume eligibility 10→2 SOL. Min claim 0.1 SOL. Fee split 90/10 (was 75/25). 39 Kani proofs.
Note (V3.7.7): V33 buyback removed, lending extended.
execute_auto_buybackinstruction removed (27 instructions). Lending utilization cap 50%→70%. Treasury simplified to fee harvest → sell → SOL → lending yield + epoch rewards.Note (V3.7.8): V34 creator revenue. Three creator income streams: bonding SOL share (0.2%→1% carved from treasury rate), 15% of post-migration fee swap proceeds, star payout (cost reduced 0.05→0.02 SOL). Transfer fee 3→4 bps (new tokens only).
creatoraccount added tobuyandswap_fees_to_sol. 43 Kani proofs.
The protocol uses a constant product bonding curve:
Buy: tokens_out = (virtual_token_reserves × sol_in) / (virtual_sol_reserves + sol_in)
Sell: sol_out = (virtual_sol_reserves × token_in) / (virtual_token_reserves + token_in)
Price: price = virtual_sol_reserves / virtual_token_reserves
Tiered Virtual Reserves (V27): Each tier has per-tier initial virtual reserves tuned for a consistent ~13.44x multiplier:
| Tier | Target | IVS (3BT/8) | IVT | Curve Supply | Treasury Lock | |------|--------|-------------|-----|-------------|---------------| | Spark | 50 SOL | 18.75 SOL | 756.25M | 700M (70%) | 300M (30%) | | Flame | 100 SOL | 37.5 SOL | 756.25M | 700M (70%) | 300M (30%) | | Torch | 200 SOL | 75 SOL | 756.25M | 700M (70%) | 300M (30%) |
BUYER'S SOL
│
▼
┌──────────────────────────────────────┐
│ TOTAL SOL INPUT │
└──────────────────────────────────────┘
│
┌──────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 1% Protocol│ │ 1% Treasury │ │ 98% │
│ Fee │ │ Fee │ │ Remaining │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
┌────┴────┐ │ ┌──────┴──────┐
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────┐
│Protocol │ │ Dev │ │ Token │ │ Token │ │ Creator │ │ Bonding │
│Treasury │ │ Wallet │ │ Treasury │ │ Treasury │ │ Wallet │ │ Curve │
│ (90%) │ │ (10%) │ │ (100%) │ │(19.8→4%)*│ │(0.2→1%)*│ │(80%→95%)* │
└─────────┘ └─────────┘ └────┬─────┘ └───────────┘ └──────────┘ └─────┬─────┘
│ │
│ *V34: Treasury split 3 ways: ▼
│ Total 20%→5% (V25 flat decay) ┌─────────────┐
│ Creator 0.2%→1% (carved out) │ TOKENS │
│ Treasury gets remainder │ OUT │
│ └──────┬──────┘
│ │
│ ┌────────┴────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌───────────┐
│ LENDING │ │ BUYER │ │ COMMUNITY │
│ (yield) │ │ (90%) │ │ TREASURY │
└─────────────┘ └─────────────┘ │ (10%) │
└─────┬─────┘
│
┌───────────┴───────────┐
│ AT MIGRATION │
│ (based on vote) │
├───────────────────────┤
│ BURN → destroy tokens │
│ RETURN → treasury lock│
└───────────────────────┘
Access Control:
initialize, update_dev_walletwithdraw_vault, link_wallet, unlink_wallet, transfer_authority, withdraw_tokensadvance_protocol_epoch, harvest_fees, swap_fees_to_sol, fund_migration_wsol, migrate_to_dex, reclaim_failed_token, liquidateVault Security (V3.1.0 — Full Custody):
creator (immutable seed) vs authority (transferable admin)Raydium Pool Validation (V27 — PDA-Based):
Pool accounts validated via PDA derivation constraints in Anchor contexts (derive_pool_state, derive_pool_vault, derive_observation_state). AMM config hardcoded to prevent fee-tier substitution. Oracle manipulation impossible — an attacker cannot derive a valid PDA pointing to a fake pool.
Core arithmetic is formally verified with Kani — 43 proof harnesses, all passing, covering every possible input in constrained ranges. Proofs cover: fee calculations, bonding curve pricing, lending formulas (borrow/repay/liquidate lifecycle), reward distribution, sell-cycle ratio math, migration conservation, and V25/V27 token distribution. No SOL can be created from nothing, no tokens can be minted from thin air, and no fees can exceed their stated rates. See VERIFICATION.md.
V3.2.1 — harvest_fees Unconstrained Destination (CRITICAL, Fixed)
The harvest_fees instruction did not validate that treasury_token_account matched the treasury PDA's ATA. An attacker could substitute their own Token-2022 ATA and steal all accumulated transfer fees. Fixed with Anchor associated_token constraints. Independent auditor verified.
V3.2.1 — Oracle Manipulation via Unconstrained Raydium Pool (Non-Issue)
Pool accounts were reported as unconstrained. Assessment: validate_pool_accounts() already validates pool ownership, vault addresses, and mint composition. V27 further hardens this with PDA-based derivation constraints.
CREATE → BONDING → COMPLETE → VOTE → MIGRATE → DEX
│ │
│ ▼
│ [0.04% Transfer Fee]
│ │
│ ▼
│ HARVEST → SWAP TO SOL → LENDING → YIELD
│ │
│ ┌────────┴────────┐
│ │ │
│ [TREASURY LENDING] [MESSAGE BOARD]
│ │
│ BORROW ↔ REPAY
│ │
│ LIQUIDATION
│
▼ (if 7 days inactive)
RECLAIM ──────────────────────────────────────────────────────┐
│ │
▼ ▼
REVIVAL (IVS per tier) ──→ TRADING RESUMES PROTOCOL TREASURY
│
▼
EPOCH REWARDS TO TRADERS
Every path in this graph feeds value back into the system. There is no terminal node that extracts value — only cycles that compound it.
| Parameter | Value | Description | |-----------|-------|-------------| | Total Supply | 1,000,000,000 | Initial token supply (6 decimals) | | Max Wallet | 2% (20,000,000) | Maximum tokens per wallet during bonding | | Bonding Target | 50 / 100 / 200 SOL | Spark / Flame / Torch tier (creator chooses at launch) | | Community Treasury | 10% | Portion of bought tokens to vote vault | | Treasury SOL Share | 20%→5% | Dynamic: decays as bonding progresses | | Token Treasury Fee | 1% | Fee on all buys (lifetime) | | Protocol Fee | 1% | Fee during bonding (90% treasury, 10% dev) | | Transfer Fee | 0.04% (4 bps) | [V34] Post-migration fee on all transfers (immutable per mint, pre-V34 tokens retain 3 bps) | | Inactivity Period | 7 days | Time before failed token can be reclaimed | | Revival Threshold (V27) | 3BT/8 per tier (18.75 / 37.5 / 75 SOL) | SOL needed to revive a reclaimed token | | Voting Duration | ~24 hours | Time for community to vote on burn/return | | Epoch Duration | 7 days | Protocol reward distribution cycle | | Reward Eligibility | 2 SOL | Minimum epoch volume for protocol rewards | | Min Claim | 0.1 SOL | Minimum payout per claim (rejects dust) | | Protocol Reserve | 0 SOL | All fees distributed each epoch (no floor) | | Max LTV | 50% | Maximum loan-to-value for treasury lending | | Liquidation Threshold | 65% | Debt-to-collateral ratio triggering liquidation | | Interest Rate | 2% / epoch | Lending interest per ~7-day epoch | | Liquidation Bonus | 10% | Discount for liquidators on seized collateral | | Utilization Cap | 70% | Max fraction of treasury SOL available for loans | | Min Borrow | 0.1 SOL | Minimum borrow amount per loan |
| Version | Features |
|---------|----------|
| V1 | Basic bonding curve, buy/sell |
| V2 | Treasury, fee accumulation, permanent burn split |
| V3 | Token-2022 with transfer fees |
| V4 | Failed token reclaim, platform rewards |
| V5 | Raydium DEX migration |
| V8 | Dev wallet split (10% of protocol fee, updated V32 from 25%) |
| V9 | Ratio-gated sell cycle (buyback removed in V33) |
| V10 | Simplified star system with auto-payout |
| V11 | Protocol treasury with epoch rewards (reserve floor removed in V32) |
| V12 | Token revival |
| V2.2 | 10% tokens to community treasury, 90% to buyer |
| V2.3 | Dynamic treasury SOL rate: 20%→5% decay |
| V2.4 | Treasury lending: borrow SOL against token collateral |
| V3.0.0 | Torch Vault — Multi-Wallet Identity. Per-creator SOL escrow with multi-wallet support. 6 new vault instructions. |
| V3.1.0 | Vault Full Custody. Buy, sell, star, borrow, repay all vault-routed. New withdraw_tokens (authority-only). |
| V3.1.1 | Vault DEX Swap. fund_vault_wsol + vault_swap for Raydium trading via vault. |
| V3.2.0 | Platform treasury merged into protocol treasury. Single reward system. |
| V3.2.1 | Security: harvest_fees hardened. Critical vulnerability fixed, auditor verified. |
| V3.3.0 | Tiered Bonding Curves. Spark (50 SOL), Flame (100 SOL), Torch (200 SOL). |
| V3.5.0 | V25 Pump-Style Token Distribution. IVS = BT/8, IVT = 900M tokens, ~81x multiplier. 35 Kani proofs. |
| V3.6.0 | V26 Permissionless Migration + Authority Revocation. Mint and freeze authority revoked permanently at migration. |
| V3.6.x | V27 Treasury Lock + PDA Pool Validation. 250M tokens locked at creation. IVS = 3BT/8, 13.44x multiplier. |
| V3.7.0 | V28 update_authority Removed. Authority transfer via multisig tooling. 27 instructions. Minimal admin surface. |
| V3.7.5 | V31 Zero-Burn Migration. CURVE_SUPPLY 750M→700M, TREASURY_LOCK 250M→300M. Transfer fee 0.1%→0.03%. Vote return → treasury lock. |
| V3.7.6 | V32 Protocol Treasury Rebalance. Reserve floor removed. Volume eligibility 10→2 SOL. Min claim 0.1 SOL. Fee split 90/10. 39 Kani proofs. |
| V3.7.7 | V33 Buyback Removed, Lending Extended. execute_auto_buyback removed (27 instructions). Lending utilization cap 50%→70%. Treasury simplified to: fee harvest → sell → SOL → lending yield + epoch rewards. |
| V3.7.8 | V34 Creator Revenue + Transfer Fee Bump. Three creator income streams: bonding SOL share (0.2%→1%), post-migration fee share (85/15 treasury/creator), star payout. Star cost 0.05→0.02 SOL. Transfer fee 3→4 bps (new tokens only). 43 Kani proofs. |
torch.market is a programmable economic substrate. Every token launched on the protocol receives a complete, self-sustaining economy: a pricing engine, a treasury with lending yield, community governance, creator rewards, a failure-recovery system, and optional privacy — all composed from a small set of on-chain primitives that enforce correctness by topology.
The protocol is non-extractive by design. There is no configuration that makes it extractive because the graph doesn't have that edge. Fees become lending yield. Lending yield becomes community liquidity. Failed tokens become protocol rewards. Interest from borrowers compounds the treasury. Every outflow is an inflow somewhere else in the system.
The Torch Vault adds a custody-aware resolution layer that makes every economic flow in the protocol accessible through a single identity — without adding economic complexity. Agents and humans use the same on-chain program, the same API, the same graph.
The individual pieces — bonding curves, treasuries, lending, governance — are not new. The arrangement is. A closed, positive-sum economic graph where anyone can launch a token and receive a complete financial ecosystem, running on Solana as a distributed computing substrate.
This is not a zero-sum game. This is not a launchpad. This is a substrate for programmable economies.
© 2026 Brightside Solutions. All rights reserved.
Terms | Privacy | torch.market
File v4.0.4:agent.json
{ "name": "Torch Liquidation Bot", "description": "Autonomous vault-based liquidation keeper for Torch Market lending on Solana. Scans all migrated tokens for underwater loan positions (LTV > 65%) using the SDK's built-in bulk loan scanner (getAllLoanPositions), builds and executes liquidation transactions through a Torch Vault, and collects a 10% collateral bonus. The agent keypair is generated in-process -- disposable, holds nothing of value. All SOL and collateral tokens route through the vault. The human principal creates the vault, funds it, links the agent, and retains full control. Built on torchsdk v3.7.22 and the Torch Market protocol.", "version": "4.0.4", "type": "protocol", "disable-model-invocation": true, "website": "https://torch.market", "socials": { "twitter": "https://twitter.com/torch_market" }, "distribution": { "clawhub": "https://clawhub.ai/mrsirg97-rgb/torch-liquidation-bot", "kit": "https://github.com/mrsirg97-rgb/torch-liquidation-kit", "npm_bot": "torch-liquidation-bot", "npm_sdk": "torchsdk" }, "requires": { "env": [ { "name": "SOLANA_RPC_URL", "description": "Solana RPC endpoint (HTTPS). Fallback: RPC_URL", "sensitive": false, "required": true }, { "name": "VAULT_CREATOR", "description": "Vault creator pubkey -- identifies which Torch Vault the bot operates through. Required.", "sensitive": false, "required": true }, { "name": "SOLANA_PRIVATE_KEY", "description": "Disposable controller keypair (base58 or byte array JSON). Optional -- the bot generates a fresh keypair in-process if not provided (recommended). If provided, should be a fresh keypair with ~0.01 SOL for gas. Holds no value. All liquidation capital lives in the vault.", "sensitive": true, "required": false } ], "install": [ { "id": "npm-torch-liquidation-bot", "kind": "npm", "package": "torch-liquidation-bot@^4.0.2", "flags": [], "label": "Install Torch Liquidation Bot (npm, optional -- SDK is bundled in lib/torchsdk/ and bot source is bundled under lib/kit on clawhub)" } ] }, "capabilities": [ "vault-full-custody", "vault-escrow", "authority-separation", "liquidation-keeper", "lending-market-scanner", "autonomous-scan-loop", "in-process-keypair", "read-only-mode", "said-verification" ], "chain": "solana", "network": "mainnet", "program_id": "8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT", "endpoints": { "skill": "https://torch.market/skill.md", "llms_txt": "https://torch.market/llms.txt", "docs": "https://torch-market-docs.vercel.app" }, "actions": [ { "name": "TORCH_SCAN_LENDING_MARKETS", "description": "Discover all migrated tokens and check their lending state for active loans" }, { "name": "TORCH_CHECK_LOAN_HEALTH", "description": "Check a borrower's loan position -- collateral, debt, interest, LTV, health status" }, { "name": "TORCH_LIQUIDATE", "description": "Liquidate underwater loan position (LTV > 65%) via vault -- vault SOL pays debt, collateral tokens at 10% discount go to vault ATA" }, { "name": "TORCH_GET_VAULT", "description": "Get vault state by creator -- SOL balance, linked wallets, authority, token holdings" }, { "name": "TORCH_GET_VAULT_FOR_WALLET", "description": "Reverse lookup -- find which vault a controller wallet is linked to" }, { "name": "TORCH_GET_LENDING_INFO", "description": "Get lending configuration and state for a migrated token (rates, caps, active loans)" }, { "name": "TORCH_GET_LOAN", "description": "Get loan position details for a wallet -- collateral, debt, interest, LTV, health status" }, { "name": "TORCH_LIST_TOKENS", "description": "List migrated tokens with active lending markets" }, { "name": "TORCH_GET_TOKEN", "description": "Get detailed token info including price, treasury state, and lending parameters" }, { "name": "TORCH_CONFIRM", "description": "Confirm transaction on-chain via Solana RPC -- verifies signer, checks Torch instructions, determines event type. Does NOT contact SAID Protocol." } ], "constants": { "lending_max_ltv_percent": 50, "lending_liquidation_threshold_percent": 65, "lending_interest_rate_per_epoch_percent": 2, "lending_liquidation_bonus_percent": 10, "lending_utilization_cap_percent": 70, "min_borrow_sol": 0.1, "default_scan_interval_ms": 30000, "min_scan_interval_ms": 5000 }, "safety": { "vault_full_custody": true, "controller_holds_no_value": true, "private_key_optional": true, "in_process_keypair_generation": true, "local_transaction_building": true, "no_api_dependency": true, "keys_never_transmitted": true, "signing_is_local_only": true, "vault_closed_economic_loop": true, "vault_authority_only_withdrawals": true, "vault_instant_revocation": true, "transaction_expiry_seconds": 60, "open_source": true, "sdk_audited": true, "rpc_timeout_seconds": 30 }, "tags": [ "solana", "defi", "liquidation", "liquidation-bot", "liquidation-keeper", "collateral-lending", "vault-custody", "ai-agents", "agent-wallet", "agent-safety", "treasury-lending", "bonding-curve", "fair-launch", "token-2022", "raydium", "community-treasury", "protocol-rewards", "solana-agent-kit", "escrow", "anchor", "pda", "on-chain", "autonomous-agent", "keeper-bot", "torch-market" ], "verification": { "said": { "wallet": "8cpWmV4kGdvxVYYNBEMPNwsJSRVQw5MQ9NXn4t293nMa", "pda": "2rNknLxB7nWYJRgr2tZrNoc7PNDy3PKwKZa9YStbLMmb", "verified": true, "trust_tier": "medium", "badge": "https://api.saidprotocol.com/api/badge/8cpWmV4kGdvxVYYNBEMPNwsJSRVQw5MQ9NXn4t293nMa.svg" } } }
File v4.0.4:lib/torchsdk/torch_market.json
{ "address": "8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT", "metadata": { "name": "torch_market", "version": "3.7.8", "spec": "0.1.0", "description": "torch.market" }, "instructions": [ { "name": "advance_protocol_epoch", "docs": [ "[V11] Advance the protocol treasury epoch.", "Permissionless crank - calculates distributable amount above reserve floor." ], "discriminator": [ 215, 39, 184, 104, 13, 104, 63, 21 ], "accounts": [ { "name": "payer", "writable": true, "signer": true }, { "name": "protocol_treasury", "writable": true, "pda": { "seeds": [ { "kind": "const", "value": [ 112, 114, 111, 116, 111, 99, 111, 108, 95, 116, 114, 101, 97, 115, 117, 114, 121, 95, 118, 49, 49 ] } ] } } ], "args": [] }, { "name": "borrow", "docs": [ "[V2.4] Borrow SOL from treasury using tokens as collateral.", "Lock tokens in collateral vault, receive SOL up to 50% of collateral value." ], "discriminator": [ 228, 253, 131, 202, 207, 116, 89, 18 ], "accounts": [ { "name": "borrower", "writable": true, "signer": true }, { "name": "mint" }, { "name": "bonding_curve", "pda": { "seeds": [ { "kind": "const", "value": [ 98, 111, 110, 100, 105, 110, 103, 95, 99, 117, 114, 118, 101 ] }, { "kind": "account", "path": "mint" } ] } }, { "name": "treasury", "writable": true, "pda": { "seeds": [ { "kind": "const", "value": [ 116, 114, 101, 97, 115, 117, 114, 121 ] }, { "kind": "account", "path": "mint" } ] } }, { "name": "collateral_vault", "docs": [ "Collateral vault - holds locked tokens. Created on first borrow for this token." ], "writable": true, "pda": { "seeds": [ { "kind": "const", "value": [ 99, 111, 108, 108, 97, 116, 101, 114, 97, 108, 95, 118, 97, 117, 108, 116 ] }, { "kind": "account", "path": "mint" } ] } }, { "name": "borrower_token_account", "docs": [ "Borrower's token account (source of collateral)" ], "writable": true, "pda": { "seeds": [ { "kind": "account", "path": "borrower" }, { "kind": "account", "path": "token_program" }, { "kind": "account", "path": "mint" } ], "program": { "kind": "const", "value": [ 140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216, 219, 233, 248, 89 ] } } }, { "name": "loan_position", "docs": [ "Loan position PDA - created on first borrow" ], "writable": true, "pda": { "seeds": [ { "kind": "const", "value": [ 108, 111, 97, 110 ] }, { "kind": "account", "path": "mint" }, { "kind": "account", "path": "borrower" } ] } }, { "name": "pool_state", "docs": [ "[V27] Raydium pool state — constrained via PDA derivation" ] }, { "name": "token_vault_0", "docs": [ "[V27] Pool token vault 0 — constrained via PDA derivation" ] }, { "name": "token_vault_1", "docs": [ "[V27] Pool token vault 1 — constrained via PDA derivation" ] }, { "name": "torch_vault", "docs": [ "[V18] Optional: Torch vault — collateral comes from vault ATA, SOL goes to vault" ], "writable": true, "optional": true }, { "name": "vault_wallet_link", "docs": [ "[V18] Optional: Proves borrower is authorized to use the vault" ], "optional": true, "pda": { "seeds": [ { "kind": "const", "value": [ 118, 97, 117, 108, 116, 95, 119, 97, 108, 108, 101, 116 ] }, { "kind": "account", "path": "borrower" } ] } }, { "name": "vault_token_account", "docs": [ "[V18] Optional: Vault's token ATA — collateral taken from here" ], "writable": true, "optional": true, "pda": { "seeds": [ { "kind": "account", "path": "torch_vault" }, { "kind": "account", "path": "token_program" }, { "kind": "account", "path": "mint" } ], "program": { "kind": "const", "value": [ 140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216, 219, 233, 248, 89 ] } } }, { "name": "token_program" }, { "name": "system_program", "address": "11111111111111111111111111111111" } ], "args": [ { "name": "args", "type": { "defined": { "name": "BorrowArgs" } } } ] }, { "name": "buy", "docs": [ "Buy tokens from the bonding curve." ], "discriminator": [ 102, 6, 61, 18, 1, 218, 235, 234 ], "accounts": [ { "name": "buyer", "writable": true, "signer": true }, { "name": "global_config", "pda": { "seeds": [ { "kind": "const", "value": [ 103, 108, 111, 98, 97, 108, 95, 99, 111, 110, 102, 105, 103 ] } ] } }, { "name": "dev_wallet", "writable": true }, { "name": "mint", "writable": true }, { "name": "bonding_curve", "writable": true, "pda": { "seeds": [ { "kind": "const", "value": [ 98, 111, 110, 100, 105, 110, 103, 95, 99, 117, 114, 118, 101 ] }, { "kind": "account", "path": "mint" } ] } }, { "name": "token_vault", "writable": true, "pda": { "seeds": [ { "kind": "account", "path": "bonding_curve" }, { "kind": "account", "path": "token_program" }, { "kind": "account", "path": "mint" } ], "program": { "kind": "const", "value": [ 140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216, 219, 233, 248, 89 ] } } }, { "name": "token_treasury", "docs": [ "Per-token treasury for buybacks [V2]" ], "writable": true, "pda": { "seeds": [ { "kind": "const", "value": [ 116,
Archive v4.0.3: 22 files, 94814 bytes
Files: agent.json (6139b), audit.md (21316b), design.md (12214b), lib/kit/config.js (1577b), lib/kit/index.js (7088b), lib/kit/types.js (182b), lib/kit/utils.js (1987b), lib/torchsdk/constants.js (6651b), lib/torchsdk/ephemeral.js (1330b), lib/torchsdk/gateway.js (1581b), lib/torchsdk/index.js (7875b), lib/torchsdk/program.js (12750b), lib/torchsdk/quotes.js (3751b), lib/torchsdk/said.js (3617b), lib/torchsdk/tokens.js (35336b), lib/torchsdk/torch_market.json (224333b), lib/torchsdk/transactions.js (65753b), lib/torchsdk/types.js (144b), SKILL.md (19765b), verification.md (16919b), whitepaper.md (48897b), _meta.json (138b)
Machine endpoints, contract coverage, trust signals, runtime metrics, benchmarks, and guardrails for agent-to-agent use.
Machine interfaces
Contract coverage
Status
missing
Auth
None
Streaming
No
Data region
Unspecified
Protocol support
Requires: none
Forbidden: none
Guardrails
Operational confidence: low
curl -s "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/snapshot"
curl -s "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/contract"
curl -s "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/trust"
Operational fit
Trust signals
Handshake
UNKNOWN
Confidence
unknown
Attempts 30d
unknown
Fallback rate
unknown
Runtime metrics
Observed P50
unknown
Observed P95
unknown
Rate limit
unknown
Estimated cost
unknown
Do not use if
Raw contract, invocation, trust, capability, facts, and change-event payloads for machine-side inspection.
Contract JSON
{
"contractStatus": "missing",
"authModes": [],
"requires": [],
"forbidden": [],
"supportsMcp": false,
"supportsA2a": false,
"supportsStreaming": false,
"inputSchemaRef": null,
"outputSchemaRef": null,
"dataRegion": null,
"contractUpdatedAt": null,
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Invocation Guide
{
"preferredApi": {
"snapshotUrl": "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/snapshot",
"contractUrl": "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/contract",
"trustUrl": "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/trust"
},
"curlExamples": [
"curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/snapshot\"",
"curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/contract\"",
"curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/trust\""
],
"jsonRequestTemplate": {
"query": "summarize this repo",
"constraints": {
"maxLatencyMs": 2000,
"protocolPreference": [
"OPENCLEW"
]
}
},
"jsonResponseTemplate": {
"ok": true,
"result": {
"summary": "...",
"confidence": 0.9
},
"meta": {
"source": "CLAWHUB",
"generatedAt": "2026-10-09T03:43:12.152Z"
}
},
"retryPolicy": {
"maxAttempts": 3,
"backoffMs": [
500,
1500,
3500
],
"retryableConditions": [
"HTTP_429",
"HTTP_503",
"NETWORK_TIMEOUT"
]
}
}Trust JSON
{
"status": "unavailable",
"handshakeStatus": "UNKNOWN",
"verificationFreshnessHours": null,
"reputationScore": null,
"p95LatencyMs": null,
"successRate30d": null,
"fallbackRate": null,
"attempts30d": null,
"trustUpdatedAt": null,
"trustConfidence": "unknown",
"sourceUpdatedAt": null,
"freshnessSeconds": null
}Capability Matrix
{
"rows": [
{
"key": "OPENCLEW",
"type": "protocol",
"support": "unknown",
"confidenceSource": "profile",
"notes": "Listed on profile"
}
],
"flattenedTokens": "protocol:OPENCLEW|unknown|profile"
}Facts JSON
[
{
"factKey": "vendor",
"category": "vendor",
"label": "Vendor",
"value": "Clawhub",
"href": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceUrl": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-04-15T00:45:39.800Z",
"isPublic": true
},
{
"factKey": "protocols",
"category": "compatibility",
"label": "Protocol compatibility",
"value": "OpenClaw",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/contract",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/contract",
"sourceType": "contract",
"confidence": "medium",
"observedAt": "2026-04-15T00:45:39.800Z",
"isPublic": true
},
{
"factKey": "traction",
"category": "adoption",
"label": "Adoption signal",
"value": "2K downloads",
"href": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceUrl": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceType": "profile",
"confidence": "medium",
"observedAt": "2026-04-15T00:45:39.800Z",
"isPublic": true
},
{
"factKey": "latest_release",
"category": "release",
"label": "Latest release",
"value": "4.0.4",
"href": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceUrl": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-02-28T15:16:50.792Z",
"isPublic": true
},
{
"factKey": "handshake_status",
"category": "security",
"label": "Handshake status",
"value": "UNKNOWN",
"href": "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/trust",
"sourceUrl": "https://www.xpersona.co/api/v1/agents/clawhub-mrsirg97-rgb-torchliquidationbot/trust",
"sourceType": "trust",
"confidence": "medium",
"observedAt": null,
"isPublic": true
}
]Change Events JSON
[
{
"eventType": "release",
"title": "Release 4.0.4",
"description": "No user-facing changes detected in this release. Version bump only. - Version number updated to 4.0.4. - No changes to files, functionality, or documentation content. - latest sdk v3.7.23 bundled",
"href": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceUrl": "https://clawhub.ai/mrsirg97-rgb/torchliquidationbot",
"sourceType": "release",
"confidence": "medium",
"observedAt": "2026-02-28T15:16:50.792Z",
"isPublic": true
}
]Sponsored
Ads related to Torch Liquidation Bot and adjacent AI workflows.