UNPKG

jito-distributor-sdk

Version:

TypeScript SDK for JITO Merkle Distributor with production-ready versioning and double-hashing support

214 lines (179 loc) • 7.41 kB
import { config } from 'dotenv'; import { Connection, PublicKey, Keypair } from '@solana/web3.js'; import { AnchorProvider, Wallet } from '@coral-xyz/anchor'; import bs58 from 'bs58'; import { MerkleDistributor } from '../src/index'; // Load environment variables config(); export interface QueryDistributionsParams { rpcEndpoint?: string; mint: string; maxVersion?: number; checkVersions?: number[]; // Specific versions to check showDetails?: boolean; // Show detailed info for each distributor } async function queryDistributions(params: QueryDistributionsParams) { console.log('šŸ” Querying Distributions\n'); const { rpcEndpoint = 'https://api.mainnet-beta.solana.com', maxVersion = 100, checkVersions = [], showDetails = false } = params; console.log('šŸ“‹ Query Configuration:'); console.log(`RPC Endpoint: ${rpcEndpoint}`); console.log(`Token Mint: ${params.mint}`); console.log(`Max Version Check: ${maxVersion}`); console.log(`Show Details: ${showDetails}\n`); // Setup connection (no wallet needed for queries) const connection = new Connection(rpcEndpoint, 'confirmed'); // Create a dummy wallet for SDK initialization (not needed for queries) const dummyKeypair = Keypair.generate(); const dummyWallet = new Wallet(dummyKeypair); const provider = new AnchorProvider(connection, dummyWallet, { commitment: 'confirmed' }); // Initialize SDK const sdk = new MerkleDistributor(provider); const mint = new PublicKey(params.mint); try { // Get comprehensive overview console.log('šŸ“Š Getting Distribution Overview...'); const overview = await sdk.getDistributionOverview(mint, maxVersion); console.log('\nšŸŽÆ Distribution Overview:'); console.log(` Mint: ${overview.mint.toString()}`); console.log(` Total Distributors: ${overview.totalDistributors}`); console.log(` Used Versions: [${overview.usedVersions.join(', ')}]`); console.log(` Next Available Version: ${overview.nextAvailableVersion}`); console.log(` Total Claimed: ${overview.totalClaimed} base units`); console.log(` Total Unclaimed: ${overview.totalUnclaimed} base units`); if (overview.totalDistributors === 0) { console.log('\n✨ No distributors found for this mint!'); console.log(`šŸ’” You can create the first distributor using version 0`); return; } // Show individual distributors console.log('\nšŸ“‹ Individual Distributors:'); for (const [version, info] of overview.distributors) { console.log(`\n šŸ“¦ Version ${version}:`); console.log(` PDA: ${info.pda.toString()}`); console.log(` Admin: ${info.account.admin.toString()}`); console.log(` Max Claim: ${info.account.maxTotalClaim.toString()} base units`); console.log(` Claimed: ${info.claimedAmount} base units`); console.log(` Remaining: ${info.remainingAmount} base units`); console.log(` Clawback Receiver: ${info.account.clawbackReceiver.toString()}`); if (showDetails) { console.log(` Start Vesting: ${new Date(Number(info.account.startTs.toString()) * 1000).toLocaleString()}`); console.log(` End Vesting: ${new Date(Number(info.account.endTs.toString()) * 1000).toLocaleString()}`); console.log(` Clawback Start: ${new Date(Number(info.account.clawbackStartTs.toString()) * 1000).toLocaleString()}`); console.log(` Max Nodes: ${info.account.maxNumNodes.toString()}`); console.log(` Merkle Root: ${Buffer.from(info.account.root).toString('hex')}`); } } // Check specific versions if requested if (checkVersions.length > 0) { console.log('\nšŸ” Checking Specific Versions:'); const versionResults = await sdk.batchCheckVersions(mint, checkVersions.map(v => BigInt(v))); for (const [version, available] of versionResults) { const status = available ? 'āœ… Available' : 'āŒ Taken'; console.log(` Version ${version}: ${status}`); } } // Show next few available versions console.log('\nšŸ”® Next Available Versions:'); let nextVersion = overview.nextAvailableVersion; for (let i = 0; i < 5; i++) { console.log(` ${nextVersion + BigInt(i)}: Available`); } console.log('\nšŸ’” Usage Tips:'); console.log(' • Use the next available version for new distributions'); console.log(' • Check remaining amounts to see if funds are available'); console.log(' • Monitor claimed amounts to track distribution progress'); } catch (error) { console.error('\nāŒ Error querying distributions:', error); if (error instanceof Error) { if (error.message.includes('could not find account')) { console.log('šŸ’” This might mean no distributors exist for this mint yet'); } else if (error.message.includes('Invalid public key')) { console.log('šŸ’” Check that the mint address is valid'); } } throw error; } } // CLI interface when run directly if (require.main === module) { const args = process.argv.slice(2); if (args.includes('--help') || args.includes('-h')) { console.log(` Usage: npx ts-node query-distributions.ts [options] Options: --mint <address> Token mint address (required) --max-version <number> Maximum version to check (default: 100) --check-version <number> Check specific version (can be used multiple times) --details Show detailed information for each distributor --rpc <endpoint> Custom RPC endpoint Examples: # Query all USDC distributors npx ts-node query-distributions.ts \\ --mint EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v # Check specific versions with details npx ts-node query-distributions.ts \\ --mint EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \\ --check-version 0 --check-version 5 --check-version 10 \\ --details # Quick check with limited scope npx ts-node query-distributions.ts \\ --mint EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \\ --max-version 20 `); process.exit(0); } // Parse CLI arguments const parseCliArgs = (): QueryDistributionsParams => { const params: QueryDistributionsParams = { mint: '', checkVersions: [] }; for (let i = 0; i < args.length; i++) { const arg = args[i]; const next = args[i + 1]; switch (arg) { case '--mint': params.mint = next; i++; break; case '--max-version': params.maxVersion = parseInt(next); i++; break; case '--check-version': params.checkVersions!.push(parseInt(next)); i++; break; case '--details': params.showDetails = true; break; case '--rpc': params.rpcEndpoint = next; i++; break; } } return params; }; const params = parseCliArgs(); if (!params.mint) { console.error('Error: --mint is required'); console.error('Use --help for usage information'); process.exit(1); } queryDistributions(params) .then(() => { console.log('\nāœ… Query completed successfully'); process.exit(0); }) .catch((error) => { console.error('Query failed:', error); process.exit(1); }); } export { queryDistributions };