torch-liquidation-bot 10.5.0 → 10.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/readme.md +67 -36
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "torch-liquidation-bot",
3
- "version": "10.5.0",
3
+ "version": "10.5.2",
4
4
  "description": "autonomous vault-based liquidation keeper for Torch Market lending on Solana using torchsdk",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # torch-liquidation-bot
2
2
 
3
- Vault-based liquidation keeper for [Torch Market](https://torch.market) on Solana. Generates an agent keypair in-process -- no user wallet required. All operations route through a Torch Vault.
3
+ Vault-based liquidation keeper for [Torch Market](https://torch.market) on Solana. Generates an agent keypair in-process no user wallet required. All operations route through a Torch Vault. Built on [torchsdk](https://www.npmjs.com/package/torchsdk) v10.5.0.
4
4
 
5
5
  ## Install
6
6
 
@@ -11,55 +11,71 @@ npm install torch-liquidation-bot
11
11
  ## Quick Start
12
12
 
13
13
  ```bash
14
- # 1. start the bot -- it prints its agent wallet on startup
14
+ # 1. start the bot it prints its agent wallet on startup
15
15
  VAULT_CREATOR=<your-vault-creator-pubkey> SOLANA_RPC_URL=<rpc> npx torch-liquidation-bot
16
16
 
17
17
  # 2. link the printed agent wallet to your vault (one-time, from your authority wallet)
18
- # the bot will print the exact instructions if the wallet is not yet linked
18
+ # the bot prints the exact instructions if the wallet is not yet linked
19
19
 
20
- # 3. restart the bot -- it will begin scanning and liquidating
20
+ # 3. restart the bot it will begin scanning and liquidating
21
21
  ```
22
22
 
23
23
  ## What It Does
24
24
 
25
- Every migrated token on Torch has a built-in lending market. Borrowers lock tokens as collateral and borrow SOL. When a position's LTV exceeds the liquidation threshold, anyone can liquidate it and earn the liquidation bonus.
25
+ Every migrated token on Torch has a built-in lending market. Borrowers lock tokens as collateral and borrow SOL. When a position's LTV exceeds the 65% liquidation threshold, anyone can liquidate it and collect a 10% collateral bonus.
26
26
 
27
27
  This bot:
28
28
 
29
- 1. Generates a disposable `Keypair` in-process (no private key leaves the process)
29
+ 1. Generates a disposable `Keypair` in-process (no private key leaves the process; optional `SOLANA_PRIVATE_KEY` overrides)
30
30
  2. Verifies the vault exists and the agent wallet is linked
31
- 3. Scans migrated tokens with `getAllLoanPositions()` -- one RPC call per token, positions pre-sorted liquidatable-first
32
- 4. Executes `buildLiquidateTransaction()` for each liquidatable position
33
- 5. Confirms the transaction via `confirmTransaction()`
31
+ 3. Scans migrated tokens with `getAllLoanPositions()` one RPC call per token, positions pre-sorted liquidatable-first
32
+ 4. Executes `buildLiquidateTransaction()` for each liquidatable position, routing bonus tokens into the vault
33
+ 5. Confirms via `confirmTransaction()` and records metrics
34
34
  6. Repeats on a configurable interval
35
35
 
36
- All value flows through the vault. The agent wallet is a stateless controller.
36
+ All value flows through the vault. The agent wallet is a stateless controller that holds only gas SOL.
37
+
38
+ **Off-chain health visibility (torchsdk v10.5.0+):** the SDK projects accrued interest forward to the current slot, so positions that have drifted past the liquidation threshold via interest accrual alone — without any on-chain instruction touching them — show up as `health=liquidatable` immediately. No need for someone else to poke the loan first.
37
39
 
38
40
  ## Configuration
39
41
 
40
42
  | Variable | Required | Default | Description |
41
43
  |----------|----------|---------|-------------|
42
- | `SOLANA_RPC_URL` | yes | -- | Solana RPC endpoint (fallback: `RPC_URL`) |
43
- | `VAULT_CREATOR` | yes | -- | Vault creator pubkey (identifies which vault to use) |
44
- | `SOLANA_PRIVATE_KEY` | no | -- | Disposable controller keypair (base58 or JSON byte array). If omitted, generates fresh keypair on startup |
44
+ | `SOLANA_RPC_URL` | yes | | Solana RPC endpoint (fallback: `RPC_URL`) |
45
+ | `VAULT_CREATOR` | yes | | Vault creator pubkey (identifies which vault to use) |
46
+ | `SOLANA_PRIVATE_KEY` | no | | Disposable controller keypair (base58 or JSON byte array). If omitted, generates fresh keypair on startup |
45
47
  | `SCAN_INTERVAL_MS` | no | `30000` | Milliseconds between scan cycles (min 5000) |
48
+ | `SCAN_LIMIT` | no | `50` | Max tokens scanned per cycle (`0` = unlimited) |
49
+ | `MIN_AGENT_BALANCE_SOL` | no | `0.01` | Pause liquidations when agent's gas balance drops below this |
46
50
  | `LOG_LEVEL` | no | `info` | `debug`, `info`, `warn`, `error` |
51
+ | `LOG_FORMAT` | no | `text` | `text` (human-readable) or `json` (structured, one record per line) |
47
52
 
48
53
  ## Vault Setup
49
54
 
50
55
  ```
51
- User (hardware wallet) -> Creates vault, deposits SOL
52
- -> Links bot's agent wallet
53
- Bot (disposable) -> Scans for liquidatable positions
54
- -> Executes liquidations using vault funds
55
- -> All proceeds return to vault
56
- User -> Withdraws from vault (authority only)
56
+ User (hardware wallet) creates vault, deposits SOL
57
+ links bot's agent wallet
58
+ Bot (disposable) scans for liquidatable positions
59
+ executes liquidations using vault funds
60
+ all proceeds return to vault
61
+ User withdraws from vault (authority only)
57
62
  ```
58
63
 
59
- The agent wallet needs minimal SOL for gas (~0.01 SOL). All liquidation value flows through the vault.
64
+ The agent wallet needs minimal SOL for gas (~0.01 SOL default, configurable via `MIN_AGENT_BALANCE_SOL`). All liquidation value flows through the vault. If the agent balance drops below the threshold, the bot pauses that cycle and logs a warning rather than failing transactions mid-flight.
65
+
66
+ ## Operational Features
67
+
68
+ - **Graceful shutdown.** `SIGINT` / `SIGTERM` abort the current scan cleanly — the bot finishes the in-flight RPC call, skips remaining tokens in the cycle, and exits with `graceful shutdown complete` + code 0. Safe for `systemctl stop`, container orchestrators, etc.
69
+ - **Retry with exponential backoff.** Every RPC call is wrapped in a 3-attempt retry with 1s / 2s / 4s delays and tracked via `stats.rpcRetries`. Transient Solana RPC failures don't kill a scan cycle.
70
+ - **30s timeout on every SDK call.** A hung RPC can't wedge the bot; the timeout throws and the retry logic kicks in.
71
+ - **Balance-pause check.** Pre-flight check before each scan cycle — if the agent's balance dips below `MIN_AGENT_BALANCE_SOL`, the cycle is skipped with an error log.
72
+ - **Structured JSON logging.** `LOG_FORMAT=json` emits one JSON record per line — pipe straight into Vector, Datadog, Loki, etc.
73
+ - **Runtime stats.** Every cycle logs cumulative counters: `cycles`, `liquidations`, `failures`, `rpc_retries`, `uptime_sec`, `lastError`.
60
74
 
61
75
  ## Programmatic Usage
62
76
 
77
+ If you want the scanning loop embedded in your own service instead of running the bot binary:
78
+
63
79
  ```typescript
64
80
  import { Connection, Keypair } from '@solana/web3.js'
65
81
  import {
@@ -74,19 +90,28 @@ import {
74
90
  const connection = new Connection('<rpc>', 'confirmed')
75
91
  const agent = Keypair.generate()
76
92
 
77
- // verify vault and link
93
+ // verify vault and link (one-time)
78
94
  const vaultCreator = '<vault-creator-pubkey>'
79
95
  const vault = await getVault(connection, vaultCreator)
96
+ if (!vault) throw new Error('vault not found')
97
+
80
98
  const link = await getVaultForWallet(connection, agent.publicKey.toBase58())
99
+ if (!link) throw new Error('agent wallet not linked to vault')
81
100
 
82
101
  // scan and liquidate
83
- const { tokens } = await getTokens(connection, { status: 'migrated', sort: 'volume', limit: 50 })
102
+ const { tokens } = await getTokens(connection, {
103
+ status: 'migrated',
104
+ sort: 'volume',
105
+ limit: 50,
106
+ })
84
107
 
85
108
  for (const token of tokens) {
86
109
  const { positions } = await getAllLoanPositions(connection, token.mint)
87
110
 
88
111
  for (const pos of positions) {
89
- if (pos.health !== 'liquidatable') break // pre-sorted, done
112
+ // positions are pre-sorted liquidatable at_risk healthy.
113
+ // health is already projected to the current slot — no need to call accrue_interest first.
114
+ if (pos.health !== 'liquidatable') break
90
115
 
91
116
  const { transaction } = await buildLiquidateTransaction(connection, {
92
117
  mint: token.mint,
@@ -104,37 +129,43 @@ for (const token of tokens) {
104
129
  ## Architecture
105
130
 
106
131
  ```
107
- src/
108
- ├── types.ts -- BotConfig interface
109
- ├── config.ts -- loadConfig() (SOLANA_RPC_URL, VAULT_CREATOR, SOLANA_PRIVATE_KEY, SCAN_INTERVAL_MS, LOG_LEVEL)
110
- ├── utils.ts -- sol(), bpsToPercent(), withTimeout(), createLogger()
111
- └── index.ts -- vault-based liquidation loop
132
+ packages/bot/src/
133
+ ├── constants.ts retry/timeout constants, log level/format tables
134
+ ├── types.ts BotConfig, BotStats, ScanContext, Logger, LogLevel, LogFormat
135
+ ├── config.ts loadConfig() + env-var validation
136
+ ├── utils.ts withTimeout, withRetry, createLogger, sol/bpsToPercent formatters
137
+ └── index.ts — scanAndLiquidate + main() with graceful shutdown
112
138
  ```
113
139
 
114
140
  ## Testing
115
141
 
116
- Requires [Surfpool](https://github.com/nicholasgasior/surfpool) running a mainnet fork:
142
+ Requires [Surfpool](https://github.com/txtx/surfpool) running a mainnet fork:
117
143
 
118
144
  ```bash
119
145
  surfpool start --network mainnet --no-tui
146
+ pnpm build
120
147
  pnpm test
121
148
  ```
122
149
 
150
+ The e2e covers the full flow: create token → bond → migrate → open loan → time-travel past threshold → scan → liquidate via vault → verify cleanup → balance-pause check → config validation → subprocess SIGTERM shutdown.
151
+
123
152
  ## Security
124
153
 
125
154
  - Agent keypair generated in-process with `Keypair.generate()` (or loaded from optional `SOLANA_PRIVATE_KEY`)
126
- - Vault model: agent is a stateless controller, all value stays in the vault
155
+ - Vault model: agent is a stateless controller; all value stays in the vault
127
156
  - Authority can unlink the agent wallet instantly via `buildUnlinkWalletTransaction()`
128
- - All SDK calls wrapped with 30-second timeout
129
- - Minimal dependencies: `@solana/web3.js` + `torchsdk`
157
+ - All SDK calls wrapped with a 30-second timeout + 3-attempt retry
158
+ - Pre-flight balance check pauses liquidations before funds run out for gas
159
+ - Minimal dependencies: `@solana/web3.js`, `torchsdk`, `bs58`, `@solana/spl-token`
130
160
  - No post-install hooks, no remote code fetching
131
- - `disable-model-invocation: true` -- agents cannot invoke this skill autonomously
161
+ - `disable-model-invocation: true` agents cannot invoke this skill autonomously
132
162
 
133
163
  ## Links
134
164
 
135
- - [torchsdk](https://github.com/mrsirg97-rgb/torchsdk) -- the SDK powering this bot
136
- - [Torch Market](https://torch.market) -- the protocol
137
- - [ClawHub](https://clawhub.ai/mrsirg97-rgb/torch-liquidation-bot) -- skill registry
165
+ - [torchsdk](https://github.com/mrsirg97-rgb/torchsdk) the SDK powering this bot
166
+ - [Torch Market](https://torch.market) the protocol
167
+ - [ClawHub](https://clawhub.ai/mrsirg97-rgb/torch-liquidation-bot) skill registry
168
+ - program id: `8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT`
138
169
 
139
170
  ## License
140
171