Refactor swapGmxTokensImpl to improve wallet balance verification and precision handling. Introduce tolerance checks for requested amounts against wallet balances to prevent errors during swaps. Update logging to provide detailed information on final amounts used in transactions, ensuring better user feedback and error handling.

This commit is contained in:
2025-12-29 20:40:47 +07:00
parent bdf62f6c9e
commit 263c1b0592

View File

@@ -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,