#!/usr/bin/env node /** * Test: Copy with target position value (not parent value) * This test verifies that copy amount is calculated based on what the target wallet deposited, * not the parent position's total value. */ import { Connection, PublicKey } from '@solana/web3.js'; import { CONFIG } from './src/config/index.js'; import { logger, setLogLevel } from './src/utils/index.js'; setLogLevel('info'); const TEST_TX = '5SnXmX8T4sytTFu8xeG7RXmui1eK65no8B3eJ3knTtdXqr3PqmDma5CaY9C7NG2oycvNs7KKZ75pPNDXB2T5XYQE'; // Expected values from manual analysis const EXPECTED = { parentPosition: 'Cbgjt5zfXd9QTpneDdADc9cKYwXxXRfe57cyfmBbQM41', targetTokenA: 0.001521, // XAUt0 targetTokenB: 6.00, // USDT targetTotalUsd: 0.001521 * 4965 + 6.00 * 1, // ~13.55 positionNft: 'GUwGkK3PHnGVrLd3fPTphAMxuUFqkad7HKYyyeHzEW7p' }; async function testTargetValueExtraction() { console.log('═══════════════════════════════════════════════════════'); console.log('🧪 Test: Target Position Value Extraction'); console.log(`📍 TX: ${TEST_TX.slice(0, 25)}...`); console.log('═══════════════════════════════════════════════════════\n'); const connection = new Connection(CONFIG.RPC_URL, 'confirmed'); try { // Fetch transaction console.log('1. Fetching transaction...'); const tx = await connection.getTransaction(TEST_TX, { commitment: 'confirmed', maxSupportedTransactionVersion: 0 }); if (!tx) { console.error('❌ Transaction not found'); return false; } console.log('✅ Transaction found\n'); // Extract parent position from memo console.log('2. Extracting parent position...'); let parentPosition = null; const message = tx.transaction.message; const accountKeys = message.staticAccountKeys || message.accountKeys || []; const instructions = message.compiledInstructions || message.instructions || []; const MEMO_PROGRAM_ID = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr'; for (const instruction of instructions) { const programId = accountKeys[instruction.programIdIndex]?.toString(); if (programId === MEMO_PROGRAM_ID) { let memoData = instruction.parsed || ''; if (instruction.data) { try { memoData = Buffer.from(instruction.data, 'base64').toString('utf8'); } catch {} } const match = memoData.match(/referer_position=([A-Za-z0-9]+)/); if (match) parentPosition = match[1]; } } console.log(` Expected: ${EXPECTED.parentPosition}`); console.log(` Got: ${parentPosition}`); console.log(` ${parentPosition === EXPECTED.parentPosition ? '✅ PASS' : '❌ FAIL'}\n`); // Extract position NFT console.log('3. Extracting position NFT...'); let positionNft = null; if (tx.meta?.postTokenBalances) { for (const balance of tx.meta.postTokenBalances) { if (balance.uiTokenAmount?.uiAmount === 1 && balance.uiTokenAmount?.decimals === 0) { positionNft = balance.mint; break; } } } console.log(` Expected: ${EXPECTED.positionNft}`); console.log(` Got: ${positionNft}`); console.log(` ${positionNft === EXPECTED.positionNft ? '✅ PASS' : '❌ FAIL'}\n`); // Extract target position value console.log('4. Extracting target position value...'); const transfers = []; if (tx.meta?.preTokenBalances && tx.meta?.postTokenBalances) { const preBalances = {}; tx.meta.preTokenBalances.forEach(balance => { const key = `${balance.accountIndex}-${balance.mint}`; preBalances[key] = parseFloat(balance.uiTokenAmount?.uiAmountString || 0); }); tx.meta.postTokenBalances.forEach(balance => { const key = `${balance.accountIndex}-${balance.mint}`; const pre = preBalances[key] || 0; const post = parseFloat(balance.uiTokenAmount?.uiAmountString || 0); const diff = pre - post; if (diff > 0.0001) { transfers.push({ mint: balance.mint, uiAmount: diff, decimals: balance.decimals }); } }); } transfers.sort((a, b) => b.uiAmount - a.uiAmount); const tokenA = transfers[0] || {}; const tokenB = transfers[1] || {}; // Known prices const TOKEN_PRICES = { 'AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P': 4965, 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB': 1 }; const tokenAPrice = TOKEN_PRICES[tokenA.mint] || 0; const tokenBPrice = TOKEN_PRICES[tokenB.mint] || 0; const totalUsd = (tokenA.uiAmount || 0) * tokenAPrice + (tokenB.uiAmount || 0) * tokenBPrice; console.log(` Token A: ${tokenA.uiAmount?.toFixed(6)} (expected: ${EXPECTED.targetTokenA})`); console.log(` Token B: ${tokenB.uiAmount?.toFixed(6)} (expected: ${EXPECTED.targetTokenB})`); console.log(` Total USD: $${totalUsd.toFixed(2)} (expected: $${EXPECTED.targetTotalUsd.toFixed(2)})`); const tolerance = 0.001; const tokenAOk = Math.abs((tokenA.uiAmount || 0) - EXPECTED.targetTokenA) < tolerance; const tokenBOk = Math.abs((tokenB.uiAmount || 0) - EXPECTED.targetTokenB) < tolerance; const totalOk = Math.abs(totalUsd - EXPECTED.targetTotalUsd) < 1; console.log(` ${tokenAOk && tokenBOk && totalOk ? '✅ PASS' : '❌ FAIL'}\n`); // Calculate copy amount console.log('5. Calculating copy amount...'); const copyMultiplier = CONFIG.COPY_MULTIPLIER; const maxUsd = CONFIG.MAX_USD_VALUE; const copyUsd = Math.min(totalUsd * copyMultiplier, maxUsd); console.log(` Target Value: $${totalUsd.toFixed(2)}`); console.log(` Multiplier: ${copyMultiplier}x`); console.log(` Calculated: $${(totalUsd * copyMultiplier).toFixed(2)}`); console.log(` Max Limit: $${maxUsd}`); console.log(` ✅ Final Copy Amount: $${copyUsd.toFixed(2)}`); console.log(`\n IMPORTANT: This is based on TARGET position ($${totalUsd.toFixed(2)}),`); console.log(` NOT parent position (which might be much larger)!\n`); console.log('═══════════════════════════════════════════════════════'); console.log('✅ Test completed successfully!'); console.log('═══════════════════════════════════════════════════════'); return true; } catch (error) { console.error('❌ Test failed:', error); return false; } } testTargetValueExtraction();