diff --git a/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts b/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts index 2de0952e..62e968fc 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts @@ -2941,10 +2941,7 @@ export const swapGmxTokensImpl = async ( throw new Error(`To token ${toTicker} has zero address - token not found or invalid`); } - // Calculate the from token amount with proper decimals - const fromTokenAmount = BigInt(Math.floor(amount * Math.pow(10, fromTokenData.decimals))); - - // Get actual wallet balance for the from token to verify we have enough + // Get actual wallet balance first to avoid precision issues let walletBalance: bigint; if (fromTokenData.isNative) { // For native tokens (ETH), get balance directly @@ -2966,11 +2963,31 @@ export const swapGmxTokensImpl = async ( walletBalance = balanceResult.data.token.balance.returnValues[0]; } + // Calculate the from token amount with proper decimals + const requestedAmountBigInt = BigInt(Math.floor(amount * Math.pow(10, fromTokenData.decimals))); + + // Convert to numbers for comparison (to handle precision issues) + const walletBalanceNumber = Number(walletBalance) / Math.pow(10, fromTokenData.decimals); + const requestedAmountNumber = amount; + + // If requested amount is very close to balance (within 0.000001 tolerance), use actual balance + // This handles floating point precision issues when swapping entire balance + const tolerance = 0.000001; + const difference = Math.abs(walletBalanceNumber - requestedAmountNumber); + + // Use actual balance if amounts are very close (likely trying to swap entire balance) + const fromTokenAmount = difference <= tolerance ? walletBalance : requestedAmountBigInt; + console.log('💰 Wallet balance check:', { fromTicker, fromTokenAddress: fromTokenData.address, - requestedAmount: fromTokenAmount.toString(), + requestedAmount: requestedAmountBigInt.toString(), walletBalance: walletBalance.toString(), + requestedAmountFormatted: requestedAmountNumber.toFixed(6), + walletBalanceFormatted: walletBalanceNumber.toFixed(6), + difference: difference.toFixed(6), + usingActualBalance: difference <= tolerance, + finalAmount: fromTokenAmount.toString(), hasEnough: walletBalance >= fromTokenAmount }); @@ -3006,7 +3023,13 @@ export const swapGmxTokensImpl = async ( } // Verify balance hasn't changed (someone else might have used the wallet) - if (latestWalletBalance !== walletBalance) { + // Allow small tolerance for potential rounding differences + const balanceDifference = latestWalletBalance > walletBalance + ? latestWalletBalance - walletBalance + : walletBalance - latestWalletBalance; + const maxAllowedDifference = BigInt(Math.floor(Math.pow(10, fromTokenData.decimals - 6))); // 0.000001 in token units + + if (balanceDifference > maxAllowedDifference) { const latestBalanceFormatted = Number(latestWalletBalance) / Math.pow(10, fromTokenData.decimals); const originalBalanceFormatted = Number(walletBalance) / Math.pow(10, fromTokenData.decimals); throw new Error( @@ -3016,10 +3039,15 @@ export const swapGmxTokensImpl = async ( ); } + // Re-calculate final amount using latest balance if we're using actual balance + const latestBalanceNumber = Number(latestWalletBalance) / Math.pow(10, fromTokenData.decimals); + const latestDifference = Math.abs(latestBalanceNumber - requestedAmountNumber); + const finalSwapAmount = latestDifference <= tolerance ? latestWalletBalance : fromTokenAmount; + // Verify we still have enough after re-check - if (latestWalletBalance < fromTokenAmount) { + if (latestWalletBalance < finalSwapAmount) { const latestBalanceFormatted = Number(latestWalletBalance) / Math.pow(10, fromTokenData.decimals); - const requestedFormatted = Number(fromTokenAmount) / Math.pow(10, fromTokenData.decimals); + const requestedFormatted = Number(finalSwapAmount) / Math.pow(10, fromTokenData.decimals); throw new Error( `Insufficient ${fromTicker} balance after verification! Wallet has ${latestBalanceFormatted.toFixed(6)} ${fromTicker} ` + `but trying to swap ${requestedFormatted.toFixed(6)} ${fromTicker}. ` + @@ -3027,14 +3055,20 @@ export const swapGmxTokensImpl = async ( ); } - console.log('✅ Token balance verified - wallet has sufficient funds and balance matches'); + // Update fromTokenAmount to use the final verified amount + const verifiedFromTokenAmount = finalSwapAmount; + + console.log('✅ Token balance verified - wallet has sufficient funds and balance matches', { + finalSwapAmount: verifiedFromTokenAmount.toString(), + finalSwapAmountFormatted: (Number(verifiedFromTokenAmount) / Math.pow(10, fromTokenData.decimals)).toFixed(6) + }); // Check and handle token allowance for SyntheticsRouter contract await approveTokenForContract( sdk, fromTicker, fromTokenData, - fromTokenAmount, + verifiedFromTokenAmount, "SyntheticsRouter" ); @@ -3042,7 +3076,7 @@ export const swapGmxTokensImpl = async ( sdk, fromTicker, fromTokenData, - fromTokenAmount, + verifiedFromTokenAmount, "ExchangeRouter" ); @@ -3060,7 +3094,7 @@ export const swapGmxTokensImpl = async ( // Try using the SDK's built-in swap method first try { const swapParams = { - fromAmount: fromTokenAmount, + fromAmount: verifiedFromTokenAmount, fromTokenAddress: fromTokenData.address, toTokenAddress: toTokenData.address, allowedSlippageBps: allowedSlippageBps, @@ -3117,7 +3151,7 @@ export const swapGmxTokensImpl = async ( await createSwapOrderTxn(sdk, { fromTokenAddress: fromTokenData.address, - fromTokenAmount: fromTokenAmount, + fromTokenAmount: verifiedFromTokenAmount, toTokenAddress: toTokenData.address, swapPath: swapPath, orderType: OrderType.MarketSwap,