|
|
@@ -60,55 +60,68 @@ export class SniperEngine {
|
|
|
logger.info(`Copying PARENT position with ${CONFIG.COPY_MULTIPLIER}x multiplier`);
|
|
|
logger.info(`Parent Target: ${formatUsd(targetUsdValue)} → Copy: ${formatUsd(copyUsdValue)}`);
|
|
|
|
|
|
- const mintA = poolInfo.mintA?.address;
|
|
|
- const mintB = poolInfo.mintB?.address;
|
|
|
-
|
|
|
- if (!mintA || !mintB) {
|
|
|
- logger.error('Pool info missing token addresses');
|
|
|
+ // Step 1: Calculate exact token amounts needed using the calculate API
|
|
|
+ logger.info('Calculating exact token amounts from parent position...');
|
|
|
+ const calculation = await ByrealAPI.calculatePosition(
|
|
|
+ parentPositionAddress,
|
|
|
+ copyUsdValue,
|
|
|
+ parentDetail.nftMint
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!calculation) {
|
|
|
+ logger.error('Failed to calculate token amounts, aborting copy');
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // Get token prices and prepare swap
|
|
|
- const tokenPrices = await this.swapper.getTokenPrices([mintA, mintB]);
|
|
|
- const priceA = tokenPrices[mintA]?.price || 1;
|
|
|
- const priceB = tokenPrices[mintB]?.price || 1;
|
|
|
-
|
|
|
- const halfUsd = copyUsdValue / 2;
|
|
|
- const amountA = halfUsd / priceA;
|
|
|
- const amountB = halfUsd / priceB;
|
|
|
+ const tokenA = calculation.tokenA;
|
|
|
+ const tokenB = calculation.tokenB;
|
|
|
|
|
|
- logger.info(`Estimated token needs: ${amountA.toFixed(4)} TokenA, ${amountB.toFixed(4)} TokenB`);
|
|
|
+ logger.success(`Calculation complete:`);
|
|
|
+ logger.info(` Token A: ${tokenA.amount} ${tokenA.symbol || ''} (${formatUsd(tokenA.valueUsd)})`);
|
|
|
+ logger.info(` Token B: ${tokenB.amount} ${tokenB.symbol || ''} (${formatUsd(tokenB.valueUsd)})`);
|
|
|
+ logger.info(` Estimated Total Value: ${formatUsd(calculation.estimatedValue)}`);
|
|
|
|
|
|
- // Check and swap tokens
|
|
|
- const tokenABalance = await this.swapper.getTokenBalance(mintA);
|
|
|
- if (tokenABalance < amountA * 0.95) {
|
|
|
+ // Step 2: Check and swap Token A
|
|
|
+ const tokenABalance = await this.swapper.getTokenBalance(tokenA.address);
|
|
|
+ const requiredAmountA = parseFloat(tokenA.amount);
|
|
|
+
|
|
|
+ if (tokenABalance < requiredAmountA * 0.95) {
|
|
|
+ logger.info(`Token A balance insufficient: ${tokenABalance.toFixed(4)} < ${requiredAmountA.toFixed(4)}`);
|
|
|
const success = await this.swapper.swapIfNeeded(
|
|
|
- 'So11111111111111111111111111111111111111112',
|
|
|
- mintA,
|
|
|
- amountA,
|
|
|
- poolInfo.mintA?.decimals || 6
|
|
|
+ 'So11111111111111111111111111111111111111112', // Use SOL as source
|
|
|
+ tokenA.address,
|
|
|
+ requiredAmountA,
|
|
|
+ tokenA.decimals
|
|
|
);
|
|
|
if (!success) {
|
|
|
logger.error('Failed to acquire sufficient Token A');
|
|
|
return false;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ logger.success(`Token A balance sufficient: ${tokenABalance.toFixed(4)} >= ${requiredAmountA.toFixed(4)}`);
|
|
|
}
|
|
|
|
|
|
- const tokenBBalance = await this.swapper.getTokenBalance(mintB);
|
|
|
- if (tokenBBalance < amountB * 0.95) {
|
|
|
+ // Step 3: Check and swap Token B
|
|
|
+ const tokenBBalance = await this.swapper.getTokenBalance(tokenB.address);
|
|
|
+ const requiredAmountB = parseFloat(tokenB.amount);
|
|
|
+
|
|
|
+ if (tokenBBalance < requiredAmountB * 0.95) {
|
|
|
+ logger.info(`Token B balance insufficient: ${tokenBBalance.toFixed(4)} < ${requiredAmountB.toFixed(4)}`);
|
|
|
const success = await this.swapper.swapIfNeeded(
|
|
|
- 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
|
- mintB,
|
|
|
- amountB,
|
|
|
- poolInfo.mintB?.decimals || 6
|
|
|
+ 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // Use USDC as source
|
|
|
+ tokenB.address,
|
|
|
+ requiredAmountB,
|
|
|
+ tokenB.decimals
|
|
|
);
|
|
|
if (!success) {
|
|
|
logger.error('Failed to acquire sufficient Token B');
|
|
|
return false;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ logger.success(`Token B balance sufficient: ${tokenBBalance.toFixed(4)} >= ${requiredAmountB.toFixed(4)}`);
|
|
|
}
|
|
|
|
|
|
- // Execute copy of PARENT position
|
|
|
+ // Step 4: Execute copy of PARENT position
|
|
|
const success = await ByrealAPI.copyPosition(
|
|
|
parentDetail.nftMint,
|
|
|
parentPositionAddress,
|
|
|
@@ -120,7 +133,8 @@ export class SniperEngine {
|
|
|
poolAddress: parentDetail.poolAddress,
|
|
|
targetUsdValue,
|
|
|
copiedAt: new Date().toISOString(),
|
|
|
- targetPositionAddress: targetPositionAddress, // Store which target position triggered this copy
|
|
|
+ targetPositionAddress: targetPositionAddress,
|
|
|
+ calculation: calculation, // Store calculation details
|
|
|
});
|
|
|
// Map target's position to the parent position we copied
|
|
|
this.targetToParentMap.set(targetPositionAddress, parentPositionAddress);
|