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:
@@ -2941,10 +2941,7 @@ export const swapGmxTokensImpl = async (
|
|||||||
throw new Error(`To token ${toTicker} has zero address - token not found or invalid`);
|
throw new Error(`To token ${toTicker} has zero address - token not found or invalid`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the from token amount with proper decimals
|
// Get actual wallet balance first to avoid precision issues
|
||||||
const fromTokenAmount = BigInt(Math.floor(amount * Math.pow(10, fromTokenData.decimals)));
|
|
||||||
|
|
||||||
// Get actual wallet balance for the from token to verify we have enough
|
|
||||||
let walletBalance: bigint;
|
let walletBalance: bigint;
|
||||||
if (fromTokenData.isNative) {
|
if (fromTokenData.isNative) {
|
||||||
// For native tokens (ETH), get balance directly
|
// For native tokens (ETH), get balance directly
|
||||||
@@ -2966,11 +2963,31 @@ export const swapGmxTokensImpl = async (
|
|||||||
walletBalance = balanceResult.data.token.balance.returnValues[0];
|
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:', {
|
console.log('💰 Wallet balance check:', {
|
||||||
fromTicker,
|
fromTicker,
|
||||||
fromTokenAddress: fromTokenData.address,
|
fromTokenAddress: fromTokenData.address,
|
||||||
requestedAmount: fromTokenAmount.toString(),
|
requestedAmount: requestedAmountBigInt.toString(),
|
||||||
walletBalance: walletBalance.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
|
hasEnough: walletBalance >= fromTokenAmount
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3006,7 +3023,13 @@ export const swapGmxTokensImpl = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify balance hasn't changed (someone else might have used the wallet)
|
// 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 latestBalanceFormatted = Number(latestWalletBalance) / Math.pow(10, fromTokenData.decimals);
|
||||||
const originalBalanceFormatted = Number(walletBalance) / Math.pow(10, fromTokenData.decimals);
|
const originalBalanceFormatted = Number(walletBalance) / Math.pow(10, fromTokenData.decimals);
|
||||||
throw new Error(
|
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
|
// Verify we still have enough after re-check
|
||||||
if (latestWalletBalance < fromTokenAmount) {
|
if (latestWalletBalance < finalSwapAmount) {
|
||||||
const latestBalanceFormatted = Number(latestWalletBalance) / Math.pow(10, fromTokenData.decimals);
|
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(
|
throw new Error(
|
||||||
`Insufficient ${fromTicker} balance after verification! Wallet has ${latestBalanceFormatted.toFixed(6)} ${fromTicker} ` +
|
`Insufficient ${fromTicker} balance after verification! Wallet has ${latestBalanceFormatted.toFixed(6)} ${fromTicker} ` +
|
||||||
`but trying to swap ${requestedFormatted.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
|
// Check and handle token allowance for SyntheticsRouter contract
|
||||||
await approveTokenForContract(
|
await approveTokenForContract(
|
||||||
sdk,
|
sdk,
|
||||||
fromTicker,
|
fromTicker,
|
||||||
fromTokenData,
|
fromTokenData,
|
||||||
fromTokenAmount,
|
verifiedFromTokenAmount,
|
||||||
"SyntheticsRouter"
|
"SyntheticsRouter"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -3042,7 +3076,7 @@ export const swapGmxTokensImpl = async (
|
|||||||
sdk,
|
sdk,
|
||||||
fromTicker,
|
fromTicker,
|
||||||
fromTokenData,
|
fromTokenData,
|
||||||
fromTokenAmount,
|
verifiedFromTokenAmount,
|
||||||
"ExchangeRouter"
|
"ExchangeRouter"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -3060,7 +3094,7 @@ export const swapGmxTokensImpl = async (
|
|||||||
// Try using the SDK's built-in swap method first
|
// Try using the SDK's built-in swap method first
|
||||||
try {
|
try {
|
||||||
const swapParams = {
|
const swapParams = {
|
||||||
fromAmount: fromTokenAmount,
|
fromAmount: verifiedFromTokenAmount,
|
||||||
fromTokenAddress: fromTokenData.address,
|
fromTokenAddress: fromTokenData.address,
|
||||||
toTokenAddress: toTokenData.address,
|
toTokenAddress: toTokenData.address,
|
||||||
allowedSlippageBps: allowedSlippageBps,
|
allowedSlippageBps: allowedSlippageBps,
|
||||||
@@ -3117,7 +3151,7 @@ export const swapGmxTokensImpl = async (
|
|||||||
|
|
||||||
await createSwapOrderTxn(sdk, {
|
await createSwapOrderTxn(sdk, {
|
||||||
fromTokenAddress: fromTokenData.address,
|
fromTokenAddress: fromTokenData.address,
|
||||||
fromTokenAmount: fromTokenAmount,
|
fromTokenAmount: verifiedFromTokenAmount,
|
||||||
toTokenAddress: toTokenData.address,
|
toTokenAddress: toTokenData.address,
|
||||||
swapPath: swapPath,
|
swapPath: swapPath,
|
||||||
orderType: OrderType.MarketSwap,
|
orderType: OrderType.MarketSwap,
|
||||||
|
|||||||
Reference in New Issue
Block a user