| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- #!/usr/bin/env node
- /**
- * Test: Calculate copy amount from target position (not parent)
- * Analyzes a specific transaction to get the target's position value
- * Transaction: 5SnXmX8T4sytTFu8xeG7RXmui1eK65no8B3eJ3knTtdXqr3PqmDma5CaY9C7NG2oycvNs7KKZ75pPNDXB2T5XYQE
- */
- import { Connection, PublicKey } from '@solana/web3.js';
- import { CONFIG } from './src/config/index.js';
- import { logger, setLogLevel } from './src/utils/index.js';
- setLogLevel('debug');
- const TX_SIGNATURE = '5SnXmX8T4sytTFu8xeG7RXmui1eK65no8B3eJ3knTtdXqr3PqmDma5CaY9C7NG2oycvNs7KKZ75pPNDXB2T5XYQE';
- async function analyzeTransaction() {
- console.log('═══════════════════════════════════════════');
- console.log('🧪 Analyzing Target Position Transaction');
- console.log(`📍 TX: ${TX_SIGNATURE.slice(0, 20)}...`);
- console.log('═══════════════════════════════════════════\n');
- const connection = new Connection(CONFIG.RPC_URL, 'confirmed');
- try {
- // Fetch transaction details
- console.log('Fetching transaction from Solana...');
- const tx = await connection.getTransaction(TX_SIGNATURE, {
- commitment: 'confirmed',
- maxSupportedTransactionVersion: 0
- });
- if (!tx) {
- console.error('❌ Transaction not found');
- return;
- }
- console.log('✅ Transaction found!\n');
- // Extract token transfers from pre/post token balances
- console.log('Step 1: Extracting token transfers from balance changes...');
- const transfers = [];
-
- // Compare pre and post token balances to find what was transferred
- if (tx.meta && tx.meta.preTokenBalances && tx.meta.postTokenBalances) {
- // Create a map of pre balances
- const preBalances = {};
- tx.meta.preTokenBalances.forEach(balance => {
- const key = `${balance.accountIndex}-${balance.mint}`;
- preBalances[key] = parseFloat(balance.uiTokenAmount?.uiAmountString || 0);
- });
-
- // Compare with post balances
- tx.meta.postTokenBalances.forEach(balance => {
- const key = `${balance.accountIndex}-${balance.mint}`;
- const preAmount = preBalances[key] || 0;
- const postAmount = parseFloat(balance.uiTokenAmount?.uiAmountString || 0);
- const diff = postAmount - preAmount;
-
- // If balance decreased significantly (transferred out), record it
- if (diff < -0.0001) {
- transfers.push({
- mint: balance.mint,
- uiAmount: Math.abs(diff),
- decimals: balance.decimals,
- accountIndex: balance.accountIndex,
- owner: balance.owner
- });
- }
- });
- }
-
- // Also try inner instructions as fallback
- if (transfers.length === 0 && tx.meta && tx.meta.innerInstructions) {
- for (const innerInst of tx.meta.innerInstructions) {
- for (const inst of innerInst.instructions) {
- if (inst.parsed?.type === 'transferChecked') {
- const info = inst.parsed.info;
- transfers.push({
- mint: info.mint,
- amount: info.tokenAmount?.amount,
- uiAmount: parseFloat(info.tokenAmount?.uiAmount || 0),
- decimals: info.tokenAmount?.decimals,
- destination: info.destination
- });
- }
- }
- }
- }
- console.log(`Found ${transfers.length} token transfers:\n`);
- transfers.forEach((t, i) => {
- console.log(` Transfer ${i + 1}:`);
- console.log(` Mint: ${t.mint}`);
- console.log(` Amount: ${t.uiAmount} (decimals: ${t.decimals})`);
- console.log(` Raw: ${t.amount}`);
- console.log(` Destination: ${t.destination?.slice(0, 16)}...`);
- });
- // Get token prices to calculate USD value
- console.log('\nStep 2: Fetching token prices...');
- const mints = [...new Set(transfers.map(t => t.mint))];
- console.log(`Token mints: ${mints.join(', ')}`);
- // Try to get prices from Jupiter price API
- let totalUsdValue = 0;
- try {
- const axios = (await import('axios')).default;
- const response = await axios.get(
- `https://api.jup.ag/price/v2?ids=${mints.join(',')}`,
- { timeout: 10000 }
- );
-
- const prices = response.data.data || {};
-
- console.log('\nToken prices:');
- transfers.forEach(t => {
- const price = prices[t.mint]?.price || 0;
- const value = t.uiAmount * price;
- totalUsdValue += value;
-
- console.log(` ${t.mint.slice(0, 8)}...: $${price} × ${t.uiAmount} = $${value.toFixed(2)}`);
- });
-
- console.log(`\n💰 Total Position Value: $${totalUsdValue.toFixed(2)}`);
- } catch (error) {
- console.log('⚠️ Could not fetch prices, showing raw amounts only');
- }
- // Calculate what we should copy
- console.log('\n═══════════════════════════════════════════');
- console.log('Step 3: Calculating copy amount');
- console.log('═══════════════════════════════════════════');
-
- const copyMultiplier = CONFIG.COPY_MULTIPLIER;
- const maxUsdValue = CONFIG.MAX_USD_VALUE;
-
- if (totalUsdValue > 0) {
- const copyUsdValue = Math.min(totalUsdValue * copyMultiplier, maxUsdValue);
-
- console.log(`Target Position Value: $${totalUsdValue.toFixed(2)}`);
- console.log(`Copy Multiplier: ${copyMultiplier}x`);
- console.log(`Calculated Copy: $${(totalUsdValue * copyMultiplier).toFixed(2)}`);
- console.log(`Max Allowed: $${maxUsdValue}`);
- console.log(`\n✅ Final Copy Amount: $${copyUsdValue.toFixed(2)}`);
-
- // Calculate token amounts proportionally
- console.log('\nToken amounts to acquire:');
- transfers.forEach(t => {
- const ratio = (t.uiAmount * copyMultiplier) / totalUsdValue * copyUsdValue;
- const withBuffer = ratio * 1.1; // 10% buffer
- console.log(` ${t.mint.slice(0, 8)}...: ${ratio.toFixed(6)} (with 10% buffer: ${withBuffer.toFixed(6)})`);
- });
- }
- // Extract position NFT and parent info from memo
- console.log('\n═══════════════════════════════════════════');
- console.log('Step 4: Extracting position info from memo');
- console.log('═══════════════════════════════════════════');
-
- const message = tx.transaction.message;
- const accountKeys = message.staticAccountKeys || message.accountKeys || [];
- const instructions = message.compiledInstructions || message.instructions || [];
-
- let parentPosition = null;
- let positionNftMint = null;
-
- // Look for memo instruction
- const MEMO_PROGRAM_ID = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
-
- for (const instruction of instructions) {
- const programId = accountKeys[instruction.programIdIndex]?.toString();
-
- if (programId === MEMO_PROGRAM_ID) {
- let memoData;
-
- if (instruction.data) {
- try {
- memoData = Buffer.from(instruction.data, 'base64').toString('utf8');
- } catch {
- memoData = instruction.data;
- }
- }
-
- if (instruction.parsed) {
- memoData = instruction.parsed;
- }
-
- if (memoData) {
- console.log(`Memo found: ${memoData}`);
-
- // Extract parent position
- const match = memoData.match(/referer_position=([A-Za-z0-9]+)/);
- if (match) {
- parentPosition = match[1];
- console.log(`✅ Parent Position: ${parentPosition}`);
- }
- }
- }
-
- // Look for Byreal program to extract position NFT
- const BYREAL_PROGRAM_ID = 'REALQqNEomY6cQGZJUGwywTBD2UmDT32rZcNnfxQ5N2';
- if (programId === BYREAL_PROGRAM_ID) {
- console.log('Found Byreal program instruction');
-
- // Position NFT is usually minted in this transaction
- // Look for it in postTokenBalances
- if (tx.meta && tx.meta.postTokenBalances) {
- for (const balance of tx.meta.postTokenBalances) {
- if (balance.uiTokenAmount?.uiAmount === 1 && balance.uiTokenAmount?.decimals === 0) {
- positionNftMint = balance.mint;
- console.log(`✅ Position NFT Mint: ${positionNftMint}`);
- break;
- }
- }
- }
- }
- }
- // Also check log messages
- if (tx.meta && tx.meta.logMessages) {
- for (const log of tx.meta.logMessages) {
- const match = log.match(/referer_position=([A-Za-z0-9]+)/);
- if (match && !parentPosition) {
- parentPosition = match[1];
- console.log(`✅ Parent Position (from logs): ${parentPosition}`);
- }
- }
- }
- console.log('\n═══════════════════════════════════════════');
- console.log('Summary');
- console.log('═══════════════════════════════════════════');
- console.log(`Transaction: ${TX_SIGNATURE}`);
- console.log(`Parent Position: ${parentPosition || 'Not found'}`);
- console.log(`Position NFT: ${positionNftMint || 'Not found'}`);
- console.log(`Target Position Value: $${totalUsdValue.toFixed(2)}`);
- console.log(`Recommended Copy: $${Math.min(totalUsdValue * copyMultiplier, maxUsdValue).toFixed(2)}`);
- console.log('\nNote: Copy amount is based on TARGET position value, not parent!');
- console.log('═══════════════════════════════════════════');
- } catch (error) {
- console.error('Error analyzing transaction:', error);
- process.exit(1);
- }
- }
- analyzeTransaction();
|