vacuum-sol 1.0.2 โ†’ 1.0.4

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 CHANGED
@@ -224,6 +224,33 @@ npm start -- bot
224
224
 
225
225
  ---
226
226
 
227
+ ## ๐Ÿ’ป Using as an SDK
228
+
229
+ Vacuum can be used as a TypeScript library to integrate rent reclamation directly into your backend or scripts.
230
+
231
+ ```typescript
232
+ import { VacuumClient } from 'vacuum-sol'
233
+
234
+ // Initialize the client
235
+ const client = new VacuumClient({
236
+ rpcUrl: 'https://api.mainnet-beta.solana.com',
237
+ treasury: 'YOUR_TREASURY_WALLET_ADDRESS',
238
+ keypairPath: './operator-keypair.json', // Optional if just checking
239
+ logLevel: 'info',
240
+ })
241
+
242
+ // 1. Scan for accounts
243
+ const accounts = await client.scan()
244
+
245
+ // 2. Check which ones are reclaimable
246
+ const reclaimable = await client.check(accounts)
247
+
248
+ // 3. Reclaim rent (returns transaction signatures)
249
+ const results = await client.reclaim(reclaimable)
250
+
251
+ console.log(`Reclaimed from ${results.length} accounts!`)
252
+ ```
253
+
227
254
  ## โš™๏ธ Configuration
228
255
 
229
256
  Create a `.env` file:
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,473 @@
1
+ #!/usr/bin/env node
2
+ import { PublicKey } from '@solana/web3.js';
3
+ import chalk from 'chalk';
4
+ import { Command } from 'commander';
5
+ import { config as loadEnv } from 'dotenv';
6
+ import ora from 'ora';
7
+ // Load environment variables
8
+ loadEnv();
9
+ // Import modules
10
+ import { getConfig } from './config.js';
11
+ import { detector } from './core/detector.js';
12
+ import { monitor } from './core/monitor.js';
13
+ import { reclaimer } from './core/reclaimer.js';
14
+ import { addProtectedAccount, getAllTrackedAccounts, getProtectedAccounts, removeProtectedAccount, } from './db/accounts.js';
15
+ import { closeDatabase, initDatabase } from './db/index.js';
16
+ import { reporter } from './services/reporter.js';
17
+ import { formatSol, isValidPubkey, shortenPubkey } from './utils/helpers.js';
18
+ import { logger, setLogLevel } from './utils/logger.js';
19
+ const program = new Command();
20
+ program
21
+ .name('vacuum')
22
+ .description('๐Ÿงน Vacuum - Suck up forgotten rent from Solana accounts')
23
+ .version('1.0.0')
24
+ .option('-v, --verbose', 'Enable verbose logging')
25
+ .hook('preAction', (thisCommand) => {
26
+ if (thisCommand.opts().verbose) {
27
+ setLogLevel('debug');
28
+ }
29
+ // Initialize database before any command
30
+ initDatabase();
31
+ });
32
+ // ==================== SCAN COMMAND ====================
33
+ program
34
+ .command('scan')
35
+ .description('Scan for sponsored accounts to track')
36
+ .option('--operator', 'Scan all token accounts owned by operator')
37
+ .option('--tx <signatures...>', 'Scan specific transaction signatures')
38
+ .action(async (options) => {
39
+ const spinner = ora('Scanning for accounts...').start();
40
+ try {
41
+ let accounts;
42
+ if (options.tx) {
43
+ accounts = await monitor.scanFromSignatures(options.tx);
44
+ }
45
+ else {
46
+ // Default: scan operator's token accounts
47
+ accounts = await monitor.scanOperatorAccounts();
48
+ }
49
+ spinner.succeed(`Found ${accounts.length} accounts`);
50
+ if (accounts.length > 0) {
51
+ const stats = await monitor.getStats();
52
+ logger.info(`\nTotal tracked: ${stats.totalTracked}`);
53
+ logger.info(`Total rent locked: ${formatSol(stats.totalRentLocked)}`);
54
+ }
55
+ }
56
+ catch (error) {
57
+ spinner.fail('Scan failed');
58
+ logger.error(String(error));
59
+ process.exit(1);
60
+ }
61
+ });
62
+ // ==================== CHECK COMMAND ====================
63
+ program
64
+ .command('check')
65
+ .description('Check for reclaimable accounts')
66
+ .option('-a, --address <pubkey>', 'Check a specific account')
67
+ .option('--all', 'Check all tracked accounts')
68
+ .action(async (options) => {
69
+ const spinner = ora('Checking accounts...').start();
70
+ try {
71
+ if (options.address) {
72
+ if (!isValidPubkey(options.address)) {
73
+ spinner.fail('Invalid public key');
74
+ process.exit(1);
75
+ }
76
+ const pubkey = new PublicKey(options.address);
77
+ const result = await detector.checkAccount(pubkey);
78
+ spinner.stop();
79
+ if (result) {
80
+ logger.success(`Account ${shortenPubkey(pubkey)} is reclaimable!`);
81
+ logger.info(` Reason: ${result.reason}`);
82
+ logger.info(` Amount: ${formatSol(result.reclaimableLamports)}`);
83
+ logger.info(` Safe: ${result.safe ? 'Yes' : 'No - Manual review needed'}`);
84
+ logger.info(` Details: ${result.details}`);
85
+ }
86
+ else {
87
+ logger.info(`Account ${shortenPubkey(pubkey)} is not reclaimable.`);
88
+ }
89
+ }
90
+ else {
91
+ // Check all accounts
92
+ const results = await detector.findAllReclaimable();
93
+ spinner.succeed(`Found ${results.length} reclaimable accounts`);
94
+ if (results.length > 0) {
95
+ const summary = await detector.getReclaimableSummary();
96
+ logger.newline();
97
+ logger.info(`๐Ÿ“Š Reclaimable Summary:`);
98
+ logger.info(` - Safe to reclaim: ${summary.safeToReclaim} accounts`);
99
+ logger.info(` - Needs review: ${summary.unsafeNeedsReview} accounts`);
100
+ logger.info(` - Total reclaimable: ${formatSol(summary.totalReclaimableLamports)}`);
101
+ logger.info(` - Safe reclaimable: ${formatSol(summary.safeReclaimableLamports)}`);
102
+ logger.newline();
103
+ logger.info('Reclaimable accounts:');
104
+ logger.divider();
105
+ for (const result of results) {
106
+ const safeTag = result.safe
107
+ ? chalk.green('[SAFE]')
108
+ : chalk.yellow('[REVIEW]');
109
+ logger.info(`${safeTag} ${result.account.pubkey.toBase58().slice(0, 20)}... | ` +
110
+ `${formatSol(result.reclaimableLamports)} | ${result.reason}`);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ catch (error) {
116
+ spinner.fail('Check failed');
117
+ logger.error(String(error));
118
+ process.exit(1);
119
+ }
120
+ });
121
+ // ==================== RECLAIM COMMAND ====================
122
+ program
123
+ .command('reclaim')
124
+ .description('Reclaim rent from eligible accounts')
125
+ .option('-n, --dry-run', 'Preview reclaim without executing')
126
+ .option('-m, --max <number>', 'Maximum accounts to reclaim', '10')
127
+ .option('-y, --yes', 'Skip confirmation prompt')
128
+ .action(async (options) => {
129
+ const dryRun = options.dryRun !== undefined ? true : getConfig().dryRun;
130
+ const maxAccounts = parseInt(options.max, 10);
131
+ const spinner = ora('Finding reclaimable accounts...').start();
132
+ try {
133
+ // Find safe reclaimable accounts
134
+ const results = await detector.findSafeReclaimable();
135
+ spinner.stop();
136
+ if (results.length === 0) {
137
+ logger.info('No accounts ready for reclaim.');
138
+ return;
139
+ }
140
+ const toReclaim = results.slice(0, maxAccounts);
141
+ const preview = await reclaimer.previewReclaim(toReclaim);
142
+ logger.newline();
143
+ logger.info(`${dryRun ? '๐Ÿ” DRY RUN - ' : ''}Will reclaim from ${toReclaim.length} accounts:`);
144
+ logger.divider();
145
+ for (const account of preview.accounts) {
146
+ logger.info(` ${account.pubkey.slice(0, 16)}... | ${account.amount} | ${account.reason}`);
147
+ }
148
+ logger.divider();
149
+ logger.info(`Total to reclaim: ${preview.totalSol}`);
150
+ logger.newline();
151
+ if (!options.yes && !dryRun) {
152
+ // In a real CLI, we'd prompt for confirmation here
153
+ logger.warn('Use --yes to skip confirmation, or --dry-run to preview');
154
+ return;
155
+ }
156
+ // Execute reclaim
157
+ const reclaimResults = await reclaimer.batchReclaim(toReclaim, {
158
+ dryRun,
159
+ maxAccounts,
160
+ });
161
+ const successful = reclaimResults.filter((r) => r.success);
162
+ const totalReclaimed = successful.reduce((sum, r) => sum + r.amountReclaimed, 0);
163
+ logger.newline();
164
+ if (dryRun) {
165
+ logger.success(`[DRY RUN] Would reclaim ${formatSol(totalReclaimed)} from ${successful.length} accounts`);
166
+ }
167
+ else {
168
+ logger.success(`Reclaimed ${formatSol(totalReclaimed)} from ${successful.length} accounts`);
169
+ }
170
+ }
171
+ catch (error) {
172
+ spinner.fail('Reclaim failed');
173
+ logger.error(String(error));
174
+ process.exit(1);
175
+ }
176
+ });
177
+ // ==================== REPORT COMMAND ====================
178
+ program
179
+ .command('report')
180
+ .description('Generate rent status report')
181
+ .option('-f, --format <format>', 'Output format (table, json)', 'table')
182
+ .option('--history', 'Show reclaim history')
183
+ .action(async (options) => {
184
+ try {
185
+ if (options.format === 'json') {
186
+ const json = await reporter.exportJson();
187
+ console.log(json);
188
+ }
189
+ else {
190
+ reporter.printSummary();
191
+ }
192
+ if (options.history) {
193
+ reporter.printHistory();
194
+ }
195
+ }
196
+ catch (error) {
197
+ logger.error(String(error));
198
+ process.exit(1);
199
+ }
200
+ });
201
+ // ==================== PROTECT COMMAND ====================
202
+ program
203
+ .command('protect')
204
+ .description('Manage protected accounts (whitelist)')
205
+ .option('-a, --add <pubkey>', 'Add account to protection list')
206
+ .option('-r, --remove <pubkey>', 'Remove account from protection list')
207
+ .option('-l, --list', 'List all protected accounts')
208
+ .option('--reason <reason>', 'Reason for protection', 'Manual protection')
209
+ .action(async (options) => {
210
+ try {
211
+ if (options.add) {
212
+ if (!isValidPubkey(options.add)) {
213
+ logger.error('Invalid public key');
214
+ process.exit(1);
215
+ }
216
+ addProtectedAccount(new PublicKey(options.add), options.reason);
217
+ logger.success(`Protected: ${options.add}`);
218
+ }
219
+ else if (options.remove) {
220
+ if (!isValidPubkey(options.remove)) {
221
+ logger.error('Invalid public key');
222
+ process.exit(1);
223
+ }
224
+ removeProtectedAccount(new PublicKey(options.remove));
225
+ logger.success(`Removed protection: ${options.remove}`);
226
+ }
227
+ else if (options.list) {
228
+ const protected_ = getProtectedAccounts();
229
+ if (protected_.length === 0) {
230
+ logger.info('No protected accounts.');
231
+ }
232
+ else {
233
+ logger.info(`\n๐Ÿ›ก๏ธ Protected Accounts (${protected_.length}):`);
234
+ logger.divider();
235
+ for (const entry of protected_) {
236
+ logger.info(` ${entry.pubkey.toBase58()} | ${entry.reason}`);
237
+ }
238
+ }
239
+ }
240
+ else {
241
+ logger.info('Use --add, --remove, or --list');
242
+ }
243
+ }
244
+ catch (error) {
245
+ logger.error(String(error));
246
+ process.exit(1);
247
+ }
248
+ });
249
+ // ==================== CONFIG COMMAND ====================
250
+ program
251
+ .command('config')
252
+ .description('Show current configuration')
253
+ .action(() => {
254
+ try {
255
+ const config = getConfig();
256
+ logger.newline();
257
+ logger.info('โš™๏ธ Current Configuration:');
258
+ logger.divider();
259
+ logger.info(` RPC URL: ${config.rpcUrl}`);
260
+ logger.info(` Treasury: ${config.treasuryAddress.toBase58()}`);
261
+ logger.info(` Keypair Path: ${config.operatorKeypairPath}`);
262
+ logger.info(` Dry Run: ${config.dryRun}`);
263
+ logger.info(` Cooldown: ${config.cooldownHours} hours`);
264
+ logger.info(` Min Inactive: ${config.minInactiveDays} days`);
265
+ logger.info(` Database: ${config.dbPath}`);
266
+ logger.divider();
267
+ }
268
+ catch (error) {
269
+ logger.error(String(error));
270
+ process.exit(1);
271
+ }
272
+ });
273
+ // ==================== TRACK COMMAND ====================
274
+ program
275
+ .command('track <pubkey>')
276
+ .description('Manually track a specific account')
277
+ .option('--tx <signature>', 'Sponsor transaction signature')
278
+ .action(async (pubkey, options) => {
279
+ try {
280
+ if (!isValidPubkey(pubkey)) {
281
+ logger.error('Invalid public key');
282
+ process.exit(1);
283
+ }
284
+ const account = await monitor.trackAccount(new PublicKey(pubkey), options.tx);
285
+ if (account) {
286
+ logger.success(`Now tracking: ${pubkey}`);
287
+ logger.info(` Type: ${account.accountType}`);
288
+ logger.info(` Rent: ${formatSol(account.rentLamports)}`);
289
+ }
290
+ }
291
+ catch (error) {
292
+ logger.error(String(error));
293
+ process.exit(1);
294
+ }
295
+ });
296
+ // ==================== LIST COMMAND ====================
297
+ program
298
+ .command('list')
299
+ .description('List all tracked accounts')
300
+ .option('--status <status>', 'Filter by status (active, reclaimable, reclaimed, protected)')
301
+ .action((options) => {
302
+ try {
303
+ const accounts = getAllTrackedAccounts();
304
+ const filtered = options.status
305
+ ? accounts.filter((a) => a.status === options.status)
306
+ : accounts;
307
+ if (filtered.length === 0) {
308
+ logger.info('No accounts found.');
309
+ return;
310
+ }
311
+ logger.newline();
312
+ logger.info(`๐Ÿ“‹ Tracked Accounts (${filtered.length}):`);
313
+ logger.divider();
314
+ for (const account of filtered) {
315
+ const statusColors = {
316
+ active: chalk.blue,
317
+ reclaimable: chalk.yellow,
318
+ reclaimed: chalk.green,
319
+ protected: chalk.magenta,
320
+ };
321
+ const colorFn = statusColors[account.status] || chalk.white;
322
+ logger.info(`${colorFn(`[${account.status.toUpperCase().padEnd(11)}]`)} ` +
323
+ `${account.pubkey.toBase58().slice(0, 24)}... | ` +
324
+ `${formatSol(account.rentLamports).padEnd(12)} | ` +
325
+ `${account.accountType}`);
326
+ }
327
+ logger.newline();
328
+ }
329
+ catch (error) {
330
+ logger.error(String(error));
331
+ process.exit(1);
332
+ }
333
+ });
334
+ // ==================== OPERATOR COMMAND ====================
335
+ program
336
+ .command('operator')
337
+ .description('Manage multiple operator accounts')
338
+ .argument('<action>', 'Action: add, list, use, remove')
339
+ .argument('[name]', 'Operator name')
340
+ .option('--keypair <path>', 'Path to keypair file')
341
+ .option('--treasury <address>', 'Treasury address')
342
+ .option('--default', 'Set as default operator')
343
+ .action(async (action, name, options) => {
344
+ try {
345
+ const { getAllOperators, addOperator, getOperatorByName, setDefaultOperator, removeOperator, } = await import('./db/operators.js');
346
+ if (action === 'list') {
347
+ const operators = getAllOperators();
348
+ if (operators.length === 0) {
349
+ logger.info('No operators configured.');
350
+ logger.info('Add an operator with: vacuum operator add <name> --keypair <path> --treasury <address>');
351
+ return;
352
+ }
353
+ logger.newline();
354
+ logger.info(`๐Ÿ‘ฅ Operators (${operators.length}):`);
355
+ logger.divider();
356
+ for (const op of operators) {
357
+ const defaultTag = op.is_default ? chalk.green(' [DEFAULT]') : '';
358
+ logger.info(` ${op.name}${defaultTag}`);
359
+ logger.info(` ID: ${op.id}`);
360
+ logger.info(` Treasury: ${op.treasury_address.toBase58()}`);
361
+ logger.info(` Keypair: ${op.keypair_path}`);
362
+ logger.info('');
363
+ }
364
+ }
365
+ else if (action === 'add') {
366
+ if (!name) {
367
+ logger.error('Operator name required');
368
+ process.exit(1);
369
+ }
370
+ if (!options.keypair || !options.treasury) {
371
+ logger.error('Both --keypair and --treasury are required');
372
+ process.exit(1);
373
+ }
374
+ addOperator(name, options.keypair, new PublicKey(options.treasury), options.default);
375
+ logger.success(`Added operator: ${name}`);
376
+ }
377
+ else if (action === 'use') {
378
+ if (!name) {
379
+ logger.error('Operator name required');
380
+ process.exit(1);
381
+ }
382
+ const op = getOperatorByName(name);
383
+ if (!op) {
384
+ logger.error(`Operator not found: ${name}`);
385
+ process.exit(1);
386
+ }
387
+ setDefaultOperator(op.id);
388
+ }
389
+ else if (action === 'remove') {
390
+ if (!name) {
391
+ logger.error('Operator name required');
392
+ process.exit(1);
393
+ }
394
+ const op = getOperatorByName(name);
395
+ if (!op) {
396
+ logger.error(`Operator not found: ${name}`);
397
+ process.exit(1);
398
+ }
399
+ removeOperator(op.id);
400
+ }
401
+ else {
402
+ logger.error(`Unknown action: ${action}`);
403
+ logger.info('Available actions: add, list, use, remove');
404
+ process.exit(1);
405
+ }
406
+ }
407
+ catch (error) {
408
+ logger.error(String(error));
409
+ process.exit(1);
410
+ }
411
+ });
412
+ // ==================== DASHBOARD COMMAND ====================
413
+ program
414
+ .command('dashboard')
415
+ .description('Start the web dashboard server')
416
+ .option('-p, --port <port>', 'Port to run on', '3333')
417
+ .action(async (options) => {
418
+ try {
419
+ process.env.DASHBOARD_PORT = options.port;
420
+ const { startDashboardServer } = await import('./server/index.js');
421
+ startDashboardServer();
422
+ }
423
+ catch (error) {
424
+ logger.error('Failed to start dashboard:', String(error));
425
+ process.exit(1);
426
+ }
427
+ });
428
+ // ==================== BOT COMMAND ====================
429
+ program
430
+ .command('bot')
431
+ .description('Start the Telegram bot for remote control')
432
+ .option('-t, --token <token>', 'Telegram bot token (or set TELEGRAM_BOT_TOKEN env)')
433
+ .option('-c, --chat <chatId>', 'Authorized chat ID (or set TELEGRAM_CHAT_ID env)')
434
+ .action(async (options) => {
435
+ const token = options.token || process.env.TELEGRAM_BOT_TOKEN;
436
+ const chatId = options.chat || process.env.TELEGRAM_CHAT_ID;
437
+ if (!token) {
438
+ logger.error('Telegram bot token required.');
439
+ logger.info('Set TELEGRAM_BOT_TOKEN env or use --token');
440
+ logger.info('');
441
+ logger.info('To create a bot:');
442
+ logger.info(' 1. Message @BotFather on Telegram');
443
+ logger.info(' 2. Send /newbot and follow prompts');
444
+ logger.info(' 3. Copy the token');
445
+ process.exit(1);
446
+ }
447
+ try {
448
+ const { startBot } = await import('./services/telegram.js');
449
+ logger.info('๐Ÿค– Starting Telegram bot...');
450
+ if (chatId) {
451
+ logger.info(`Authorized chat: ${chatId}`);
452
+ }
453
+ else {
454
+ logger.warn('No chat ID set - bot will respond to anyone!');
455
+ }
456
+ await startBot(token, chatId);
457
+ }
458
+ catch (error) {
459
+ logger.error('Failed to start Telegram bot:', String(error));
460
+ process.exit(1);
461
+ }
462
+ });
463
+ // Handle cleanup on exit
464
+ process.on('exit', () => {
465
+ closeDatabase();
466
+ });
467
+ process.on('SIGINT', () => {
468
+ closeDatabase();
469
+ process.exit(0);
470
+ });
471
+ // Parse and run
472
+ program.parse();
473
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,QAAQ,CAAA;AAC1C,OAAO,GAAG,MAAM,KAAK,CAAA;AAErB,6BAA6B;AAC7B,OAAO,EAAE,CAAA;AAET,iBAAiB;AACjB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAC5E,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,yDAAyD,CAAC;KACtE,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,eAAe,EAAE,wBAAwB,CAAC;KACjD,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,EAAE;IACjC,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;QAC/B,WAAW,CAAC,OAAO,CAAC,CAAA;IACtB,CAAC;IACD,yCAAyC;IACzC,YAAY,EAAE,CAAA;AAChB,CAAC,CAAC,CAAA;AAEJ,yDAAyD;AACzD,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,YAAY,EAAE,2CAA2C,CAAC;KACjE,MAAM,CAAC,sBAAsB,EAAE,sCAAsC,CAAC;KACtE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,OAAO,GAAG,GAAG,CAAC,0BAA0B,CAAC,CAAC,KAAK,EAAE,CAAA;IAEvD,IAAI,CAAC;QACH,IAAI,QAAQ,CAAA;QAEZ,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;YACf,QAAQ,GAAG,MAAM,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACzD,CAAC;aAAM,CAAC;YACN,0CAA0C;YAC1C,QAAQ,GAAG,MAAM,OAAO,CAAC,oBAAoB,EAAE,CAAA;QACjD,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,SAAS,QAAQ,CAAC,MAAM,WAAW,CAAC,CAAA;QAEpD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAA;YACtC,MAAM,CAAC,IAAI,CAAC,oBAAoB,KAAK,CAAC,YAAY,EAAE,CAAC,CAAA;YACrD,MAAM,CAAC,IAAI,CAAC,sBAAsB,SAAS,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;QACvE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAC3B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,0DAA0D;AAC1D,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,gCAAgC,CAAC;KAC7C,MAAM,CAAC,wBAAwB,EAAE,0BAA0B,CAAC;KAC5D,MAAM,CAAC,OAAO,EAAE,4BAA4B,CAAC;KAC7C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,OAAO,GAAG,GAAG,CAAC,sBAAsB,CAAC,CAAC,KAAK,EAAE,CAAA;IAEnD,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YAC7C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;YAElD,OAAO,CAAC,IAAI,EAAE,CAAA;YAEd,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,OAAO,CAAC,WAAW,aAAa,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAA;gBAClE,MAAM,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;gBACzC,MAAM,CAAC,IAAI,CAAC,aAAa,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAA;gBACjE,MAAM,CAAC,IAAI,CACT,WAAW,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,2BAA2B,EAAE,CAC/D,CAAA;gBACD,MAAM,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;YAC7C,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,WAAW,aAAa,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAA;YACrE,CAAC;QACH,CAAC;aAAM,CAAC;YACN,qBAAqB;YACrB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,kBAAkB,EAAE,CAAA;YACnD,OAAO,CAAC,OAAO,CAAC,SAAS,OAAO,CAAC,MAAM,uBAAuB,CAAC,CAAA;YAE/D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,qBAAqB,EAAE,CAAA;gBACtD,MAAM,CAAC,OAAO,EAAE,CAAA;gBAChB,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;gBACtC,MAAM,CAAC,IAAI,CAAC,wBAAwB,OAAO,CAAC,aAAa,WAAW,CAAC,CAAA;gBACrE,MAAM,CAAC,IAAI,CAAC,qBAAqB,OAAO,CAAC,iBAAiB,WAAW,CAAC,CAAA;gBACtE,MAAM,CAAC,IAAI,CACT,0BAA0B,SAAS,CAAC,OAAO,CAAC,wBAAwB,CAAC,EAAE,CACxE,CAAA;gBACD,MAAM,CAAC,IAAI,CACT,yBAAyB,SAAS,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,CACtE,CAAA;gBAED,MAAM,CAAC,OAAO,EAAE,CAAA;gBAChB,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;gBACpC,MAAM,CAAC,OAAO,EAAE,CAAA;gBAEhB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI;wBACzB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;wBACvB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;oBAC5B,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ;wBACjE,GAAG,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,CAChE,CAAA;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAC5B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,4DAA4D;AAC5D,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,eAAe,EAAE,mCAAmC,CAAC;KAC5D,MAAM,CAAC,oBAAoB,EAAE,6BAA6B,EAAE,IAAI,CAAC;KACjE,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;KAC/C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,MAAM,CAAA;IACvE,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAE7C,MAAM,OAAO,GAAG,GAAG,CAAC,iCAAiC,CAAC,CAAC,KAAK,EAAE,CAAA;IAE9D,IAAI,CAAC;QACH,iCAAiC;QACjC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,mBAAmB,EAAE,CAAA;QACpD,OAAO,CAAC,IAAI,EAAE,CAAA;QAEd,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;YAC7C,OAAM;QACR,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAA;QAC/C,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,cAAc,CAAC,SAAS,CAAC,CAAA;QAEzD,MAAM,CAAC,OAAO,EAAE,CAAA;QAChB,MAAM,CAAC,IAAI,CACT,GAAG,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,qBAAqB,SAAS,CAAC,MAAM,YAAY,CAClF,CAAA;QACD,MAAM,CAAC,OAAO,EAAE,CAAA;QAEhB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CACT,KAAK,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,OAAO,CAAC,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,CAC9E,CAAA;QACH,CAAC;QAED,MAAM,CAAC,OAAO,EAAE,CAAA;QAChB,MAAM,CAAC,IAAI,CAAC,qBAAqB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;QACpD,MAAM,CAAC,OAAO,EAAE,CAAA;QAEhB,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5B,mDAAmD;YACnD,MAAM,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAA;YACtE,OAAM;QACR,CAAC;QAED,kBAAkB;QAClB,MAAM,cAAc,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE;YAC7D,MAAM;YACN,WAAW;SACZ,CAAC,CAAA;QAEF,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;QAC1D,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CACtC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,eAAe,EACnC,CAAC,CACF,CAAA;QAED,MAAM,CAAC,OAAO,EAAE,CAAA;QAChB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,OAAO,CACZ,2BAA2B,SAAS,CAAC,cAAc,CAAC,SAAS,UAAU,CAAC,MAAM,WAAW,CAC1F,CAAA;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,CACZ,aAAa,SAAS,CAAC,cAAc,CAAC,SAAS,UAAU,CAAC,MAAM,WAAW,CAC5E,CAAA;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC9B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,2DAA2D;AAC3D,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,uBAAuB,EAAE,6BAA6B,EAAE,OAAO,CAAC;KACvE,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAA;YACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACnB,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,YAAY,EAAE,CAAA;QACzB,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,QAAQ,CAAC,YAAY,EAAE,CAAA;QACzB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,4DAA4D;AAC5D,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,uCAAuC,CAAC;KACpD,MAAM,CAAC,oBAAoB,EAAE,gCAAgC,CAAC;KAC9D,MAAM,CAAC,uBAAuB,EAAE,qCAAqC,CAAC;KACtE,MAAM,CAAC,YAAY,EAAE,6BAA6B,CAAC;KACnD,MAAM,CAAC,mBAAmB,EAAE,uBAAuB,EAAE,mBAAmB,CAAC;KACzE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,mBAAmB,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;YAC/D,MAAM,CAAC,OAAO,CAAC,cAAc,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;QAC7C,CAAC;aAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,sBAAsB,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;YACrD,MAAM,CAAC,OAAO,CAAC,uBAAuB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;QACzD,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACxB,MAAM,UAAU,GAAG,oBAAoB,EAAE,CAAA;YACzC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAA;YACvC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,6BAA6B,UAAU,CAAC,MAAM,IAAI,CAAC,CAAA;gBAC/D,MAAM,CAAC,OAAO,EAAE,CAAA;gBAChB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;oBAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;gBAC/D,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;QAC/C,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,2DAA2D;AAC3D,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,GAAG,EAAE;IACX,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;QAC1B,MAAM,CAAC,OAAO,EAAE,CAAA;QAChB,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;QACxC,MAAM,CAAC,OAAO,EAAE,CAAA;QAChB,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;QACjD,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACrE,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;QACjD,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,aAAa,QAAQ,CAAC,CAAA;QAC9D,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,eAAe,OAAO,CAAC,CAAA;QAC/D,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;QACjD,MAAM,CAAC,OAAO,EAAE,CAAA;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,0DAA0D;AAC1D,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,kBAAkB,EAAE,+BAA+B,CAAC;KAC3D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;IAChC,IAAI,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;YAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,CACxC,IAAI,SAAS,CAAC,MAAM,CAAC,EACrB,OAAO,CAAC,EAAE,CACX,CAAA;QAED,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,OAAO,CAAC,iBAAiB,MAAM,EAAE,CAAC,CAAA;YACzC,MAAM,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;YAC7C,MAAM,CAAC,IAAI,CAAC,WAAW,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,yDAAyD;AACzD,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CACL,mBAAmB,EACnB,8DAA8D,CAC/D;KACA,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAA;QAExC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM;YAC7B,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC;YACrD,CAAC,CAAC,QAAQ,CAAA;QAEZ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;YACjC,OAAM;QACR,CAAC;QAED,MAAM,CAAC,OAAO,EAAE,CAAA;QAChB,MAAM,CAAC,IAAI,CAAC,wBAAwB,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAA;QACxD,MAAM,CAAC,OAAO,EAAE,CAAA;QAEhB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,YAAY,GAA0C;gBAC1D,MAAM,EAAE,KAAK,CAAC,IAAI;gBAClB,WAAW,EAAE,KAAK,CAAC,MAAM;gBACzB,SAAS,EAAE,KAAK,CAAC,KAAK;gBACtB,SAAS,EAAE,KAAK,CAAC,OAAO;aACzB,CAAA;YACD,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAA;YAE3D,MAAM,CAAC,IAAI,CACT,GAAG,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG;gBAC3D,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ;gBACjD,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK;gBAClD,GAAG,OAAO,CAAC,WAAW,EAAE,CAC3B,CAAA;QACH,CAAC;QAED,MAAM,CAAC,OAAO,EAAE,CAAA;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,6DAA6D;AAC7D,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,mCAAmC,CAAC;KAChD,QAAQ,CAAC,UAAU,EAAE,gCAAgC,CAAC;KACtD,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;KACnC,MAAM,CAAC,kBAAkB,EAAE,sBAAsB,CAAC;KAClD,MAAM,CAAC,sBAAsB,EAAE,kBAAkB,CAAC;KAClD,MAAM,CAAC,WAAW,EAAE,yBAAyB,CAAC;KAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;IACtC,IAAI,CAAC;QACH,MAAM,EACJ,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,GACf,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;QAErC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,eAAe,EAAE,CAAA;YACnC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;gBACvC,MAAM,CAAC,IAAI,CACT,wFAAwF,CACzF,CAAA;gBACD,OAAM;YACR,CAAC;YAED,MAAM,CAAC,OAAO,EAAE,CAAA;YAChB,MAAM,CAAC,IAAI,CAAC,iBAAiB,SAAS,CAAC,MAAM,IAAI,CAAC,CAAA;YAClD,MAAM,CAAC,OAAO,EAAE,CAAA;YAChB,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;gBAC3B,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;gBACjE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,GAAG,UAAU,EAAE,CAAC,CAAA;gBACxC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;gBAC/B,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;gBAC9D,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,YAAY,EAAE,CAAC,CAAA;gBAC9C,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YACjB,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;gBAC1C,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAA;gBAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,WAAW,CACT,IAAI,EACJ,OAAO,CAAC,OAAO,EACf,IAAI,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAC/B,OAAO,CAAC,OAAO,CAChB,CAAA;YACD,MAAM,CAAC,OAAO,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAA;QAC3C,CAAC;aAAM,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAA;YAClC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,MAAM,CAAC,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAA;gBAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QAC3B,CAAC;aAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,MAAM,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAA;YAClC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,MAAM,CAAC,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAA;gBAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,cAAc,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAA;YACzC,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAA;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,8DAA8D;AAC9D,OAAO;KACJ,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,gCAAgC,CAAC;KAC7C,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,CAAC;KACrD,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC,IAAI,CAAA;QACzC,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;QAClE,oBAAoB,EAAE,CAAA;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,4BAA4B,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,wDAAwD;AACxD,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CACL,qBAAqB,EACrB,oDAAoD,CACrD;KACA,MAAM,CACL,qBAAqB,EACrB,kDAAkD,CACnD;KACA,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;IAE3D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAA;QAC5C,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAA;QACxD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACf,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QAC/B,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAA;QAClD,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAA;QACnD,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAA;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAA;QAC3D,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAA;QAC1C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAA;QAC3C,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAA;QAC7D,CAAC;QACD,MAAM,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA;AAEJ,yBAAyB;AACzB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;IACtB,aAAa,EAAE,CAAA;AACjB,CAAC,CAAC,CAAA;AAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,aAAa,EAAE,CAAA;IACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA;AAEF,gBAAgB;AAChB,OAAO,CAAC,KAAK,EAAE,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { Keypair } from '@solana/web3.js';
2
+ import type { DetectionResult, ReclaimOptions, ReclaimResult, TrackedAccount } from './core/types.js';
3
+ export interface VacuumConfig {
4
+ rpcUrl?: string;
5
+ treasury: string;
6
+ keypairPath?: string;
7
+ keypair?: Keypair;
8
+ dryRun?: boolean;
9
+ logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
10
+ dbPath?: string;
11
+ }
12
+ export declare class VacuumClient {
13
+ constructor(config: VacuumConfig);
14
+ /**
15
+ * Scan for accounts owned by the configured operator
16
+ */
17
+ scan(): Promise<TrackedAccount[]>;
18
+ /**
19
+ * Check which tracked accounts are reclaimable
20
+ * If accounts list is provided, checks those specific accounts.
21
+ * Otherwise checks all tracked accounts in DB.
22
+ */
23
+ check(accounts?: TrackedAccount[]): Promise<DetectionResult[]>;
24
+ /**
25
+ * Execute reclaim on reclaimable accounts
26
+ */
27
+ reclaim(reclaimables: DetectionResult[], options?: ReclaimOptions): Promise<ReclaimResult[]>;
28
+ /**
29
+ * Get summary report
30
+ */
31
+ getReport(): Promise<{
32
+ totalAccounts: number;
33
+ safeToReclaim: number;
34
+ unsafeNeedsReview: number;
35
+ totalReclaimableLamports: number;
36
+ safeReclaimableLamports: number;
37
+ }>;
38
+ }
39
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAa,MAAM,iBAAiB,CAAA;AAKpD,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACb,cAAc,EACf,MAAM,iBAAiB,CAAA;AAIxB,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;IACzD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qBAAa,YAAY;gBACX,MAAM,EAAE,YAAY;IAsBhC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAKvC;;;;OAIG;IACG,KAAK,CAAC,QAAQ,CAAC,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAYpE;;OAEG;IACG,OAAO,CACX,YAAY,EAAE,eAAe,EAAE,EAC/B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,aAAa,EAAE,CAAC;IAI3B;;OAEG;IACG,SAAS;;;;;;;CAGhB"}
package/dist/client.js ADDED
@@ -0,0 +1,66 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import { setConfig } from './config.js';
3
+ import { detector } from './core/detector.js';
4
+ import { monitor } from './core/monitor.js';
5
+ import { reclaimer } from './core/reclaimer.js';
6
+ import { initDatabase } from './db/index.js';
7
+ import { setLogLevel } from './utils/logger.js';
8
+ export class VacuumClient {
9
+ constructor(config) {
10
+ // initialize logging
11
+ setLogLevel(config.logLevel || 'info');
12
+ // Prepare internal config object
13
+ const internalConfig = {};
14
+ if (config.rpcUrl)
15
+ internalConfig.rpcUrl = config.rpcUrl;
16
+ if (config.treasury)
17
+ internalConfig.treasuryAddress = new PublicKey(config.treasury);
18
+ if (config.keypairPath)
19
+ internalConfig.operatorKeypairPath = config.keypairPath;
20
+ if (config.dryRun !== undefined)
21
+ internalConfig.dryRun = config.dryRun;
22
+ if (config.dbPath)
23
+ internalConfig.dbPath = config.dbPath;
24
+ // Update global config singleton
25
+ setConfig(internalConfig);
26
+ // Initialize DB if not already done
27
+ initDatabase();
28
+ }
29
+ /**
30
+ * Scan for accounts owned by the configured operator
31
+ */
32
+ async scan() {
33
+ // Scan operator accounts
34
+ return monitor.scanOperatorAccounts();
35
+ }
36
+ /**
37
+ * Check which tracked accounts are reclaimable
38
+ * If accounts list is provided, checks those specific accounts.
39
+ * Otherwise checks all tracked accounts in DB.
40
+ */
41
+ async check(accounts) {
42
+ if (accounts) {
43
+ const results = [];
44
+ for (const account of accounts) {
45
+ const result = await detector.checkAccount(account.pubkey);
46
+ if (result)
47
+ results.push(result);
48
+ }
49
+ return results;
50
+ }
51
+ return detector.findAllReclaimable();
52
+ }
53
+ /**
54
+ * Execute reclaim on reclaimable accounts
55
+ */
56
+ async reclaim(reclaimables, options) {
57
+ return reclaimer.batchReclaim(reclaimables, options);
58
+ }
59
+ /**
60
+ * Get summary report
61
+ */
62
+ async getReport() {
63
+ return detector.getReclaimableSummary();
64
+ }
65
+ }
66
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAO/C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAY/C,MAAM,OAAO,YAAY;IACvB,YAAY,MAAoB;QAC9B,qBAAqB;QACrB,WAAW,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAA;QAEtC,iCAAiC;QACjC,MAAM,cAAc,GAAQ,EAAE,CAAA;QAE9B,IAAI,MAAM,CAAC,MAAM;YAAE,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;QACxD,IAAI,MAAM,CAAC,QAAQ;YACjB,cAAc,CAAC,eAAe,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACjE,IAAI,MAAM,CAAC,WAAW;YACpB,cAAc,CAAC,mBAAmB,GAAG,MAAM,CAAC,WAAW,CAAA;QACzD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;YAAE,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;QACtE,IAAI,MAAM,CAAC,MAAM;YAAE,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;QAExD,iCAAiC;QACjC,SAAS,CAAC,cAAc,CAAC,CAAA;QAEzB,oCAAoC;QACpC,YAAY,EAAE,CAAA;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,yBAAyB;QACzB,OAAO,OAAO,CAAC,oBAAoB,EAAE,CAAA;IACvC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,QAA2B;QACrC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,OAAO,GAAsB,EAAE,CAAA;YACrC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;gBAC1D,IAAI,MAAM;oBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAClC,CAAC;YACD,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,OAAO,QAAQ,CAAC,kBAAkB,EAAE,CAAA;IACtC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CACX,YAA+B,EAC/B,OAAwB;QAExB,OAAO,SAAS,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QACb,OAAO,QAAQ,CAAC,qBAAqB,EAAE,CAAA;IACzC,CAAC;CACF"}
package/dist/config.d.ts CHANGED
@@ -12,4 +12,6 @@ export interface Config {
12
12
  export declare function loadConfig(): Config;
13
13
  export declare function loadOperatorKeypair(keypairPath: string): Uint8Array;
14
14
  export declare function getConfig(): Config;
15
+ export declare function setConfig(config: Partial<Config>): void;
16
+ export declare function resetConfig(): void;
15
17
  //# sourceMappingURL=config.d.ts.map