torch-liquidation-bot 1.0.4 → 2.0.1
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.
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +51 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +18 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +91 -126
- package/dist/index.js.map +1 -1
- package/dist/liquidator.d.ts +17 -0
- package/dist/liquidator.d.ts.map +1 -0
- package/dist/liquidator.js +72 -0
- package/dist/liquidator.js.map +1 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +54 -0
- package/dist/logger.js.map +1 -0
- package/dist/monitor.d.ts +27 -0
- package/dist/monitor.d.ts.map +1 -0
- package/dist/monitor.js +136 -0
- package/dist/monitor.js.map +1 -0
- package/dist/risk-scorer.d.ts +13 -0
- package/dist/risk-scorer.d.ts.map +1 -0
- package/dist/risk-scorer.js +102 -0
- package/dist/risk-scorer.js.map +1 -0
- package/dist/scanner.d.ts +11 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +55 -0
- package/dist/scanner.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +24 -0
- package/dist/utils.js.map +1 -0
- package/dist/wallet-profiler.d.ts +21 -0
- package/dist/wallet-profiler.d.ts.map +1 -0
- package/dist/wallet-profiler.js +116 -0
- package/dist/wallet-profiler.js.map +1 -0
- package/package.json +4 -3
- package/readme.md +64 -78
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,SAAS,CAAA;AAIlD,wBAAgB,UAAU,IAAI,SAAS,CAuCtC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* config.ts — loads environment variables into a typed BotConfig.
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.loadConfig = loadConfig;
|
|
10
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
11
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
12
|
+
const torchsdk_1 = require("torchsdk");
|
|
13
|
+
const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
|
|
14
|
+
function loadConfig() {
|
|
15
|
+
const rpcUrl = process.env.RPC_URL;
|
|
16
|
+
if (!rpcUrl)
|
|
17
|
+
throw new Error('RPC_URL env var is required');
|
|
18
|
+
const walletKey = process.env.WALLET;
|
|
19
|
+
if (!walletKey)
|
|
20
|
+
throw new Error('WALLET env var is required (base58 private key)');
|
|
21
|
+
const logLevel = (process.env.LOG_LEVEL ?? 'info');
|
|
22
|
+
if (!LOG_LEVELS.includes(logLevel)) {
|
|
23
|
+
throw new Error(`LOG_LEVEL must be one of: ${LOG_LEVELS.join(', ')}`);
|
|
24
|
+
}
|
|
25
|
+
const minProfitSol = Number(process.env.MIN_PROFIT_SOL ?? '0.01');
|
|
26
|
+
const scanIntervalMs = Number(process.env.SCAN_INTERVAL_MS ?? '60000');
|
|
27
|
+
const scoreIntervalMs = Number(process.env.SCORE_INTERVAL_MS ?? '15000');
|
|
28
|
+
const riskThreshold = Number(process.env.RISK_THRESHOLD ?? '60');
|
|
29
|
+
const priceHistoryDepth = Number(process.env.PRICE_HISTORY ?? '20');
|
|
30
|
+
if (isNaN(scanIntervalMs) || scanIntervalMs < 1000)
|
|
31
|
+
throw new Error('SCAN_INTERVAL_MS must be >= 1000');
|
|
32
|
+
if (isNaN(scoreIntervalMs) || scoreIntervalMs < 1000)
|
|
33
|
+
throw new Error('SCORE_INTERVAL_MS must be >= 1000');
|
|
34
|
+
if (isNaN(riskThreshold) || riskThreshold < 0 || riskThreshold > 100)
|
|
35
|
+
throw new Error('RISK_THRESHOLD must be 0-100');
|
|
36
|
+
if (isNaN(priceHistoryDepth) || priceHistoryDepth < 2)
|
|
37
|
+
throw new Error('PRICE_HISTORY must be >= 2');
|
|
38
|
+
if (isNaN(minProfitSol) || minProfitSol < 0)
|
|
39
|
+
throw new Error('MIN_PROFIT_SOL must be >= 0');
|
|
40
|
+
return {
|
|
41
|
+
rpcUrl,
|
|
42
|
+
walletKeypair: web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(walletKey)),
|
|
43
|
+
scanIntervalMs,
|
|
44
|
+
scoreIntervalMs,
|
|
45
|
+
minProfitLamports: Math.floor(minProfitSol * torchsdk_1.LAMPORTS_PER_SOL),
|
|
46
|
+
riskThreshold,
|
|
47
|
+
priceHistoryDepth,
|
|
48
|
+
logLevel,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;AASH,gCAuCC;AA9CD,6CAAyC;AACzC,gDAAuB;AACvB,uCAA2C;AAG3C,MAAM,UAAU,GAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;AAEjE,SAAgB,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAA;IAClC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;IAE3D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAA;IACpC,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IAElF,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,CAAa,CAAA;IAC9D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,6BAA6B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACvE,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM,CAAC,CAAA;IACjE,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO,CAAC,CAAA;IACtE,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,CAAA;IACxE,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,CAAA;IAChE,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC,CAAA;IAEnE,IAAI,KAAK,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,IAAI;QAChD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,IAAI,KAAK,CAAC,eAAe,CAAC,IAAI,eAAe,GAAG,IAAI;QAClD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IACtD,IAAI,KAAK,CAAC,aAAa,CAAC,IAAI,aAAa,GAAG,CAAC,IAAI,aAAa,GAAG,GAAG;QAClE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IACjD,IAAI,KAAK,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,GAAG,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,IAAI,KAAK,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;IAEhD,OAAO;QACL,MAAM;QACN,aAAa,EAAE,iBAAO,CAAC,aAAa,CAAC,cAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC5D,cAAc;QACd,eAAe;QACf,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,2BAAgB,CAAC;QAC9D,aAAa;QACb,iBAAiB;QACjB,QAAQ;KACT,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
/**
|
|
2
3
|
* torch-lending-monitor
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 3. Auto-liquidate underwater positions for the liquidation bonus.
|
|
5
|
+
* multi-token liquidation bot that discovers lending markets, profiles
|
|
6
|
+
* borrower wallets, predicts which loans will fail, and executes
|
|
7
|
+
* profitable liquidations.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* modes:
|
|
10
|
+
* info — display lending parameters for a token (or all tokens) (default)
|
|
11
|
+
* watch — monitor your own loan health in real-time
|
|
12
|
+
* bot — run the full liquidation bot
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
* #
|
|
14
|
-
*
|
|
14
|
+
* usage:
|
|
15
|
+
* # show all migrated tokens with lending
|
|
16
|
+
* RPC_URL=<rpc> npx tsx src/index.ts
|
|
15
17
|
*
|
|
16
|
-
* #
|
|
17
|
-
* MODE=
|
|
18
|
+
* # show lending info for one token
|
|
19
|
+
* MODE=info MINT=<mint> RPC_URL=<rpc> npx tsx src/index.ts
|
|
18
20
|
*
|
|
19
|
-
* #
|
|
20
|
-
* MODE=
|
|
21
|
+
* # watch your loan health
|
|
22
|
+
* MODE=watch MINT=<mint> WALLET=<key> RPC_URL=<rpc> npx tsx src/index.ts
|
|
23
|
+
*
|
|
24
|
+
* # run the liquidation bot
|
|
25
|
+
* MODE=bot WALLET=<key> RPC_URL=<rpc> npx tsx src/index.ts
|
|
21
26
|
*/
|
|
22
27
|
export {};
|
|
23
28
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|
package/dist/index.js
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
2
3
|
/**
|
|
3
4
|
* torch-lending-monitor
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* 3. Auto-liquidate underwater positions for the liquidation bonus.
|
|
6
|
+
* multi-token liquidation bot that discovers lending markets, profiles
|
|
7
|
+
* borrower wallets, predicts which loans will fail, and executes
|
|
8
|
+
* profitable liquidations.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* modes:
|
|
11
|
+
* info — display lending parameters for a token (or all tokens) (default)
|
|
12
|
+
* watch — monitor your own loan health in real-time
|
|
13
|
+
* bot — run the full liquidation bot
|
|
12
14
|
*
|
|
13
|
-
*
|
|
14
|
-
* #
|
|
15
|
-
*
|
|
15
|
+
* usage:
|
|
16
|
+
* # show all migrated tokens with lending
|
|
17
|
+
* RPC_URL=<rpc> npx tsx src/index.ts
|
|
16
18
|
*
|
|
17
|
-
* #
|
|
18
|
-
* MODE=
|
|
19
|
+
* # show lending info for one token
|
|
20
|
+
* MODE=info MINT=<mint> RPC_URL=<rpc> npx tsx src/index.ts
|
|
19
21
|
*
|
|
20
|
-
* #
|
|
21
|
-
* MODE=
|
|
22
|
+
* # watch your loan health
|
|
23
|
+
* MODE=watch MINT=<mint> WALLET=<key> RPC_URL=<rpc> npx tsx src/index.ts
|
|
24
|
+
*
|
|
25
|
+
* # run the liquidation bot
|
|
26
|
+
* MODE=bot WALLET=<key> RPC_URL=<rpc> npx tsx src/index.ts
|
|
22
27
|
*/
|
|
23
28
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
24
29
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -27,15 +32,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
27
32
|
const web3_js_1 = require("@solana/web3.js");
|
|
28
33
|
const bs58_1 = __importDefault(require("bs58"));
|
|
29
34
|
const torchsdk_1 = require("torchsdk");
|
|
35
|
+
const monitor_1 = require("./monitor");
|
|
36
|
+
const config_1 = require("./config");
|
|
37
|
+
const utils_1 = require("./utils");
|
|
30
38
|
// ---------------------------------------------------------------------------
|
|
31
|
-
//
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
const RPC_URL = process.env.RPC_URL ?? 'https://api.mainnet-beta.solana.com';
|
|
34
|
-
const MINT = process.env.MINT;
|
|
35
|
-
const MODE = process.env.MODE ?? 'info';
|
|
36
|
-
const POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS ?? '15000');
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// Helpers
|
|
39
|
+
// helpers for info/watch modes (don't need full config)
|
|
39
40
|
// ---------------------------------------------------------------------------
|
|
40
41
|
function loadWallet() {
|
|
41
42
|
const key = process.env.WALLET;
|
|
@@ -43,36 +44,49 @@ function loadWallet() {
|
|
|
43
44
|
throw new Error('Set WALLET env var to a base58-encoded private key');
|
|
44
45
|
return web3_js_1.Keypair.fromSecretKey(bs58_1.default.decode(key));
|
|
45
46
|
}
|
|
46
|
-
function sleep(ms) {
|
|
47
|
-
return new Promise((r) => setTimeout(r, ms));
|
|
48
|
-
}
|
|
49
|
-
function sol(lamports) {
|
|
50
|
-
return (lamports / torchsdk_1.LAMPORTS_PER_SOL).toFixed(4);
|
|
51
|
-
}
|
|
52
|
-
function bpsToPercent(bps) {
|
|
53
|
-
return (bps / 100).toFixed(2) + '%';
|
|
54
|
-
}
|
|
55
47
|
// ---------------------------------------------------------------------------
|
|
56
|
-
//
|
|
48
|
+
// mode: info
|
|
57
49
|
// ---------------------------------------------------------------------------
|
|
58
50
|
async function showLendingInfo(connection, mint) {
|
|
59
51
|
const token = await (0, torchsdk_1.getToken)(connection, mint);
|
|
60
52
|
const lending = await (0, torchsdk_1.getLendingInfo)(connection, mint);
|
|
61
53
|
console.log(`\n=== lending info: ${token.name} (${token.symbol}) ===`);
|
|
62
54
|
console.log(`status: ${token.status}`);
|
|
63
|
-
console.log(`token price: ${sol(token.price_sol)} SOL`);
|
|
64
|
-
console.log(`interest rate: ${bpsToPercent(lending.interest_rate_bps)}`);
|
|
65
|
-
console.log(`max LTV: ${bpsToPercent(lending.max_ltv_bps)}`);
|
|
66
|
-
console.log(`liquidation threshold: ${bpsToPercent(lending.liquidation_threshold_bps)}`);
|
|
67
|
-
console.log(`liquidation bonus: ${bpsToPercent(lending.liquidation_bonus_bps)}`);
|
|
68
|
-
console.log(`treasury SOL avail: ${sol(lending.treasury_sol_available)} SOL`);
|
|
69
|
-
console.log(`total SOL lent: ${sol(lending.total_sol_lent)} SOL`);
|
|
55
|
+
console.log(`token price: ${(0, utils_1.sol)(token.price_sol)} SOL`);
|
|
56
|
+
console.log(`interest rate: ${(0, utils_1.bpsToPercent)(lending.interest_rate_bps)}`);
|
|
57
|
+
console.log(`max LTV: ${(0, utils_1.bpsToPercent)(lending.max_ltv_bps)}`);
|
|
58
|
+
console.log(`liquidation threshold: ${(0, utils_1.bpsToPercent)(lending.liquidation_threshold_bps)}`);
|
|
59
|
+
console.log(`liquidation bonus: ${(0, utils_1.bpsToPercent)(lending.liquidation_bonus_bps)}`);
|
|
60
|
+
console.log(`treasury SOL avail: ${(0, utils_1.sol)(lending.treasury_sol_available)} SOL`);
|
|
61
|
+
console.log(`total SOL lent: ${(0, utils_1.sol)(lending.total_sol_lent)} SOL`);
|
|
70
62
|
console.log(`active loans: ${lending.active_loans}`);
|
|
71
63
|
}
|
|
64
|
+
async function showAllLending(connection) {
|
|
65
|
+
console.log('=== torch lending monitor ===\n');
|
|
66
|
+
console.log('no MINT specified — showing all migrated tokens with lending\n');
|
|
67
|
+
const { tokens } = await (0, torchsdk_1.getTokens)(connection, {
|
|
68
|
+
status: 'migrated',
|
|
69
|
+
sort: 'volume',
|
|
70
|
+
limit: 10,
|
|
71
|
+
});
|
|
72
|
+
for (const t of tokens) {
|
|
73
|
+
try {
|
|
74
|
+
const lending = await (0, torchsdk_1.getLendingInfo)(connection, t.mint);
|
|
75
|
+
console.log(`${t.symbol.padEnd(10)} | ` +
|
|
76
|
+
`rate: ${(0, utils_1.bpsToPercent)(lending.interest_rate_bps).padEnd(7)} | ` +
|
|
77
|
+
`loans: ${String(lending.active_loans).padEnd(4)} | ` +
|
|
78
|
+
`avail: ${(0, utils_1.sol)(lending.treasury_sol_available)} SOL`);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// token may not have lending enabled yet
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
72
85
|
// ---------------------------------------------------------------------------
|
|
73
|
-
//
|
|
86
|
+
// mode: watch
|
|
74
87
|
// ---------------------------------------------------------------------------
|
|
75
88
|
async function watchPosition(connection, mint, wallet) {
|
|
89
|
+
const pollMs = Number(process.env.POLL_INTERVAL_MS ?? '15000');
|
|
76
90
|
console.log(`\n=== watching loan: ${wallet.publicKey.toBase58()} ===`);
|
|
77
91
|
console.log(`mint: ${mint}\n`);
|
|
78
92
|
while (true) {
|
|
@@ -84,17 +98,16 @@ async function watchPosition(connection, mint, wallet) {
|
|
|
84
98
|
const healthColor = pos.health === 'healthy' ? 'OK' : pos.health === 'at_risk' ? 'WARNING' : 'DANGER';
|
|
85
99
|
console.log(`[${new Date().toISOString()}] health: ${healthColor} (${pos.health})`);
|
|
86
100
|
console.log(` collateral: ${pos.collateral_amount} tokens`);
|
|
87
|
-
console.log(` collat value: ${sol(pos.collateral_value_sol)} SOL`);
|
|
88
|
-
console.log(` borrowed: ${sol(pos.borrowed_amount)} SOL`);
|
|
89
|
-
console.log(` interest: ${sol(pos.accrued_interest)} SOL`);
|
|
90
|
-
console.log(` total owed: ${sol(pos.total_owed)} SOL`);
|
|
91
|
-
console.log(` current LTV: ${bpsToPercent(pos.current_ltv_bps)}`);
|
|
101
|
+
console.log(` collat value: ${(0, utils_1.sol)(pos.collateral_value_sol)} SOL`);
|
|
102
|
+
console.log(` borrowed: ${(0, utils_1.sol)(pos.borrowed_amount)} SOL`);
|
|
103
|
+
console.log(` interest: ${(0, utils_1.sol)(pos.accrued_interest)} SOL`);
|
|
104
|
+
console.log(` total owed: ${(0, utils_1.sol)(pos.total_owed)} SOL`);
|
|
105
|
+
console.log(` current LTV: ${(0, utils_1.bpsToPercent)(pos.current_ltv_bps)}`);
|
|
92
106
|
if (pos.health === 'at_risk') {
|
|
93
107
|
console.log(' --> consider adding collateral or repaying to avoid liquidation');
|
|
94
108
|
}
|
|
95
109
|
if (pos.health === 'liquidatable') {
|
|
96
110
|
console.log(' --> your position can be liquidated! repay immediately');
|
|
97
|
-
// auto-repay if enabled
|
|
98
111
|
if (process.env.AUTO_REPAY === 'true') {
|
|
99
112
|
console.log(' --> auto-repaying...');
|
|
100
113
|
const { transaction, message } = await (0, torchsdk_1.buildRepayTransaction)(connection, {
|
|
@@ -110,98 +123,50 @@ async function watchPosition(connection, mint, wallet) {
|
|
|
110
123
|
}
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
|
-
await sleep(
|
|
126
|
+
await (0, utils_1.sleep)(pollMs);
|
|
114
127
|
}
|
|
115
128
|
}
|
|
116
129
|
// ---------------------------------------------------------------------------
|
|
117
|
-
//
|
|
130
|
+
// main
|
|
118
131
|
// ---------------------------------------------------------------------------
|
|
119
|
-
async function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
console.log(`[${new Date().toISOString()}] scanning holders...`);
|
|
129
|
-
const { holders } = await (0, torchsdk_1.getHolders)(connection, mint, 100);
|
|
130
|
-
let liquidatable = 0;
|
|
131
|
-
for (const holder of holders) {
|
|
132
|
-
const pos = await (0, torchsdk_1.getLoanPosition)(connection, mint, holder.address);
|
|
133
|
-
if (pos.health === 'liquidatable') {
|
|
134
|
-
liquidatable++;
|
|
135
|
-
console.log(` LIQUIDATABLE: ${holder.address}`);
|
|
136
|
-
console.log(` collateral: ${pos.collateral_amount} tokens (${sol(pos.collateral_value_sol)} SOL)`);
|
|
137
|
-
console.log(` owes: ${sol(pos.total_owed)} SOL`);
|
|
138
|
-
console.log(` LTV: ${bpsToPercent(pos.current_ltv_bps)}`);
|
|
139
|
-
try {
|
|
140
|
-
const { transaction, message } = await (0, torchsdk_1.buildLiquidateTransaction)(connection, {
|
|
141
|
-
mint,
|
|
142
|
-
liquidator: wallet.publicKey.toBase58(),
|
|
143
|
-
borrower: holder.address,
|
|
144
|
-
});
|
|
145
|
-
console.log(` tx: ${message}`);
|
|
146
|
-
const sig = await (0, web3_js_1.sendAndConfirmTransaction)(connection, transaction, [wallet]);
|
|
147
|
-
console.log(` confirmed: ${sig}`);
|
|
148
|
-
const result = await (0, torchsdk_1.confirmTransaction)(connection, sig, wallet.publicKey.toBase58());
|
|
149
|
-
console.log(` SAID event: ${result.event_type}`);
|
|
150
|
-
}
|
|
151
|
-
catch (err) {
|
|
152
|
-
console.error(` failed: ${err instanceof Error ? err.message : err}`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
132
|
+
async function main() {
|
|
133
|
+
const MODE = process.env.MODE ?? 'info';
|
|
134
|
+
const MINT = process.env.MINT;
|
|
135
|
+
const RPC_URL = process.env.RPC_URL ?? 'https://api.mainnet-beta.solana.com';
|
|
136
|
+
// info mode: no wallet needed
|
|
137
|
+
if (MODE === 'info') {
|
|
138
|
+
const connection = new web3_js_1.Connection(RPC_URL, 'confirmed');
|
|
139
|
+
if (MINT) {
|
|
140
|
+
await showLendingInfo(connection, MINT);
|
|
155
141
|
}
|
|
156
|
-
|
|
157
|
-
|
|
142
|
+
else {
|
|
143
|
+
await showAllLending(connection);
|
|
158
144
|
}
|
|
159
|
-
|
|
145
|
+
return;
|
|
160
146
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
async function main() {
|
|
166
|
-
if (!MINT) {
|
|
167
|
-
// If no mint is specified, show lending info for all migrated tokens
|
|
168
|
-
console.log('=== torch lending monitor ===\n');
|
|
169
|
-
console.log('no MINT specified — showing all migrated tokens with lending\n');
|
|
147
|
+
// watch mode: single token + wallet
|
|
148
|
+
if (MODE === 'watch') {
|
|
149
|
+
if (!MINT)
|
|
150
|
+
throw new Error('MINT env var required for watch mode');
|
|
170
151
|
const connection = new web3_js_1.Connection(RPC_URL, 'confirmed');
|
|
171
|
-
|
|
172
|
-
status: 'migrated',
|
|
173
|
-
sort: 'volume',
|
|
174
|
-
limit: 10,
|
|
175
|
-
});
|
|
176
|
-
for (const t of tokens) {
|
|
177
|
-
try {
|
|
178
|
-
const lending = await (0, torchsdk_1.getLendingInfo)(connection, t.mint);
|
|
179
|
-
console.log(`${t.symbol.padEnd(10)} | ` +
|
|
180
|
-
`rate: ${bpsToPercent(lending.interest_rate_bps).padEnd(7)} | ` +
|
|
181
|
-
`loans: ${String(lending.active_loans).padEnd(4)} | ` +
|
|
182
|
-
`avail: ${sol(lending.treasury_sol_available)} SOL`);
|
|
183
|
-
}
|
|
184
|
-
catch {
|
|
185
|
-
// token may not have lending enabled yet
|
|
186
|
-
}
|
|
187
|
-
}
|
|
152
|
+
await watchPosition(connection, MINT, loadWallet());
|
|
188
153
|
return;
|
|
189
154
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
console.error(`unknown MODE: ${MODE}. use info | watch | liquidate`);
|
|
203
|
-
process.exit(1);
|
|
155
|
+
// bot mode: full liquidation bot
|
|
156
|
+
if (MODE === 'bot') {
|
|
157
|
+
const config = (0, config_1.loadConfig)();
|
|
158
|
+
const connection = new web3_js_1.Connection(config.rpcUrl, 'confirmed');
|
|
159
|
+
const monitor = new monitor_1.Monitor(connection, config);
|
|
160
|
+
// graceful shutdown
|
|
161
|
+
process.on('SIGINT', () => {
|
|
162
|
+
monitor.stop();
|
|
163
|
+
process.exit(0);
|
|
164
|
+
});
|
|
165
|
+
await monitor.start();
|
|
166
|
+
return;
|
|
204
167
|
}
|
|
168
|
+
console.error(`unknown MODE: ${MODE}. use info | watch | bot`);
|
|
169
|
+
process.exit(1);
|
|
205
170
|
}
|
|
206
171
|
main();
|
|
207
172
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AACA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;;;AAEH,6CAAgF;AAChF,gDAAuB;AACvB,uCASiB;AACjB,uCAAmC;AACnC,qCAAqC;AACrC,mCAAkD;AAElD,8EAA8E;AAC9E,wDAAwD;AACxD,8EAA8E;AAE9E,SAAS,UAAU;IACjB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAA;IAC9B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IAC/E,OAAO,iBAAO,CAAC,aAAa,CAAC,cAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;AAChD,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,KAAK,UAAU,eAAe,CAAC,UAAsB,EAAE,IAAY;IACjE,MAAM,KAAK,GAAG,MAAM,IAAA,mBAAQ,EAAC,UAAU,EAAE,IAAI,CAAC,CAAA;IAC9C,MAAM,OAAO,GAAgB,MAAM,IAAA,yBAAc,EAAC,UAAU,EAAE,IAAI,CAAC,CAAA;IAEnE,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,OAAO,CAAC,CAAA;IACtE,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;IACrD,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAA,WAAG,EAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IACjE,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAA,oBAAY,EAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAA;IAChF,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAA,oBAAY,EAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;IAC1E,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAA,oBAAY,EAAC,OAAO,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAA;IACxF,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAA,oBAAY,EAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAA;IACpF,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAA,WAAG,EAAC,OAAO,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAA;IAChF,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAA,WAAG,EAAC,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;IACxE,OAAO,CAAC,GAAG,CAAC,0BAA0B,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;AAC/D,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,UAAsB;IAClD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAA;IAC9C,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAA;IAE7E,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAA,oBAAS,EAAC,UAAU,EAAE;QAC7C,MAAM,EAAE,UAAU;QAClB,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,EAAE;KACV,CAAC,CAAA;IAEF,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAA,yBAAc,EAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;YACxD,OAAO,CAAC,GAAG,CACT,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;gBACzB,SAAS,IAAA,oBAAY,EAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;gBAC/D,UAAU,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;gBACrD,UAAU,IAAA,WAAG,EAAC,OAAO,CAAC,sBAAsB,CAAC,MAAM,CACtD,CAAA;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yCAAyC;QAC3C,CAAC;IACH,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,KAAK,UAAU,aAAa,CAAC,UAAsB,EAAE,IAAY,EAAE,MAAe;IAChF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,OAAO,CAAC,CAAA;IAE9D,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IACtE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,CAAA;IAE9B,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAqB,MAAM,IAAA,0BAAe,EACjD,UAAU,EACV,IAAI,EACJ,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAC5B,CAAA;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAA;QAC7D,CAAC;aAAM,CAAC;YACN,MAAM,WAAW,GACf,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAA;YAEnF,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,aAAa,WAAW,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;YACnF,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,CAAC,iBAAiB,SAAS,CAAC,CAAA;YAC/D,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAA,WAAG,EAAC,GAAG,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAA;YACpE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAA,WAAG,EAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;YAC/D,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAA,WAAG,EAAC,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAA;YAChE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAA,WAAG,EAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YAC1D,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAA,oBAAY,EAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;YAEpE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAA;YAClF,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAA;gBAEvE,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;oBACtC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAA;oBACrC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,IAAA,gCAAqB,EAAC,UAAU,EAAE;wBACvE,IAAI;wBACJ,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE;wBACrC,UAAU,EAAE,GAAG,CAAC,UAAU;qBAC3B,CAAC,CAAA;oBACF,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,EAAE,CAAC,CAAA;oBAC/B,MAAM,GAAG,GAAG,MAAM,IAAA,mCAAyB,EAAC,UAAU,EAAE,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;oBAC9E,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAA;oBAClC,MAAM,MAAM,GAAG,MAAM,IAAA,6BAAkB,EAAC,UAAU,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAA;oBACrF,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;gBACnD,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,IAAA,aAAK,EAAC,MAAM,CAAC,CAAA;IACrB,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAA;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAA;IAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,qCAAqC,CAAA;IAE5E,8BAA8B;IAC9B,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,IAAI,oBAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QACvD,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QACzC,CAAC;aAAM,CAAC;YACN,MAAM,cAAc,CAAC,UAAU,CAAC,CAAA;QAClC,CAAC;QACD,OAAM;IACR,CAAC;IAED,oCAAoC;IACpC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;QAClE,MAAM,UAAU,GAAG,IAAI,oBAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;QACvD,MAAM,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;QACnD,OAAM;IACR,CAAC;IAED,iCAAiC;IACjC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAA;QAC3B,MAAM,UAAU,GAAG,IAAI,oBAAU,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;QAC7D,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;QAE/C,oBAAoB;QACpB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACxB,OAAO,CAAC,IAAI,EAAE,CAAA;YACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC,CAAC,CAAA;QAEF,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;QACrB,OAAM;IACR,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,iBAAiB,IAAI,0BAA0B,CAAC,CAAA;IAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;AAED,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* liquidator.ts — executes liquidation transactions.
|
|
3
|
+
*
|
|
4
|
+
* receives a target, calculates expected profit, builds the tx,
|
|
5
|
+
* signs and sends it, then confirms via SAID for reputation.
|
|
6
|
+
*/
|
|
7
|
+
import { type Connection } from '@solana/web3.js';
|
|
8
|
+
import type { ScoredLoan, LiquidationResult, BotConfig } from './types';
|
|
9
|
+
import type { Logger } from './logger';
|
|
10
|
+
export declare class Liquidator {
|
|
11
|
+
private log;
|
|
12
|
+
private wallet;
|
|
13
|
+
private minProfitLamports;
|
|
14
|
+
constructor(config: BotConfig, log: Logger);
|
|
15
|
+
tryLiquidate(connection: Connection, loan: ScoredLoan): Promise<LiquidationResult | null>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=liquidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liquidator.d.ts","sourceRoot":"","sources":["../src/liquidator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,UAAU,EAA2C,MAAM,iBAAiB,CAAA;AAE1F,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAGtC,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAQ;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAAQ;gBAErB,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM;IAMpC,YAAY,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;CA4DhG"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* liquidator.ts — executes liquidation transactions.
|
|
4
|
+
*
|
|
5
|
+
* receives a target, calculates expected profit, builds the tx,
|
|
6
|
+
* signs and sends it, then confirms via SAID for reputation.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.Liquidator = void 0;
|
|
10
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
11
|
+
const torchsdk_1 = require("torchsdk");
|
|
12
|
+
const utils_1 = require("./utils");
|
|
13
|
+
class Liquidator {
|
|
14
|
+
constructor(config, log) {
|
|
15
|
+
this.wallet = config.walletKeypair;
|
|
16
|
+
this.minProfitLamports = config.minProfitLamports;
|
|
17
|
+
this.log = log;
|
|
18
|
+
}
|
|
19
|
+
async tryLiquidate(connection, loan) {
|
|
20
|
+
if (loan.position.health !== 'liquidatable') {
|
|
21
|
+
this.log.debug(`skipping ${loan.borrower.slice(0, 8)}... — not liquidatable yet`);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (loan.estimatedProfitLamports < this.minProfitLamports) {
|
|
25
|
+
this.log.debug(`skipping ${loan.borrower.slice(0, 8)}... — profit too low`, {
|
|
26
|
+
expected: (0, utils_1.sol)(loan.estimatedProfitLamports),
|
|
27
|
+
minimum: (0, utils_1.sol)(this.minProfitLamports),
|
|
28
|
+
});
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
this.log.info(`liquidating ${loan.borrower.slice(0, 8)}...`, {
|
|
32
|
+
token: loan.tokenName,
|
|
33
|
+
profit: `${(0, utils_1.sol)(loan.estimatedProfitLamports)} SOL`,
|
|
34
|
+
risk: loan.riskScore,
|
|
35
|
+
});
|
|
36
|
+
try {
|
|
37
|
+
const { transaction, message } = await (0, torchsdk_1.buildLiquidateTransaction)(connection, {
|
|
38
|
+
mint: loan.mint,
|
|
39
|
+
liquidator: this.wallet.publicKey.toBase58(),
|
|
40
|
+
borrower: loan.borrower,
|
|
41
|
+
});
|
|
42
|
+
this.log.debug(`tx built: ${message}`);
|
|
43
|
+
const signature = await (0, web3_js_1.sendAndConfirmTransaction)(connection, transaction, [this.wallet]);
|
|
44
|
+
this.log.info(`liquidation confirmed`, { sig: signature });
|
|
45
|
+
// confirm via SAID for reputation
|
|
46
|
+
let confirmed = false;
|
|
47
|
+
try {
|
|
48
|
+
const result = await (0, torchsdk_1.confirmTransaction)(connection, signature, this.wallet.publicKey.toBase58());
|
|
49
|
+
confirmed = result.confirmed;
|
|
50
|
+
this.log.debug(`SAID confirmation`, { event: result.event_type });
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
this.log.warn('SAID confirmation failed — tx still went through');
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
mint: loan.mint,
|
|
57
|
+
borrower: loan.borrower,
|
|
58
|
+
signature,
|
|
59
|
+
profitLamports: loan.estimatedProfitLamports,
|
|
60
|
+
timestamp: Date.now(),
|
|
61
|
+
confirmed,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
66
|
+
this.log.error(`liquidation failed for ${loan.borrower.slice(0, 8)}...`, { error: msg });
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.Liquidator = Liquidator;
|
|
72
|
+
//# sourceMappingURL=liquidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liquidator.js","sourceRoot":"","sources":["../src/liquidator.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,6CAA0F;AAC1F,uCAAwE;AAGxE,mCAA6B;AAE7B,MAAa,UAAU;IAKrB,YAAY,MAAiB,EAAE,GAAW;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,aAAa,CAAA;QAClC,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAA;QACjD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;IAChB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,UAAsB,EAAE,IAAgB;QACzD,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;YAC5C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,4BAA4B,CAAC,CAAA;YACjF,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC1D,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,sBAAsB,EAAE;gBAC1E,QAAQ,EAAE,IAAA,WAAG,EAAC,IAAI,CAAC,uBAAuB,CAAC;gBAC3C,OAAO,EAAE,IAAA,WAAG,EAAC,IAAI,CAAC,iBAAiB,CAAC;aACrC,CAAC,CAAA;YACF,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE;YAC3D,KAAK,EAAE,IAAI,CAAC,SAAS;YACrB,MAAM,EAAE,GAAG,IAAA,WAAG,EAAC,IAAI,CAAC,uBAAuB,CAAC,MAAM;YAClD,IAAI,EAAE,IAAI,CAAC,SAAS;SACrB,CAAC,CAAA;QAEF,IAAI,CAAC;YACH,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,IAAA,oCAAyB,EAAC,UAAU,EAAE;gBAC3E,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE;gBAC5C,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC,CAAA;YAEF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,OAAO,EAAE,CAAC,CAAA;YAEtC,MAAM,SAAS,GAAG,MAAM,IAAA,mCAAyB,EAAC,UAAU,EAAE,WAAW,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;YACzF,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAA;YAE1D,kCAAkC;YAClC,IAAI,SAAS,GAAG,KAAK,CAAA;YACrB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAA,6BAAkB,EACrC,UAAU,EACV,SAAS,EACT,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CACjC,CAAA;gBACD,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;gBAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,mBAAmB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAA;YACnE,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAA;YACnE,CAAC;YAED,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,SAAS;gBACT,cAAc,EAAE,IAAI,CAAC,uBAAuB;gBAC5C,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,SAAS;aACV,CAAA;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAC5D,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,0BAA0B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;YACxF,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;CACF;AAvED,gCAuEC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* logger.ts — simple structured logging with levels.
|
|
3
|
+
*/
|
|
4
|
+
import type { LogLevel } from './types';
|
|
5
|
+
export declare class Logger {
|
|
6
|
+
private module;
|
|
7
|
+
private minLevel;
|
|
8
|
+
constructor(module: string, level: LogLevel);
|
|
9
|
+
debug(msg: string, data?: Record<string, unknown>): void;
|
|
10
|
+
info(msg: string, data?: Record<string, unknown>): void;
|
|
11
|
+
warn(msg: string, data?: Record<string, unknown>): void;
|
|
12
|
+
error(msg: string, data?: Record<string, unknown>): void;
|
|
13
|
+
child(module: string): Logger;
|
|
14
|
+
private levelName;
|
|
15
|
+
private log;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AASvC,qBAAa,MAAM;IAIf,OAAO,CAAC,MAAM;IAHhB,OAAO,CAAC,QAAQ,CAAQ;gBAGd,MAAM,EAAE,MAAM,EACtB,KAAK,EAAE,QAAQ;IAKjB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIjD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIhD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIhD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIjD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAI7B,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,GAAG;CAeZ"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* logger.ts — simple structured logging with levels.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Logger = void 0;
|
|
7
|
+
const LEVEL_PRIORITY = {
|
|
8
|
+
debug: 0,
|
|
9
|
+
info: 1,
|
|
10
|
+
warn: 2,
|
|
11
|
+
error: 3,
|
|
12
|
+
};
|
|
13
|
+
class Logger {
|
|
14
|
+
constructor(module, level) {
|
|
15
|
+
this.module = module;
|
|
16
|
+
this.minLevel = LEVEL_PRIORITY[level];
|
|
17
|
+
}
|
|
18
|
+
debug(msg, data) {
|
|
19
|
+
this.log('debug', msg, data);
|
|
20
|
+
}
|
|
21
|
+
info(msg, data) {
|
|
22
|
+
this.log('info', msg, data);
|
|
23
|
+
}
|
|
24
|
+
warn(msg, data) {
|
|
25
|
+
this.log('warn', msg, data);
|
|
26
|
+
}
|
|
27
|
+
error(msg, data) {
|
|
28
|
+
this.log('error', msg, data);
|
|
29
|
+
}
|
|
30
|
+
child(module) {
|
|
31
|
+
return new Logger(`${this.module}:${module}`, this.levelName());
|
|
32
|
+
}
|
|
33
|
+
levelName() {
|
|
34
|
+
const entry = Object.entries(LEVEL_PRIORITY).find(([, v]) => v === this.minLevel);
|
|
35
|
+
return (entry?.[0] ?? 'info');
|
|
36
|
+
}
|
|
37
|
+
log(level, msg, data) {
|
|
38
|
+
if (LEVEL_PRIORITY[level] < this.minLevel)
|
|
39
|
+
return;
|
|
40
|
+
const ts = new Date().toISOString();
|
|
41
|
+
const prefix = `[${ts}] [${level.toUpperCase().padEnd(5)}] [${this.module}]`;
|
|
42
|
+
if (data) {
|
|
43
|
+
const parts = Object.entries(data)
|
|
44
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
45
|
+
.join(' ');
|
|
46
|
+
console.log(`${prefix} ${msg} | ${parts}`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.log(`${prefix} ${msg}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.Logger = Logger;
|
|
54
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAIH,MAAM,cAAc,GAA6B;IAC/C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAA;AAED,MAAa,MAAM;IAGjB,YACU,MAAc,EACtB,KAAe;QADP,WAAM,GAAN,MAAM,CAAQ;QAGtB,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,CAAA;IACvC,CAAC;IAED,KAAK,CAAC,GAAW,EAAE,IAA8B;QAC/C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,CAAC,GAAW,EAAE,IAA8B;QAC9C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7B,CAAC;IAED,IAAI,CAAC,GAAW,EAAE,IAA8B;QAC9C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7B,CAAC;IAED,KAAK,CAAC,GAAW,EAAE,IAA8B;QAC/C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,MAAc;QAClB,OAAO,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;IACjE,CAAC;IAEO,SAAS;QACf,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAA;QACjF,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAa,CAAA;IAC3C,CAAC;IAEO,GAAG,CAAC,KAAe,EAAE,GAAW,EAAE,IAA8B;QACtE,IAAI,cAAc,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ;YAAE,OAAM;QAEjD,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACnC,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,GAAG,CAAA;QAE5E,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;iBAC/B,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;iBAC5B,IAAI,CAAC,GAAG,CAAC,CAAA;YACZ,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE,CAAC,CAAA;QAC5C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;CACF;AAlDD,wBAkDC"}
|