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.
- package/README.md +362 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +58 -0
- package/dist/config.js.map +1 -0
- package/dist/core/detector.d.ts +36 -0
- package/dist/core/detector.d.ts.map +1 -0
- package/dist/core/detector.js +142 -0
- package/dist/core/detector.js.map +1 -0
- package/dist/core/monitor.d.ts +31 -0
- package/dist/core/monitor.d.ts.map +1 -0
- package/dist/core/monitor.js +172 -0
- package/dist/core/monitor.js.map +1 -0
- package/dist/core/reclaimer.d.ts +30 -0
- package/dist/core/reclaimer.d.ts.map +1 -0
- package/dist/core/reclaimer.js +182 -0
- package/dist/core/reclaimer.js.map +1 -0
- package/dist/core/types.d.ts +125 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/db/accounts.d.ts +71 -0
- package/dist/db/accounts.d.ts.map +1 -0
- package/dist/db/accounts.js +205 -0
- package/dist/db/accounts.js.map +1 -0
- package/dist/db/index.d.ts +14 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +104 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/operators.d.ts +48 -0
- package/dist/db/operators.d.ts.map +1 -0
- package/dist/db/operators.js +201 -0
- package/dist/db/operators.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +473 -0
- package/dist/index.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +121 -0
- package/dist/server/index.js.map +1 -0
- package/dist/services/reporter.d.ts +28 -0
- package/dist/services/reporter.d.ts.map +1 -0
- package/dist/services/reporter.js +107 -0
- package/dist/services/reporter.js.map +1 -0
- package/dist/services/solana.d.ts +59 -0
- package/dist/services/solana.d.ts.map +1 -0
- package/dist/services/solana.js +162 -0
- package/dist/services/solana.js.map +1 -0
- package/dist/services/telegram.d.ts +20 -0
- package/dist/services/telegram.d.ts.map +1 -0
- package/dist/services/telegram.js +213 -0
- package/dist/services/telegram.js.map +1 -0
- package/dist/utils/helpers.d.ts +55 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +116 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +70 -0
- package/dist/utils/logger.js.map +1 -0
- 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"}
|