vacuum-sol 1.0.0

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 (62) hide show
  1. package/README.md +362 -0
  2. package/dist/config.d.ts +15 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +58 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/core/detector.d.ts +36 -0
  7. package/dist/core/detector.d.ts.map +1 -0
  8. package/dist/core/detector.js +142 -0
  9. package/dist/core/detector.js.map +1 -0
  10. package/dist/core/monitor.d.ts +31 -0
  11. package/dist/core/monitor.d.ts.map +1 -0
  12. package/dist/core/monitor.js +172 -0
  13. package/dist/core/monitor.js.map +1 -0
  14. package/dist/core/reclaimer.d.ts +30 -0
  15. package/dist/core/reclaimer.d.ts.map +1 -0
  16. package/dist/core/reclaimer.js +182 -0
  17. package/dist/core/reclaimer.js.map +1 -0
  18. package/dist/core/types.d.ts +125 -0
  19. package/dist/core/types.d.ts.map +1 -0
  20. package/dist/core/types.js +2 -0
  21. package/dist/core/types.js.map +1 -0
  22. package/dist/db/accounts.d.ts +71 -0
  23. package/dist/db/accounts.d.ts.map +1 -0
  24. package/dist/db/accounts.js +205 -0
  25. package/dist/db/accounts.js.map +1 -0
  26. package/dist/db/index.d.ts +14 -0
  27. package/dist/db/index.d.ts.map +1 -0
  28. package/dist/db/index.js +104 -0
  29. package/dist/db/index.js.map +1 -0
  30. package/dist/db/operators.d.ts +48 -0
  31. package/dist/db/operators.d.ts.map +1 -0
  32. package/dist/db/operators.js +201 -0
  33. package/dist/db/operators.js.map +1 -0
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +473 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/server/index.d.ts +5 -0
  39. package/dist/server/index.d.ts.map +1 -0
  40. package/dist/server/index.js +121 -0
  41. package/dist/server/index.js.map +1 -0
  42. package/dist/services/reporter.d.ts +28 -0
  43. package/dist/services/reporter.d.ts.map +1 -0
  44. package/dist/services/reporter.js +107 -0
  45. package/dist/services/reporter.js.map +1 -0
  46. package/dist/services/solana.d.ts +59 -0
  47. package/dist/services/solana.d.ts.map +1 -0
  48. package/dist/services/solana.js +162 -0
  49. package/dist/services/solana.js.map +1 -0
  50. package/dist/services/telegram.d.ts +20 -0
  51. package/dist/services/telegram.d.ts.map +1 -0
  52. package/dist/services/telegram.js +213 -0
  53. package/dist/services/telegram.js.map +1 -0
  54. package/dist/utils/helpers.d.ts +55 -0
  55. package/dist/utils/helpers.d.ts.map +1 -0
  56. package/dist/utils/helpers.js +116 -0
  57. package/dist/utils/helpers.js.map +1 -0
  58. package/dist/utils/logger.d.ts +14 -0
  59. package/dist/utils/logger.d.ts.map +1 -0
  60. package/dist/utils/logger.js +70 -0
  61. package/dist/utils/logger.js.map +1 -0
  62. package/package.json +69 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../../src/services/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAKlD;;GAEG;AACH,qBAAa,QAAQ;IACnB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC;IAsB3C;;OAEG;IACH,YAAY,IAAI,IAAI;IAmBpB;;OAEG;IACH,YAAY,CAAC,KAAK,SAAK,GAAG,IAAI;IAwB9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAuBnC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;CAexE;AAGD,eAAO,MAAM,QAAQ,UAAiB,CAAA"}
@@ -0,0 +1,107 @@
1
+ import { getAccountStats, getReclaimHistory } from '../db/accounts.js';
2
+ import { formatDate, formatSol, lamportsToSol } from '../utils/helpers.js';
3
+ import { logger } from '../utils/logger.js';
4
+ /**
5
+ * Generate comprehensive rent reports
6
+ */
7
+ export class Reporter {
8
+ /**
9
+ * Generate a full rent report
10
+ */
11
+ async generateReport() {
12
+ const stats = getAccountStats();
13
+ return {
14
+ totalTrackedAccounts: stats.total,
15
+ activeAccounts: stats.active,
16
+ reclaimableAccounts: stats.reclaimable,
17
+ reclaimedAccounts: stats.reclaimed,
18
+ protectedAccounts: stats.protected,
19
+ totalRentLockedLamports: stats.totalRentLocked,
20
+ totalRentReclaimedLamports: stats.totalRentReclaimed,
21
+ reclaimableNowLamports: 0, // Will be calculated by detector
22
+ accountsByType: {
23
+ token_account: 0,
24
+ ata: 0,
25
+ pda: 0,
26
+ unknown: 0,
27
+ },
28
+ generatedAt: new Date(),
29
+ };
30
+ }
31
+ /**
32
+ * Print a summary report to console
33
+ */
34
+ printSummary() {
35
+ const stats = getAccountStats();
36
+ logger.newline();
37
+ logger.box('📊 Rent Reclaim Summary', `Total Accounts Tracked: ${stats.total}
38
+ ├─ Active: ${stats.active}
39
+ ├─ Reclaimable: ${stats.reclaimable}
40
+ ├─ Reclaimed: ${stats.reclaimed}
41
+ └─ Protected: ${stats.protected}
42
+
43
+ 💰 Rent Status
44
+ ├─ Locked: ${formatSol(stats.totalRentLocked)}
45
+ └─ Reclaimed: ${formatSol(stats.totalRentReclaimed)}`);
46
+ logger.newline();
47
+ }
48
+ /**
49
+ * Print recent reclaim history
50
+ */
51
+ printHistory(limit = 10) {
52
+ const history = getReclaimHistory(limit);
53
+ if (history.length === 0) {
54
+ logger.info('No reclaim history yet.');
55
+ return;
56
+ }
57
+ logger.newline();
58
+ logger.info('📜 Recent Reclaim History:');
59
+ logger.divider();
60
+ const tableData = history.map((entry) => ({
61
+ Account: entry.account_pubkey.slice(0, 8) + '...',
62
+ Amount: formatSol(entry.amount_reclaimed),
63
+ Reason: entry.reason,
64
+ Date: formatDate(new Date(entry.reclaimed_at)),
65
+ TX: entry.tx_signature.slice(0, 8) + '...',
66
+ }));
67
+ logger.table(tableData);
68
+ logger.newline();
69
+ }
70
+ /**
71
+ * Export report as JSON
72
+ */
73
+ async exportJson() {
74
+ const report = await this.generateReport();
75
+ const history = getReclaimHistory();
76
+ return JSON.stringify({
77
+ report: {
78
+ ...report,
79
+ totalRentLockedSol: lamportsToSol(report.totalRentLockedLamports),
80
+ totalRentReclaimedSol: lamportsToSol(report.totalRentReclaimedLamports),
81
+ },
82
+ history: history.map((h) => ({
83
+ ...h,
84
+ amount_sol: lamportsToSol(h.amount_reclaimed),
85
+ })),
86
+ }, null, 2);
87
+ }
88
+ /**
89
+ * Print alert-style message for significant findings
90
+ */
91
+ printAlert(type, message) {
92
+ const icons = {
93
+ warning: '⚠️',
94
+ success: '✅',
95
+ info: 'ℹ️',
96
+ };
97
+ const colors = {
98
+ warning: logger.warn,
99
+ success: logger.success,
100
+ info: logger.info,
101
+ };
102
+ colors[type](`${icons[type]} ${message}`);
103
+ }
104
+ }
105
+ // Export singleton instance
106
+ export const reporter = new Reporter();
107
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/services/reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { AccountInfo, Connection, Keypair, ParsedAccountData, PublicKey } from '@solana/web3.js';
2
+ import type { AccountType } from '../core/types.js';
3
+ /**
4
+ * Get or create a Solana connection
5
+ */
6
+ export declare function getConnection(): Connection;
7
+ /**
8
+ * Get the operator keypair for signing transactions
9
+ */
10
+ export declare function getOperatorKeypair(): Keypair;
11
+ /**
12
+ * Get account info with retry logic
13
+ */
14
+ export declare function getAccountInfo(pubkey: PublicKey): Promise<AccountInfo<Buffer> | null>;
15
+ /**
16
+ * Get multiple accounts info
17
+ */
18
+ export declare function getMultipleAccountsInfo(pubkeys: PublicKey[]): Promise<(AccountInfo<Buffer> | null)[]>;
19
+ /**
20
+ * Check if an account exists (has lamports)
21
+ */
22
+ export declare function accountExists(pubkey: PublicKey): Promise<boolean>;
23
+ /**
24
+ * Get the type of account based on owner program
25
+ */
26
+ export declare function detectAccountType(accountInfo: AccountInfo<Buffer>): AccountType;
27
+ /**
28
+ * Get token account data (balance, owner, mint)
29
+ */
30
+ export declare function getTokenAccountData(pubkey: PublicKey): Promise<{
31
+ mint: PublicKey;
32
+ owner: PublicKey;
33
+ amount: bigint;
34
+ lamports: number;
35
+ } | null>;
36
+ /**
37
+ * Close a token account and reclaim rent
38
+ */
39
+ export declare function closeTokenAccount(tokenAccountPubkey: PublicKey, destinationPubkey: PublicKey, authorityKeypair: Keypair): Promise<string>;
40
+ /**
41
+ * Get recent transactions for an account
42
+ */
43
+ export declare function getRecentSignatures(pubkey: PublicKey, limit?: number): Promise<string[]>;
44
+ /**
45
+ * Get all token accounts owned by operator
46
+ */
47
+ export declare function getOperatorTokenAccounts(): Promise<{
48
+ pubkey: PublicKey;
49
+ account: AccountInfo<ParsedAccountData>;
50
+ }[]>;
51
+ /**
52
+ * Get current slot
53
+ */
54
+ export declare function getCurrentSlot(): Promise<number>;
55
+ /**
56
+ * Get rent exempt minimum for a given data size
57
+ */
58
+ export declare function getRentExemptMinimum(dataSize: number): Promise<number>;
59
+ //# sourceMappingURL=solana.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana.d.ts","sourceRoot":"","sources":["../../src/services/solana.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,WAAW,EACX,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,SAAS,EAGV,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAOnD;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAO1C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAQ5C;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAKrC;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,SAAS,EAAE,GACnB,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAKzC;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAGvE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B,WAAW,CAsBb;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IACpE,IAAI,EAAE,SAAS,CAAA;IACf,KAAK,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB,GAAG,IAAI,CAAC,CAuBR;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,kBAAkB,EAAE,SAAS,EAC7B,iBAAiB,EAAE,SAAS,EAC5B,gBAAgB,EAAE,OAAO,GACxB,OAAO,CAAC,MAAM,CAAC,CA2CjB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS,EACjB,KAAK,SAAK,GACT,OAAO,CAAC,MAAM,EAAE,CAAC,CAInB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CACvD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;CAAE,EAAE,CACjE,CASA;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAGtD;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5E"}
@@ -0,0 +1,162 @@
1
+ import { TOKEN_PROGRAM_ID, TokenAccountNotFoundError, TokenInvalidAccountOwnerError, createCloseAccountInstruction, getAccount, } from '@solana/spl-token';
2
+ import { Connection, Keypair, PublicKey, Transaction, sendAndConfirmTransaction, } from '@solana/web3.js';
3
+ import { getConfig, loadOperatorKeypair } from '../config.js';
4
+ import { retry } from '../utils/helpers.js';
5
+ import { logger } from '../utils/logger.js';
6
+ let connection = null;
7
+ let operatorKeypair = null;
8
+ /**
9
+ * Get or create a Solana connection
10
+ */
11
+ export function getConnection() {
12
+ if (!connection) {
13
+ const config = getConfig();
14
+ connection = new Connection(config.rpcUrl, 'confirmed');
15
+ logger.debug(`Connected to Solana RPC: ${config.rpcUrl}`);
16
+ }
17
+ return connection;
18
+ }
19
+ /**
20
+ * Get the operator keypair for signing transactions
21
+ */
22
+ export function getOperatorKeypair() {
23
+ if (!operatorKeypair) {
24
+ const config = getConfig();
25
+ const secretKey = loadOperatorKeypair(config.operatorKeypairPath);
26
+ operatorKeypair = Keypair.fromSecretKey(secretKey);
27
+ logger.debug(`Operator address: ${operatorKeypair.publicKey.toBase58()}`);
28
+ }
29
+ return operatorKeypair;
30
+ }
31
+ /**
32
+ * Get account info with retry logic
33
+ */
34
+ export async function getAccountInfo(pubkey) {
35
+ const conn = getConnection();
36
+ return retry(async () => {
37
+ return conn.getAccountInfo(pubkey);
38
+ });
39
+ }
40
+ /**
41
+ * Get multiple accounts info
42
+ */
43
+ export async function getMultipleAccountsInfo(pubkeys) {
44
+ const conn = getConnection();
45
+ return retry(async () => {
46
+ return conn.getMultipleAccountsInfo(pubkeys);
47
+ });
48
+ }
49
+ /**
50
+ * Check if an account exists (has lamports)
51
+ */
52
+ export async function accountExists(pubkey) {
53
+ const info = await getAccountInfo(pubkey);
54
+ return info !== null && info.lamports > 0;
55
+ }
56
+ /**
57
+ * Get the type of account based on owner program
58
+ */
59
+ export function detectAccountType(accountInfo) {
60
+ const owner = accountInfo.owner;
61
+ if (owner.equals(TOKEN_PROGRAM_ID)) {
62
+ return 'token_account';
63
+ }
64
+ // Check for Associated Token Program
65
+ const ASSOCIATED_TOKEN_PROGRAM_ID = new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL');
66
+ if (owner.equals(ASSOCIATED_TOKEN_PROGRAM_ID)) {
67
+ return 'ata';
68
+ }
69
+ // If owned by a program (not system), it's likely a PDA
70
+ const SYSTEM_PROGRAM_ID = new PublicKey('11111111111111111111111111111111');
71
+ if (!owner.equals(SYSTEM_PROGRAM_ID)) {
72
+ return 'pda';
73
+ }
74
+ return 'unknown';
75
+ }
76
+ /**
77
+ * Get token account data (balance, owner, mint)
78
+ */
79
+ export async function getTokenAccountData(pubkey) {
80
+ try {
81
+ const conn = getConnection();
82
+ const account = await getAccount(conn, pubkey);
83
+ const info = await getAccountInfo(pubkey);
84
+ const lamports = info?.lamports || 0;
85
+ return {
86
+ mint: account.mint,
87
+ owner: account.owner,
88
+ amount: account.amount,
89
+ lamports,
90
+ };
91
+ }
92
+ catch (error) {
93
+ if (error instanceof TokenAccountNotFoundError ||
94
+ error instanceof TokenInvalidAccountOwnerError) {
95
+ return null;
96
+ }
97
+ throw error;
98
+ }
99
+ }
100
+ /**
101
+ * Close a token account and reclaim rent
102
+ */
103
+ export async function closeTokenAccount(tokenAccountPubkey, destinationPubkey, authorityKeypair) {
104
+ const conn = getConnection();
105
+ // Verify the token account has zero balance
106
+ const tokenData = await getTokenAccountData(tokenAccountPubkey);
107
+ if (!tokenData) {
108
+ throw new Error(`Token account not found: ${tokenAccountPubkey.toBase58()}`);
109
+ }
110
+ if (tokenData.amount > 0n) {
111
+ throw new Error(`Cannot close token account with non-zero balance: ${tokenData.amount}`);
112
+ }
113
+ // Verify authority matches
114
+ if (!tokenData.owner.equals(authorityKeypair.publicKey)) {
115
+ throw new Error(`Authority mismatch. Account owner: ${tokenData.owner.toBase58()}, ` +
116
+ `provided authority: ${authorityKeypair.publicKey.toBase58()}`);
117
+ }
118
+ // Build close instruction
119
+ const closeInstruction = createCloseAccountInstruction(tokenAccountPubkey, destinationPubkey, authorityKeypair.publicKey);
120
+ const transaction = new Transaction().add(closeInstruction);
121
+ // Send and confirm transaction
122
+ const signature = await sendAndConfirmTransaction(conn, transaction, [
123
+ authorityKeypair,
124
+ ]);
125
+ logger.success(`Closed token account ${tokenAccountPubkey.toBase58()}, ` +
126
+ `reclaimed ${tokenData.lamports} lamports. TX: ${signature}`);
127
+ return signature;
128
+ }
129
+ /**
130
+ * Get recent transactions for an account
131
+ */
132
+ export async function getRecentSignatures(pubkey, limit = 10) {
133
+ const conn = getConnection();
134
+ const signatures = await conn.getSignaturesForAddress(pubkey, { limit });
135
+ return signatures.map((s) => s.signature);
136
+ }
137
+ /**
138
+ * Get all token accounts owned by operator
139
+ */
140
+ export async function getOperatorTokenAccounts() {
141
+ const conn = getConnection();
142
+ const operator = getOperatorKeypair();
143
+ const result = await conn.getParsedTokenAccountsByOwner(operator.publicKey, {
144
+ programId: TOKEN_PROGRAM_ID,
145
+ });
146
+ return result.value;
147
+ }
148
+ /**
149
+ * Get current slot
150
+ */
151
+ export async function getCurrentSlot() {
152
+ const conn = getConnection();
153
+ return conn.getSlot();
154
+ }
155
+ /**
156
+ * Get rent exempt minimum for a given data size
157
+ */
158
+ export async function getRentExemptMinimum(dataSize) {
159
+ const conn = getConnection();
160
+ return conn.getMinimumBalanceForRentExemption(dataSize);
161
+ }
162
+ //# sourceMappingURL=solana.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solana.js","sourceRoot":"","sources":["../../src/services/solana.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { Telegraf } from 'telegraf';
2
+ declare let bot: Telegraf | null;
3
+ /**
4
+ * Initialize the Telegram bot
5
+ */
6
+ export declare function initTelegramBot(token: string, chatId?: string): Telegraf;
7
+ /**
8
+ * Send a notification message
9
+ */
10
+ export declare function sendNotification(message: string): Promise<void>;
11
+ /**
12
+ * Send reclaim alert
13
+ */
14
+ export declare function sendReclaimAlert(amount: number, accounts: number, txSignatures: string[]): Promise<void>;
15
+ /**
16
+ * Start the Telegram bot (polling mode)
17
+ */
18
+ export declare function startBot(token: string, chatId?: string): Promise<void>;
19
+ export { bot };
20
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/services/telegram.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AASnC,QAAA,IAAI,GAAG,EAAE,QAAQ,GAAG,IAAW,CAAA;AAG/B;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAsMxE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAarE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS5E;AAED,OAAO,EAAE,GAAG,EAAE,CAAA"}
@@ -0,0 +1,213 @@
1
+ import { Telegraf } from 'telegraf';
2
+ import { detector } from '../core/detector.js';
3
+ import { monitor } from '../core/monitor.js';
4
+ import { reclaimer } from '../core/reclaimer.js';
5
+ import { getAccountStats, getReclaimHistory } from '../db/accounts.js';
6
+ import { initDatabase } from '../db/index.js';
7
+ import { formatSol, shortenPubkey } from '../utils/helpers.js';
8
+ import { logger } from '../utils/logger.js';
9
+ let bot = null;
10
+ let authorizedChatId = null;
11
+ /**
12
+ * Initialize the Telegram bot
13
+ */
14
+ export function initTelegramBot(token, chatId) {
15
+ if (bot)
16
+ return bot;
17
+ bot = new Telegraf(token);
18
+ authorizedChatId = chatId || null;
19
+ // Initialize database
20
+ initDatabase();
21
+ // Middleware to check authorization
22
+ bot.use(async (ctx, next) => {
23
+ if (authorizedChatId && ctx.chat?.id.toString() !== authorizedChatId) {
24
+ await ctx.reply('⛔ Unauthorized. This bot is private.');
25
+ return;
26
+ }
27
+ return next();
28
+ });
29
+ // Start command
30
+ bot.command('start', async (ctx) => {
31
+ await ctx.reply(`🧹 *Vacuum - Solana Rent Reclaim Bot*\n\n` +
32
+ `Available commands:\n` +
33
+ `/status - Show rent summary\n` +
34
+ `/scan - Scan for new accounts\n` +
35
+ `/check - Find reclaimable accounts\n` +
36
+ `/reclaim - Reclaim rent (dry-run)\n` +
37
+ `/reclaim\\_execute - Actually reclaim\n` +
38
+ `/history - Show reclaim history\n` +
39
+ `/help - Show this message`, { parse_mode: 'Markdown' });
40
+ });
41
+ // Help command
42
+ bot.command('help', async (ctx) => {
43
+ await ctx.reply(`🔧 *Commands*\n\n` +
44
+ `/status - Current rent status\n` +
45
+ `/scan - Scan operator token accounts\n` +
46
+ `/check - Check for reclaimable\n` +
47
+ `/reclaim - Preview reclaim (safe)\n` +
48
+ `/reclaim\\_execute - Execute reclaim\n` +
49
+ `/history - Recent reclaims`, { parse_mode: 'Markdown' });
50
+ });
51
+ // Status command
52
+ bot.command('status', async (ctx) => {
53
+ try {
54
+ const stats = getAccountStats();
55
+ await ctx.reply(`📊 *Rent Status*\n\n` +
56
+ `Total Tracked: ${stats.total}\n` +
57
+ `├ Active: ${stats.active}\n` +
58
+ `├ Reclaimable: ${stats.reclaimable}\n` +
59
+ `├ Reclaimed: ${stats.reclaimed}\n` +
60
+ `└ Protected: ${stats.protected}\n\n` +
61
+ `💰 *Rent*\n` +
62
+ `├ Locked: ${formatSol(stats.totalRentLocked)}\n` +
63
+ `└ Reclaimed: ${formatSol(stats.totalRentReclaimed)}`, { parse_mode: 'Markdown' });
64
+ }
65
+ catch (error) {
66
+ await ctx.reply(`❌ Error: ${error}`);
67
+ }
68
+ });
69
+ // Scan command
70
+ bot.command('scan', async (ctx) => {
71
+ try {
72
+ await ctx.reply('🔍 Scanning for accounts...');
73
+ const accounts = await monitor.scanOperatorAccounts();
74
+ await ctx.reply(`✅ Found ${accounts.length} token accounts\n` +
75
+ `Total rent: ${formatSol(accounts.reduce((s, a) => s + a.rentLamports, 0))}`);
76
+ }
77
+ catch (error) {
78
+ await ctx.reply(`❌ Scan failed: ${error}`);
79
+ }
80
+ });
81
+ // Check command
82
+ bot.command('check', async (ctx) => {
83
+ try {
84
+ await ctx.reply('🔍 Checking for reclaimable accounts...');
85
+ const results = await detector.findSafeReclaimable();
86
+ if (results.length === 0) {
87
+ await ctx.reply('✅ No accounts ready for reclaim.');
88
+ return;
89
+ }
90
+ const totalLamports = results.reduce((s, r) => s + r.reclaimableLamports, 0);
91
+ let message = `💰 *${results.length} accounts reclaimable*\n\n`;
92
+ for (const r of results.slice(0, 10)) {
93
+ message += `• ${shortenPubkey(r.account.pubkey)} - ${formatSol(r.reclaimableLamports)}\n`;
94
+ }
95
+ if (results.length > 10) {
96
+ message += `\n... and ${results.length - 10} more\n`;
97
+ }
98
+ message += `\n*Total: ${formatSol(totalLamports)}*`;
99
+ message += `\n\nUse /reclaim to preview or /reclaim\\_execute to reclaim.`;
100
+ await ctx.reply(message, { parse_mode: 'Markdown' });
101
+ }
102
+ catch (error) {
103
+ await ctx.reply(`❌ Check failed: ${error}`);
104
+ }
105
+ });
106
+ // Reclaim dry-run
107
+ bot.command('reclaim', async (ctx) => {
108
+ try {
109
+ await ctx.reply('🔍 Finding reclaimable accounts...');
110
+ const results = await detector.findSafeReclaimable();
111
+ if (results.length === 0) {
112
+ await ctx.reply('✅ Nothing to reclaim.');
113
+ return;
114
+ }
115
+ const preview = await reclaimer.previewReclaim(results);
116
+ await ctx.reply(`🔍 *DRY RUN Preview*\n\n` +
117
+ `Accounts: ${preview.accounts.length}\n` +
118
+ `Total: ${preview.totalSol}\n\n` +
119
+ `Use /reclaim\\_execute to actually reclaim.`, { parse_mode: 'Markdown' });
120
+ }
121
+ catch (error) {
122
+ await ctx.reply(`❌ Error: ${error}`);
123
+ }
124
+ });
125
+ // Reclaim execute (actual)
126
+ bot.command('reclaim_execute', async (ctx) => {
127
+ try {
128
+ await ctx.reply('⏳ Finding and reclaiming accounts...');
129
+ const results = await detector.findSafeReclaimable();
130
+ if (results.length === 0) {
131
+ await ctx.reply('✅ Nothing to reclaim.');
132
+ return;
133
+ }
134
+ const reclaimResults = await reclaimer.batchReclaim(results, {
135
+ dryRun: false,
136
+ maxAccounts: 10,
137
+ });
138
+ const successful = reclaimResults.filter((r) => r.success);
139
+ const totalReclaimed = successful.reduce((s, r) => s + r.amountReclaimed, 0);
140
+ await ctx.reply(`✅ *Reclaim Complete*\n\n` +
141
+ `Successful: ${successful.length}/${reclaimResults.length}\n` +
142
+ `Total Reclaimed: ${formatSol(totalReclaimed)}`, { parse_mode: 'Markdown' });
143
+ }
144
+ catch (error) {
145
+ await ctx.reply(`❌ Reclaim failed: ${error}`);
146
+ }
147
+ });
148
+ // History command
149
+ bot.command('history', async (ctx) => {
150
+ try {
151
+ const history = getReclaimHistory(5);
152
+ if (history.length === 0) {
153
+ await ctx.reply('📜 No reclaim history yet.');
154
+ return;
155
+ }
156
+ let message = '📜 *Recent Reclaims*\n\n';
157
+ for (const h of history) {
158
+ message += `• ${formatSol(h.amount_reclaimed)} - ${h.reason}\n`;
159
+ message += ` ${h.reclaimed_at.slice(0, 16)}\n\n`;
160
+ }
161
+ await ctx.reply(message, { parse_mode: 'Markdown' });
162
+ }
163
+ catch (error) {
164
+ await ctx.reply(`❌ Error: ${error}`);
165
+ }
166
+ });
167
+ logger.info('Telegram bot initialized');
168
+ return bot;
169
+ }
170
+ /**
171
+ * Send a notification message
172
+ */
173
+ export async function sendNotification(message) {
174
+ if (!bot || !authorizedChatId) {
175
+ logger.warn('Telegram bot not configured, skipping notification');
176
+ return;
177
+ }
178
+ try {
179
+ await bot.telegram.sendMessage(authorizedChatId, message, {
180
+ parse_mode: 'Markdown',
181
+ });
182
+ }
183
+ catch (error) {
184
+ logger.error('Failed to send Telegram notification:', error);
185
+ }
186
+ }
187
+ /**
188
+ * Send reclaim alert
189
+ */
190
+ export async function sendReclaimAlert(amount, accounts, txSignatures) {
191
+ const message = `✅ *Rent Reclaimed*\n\n` +
192
+ `Amount: ${formatSol(amount)}\n` +
193
+ `Accounts: ${accounts}\n\n` +
194
+ `Transactions:\n` +
195
+ txSignatures
196
+ .slice(0, 3)
197
+ .map((tx) => `• ${shortenPubkey(tx)}`)
198
+ .join('\n');
199
+ await sendNotification(message);
200
+ }
201
+ /**
202
+ * Start the Telegram bot (polling mode)
203
+ */
204
+ export async function startBot(token, chatId) {
205
+ const telegramBot = initTelegramBot(token, chatId);
206
+ logger.info('Starting Telegram bot...');
207
+ await telegramBot.launch();
208
+ // Graceful shutdown
209
+ process.once('SIGINT', () => telegramBot.stop('SIGINT'));
210
+ process.once('SIGTERM', () => telegramBot.stop('SIGTERM'));
211
+ }
212
+ export { bot };
213
+ //# sourceMappingURL=telegram.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/services/telegram.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ /**
3
+ * Convert lamports to SOL with fixed decimal places
4
+ */
5
+ export declare function lamportsToSol(lamports: number, decimals?: number): number;
6
+ /**
7
+ * Convert SOL to lamports
8
+ */
9
+ export declare function solToLamports(sol: number): number;
10
+ /**
11
+ * Format lamports as SOL string with symbol
12
+ */
13
+ export declare function formatSol(lamports: number): string;
14
+ /**
15
+ * Shorten a public key for display
16
+ */
17
+ export declare function shortenPubkey(pubkey: PublicKey | string, chars?: number): string;
18
+ /**
19
+ * Validate a public key string
20
+ */
21
+ export declare function isValidPubkey(str: string): boolean;
22
+ /**
23
+ * Parse a public key string safely
24
+ */
25
+ export declare function parsePubkey(str: string): PublicKey | null;
26
+ /**
27
+ * Calculate rent for a given account size
28
+ * Based on Solana's rent calculation (approx 0.00089 SOL per byte per year for 2 years)
29
+ */
30
+ export declare function calculateMinimumRent(dataSize: number): number;
31
+ /**
32
+ * Token Account size (165 bytes) minimum rent
33
+ */
34
+ export declare const TOKEN_ACCOUNT_RENT = 2039280;
35
+ /**
36
+ * Sleep for a given duration
37
+ */
38
+ export declare function sleep(ms: number): Promise<void>;
39
+ /**
40
+ * Retry a function with exponential backoff
41
+ */
42
+ export declare function retry<T>(fn: () => Promise<T>, maxRetries?: number, baseDelayMs?: number): Promise<T>;
43
+ /**
44
+ * Format a date for display
45
+ */
46
+ export declare function formatDate(date: Date): string;
47
+ /**
48
+ * Calculate days since a date
49
+ */
50
+ export declare function daysSince(date: Date): number;
51
+ /**
52
+ * Chunk an array into smaller arrays
53
+ */
54
+ export declare function chunk<T>(array: T[], size: number): T[][];
55
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE7D;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAEpE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAG3E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOlD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAMzD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,UAAU,CAAA;AAEzC;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,CAAC,EAC3B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,UAAU,SAAI,EACd,WAAW,SAAO,GACjB,OAAO,CAAC,CAAC,CAAC,CAgBZ;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAI5C;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAMxD"}