|
|
@@ -101,52 +101,47 @@ export class SniperEngine {
|
|
|
|
|
|
const BUFFER_PCT = 1.2;
|
|
|
|
|
|
- const needSwapUsd = async (token, valueUsd) => {
|
|
|
- const requiredWithBuffer = valueUsd * BUFFER_PCT;
|
|
|
+ const checkAndSwap = async (label, token, valueUsd) => {
|
|
|
const balance = await this.swapper.getTokenBalance(token.address);
|
|
|
- const price = parseFloat(token.priceUsd) || 0;
|
|
|
- if (price <= 0) {
|
|
|
- logger.warn(`Token ${token.symbol || token.address} priceUsd is ${token.priceUsd}, cannot calculate balance value, will swap full amount`);
|
|
|
- return { skip: false, swapUsd: requiredWithBuffer, currentValueUsd: 0, requiredWithBuffer };
|
|
|
+ const requiredAmount = parseFloat(token.amount) || 0;
|
|
|
+ const bufferedAmount = requiredAmount * BUFFER_PCT;
|
|
|
+ const bufferedValueUsd = valueUsd * BUFFER_PCT;
|
|
|
+
|
|
|
+ logger.info(` ${label} (${token.symbol || token.address}): 余额=${balance}, 需要=${requiredAmount}, 含缓冲=${bufferedAmount.toFixed(6)}, valueUsd=${formatUsd(valueUsd)}, priceUsd=${token.priceUsd}`);
|
|
|
+
|
|
|
+ // 直接用代币数量比较余额
|
|
|
+ if (requiredAmount > 0 && balance >= bufferedAmount) {
|
|
|
+ logger.success(` ${label}: 余额充足 ${balance} >= ${bufferedAmount.toFixed(6)},跳过 swap`);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 余额不足,计算需要 swap 的 USD 金额
|
|
|
+ let swapUsd = bufferedValueUsd;
|
|
|
+ if (requiredAmount > 0 && balance > 0) {
|
|
|
+ // 按比例计算缺口的 USD
|
|
|
+ const ratio = balance / bufferedAmount;
|
|
|
+ swapUsd = bufferedValueUsd * (1 - ratio);
|
|
|
}
|
|
|
- const currentValueUsd = balance * price;
|
|
|
- if (currentValueUsd >= requiredWithBuffer) {
|
|
|
- return { skip: true, currentValueUsd, requiredWithBuffer };
|
|
|
+
|
|
|
+ logger.info(` ${label}: 余额不足,需 swap ${formatUsd(swapUsd)}`);
|
|
|
+ const success = await this.swapper.swapIfNeeded(token.address, swapUsd);
|
|
|
+ if (!success) {
|
|
|
+ logger.error(`Failed to acquire ${label}`);
|
|
|
+ return false;
|
|
|
}
|
|
|
- const swapUsd = requiredWithBuffer - currentValueUsd;
|
|
|
- return { skip: false, swapUsd, currentValueUsd, requiredWithBuffer };
|
|
|
+ return true;
|
|
|
};
|
|
|
|
|
|
- // Step 2: Token A — 检查持仓,不足则多换 20% 富裕
|
|
|
+ // Step 2: Token A — 检查持仓,不足则 swap
|
|
|
const valueA = parseFloat(tokenA.valueUsd) || 0;
|
|
|
if (valueA > 0) {
|
|
|
- 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;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (!await checkAndSwap('Token A', tokenA, valueA)) return false;
|
|
|
}
|
|
|
|
|
|
- // Step 3: Token B — 检查持仓,不足则多换 20% 富裕
|
|
|
+ // Step 3: Token B — 检查持仓,不足则 swap
|
|
|
const valueB = parseFloat(tokenB.valueUsd) || 0;
|
|
|
if (valueB > 0) {
|
|
|
- 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;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (!await checkAndSwap('Token B', tokenB, valueB)) return false;
|
|
|
}
|
|
|
|
|
|
// Step 4: Execute copy of PARENT position
|