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,172 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { addTrackedAccount, getAllTrackedAccounts, getTrackedAccount, } from '../db/accounts.js';
|
|
3
|
+
import { detectAccountType, getAccountInfo, getConnection, getOperatorTokenAccounts, } from '../services/solana.js';
|
|
4
|
+
import { formatSol, shortenPubkey } from '../utils/helpers.js';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Monitor for tracking sponsored accounts
|
|
8
|
+
*/
|
|
9
|
+
export class AccountMonitor {
|
|
10
|
+
/**
|
|
11
|
+
* Scan all token accounts owned by the operator and add them to tracking
|
|
12
|
+
*/
|
|
13
|
+
async scanOperatorAccounts() {
|
|
14
|
+
logger.info('Scanning operator token accounts...');
|
|
15
|
+
const tokenAccounts = await getOperatorTokenAccounts();
|
|
16
|
+
const tracked = [];
|
|
17
|
+
for (const { pubkey, account } of tokenAccounts) {
|
|
18
|
+
const parsed = account.data.parsed;
|
|
19
|
+
if (!parsed || parsed.type !== 'account')
|
|
20
|
+
continue;
|
|
21
|
+
const info = parsed.info;
|
|
22
|
+
const amount = BigInt(info.tokenAmount.amount);
|
|
23
|
+
// Get current lamports (rent)
|
|
24
|
+
const accountInfo = await getAccountInfo(pubkey);
|
|
25
|
+
const lamports = accountInfo?.lamports || 0;
|
|
26
|
+
const trackedAccount = {
|
|
27
|
+
pubkey,
|
|
28
|
+
accountType: 'token_account',
|
|
29
|
+
rentLamports: lamports,
|
|
30
|
+
owner: new PublicKey(info.owner),
|
|
31
|
+
mint: new PublicKey(info.mint),
|
|
32
|
+
createdAt: new Date(),
|
|
33
|
+
lastCheckedAt: new Date(),
|
|
34
|
+
status: amount === 0n ? 'reclaimable' : 'active',
|
|
35
|
+
};
|
|
36
|
+
addTrackedAccount(trackedAccount);
|
|
37
|
+
tracked.push(trackedAccount);
|
|
38
|
+
logger.debug(`Tracked: ${shortenPubkey(pubkey)} | ` +
|
|
39
|
+
`Balance: ${info.tokenAmount.uiAmount} | ` +
|
|
40
|
+
`Rent: ${formatSol(lamports)}`);
|
|
41
|
+
}
|
|
42
|
+
logger.success(`Scanned ${tracked.length} token accounts`);
|
|
43
|
+
return tracked;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Scan accounts from transaction signatures (for Kora-sponsored accounts)
|
|
47
|
+
* This would parse transaction logs to find sponsored account creations
|
|
48
|
+
*/
|
|
49
|
+
async scanFromSignatures(signatures, options = {}) {
|
|
50
|
+
const conn = getConnection();
|
|
51
|
+
const tracked = [];
|
|
52
|
+
logger.info(`Scanning ${signatures.length} transactions for sponsored accounts...`);
|
|
53
|
+
for (const signature of signatures) {
|
|
54
|
+
try {
|
|
55
|
+
const tx = await conn.getParsedTransaction(signature, {
|
|
56
|
+
maxSupportedTransactionVersion: 0,
|
|
57
|
+
});
|
|
58
|
+
if (!tx || !tx.meta)
|
|
59
|
+
continue;
|
|
60
|
+
// Look for account creation in inner instructions
|
|
61
|
+
// This is where Kora would create sponsored accounts
|
|
62
|
+
const innerInstructions = tx.meta.innerInstructions || [];
|
|
63
|
+
for (const inner of innerInstructions) {
|
|
64
|
+
for (const instruction of inner.instructions) {
|
|
65
|
+
// Check for createAccount or initializeAccount instructions
|
|
66
|
+
if ('parsed' in instruction) {
|
|
67
|
+
const parsed = instruction.parsed;
|
|
68
|
+
if (parsed.type === 'createAccount' ||
|
|
69
|
+
parsed.type === 'initializeAccount' ||
|
|
70
|
+
parsed.type === 'initializeAccount3') {
|
|
71
|
+
const info = parsed.info;
|
|
72
|
+
const accountPubkey = new PublicKey(info.account || info.newAccount);
|
|
73
|
+
// Check if account exists and get its info
|
|
74
|
+
const accountInfo = await getAccountInfo(accountPubkey);
|
|
75
|
+
if (!accountInfo)
|
|
76
|
+
continue;
|
|
77
|
+
const accountType = detectAccountType(accountInfo);
|
|
78
|
+
const trackedAccount = {
|
|
79
|
+
pubkey: accountPubkey,
|
|
80
|
+
accountType,
|
|
81
|
+
sponsorTx: signature,
|
|
82
|
+
rentLamports: accountInfo.lamports,
|
|
83
|
+
createdAt: new Date(),
|
|
84
|
+
lastCheckedAt: new Date(),
|
|
85
|
+
status: 'active',
|
|
86
|
+
};
|
|
87
|
+
// Avoid duplicates
|
|
88
|
+
if (!getTrackedAccount(accountPubkey)) {
|
|
89
|
+
addTrackedAccount(trackedAccount);
|
|
90
|
+
tracked.push(trackedAccount);
|
|
91
|
+
logger.debug(`Found sponsored account: ${shortenPubkey(accountPubkey)} | ` +
|
|
92
|
+
`Type: ${accountType} | Rent: ${formatSol(accountInfo.lamports)}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger.debug(`Error parsing transaction ${shortenPubkey(signature)}:`, error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
logger.success(`Found ${tracked.length} new sponsored accounts`);
|
|
104
|
+
return tracked;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Add a single account to tracking
|
|
108
|
+
*/
|
|
109
|
+
async trackAccount(pubkey, sponsorTx) {
|
|
110
|
+
// Check if already tracked
|
|
111
|
+
const existing = getTrackedAccount(pubkey);
|
|
112
|
+
if (existing) {
|
|
113
|
+
logger.debug(`Account already tracked: ${pubkey.toBase58()}`);
|
|
114
|
+
return existing;
|
|
115
|
+
}
|
|
116
|
+
// Get account info
|
|
117
|
+
const accountInfo = await getAccountInfo(pubkey);
|
|
118
|
+
if (!accountInfo) {
|
|
119
|
+
logger.warn(`Account not found on chain: ${pubkey.toBase58()}`);
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const accountType = detectAccountType(accountInfo);
|
|
123
|
+
const trackedAccount = {
|
|
124
|
+
pubkey,
|
|
125
|
+
accountType,
|
|
126
|
+
sponsorTx,
|
|
127
|
+
rentLamports: accountInfo.lamports,
|
|
128
|
+
createdAt: new Date(),
|
|
129
|
+
lastCheckedAt: new Date(),
|
|
130
|
+
status: 'active',
|
|
131
|
+
};
|
|
132
|
+
const id = addTrackedAccount(trackedAccount);
|
|
133
|
+
logger.success(`Now tracking: ${pubkey.toBase58()} | Type: ${accountType} | ` +
|
|
134
|
+
`Rent: ${formatSol(accountInfo.lamports)}`);
|
|
135
|
+
return { ...trackedAccount, id };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get tracking statistics
|
|
139
|
+
*/
|
|
140
|
+
async getStats() {
|
|
141
|
+
const accounts = getAllTrackedAccounts();
|
|
142
|
+
const byType = {
|
|
143
|
+
token_account: 0,
|
|
144
|
+
ata: 0,
|
|
145
|
+
pda: 0,
|
|
146
|
+
unknown: 0,
|
|
147
|
+
};
|
|
148
|
+
const byStatus = {
|
|
149
|
+
active: 0,
|
|
150
|
+
reclaimable: 0,
|
|
151
|
+
reclaimed: 0,
|
|
152
|
+
protected: 0,
|
|
153
|
+
};
|
|
154
|
+
let totalRentLocked = 0;
|
|
155
|
+
for (const account of accounts) {
|
|
156
|
+
byType[account.accountType] = (byType[account.accountType] || 0) + 1;
|
|
157
|
+
byStatus[account.status] = (byStatus[account.status] || 0) + 1;
|
|
158
|
+
if (account.status !== 'reclaimed') {
|
|
159
|
+
totalRentLocked += account.rentLamports;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
totalTracked: accounts.length,
|
|
164
|
+
byType,
|
|
165
|
+
byStatus,
|
|
166
|
+
totalRentLocked,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Export singleton instance
|
|
171
|
+
export const monitor = new AccountMonitor();
|
|
172
|
+
//# sourceMappingURL=monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../src/core/monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DetectionResult, ReclaimOptions, ReclaimResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reclaimer for executing rent reclaim transactions
|
|
4
|
+
*/
|
|
5
|
+
export declare class RentReclaimer {
|
|
6
|
+
private get treasuryAddress();
|
|
7
|
+
private get dryRunDefault();
|
|
8
|
+
/**
|
|
9
|
+
* Reclaim rent from a single token account
|
|
10
|
+
*/
|
|
11
|
+
reclaimTokenAccount(detection: DetectionResult, options?: ReclaimOptions): Promise<ReclaimResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Batch reclaim from multiple accounts
|
|
14
|
+
*/
|
|
15
|
+
batchReclaim(detections: DetectionResult[], options?: ReclaimOptions): Promise<ReclaimResult[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Preview what would be reclaimed (always dry run)
|
|
18
|
+
*/
|
|
19
|
+
previewReclaim(detections: DetectionResult[]): Promise<{
|
|
20
|
+
accounts: {
|
|
21
|
+
pubkey: string;
|
|
22
|
+
amount: string;
|
|
23
|
+
reason: string;
|
|
24
|
+
}[];
|
|
25
|
+
totalLamports: number;
|
|
26
|
+
totalSol: string;
|
|
27
|
+
}>;
|
|
28
|
+
}
|
|
29
|
+
export declare const reclaimer: RentReclaimer;
|
|
30
|
+
//# sourceMappingURL=reclaimer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reclaimer.d.ts","sourceRoot":"","sources":["../../src/core/reclaimer.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEhF;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,aAAa,GAExB;IAED;;OAEG;IACG,mBAAmB,CACvB,SAAS,EAAE,eAAe,EAC1B,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC;IAiJzB;;OAEG;IACG,YAAY,CAChB,UAAU,EAAE,eAAe,EAAE,EAC7B,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,EAAE,CAAC;IAsC3B;;OAEG;IACG,cAAc,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAC3D,QAAQ,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;QAC9D,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAC;CAmBH;AAGD,eAAO,MAAM,SAAS,eAAsB,CAAA"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { getConfig } from '../config.js';
|
|
2
|
+
import { addReclaimHistory, isAccountProtected, updateAccountStatus, } from '../db/accounts.js';
|
|
3
|
+
import { closeTokenAccount, getOperatorKeypair, getTokenAccountData, } from '../services/solana.js';
|
|
4
|
+
import { formatSol, shortenPubkey } from '../utils/helpers.js';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Reclaimer for executing rent reclaim transactions
|
|
8
|
+
*/
|
|
9
|
+
export class RentReclaimer {
|
|
10
|
+
get treasuryAddress() {
|
|
11
|
+
return getConfig().treasuryAddress;
|
|
12
|
+
}
|
|
13
|
+
get dryRunDefault() {
|
|
14
|
+
return getConfig().dryRun;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reclaim rent from a single token account
|
|
18
|
+
*/
|
|
19
|
+
async reclaimTokenAccount(detection, options = {}) {
|
|
20
|
+
const dryRun = options.dryRun ?? this.dryRunDefault;
|
|
21
|
+
const accountPubkey = detection.account.pubkey;
|
|
22
|
+
// Safety checks
|
|
23
|
+
if (!detection.safe) {
|
|
24
|
+
logger.warn(`Account ${shortenPubkey(accountPubkey)} is not safe to reclaim. Reason: ${detection.details}`);
|
|
25
|
+
return {
|
|
26
|
+
accountPubkey,
|
|
27
|
+
amountReclaimed: 0,
|
|
28
|
+
txSignature: '',
|
|
29
|
+
timestamp: new Date(),
|
|
30
|
+
success: false,
|
|
31
|
+
error: 'Account marked as unsafe for automatic reclaim',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (isAccountProtected(accountPubkey)) {
|
|
35
|
+
return {
|
|
36
|
+
accountPubkey,
|
|
37
|
+
amountReclaimed: 0,
|
|
38
|
+
txSignature: '',
|
|
39
|
+
timestamp: new Date(),
|
|
40
|
+
success: false,
|
|
41
|
+
error: 'Account is protected',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Only token accounts can be closed via this method
|
|
45
|
+
if (detection.account.accountType !== 'token_account' &&
|
|
46
|
+
detection.account.accountType !== 'ata') {
|
|
47
|
+
return {
|
|
48
|
+
accountPubkey,
|
|
49
|
+
amountReclaimed: 0,
|
|
50
|
+
txSignature: '',
|
|
51
|
+
timestamp: new Date(),
|
|
52
|
+
success: false,
|
|
53
|
+
error: `Cannot reclaim non-token account type: ${detection.account.accountType}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Verify token balance is still 0
|
|
57
|
+
const tokenData = await getTokenAccountData(accountPubkey);
|
|
58
|
+
if (!tokenData) {
|
|
59
|
+
// Account already closed
|
|
60
|
+
updateAccountStatus(accountPubkey, 'reclaimed');
|
|
61
|
+
return {
|
|
62
|
+
accountPubkey,
|
|
63
|
+
amountReclaimed: 0,
|
|
64
|
+
txSignature: '',
|
|
65
|
+
timestamp: new Date(),
|
|
66
|
+
success: true,
|
|
67
|
+
error: 'Account already closed',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (tokenData.amount > 0n) {
|
|
71
|
+
return {
|
|
72
|
+
accountPubkey,
|
|
73
|
+
amountReclaimed: 0,
|
|
74
|
+
txSignature: '',
|
|
75
|
+
timestamp: new Date(),
|
|
76
|
+
success: false,
|
|
77
|
+
error: `Token account has non-zero balance: ${tokenData.amount}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// Dry run mode - just log what would happen
|
|
81
|
+
if (dryRun) {
|
|
82
|
+
logger.info(`[DRY RUN] Would close ${shortenPubkey(accountPubkey)} and reclaim ${formatSol(tokenData.lamports)} to treasury`);
|
|
83
|
+
return {
|
|
84
|
+
accountPubkey,
|
|
85
|
+
amountReclaimed: tokenData.lamports,
|
|
86
|
+
txSignature: 'DRY_RUN',
|
|
87
|
+
timestamp: new Date(),
|
|
88
|
+
success: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Execute the close transaction
|
|
92
|
+
try {
|
|
93
|
+
const operator = getOperatorKeypair();
|
|
94
|
+
// Verify operator is the token account owner
|
|
95
|
+
if (!tokenData.owner.equals(operator.publicKey)) {
|
|
96
|
+
return {
|
|
97
|
+
accountPubkey,
|
|
98
|
+
amountReclaimed: 0,
|
|
99
|
+
txSignature: '',
|
|
100
|
+
timestamp: new Date(),
|
|
101
|
+
success: false,
|
|
102
|
+
error: `Operator is not the account owner. Owner: ${tokenData.owner.toBase58()}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const txSignature = await closeTokenAccount(accountPubkey, this.treasuryAddress, operator);
|
|
106
|
+
// Update database
|
|
107
|
+
updateAccountStatus(accountPubkey, 'reclaimed');
|
|
108
|
+
addReclaimHistory(accountPubkey, tokenData.lamports, txSignature, detection.reason);
|
|
109
|
+
logger.success(`Reclaimed ${formatSol(tokenData.lamports)} from ${shortenPubkey(accountPubkey)}`);
|
|
110
|
+
return {
|
|
111
|
+
accountPubkey,
|
|
112
|
+
amountReclaimed: tokenData.lamports,
|
|
113
|
+
txSignature,
|
|
114
|
+
timestamp: new Date(),
|
|
115
|
+
success: true,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
120
|
+
logger.error(`Failed to reclaim ${shortenPubkey(accountPubkey)}:`, errorMsg);
|
|
121
|
+
return {
|
|
122
|
+
accountPubkey,
|
|
123
|
+
amountReclaimed: 0,
|
|
124
|
+
txSignature: '',
|
|
125
|
+
timestamp: new Date(),
|
|
126
|
+
success: false,
|
|
127
|
+
error: errorMsg,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Batch reclaim from multiple accounts
|
|
133
|
+
*/
|
|
134
|
+
async batchReclaim(detections, options = {}) {
|
|
135
|
+
const maxAccounts = options.maxAccounts ?? detections.length;
|
|
136
|
+
const toProcess = detections.slice(0, maxAccounts);
|
|
137
|
+
const results = [];
|
|
138
|
+
logger.info(`Processing ${toProcess.length} accounts for reclaim...`);
|
|
139
|
+
logger.divider();
|
|
140
|
+
for (let i = 0; i < toProcess.length; i++) {
|
|
141
|
+
const detection = toProcess[i];
|
|
142
|
+
logger.info(`[${i + 1}/${toProcess.length}] Processing ${shortenPubkey(detection.account.pubkey)}...`);
|
|
143
|
+
const result = await this.reclaimTokenAccount(detection, options);
|
|
144
|
+
results.push(result);
|
|
145
|
+
// Small delay between transactions to avoid rate limiting
|
|
146
|
+
if (i < toProcess.length - 1 && result.success && !options.dryRun) {
|
|
147
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Summary
|
|
151
|
+
const successful = results.filter((r) => r.success);
|
|
152
|
+
const totalReclaimed = successful.reduce((sum, r) => sum + r.amountReclaimed, 0);
|
|
153
|
+
logger.divider();
|
|
154
|
+
logger.info(`Reclaim complete:`);
|
|
155
|
+
logger.info(` - Successful: ${successful.length}/${results.length}`);
|
|
156
|
+
logger.info(` - Total reclaimed: ${formatSol(totalReclaimed)}`);
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Preview what would be reclaimed (always dry run)
|
|
161
|
+
*/
|
|
162
|
+
async previewReclaim(detections) {
|
|
163
|
+
const accounts = detections
|
|
164
|
+
.filter((d) => d.safe)
|
|
165
|
+
.map((d) => ({
|
|
166
|
+
pubkey: d.account.pubkey.toBase58(),
|
|
167
|
+
amount: formatSol(d.reclaimableLamports),
|
|
168
|
+
reason: d.reason,
|
|
169
|
+
}));
|
|
170
|
+
const totalLamports = detections
|
|
171
|
+
.filter((d) => d.safe)
|
|
172
|
+
.reduce((sum, d) => sum + d.reclaimableLamports, 0);
|
|
173
|
+
return {
|
|
174
|
+
accounts,
|
|
175
|
+
totalLamports,
|
|
176
|
+
totalSol: formatSol(totalLamports),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Export singleton instance
|
|
181
|
+
export const reclaimer = new RentReclaimer();
|
|
182
|
+
//# sourceMappingURL=reclaimer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reclaimer.js","sourceRoot":"","sources":["../../src/core/reclaimer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
/**
|
|
3
|
+
* Types of accounts that can be sponsored and tracked
|
|
4
|
+
*/
|
|
5
|
+
export type AccountType = 'token_account' | 'ata' | 'pda' | 'unknown';
|
|
6
|
+
/**
|
|
7
|
+
* Status of a tracked account
|
|
8
|
+
*/
|
|
9
|
+
export type AccountStatus = 'active' | 'reclaimable' | 'reclaimed' | 'protected';
|
|
10
|
+
/**
|
|
11
|
+
* Reason why an account is reclaimable
|
|
12
|
+
*/
|
|
13
|
+
export type ReclaimReason = 'closed' | 'zero_balance' | 'inactive';
|
|
14
|
+
/**
|
|
15
|
+
* A sponsored account being tracked by the bot
|
|
16
|
+
*/
|
|
17
|
+
export interface TrackedAccount {
|
|
18
|
+
id?: number;
|
|
19
|
+
pubkey: PublicKey;
|
|
20
|
+
accountType: AccountType;
|
|
21
|
+
sponsorTx?: string;
|
|
22
|
+
rentLamports: number;
|
|
23
|
+
owner?: PublicKey;
|
|
24
|
+
mint?: PublicKey;
|
|
25
|
+
createdAt: Date;
|
|
26
|
+
lastCheckedAt: Date;
|
|
27
|
+
lastActivityAt?: Date;
|
|
28
|
+
status: AccountStatus;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Database row representation of a tracked account
|
|
32
|
+
*/
|
|
33
|
+
export interface TrackedAccountRow {
|
|
34
|
+
id: number;
|
|
35
|
+
pubkey: string;
|
|
36
|
+
account_type: string;
|
|
37
|
+
sponsor_tx: string | null;
|
|
38
|
+
rent_lamports: number;
|
|
39
|
+
owner: string | null;
|
|
40
|
+
mint: string | null;
|
|
41
|
+
created_at: string;
|
|
42
|
+
last_checked_at: string;
|
|
43
|
+
last_activity_at: string | null;
|
|
44
|
+
status: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result of checking if an account is reclaimable
|
|
48
|
+
*/
|
|
49
|
+
export interface DetectionResult {
|
|
50
|
+
account: TrackedAccount;
|
|
51
|
+
reason: ReclaimReason;
|
|
52
|
+
reclaimableLamports: number;
|
|
53
|
+
safe: boolean;
|
|
54
|
+
details: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Result of a rent reclaim operation
|
|
58
|
+
*/
|
|
59
|
+
export interface ReclaimResult {
|
|
60
|
+
accountPubkey: PublicKey;
|
|
61
|
+
amountReclaimed: number;
|
|
62
|
+
txSignature: string;
|
|
63
|
+
timestamp: Date;
|
|
64
|
+
success: boolean;
|
|
65
|
+
error?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Database row for reclaim history
|
|
69
|
+
*/
|
|
70
|
+
export interface ReclaimHistoryRow {
|
|
71
|
+
id: number;
|
|
72
|
+
account_pubkey: string;
|
|
73
|
+
amount_reclaimed: number;
|
|
74
|
+
tx_signature: string;
|
|
75
|
+
reclaimed_at: string;
|
|
76
|
+
reason: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Summary report of rent status
|
|
80
|
+
*/
|
|
81
|
+
export interface RentReport {
|
|
82
|
+
totalTrackedAccounts: number;
|
|
83
|
+
activeAccounts: number;
|
|
84
|
+
reclaimableAccounts: number;
|
|
85
|
+
reclaimedAccounts: number;
|
|
86
|
+
protectedAccounts: number;
|
|
87
|
+
totalRentLockedLamports: number;
|
|
88
|
+
totalRentReclaimedLamports: number;
|
|
89
|
+
reclaimableNowLamports: number;
|
|
90
|
+
accountsByType: Record<AccountType, number>;
|
|
91
|
+
generatedAt: Date;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Options for scanning accounts
|
|
95
|
+
*/
|
|
96
|
+
export interface ScanOptions {
|
|
97
|
+
fromSignature?: string;
|
|
98
|
+
limit?: number;
|
|
99
|
+
accountType?: AccountType;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Options for checking reclaimable accounts
|
|
103
|
+
*/
|
|
104
|
+
export interface CheckOptions {
|
|
105
|
+
address?: PublicKey;
|
|
106
|
+
includeProtected?: boolean;
|
|
107
|
+
force?: boolean;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Options for reclaiming rent
|
|
111
|
+
*/
|
|
112
|
+
export interface ReclaimOptions {
|
|
113
|
+
dryRun?: boolean;
|
|
114
|
+
maxAccounts?: number;
|
|
115
|
+
skipConfirmation?: boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Whitelist/blacklist entry
|
|
119
|
+
*/
|
|
120
|
+
export interface ProtectionEntry {
|
|
121
|
+
pubkey: PublicKey;
|
|
122
|
+
reason: string;
|
|
123
|
+
addedAt: Date;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { PublicKey } from '@solana/web3.js';
|
|
2
|
+
import type { AccountStatus, ProtectionEntry, ReclaimHistoryRow, TrackedAccount } from '../core/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Add a new account to track
|
|
5
|
+
*/
|
|
6
|
+
export declare function addTrackedAccount(account: Omit<TrackedAccount, 'id'>): number;
|
|
7
|
+
/**
|
|
8
|
+
* Get all tracked accounts
|
|
9
|
+
*/
|
|
10
|
+
export declare function getAllTrackedAccounts(operatorId?: number): TrackedAccount[];
|
|
11
|
+
/**
|
|
12
|
+
* Get tracked accounts by status
|
|
13
|
+
*/
|
|
14
|
+
export declare function getAccountsByStatus(status: AccountStatus): TrackedAccount[];
|
|
15
|
+
/**
|
|
16
|
+
* Get a specific tracked account by pubkey
|
|
17
|
+
*/
|
|
18
|
+
export declare function getTrackedAccount(pubkey: PublicKey): TrackedAccount | null;
|
|
19
|
+
/**
|
|
20
|
+
* Update account status
|
|
21
|
+
*/
|
|
22
|
+
export declare function updateAccountStatus(pubkey: PublicKey, status: AccountStatus): void;
|
|
23
|
+
/**
|
|
24
|
+
* Update account after checking state
|
|
25
|
+
*/
|
|
26
|
+
export declare function updateAccountState(pubkey: PublicKey, updates: {
|
|
27
|
+
status?: AccountStatus;
|
|
28
|
+
rentLamports?: number;
|
|
29
|
+
lastActivityAt?: Date;
|
|
30
|
+
}): void;
|
|
31
|
+
/**
|
|
32
|
+
* Delete a tracked account
|
|
33
|
+
*/
|
|
34
|
+
export declare function deleteTrackedAccount(pubkey: PublicKey): void;
|
|
35
|
+
/**
|
|
36
|
+
* Get account statistics
|
|
37
|
+
*/
|
|
38
|
+
export declare function getAccountStats(): {
|
|
39
|
+
total: number;
|
|
40
|
+
active: number;
|
|
41
|
+
reclaimable: number;
|
|
42
|
+
reclaimed: number;
|
|
43
|
+
protected: number;
|
|
44
|
+
totalRentLocked: number;
|
|
45
|
+
totalRentReclaimed: number;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Add reclaim history entry
|
|
49
|
+
*/
|
|
50
|
+
export declare function addReclaimHistory(accountPubkey: PublicKey, amountReclaimed: number, txSignature: string, reason: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* Get reclaim history
|
|
53
|
+
*/
|
|
54
|
+
export declare function getReclaimHistory(limit?: number): ReclaimHistoryRow[];
|
|
55
|
+
/**
|
|
56
|
+
* Add account to protection list
|
|
57
|
+
*/
|
|
58
|
+
export declare function addProtectedAccount(pubkey: PublicKey, reason: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Remove account from protection list
|
|
61
|
+
*/
|
|
62
|
+
export declare function removeProtectedAccount(pubkey: PublicKey): void;
|
|
63
|
+
/**
|
|
64
|
+
* Check if account is protected
|
|
65
|
+
*/
|
|
66
|
+
export declare function isAccountProtected(pubkey: PublicKey): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Get all protected accounts
|
|
69
|
+
*/
|
|
70
|
+
export declare function getProtectedAccounts(): ProtectionEntry[];
|
|
71
|
+
//# sourceMappingURL=accounts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/db/accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EACV,aAAa,EAEb,eAAe,EACf,iBAAiB,EACjB,cAAc,EAEf,MAAM,kBAAkB,CAAA;AA0BzB;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,GAAG,MAAM,CAyB7E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAY3E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,EAAE,CAQ3E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,cAAc,GAAG,IAAI,CAM1E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,aAAa,GACpB,IAAI,CAKN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE;IACP,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,IAAI,CAAA;CACtB,GACA,IAAI,CAwBN;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAK5D;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,MAAM,CAAA;CAC3B,CAwCA;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,SAAS,EACxB,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,SAAM,GAAG,iBAAiB,EAAE,CAKlE;AAID;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAa3E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAU9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAM7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,eAAe,EAAE,CAaxD"}
|