1
0
Эх сурвалжийг харах

swap: 增加 20% 缓冲并检查当前持仓,足够则跳过 swap

Co-authored-by: Cursor <cursoragent@cursor.com>
lushdog@outlook.com 1 сар өмнө
parent
commit
2e3e90f8f4
2 өөрчлөгдсөн 75 нэмэгдсэн , 27 устгасан
  1. 38 13
      src/core/sniper.js
  2. 37 14
      test-copy.js

+ 38 - 13
src/core/sniper.js

@@ -94,30 +94,55 @@ export class SniperEngine {
     const tokenA = calculation.tokenA;
     const tokenB = calculation.tokenB;
 
-    logger.success(`Calculation complete (using valueUsd for swap):`);
+    logger.success(`Calculation complete (using valueUsd for swap, +20% buffer):`);
     logger.info(`  Token A: ${tokenA.symbol || ''} ${formatUsd(tokenA.valueUsd)}`);
     logger.info(`  Token B: ${tokenB.symbol || ''} ${formatUsd(tokenB.valueUsd)}`);
     logger.info(`  Estimated Total Value: ${formatUsd(calculation.estimatedValue)}`);
 
-    // Step 2: Swap by USD value (ExactIn) - no amount, use valueUsd only
+    const BUFFER_PCT = 1.2;
+    const prices = await this.swapper.getTokenPrices([tokenA.address, tokenB.address]);
+
+    const needSwapUsd = async (token, valueUsd) => {
+      const requiredWithBuffer = valueUsd * BUFFER_PCT;
+      const balance = await this.swapper.getTokenBalance(token.address);
+      const price = prices[token.address]?.price ?? 0;
+      const currentValueUsd = balance * price;
+      if (currentValueUsd >= requiredWithBuffer) {
+        return { skip: true, currentValueUsd, requiredWithBuffer };
+      }
+      const swapUsd = requiredWithBuffer - currentValueUsd;
+      return { skip: false, swapUsd, currentValueUsd, requiredWithBuffer };
+    };
+
+    // Step 2: Token A — 检查持仓,不足则多换 20% 富裕
     const valueA = parseFloat(tokenA.valueUsd) || 0;
     if (valueA > 0) {
-      logger.info(`Swapping $${valueA} USDC -> Token A (${tokenA.symbol || ''})...`);
-      const success = await this.swapper.swapIfNeeded(tokenA.address, valueA);
-      if (!success) {
-        logger.error('Failed to acquire Token A');
-        return false;
+      const planA = await needSwapUsd(tokenA, valueA);
+      if (planA.skip) {
+        logger.success(`Token A (${tokenA.symbol || ''}): 已有 ${formatUsd(planA.currentValueUsd)} >= 需要 ${formatUsd(planA.requiredWithBuffer)},跳过 swap`);
+      } else {
+        logger.info(`Token A (${tokenA.symbol || ''}): 已有 ${formatUsd(planA.currentValueUsd)},需 ${formatUsd(planA.requiredWithBuffer)}(含 20% 缓冲),swap $${planA.swapUsd.toFixed(2)}`);
+        const success = await this.swapper.swapIfNeeded(tokenA.address, planA.swapUsd);
+        if (!success) {
+          logger.error('Failed to acquire Token A');
+          return false;
+        }
       }
     }
 
-    // Step 3: Swap by USD value (ExactIn)
+    // Step 3: Token B — 检查持仓,不足则多换 20% 富裕
     const valueB = parseFloat(tokenB.valueUsd) || 0;
     if (valueB > 0) {
-      logger.info(`Swapping $${valueB} USDC -> Token B (${tokenB.symbol || ''})...`);
-      const success = await this.swapper.swapIfNeeded(tokenB.address, valueB);
-      if (!success) {
-        logger.error('Failed to acquire Token B');
-        return false;
+      const planB = await needSwapUsd(tokenB, valueB);
+      if (planB.skip) {
+        logger.success(`Token B (${tokenB.symbol || ''}): 已有 ${formatUsd(planB.currentValueUsd)} >= 需要 ${formatUsd(planB.requiredWithBuffer)},跳过 swap`);
+      } else {
+        logger.info(`Token B (${tokenB.symbol || ''}): 已有 ${formatUsd(planB.currentValueUsd)},需 ${formatUsd(planB.requiredWithBuffer)}(含 20% 缓冲),swap $${planB.swapUsd.toFixed(2)}`);
+        const success = await this.swapper.swapIfNeeded(tokenB.address, planB.swapUsd);
+        if (!success) {
+          logger.error('Failed to acquire Token B');
+          return false;
+        }
       }
     }
 

+ 37 - 14
test-copy.js

@@ -121,31 +121,54 @@ async function testCopy() {
   console.log(`    Token B valueUsd field: ${calculation.tokenB?.valueUsd}`);
   console.log(`    If amount ≈ valueUsd, then amount is USD value, not token quantity!`);
 
-  // Step 4: Swap by USD value (ExactIn) - use valueUsd only, no amount
-  console.log('\nStep 4: Swapping by valueUsd (ExactIn)...');
+  // Step 4: Swap by valueUsd + 20% buffer, 仅当当前持仓不足时才 swap
+  console.log('\nStep 4: Check balance & swap (valueUsd + 20% buffer)...');
   const swapper = new JupiterSwapper();
   const tokenA = calculation.tokenA;
   const tokenB = calculation.tokenB;
+  const BUFFER_PCT = 1.2;
+  const prices = await swapper.getTokenPrices([tokenA.address, tokenB.address]);
+
+  const needSwapUsd = async (token, valueUsd) => {
+    const requiredWithBuffer = valueUsd * BUFFER_PCT;
+    const balance = await swapper.getTokenBalance(token.address);
+    const price = prices[token.address]?.price ?? 0;
+    const currentValueUsd = balance * price;
+    if (currentValueUsd >= requiredWithBuffer) {
+      return { skip: true, currentValueUsd, requiredWithBuffer };
+    }
+    return { skip: false, swapUsd: requiredWithBuffer - currentValueUsd, currentValueUsd, requiredWithBuffer };
+  };
 
   const valueA = parseFloat(tokenA.valueUsd) || 0;
   if (valueA > 0) {
-    console.log(`\n  Token A (${tokenA.symbol}): swap $${valueA} USDC -> ${tokenA.symbol}`);
-    console.log('    Ready to swap. Continue? (Ctrl+C to cancel)');
-    await new Promise(resolve => setTimeout(resolve, 3000));
-    const success = await swapper.swapIfNeeded(tokenA.address, valueA);
-    if (!success) {
-      console.error('❌ Failed to acquire Token A');
-      process.exit(1);
+    const planA = await needSwapUsd(tokenA, valueA);
+    if (planA.skip) {
+      console.log(`  Token A (${tokenA.symbol}): 已有 $${planA.currentValueUsd.toFixed(2)} >= 需要 $${planA.requiredWithBuffer.toFixed(2)},跳过 swap`);
+    } else {
+      console.log(`  Token A (${tokenA.symbol}): 已有 $${planA.currentValueUsd.toFixed(2)},需 $${planA.requiredWithBuffer.toFixed(2)}(含 20% 缓冲),swap $${planA.swapUsd.toFixed(2)}`);
+      console.log('    Ready to swap. Continue? (Ctrl+C to cancel)');
+      await new Promise(resolve => setTimeout(resolve, 3000));
+      const success = await swapper.swapIfNeeded(tokenA.address, planA.swapUsd);
+      if (!success) {
+        console.error('❌ Failed to acquire Token A');
+        process.exit(1);
+      }
     }
   }
 
   const valueB = parseFloat(tokenB.valueUsd) || 0;
   if (valueB > 0) {
-    console.log(`\n  Token B (${tokenB.symbol}): swap $${valueB} USDC -> ${tokenB.symbol}`);
-    const success = await swapper.swapIfNeeded(tokenB.address, valueB);
-    if (!success) {
-      console.error('❌ Failed to acquire Token B');
-      process.exit(1);
+    const planB = await needSwapUsd(tokenB, valueB);
+    if (planB.skip) {
+      console.log(`  Token B (${tokenB.symbol}): 已有 $${planB.currentValueUsd.toFixed(2)} >= 需要 $${planB.requiredWithBuffer.toFixed(2)},跳过 swap`);
+    } else {
+      console.log(`  Token B (${tokenB.symbol}): 已有 $${planB.currentValueUsd.toFixed(2)},需 $${planB.requiredWithBuffer.toFixed(2)}(含 20% 缓冲),swap $${planB.swapUsd.toFixed(2)}`);
+      const success = await swapper.swapIfNeeded(tokenB.address, planB.swapUsd);
+      if (!success) {
+        console.error('❌ Failed to acquire Token B');
+        process.exit(1);
+      }
     }
   }