diff --git a/src/Managing.Web3Proxy/src/generated/gmxsdk/modules/orders/orders.ts b/src/Managing.Web3Proxy/src/generated/gmxsdk/modules/orders/orders.ts index d7882857..77e2a677 100644 --- a/src/Managing.Web3Proxy/src/generated/gmxsdk/modules/orders/orders.ts +++ b/src/Managing.Web3Proxy/src/generated/gmxsdk/modules/orders/orders.ts @@ -1,23 +1,28 @@ -import { Address } from "viem"; +import {Address} from "viem"; -import { getWrappedToken } from "../../configs/tokens.js"; -import { MarketFilterLongShortItemData } from "../../modules/trades/trades.js"; -import { MarketInfo, MarketsInfoData } from "../../types/markets.js"; -import { OrdersData, OrdersInfoData, OrderType, PositionOrderInfo } from "../../types/orders.js"; -import { SidecarLimitOrderEntryValid, SidecarSlTpOrderEntryValid } from "../../types/sidecarOrders.js"; -import { TokenData, TokensData } from "../../types/tokens.js"; -import { DecreasePositionAmounts, IncreasePositionAmounts, SwapAmounts } from "../../types/trade.js"; -import { getByKey } from "../../utils/objects.js"; -import { getOrderInfo, isOrderForPositionByData, isVisibleOrder } from "../../utils/orders.js"; +import {getWrappedToken} from "../../configs/tokens.js"; +import {MarketFilterLongShortItemData} from "../../modules/trades/trades.js"; +import {MarketInfo, MarketsInfoData} from "../../types/markets.js"; +import {OrdersData, OrdersInfoData, OrderType, PositionOrderInfo} from "../../types/orders.js"; +import {SidecarLimitOrderEntryValid, SidecarSlTpOrderEntryValid} from "../../types/sidecarOrders.js"; +import {TokenData, TokensData} from "../../types/tokens.js"; +import {DecreasePositionAmounts, IncreasePositionAmounts, SwapAmounts} from "../../types/trade.js"; +import {getByKey} from "../../utils/objects.js"; +import {getOrderInfo, isOrderForPositionByData, isVisibleOrder} from "../../utils/orders.js"; -import { createDecreaseOrderTxn } from "./transactions/createDecreaseOrderTxn.js"; -import { createIncreaseOrderTxn } from "./transactions/createIncreaseOrderTxn.js"; -import { buildGetOrdersMulticall, getExecutionFeeAmountForEntry, matchByMarket, parseGetOrdersResponse } from "./utils.js"; -import { Module } from "../base.js"; -import { PositionIncreaseParams, SwapParams, increaseOrderHelper, swap } from "./helpers.js"; -import { cancelOrdersTxn } from "./transactions/cancelOrdersTxn.js"; -import { createSwapOrderTxn } from "./transactions/createSwapOrderTxn.js"; -import { createWrapOrUnwrapTxn, WrapOrUnwrapParams } from "./transactions/createWrapOrUnwrapTxn.js"; +import {createDecreaseOrderTxn} from "./transactions/createDecreaseOrderTxn.js"; +import {createIncreaseOrderTxn} from "./transactions/createIncreaseOrderTxn.js"; +import { + buildGetOrdersMulticall, + getExecutionFeeAmountForEntry, + matchByMarket, + parseGetOrdersResponse +} from "./utils.js"; +import {Module} from "../base.js"; +import {increaseOrderHelper, PositionIncreaseParams, swap, SwapParams} from "./helpers.js"; +import {cancelOrdersTxn} from "./transactions/cancelOrdersTxn.js"; +import {createSwapOrderTxn} from "./transactions/createSwapOrderTxn.js"; +import {createWrapOrUnwrapTxn, WrapOrUnwrapParams} from "./transactions/createWrapOrUnwrapTxn.js"; export class Orders extends Module { async getOrders({ @@ -245,7 +250,7 @@ export class Orders extends Module { referralCode: referralCodeForTxn, indexToken: marketInfo.indexToken, tokensData, - skipSimulation: skipSimulation || isLimit, + skipSimulation: true, }, createDecreaseOrderParams: createSltpEntries?.map((entry, i) => { return { @@ -262,7 +267,7 @@ export class Orders extends Module { executionFee: getExecutionFeeAmountForEntry(this.sdk, entry, gasLimits, tokensData, gasPrice) ?? 0n, tokensData, txnType: entry.txnType!, - skipSimulation: isLimit, + skipSimulation: true, autoCancel: i < autoCancelOrdersLimit, }; }), diff --git a/src/Managing.Web3Proxy/src/generated/gmxsdk/utils/callContract.ts b/src/Managing.Web3Proxy/src/generated/gmxsdk/utils/callContract.ts index bdd66b5c..96656aa6 100644 --- a/src/Managing.Web3Proxy/src/generated/gmxsdk/utils/callContract.ts +++ b/src/Managing.Web3Proxy/src/generated/gmxsdk/utils/callContract.ts @@ -4,11 +4,11 @@ import {getChainName, getPrivyClient} from '../../../plugins/custom/privy.js'; import type {GmxSdk} from "../index.js"; import {bigMath} from "./bigmath.js"; import { - GAS_PRICE_BUFFER_MAP, - GAS_PRICE_PREMIUM_MAP, - getViemChain, - MAX_FEE_PER_GAS_MAP, - MAX_PRIORITY_FEE_PER_GAS_MAP + GAS_PRICE_BUFFER_MAP, + GAS_PRICE_PREMIUM_MAP, + getViemChain, + MAX_FEE_PER_GAS_MAP, + MAX_PRIORITY_FEE_PER_GAS_MAP } from "../configs/chains.js"; import {BASIS_POINTS_DIVISOR_BIGINT} from "../configs/factors.js"; @@ -214,12 +214,12 @@ export async function callContract( console.log('Address', sdk.config.account) console.log('Method', method) console.log('Params', params) - + const response = await privy.walletApi.ethereum.sendTransaction(param as any); - + return response.hash; } catch (error) { - console.error("Transaction failed:", error); + console.error("Transaction failed:", error); throw error; } } diff --git a/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts b/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts index 0b62b334..f572a518 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/gmx.ts @@ -17,14 +17,14 @@ import {PositionIncreaseParams, SwapParams} from '../../generated/gmxsdk/modules import { basisPointsToFloat, bigintToNumber, + calculateDisplayDecimals, + formatUsd, numberToBigint, PRECISION_DECIMALS } from '../../generated/gmxsdk/utils/numbers.js'; import {DecreasePositionSwapType, OrderType, PositionOrderInfo} from '../../generated/gmxsdk/types/orders.js'; import {DecreasePositionAmounts} from '../../generated/gmxsdk/types/trade.js'; import {decodeReferralCode, encodeReferralCode} from '../../generated/gmxsdk/utils/referrals.js'; -import {formatUsd} from '../../generated/gmxsdk/utils/numbers.js'; -import {calculateDisplayDecimals} from '../../generated/gmxsdk/utils/numbers.js'; import {handleError} from '../../utils/errorHandler.js'; import {Abi, formatEther, parseEther, zeroHash} from 'viem'; import {CLAIMABLE_FUNDING_AMOUNT} from '../../generated/gmxsdk/configs/dataStore.js'; @@ -114,8 +114,12 @@ export async function checkGasFeeBalance( const estimatedGasFeeEth = Number(formatEther(estimatedGasFee)); const estimatedGasFeeUsd = estimatedGasFeeEth * ethPrice; - // Check if gas fee exceeds maximum allowed (1 USDC) - const hasSufficientBalance = estimatedGasFeeUsd <= MAX_GAS_FEE_USD; + // Check if: + // 1. Wallet has enough ETH balance to cover gas + // 2. Gas fee is under the maximum allowed USD threshold + const hasEnoughEth = ethBalance >= estimatedGasFee; + const isUnderMaxFee = estimatedGasFeeUsd <= MAX_GAS_FEE_USD; + const hasSufficientBalance = hasEnoughEth && isUnderMaxFee; console.log(`⛽ Gas fee check:`, { ethBalance: ethBalanceFormatted, @@ -123,16 +127,27 @@ export async function checkGasFeeBalance( estimatedGasFeeUsd: estimatedGasFeeUsd.toFixed(2), ethPrice: ethPrice.toFixed(2), maxAllowedUsd: MAX_GAS_FEE_USD, + hasEnoughEth, + isUnderMaxFee, hasSufficientBalance }); + // Generate appropriate error message + let errorMessage: string | undefined; + if (!hasSufficientBalance) { + if (!hasEnoughEth) { + errorMessage = `Insufficient ETH balance for gas: need ${estimatedGasFeeEth.toFixed(6)} ETH (~$${estimatedGasFeeUsd.toFixed(2)}), but only have ${ethBalanceFormatted} ETH. Please add more ETH to your wallet.`; + } else if (!isUnderMaxFee) { + errorMessage = `Gas fee too high: $${estimatedGasFeeUsd.toFixed(2)} exceeds maximum of $${MAX_GAS_FEE_USD}. Please wait for lower gas fees.`; + } + } + return { hasSufficientBalance, ethBalance: ethBalanceFormatted, estimatedGasFeeUsd, ethPrice, - errorMessage: hasSufficientBalance ? undefined : - `Gas fee too high: $${estimatedGasFeeUsd.toFixed(2)} exceeds maximum of $${MAX_GAS_FEE_USD}. Please wait for lower gas fees or add more ETH.` + errorMessage }; } catch (error) { @@ -505,12 +520,20 @@ async function approveTokenForContract( try { const contractAddress = getContract(sdk.chainId, contractName as ContractName); + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:523',message:'Allowance check start',data:{ticker:fromTicker,contractName,contractAddress,tokenAddress:fromTokenData.address,requiredAmount:fromTokenAmount.toString(),account:sdk.account},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{}); + // #endregion + const currentAllowance = await getTokenAllowance( sdk.account, fromTokenData.address, contractAddress ); + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:530',message:'Allowance check result',data:{ticker:fromTicker,contractName,currentAllowance:currentAllowance.toString(),requiredAmount:fromTokenAmount.toString(),isSufficient:currentAllowance>=fromTokenAmount},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{}); + // #endregion + console.log(`Current allowance for ${fromTicker}:`, currentAllowance); console.log(`Required amount:`, fromTokenAmount); @@ -519,20 +542,88 @@ async function approveTokenForContract( // Approve maximum amount (2^256 - 1) to avoid future approval transactions const maxApprovalAmount = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:537',message:'Approval transaction start',data:{ticker:fromTicker,contractName,contractAddress,approvalAmount:maxApprovalAmount.toString()},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{}); + // #endregion + const approvalHash = await approveContractImpl( sdk.account, fromTokenData.address, contractAddress, sdk.chainId, - maxApprovalAmount + maxApprovalAmount, + true // waitForConfirmation = true (already default, but being explicit) ); + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:545',message:'Approval transaction hash received',data:{ticker:fromTicker,contractName,approvalHash},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{}); + // #endregion + console.log(`✅ Token approval successful! Hash: ${approvalHash}`); console.log(`📝 Approved maximum amount ${fromTicker} for ${contractName}`); + console.log(`🔍 DEBUG: Contract ${contractName} address: ${contractAddress}`); + console.log(`🔍 DEBUG: Token ${fromTicker} address: ${fromTokenData.address}`); + console.log(`🔍 DEBUG: Account: ${sdk.account}`); + + // Verify the approval transaction was actually mined by checking the receipt + try { + const receipt = await sdk.publicClient.getTransactionReceipt({ hash: approvalHash as `0x${string}` }); + console.log(`✅ Approval transaction confirmed in block ${receipt.blockNumber}`); + console.log(`🔍 DEBUG: Approval transaction status: ${receipt.status === 'success' ? 'success' : 'failed'}`); + + if (receipt.status !== 'success') { + throw new Error(`Approval transaction failed: ${approvalHash}`); + } + } catch (receiptError) { + console.warn(`⚠️ Could not verify approval transaction receipt: ${receiptError}`); + // Continue anyway as approveContractImpl should have already waited + } + + // Wait additional time for state to propagate across RPC nodes + console.log(`⏳ Waiting 5 seconds for state to propagate across RPC nodes...`); + await new Promise(resolve => setTimeout(resolve, 5000)); + + // Verify allowance multiple times to ensure state has propagated + let postApprovalAllowance = await getTokenAllowance( + sdk.account, + fromTokenData.address, + contractAddress + ); + + console.log(`🔍 DEBUG: Post-approval allowance (first read): ${postApprovalAllowance.toString()}`); + + // If still insufficient, wait more and retry with fresh RPC call + if (postApprovalAllowance < fromTokenAmount) { + console.log(`⏳ Allowance still insufficient, waiting 5 more seconds and retrying...`); + await new Promise(resolve => setTimeout(resolve, 5000)); + postApprovalAllowance = await getTokenAllowance( + sdk.account, + fromTokenData.address, + contractAddress + ); + console.log(`🔍 DEBUG: Post-approval allowance (second read): ${postApprovalAllowance.toString()}`); + } + + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:575',message:'Post-approval allowance check',data:{ticker:fromTicker,contractName,postApprovalAllowance:postApprovalAllowance.toString(),requiredAmount:fromTokenAmount.toString(),isSufficient:postApprovalAllowance>=fromTokenAmount},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'B'})}).catch(()=>{}); + // #endregion + + console.log(`🔍 DEBUG: Final post-approval allowance: ${postApprovalAllowance.toString()}`); + console.log(`🔍 DEBUG: Required amount: ${fromTokenAmount.toString()}`); + console.log(`🔍 DEBUG: Is sufficient: ${postApprovalAllowance >= fromTokenAmount}`); + + if (postApprovalAllowance < fromTokenAmount) { + console.error(`❌ CRITICAL: Approval failed! Allowance ${postApprovalAllowance.toString()} is less than required ${fromTokenAmount.toString()}`); + throw new Error(`Token approval failed: allowance ${postApprovalAllowance.toString()} is less than required ${fromTokenAmount.toString()}`); + } } else { console.log(`✅ Sufficient allowance already exists for ${fromTicker}`); } } catch (allowanceError) { + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:550',message:'Allowance approval error',data:{ticker:fromTicker,contractName,error:allowanceError instanceof Error ? allowanceError.message : 'Unknown error'},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'E'})}).catch(()=>{}); + // #endregion console.warn('Could not check or approve token allowance:', allowanceError); throw new Error(`Failed to handle token allowance: ${allowanceError instanceof Error ? allowanceError.message : 'Unknown error'}`); } @@ -736,8 +827,58 @@ export const openGmxPositionImpl = async ( console.log(`No price provided, using current market price: ${currentPrice}`); } - // Calculate the collateral amount in USDC (quantity * price) - const collateralAmount = BigInt(Math.floor((quantity || 0) * currentPrice * 1e6)); // USDC has 6 decimals + // Calculate the collateral amount in USDC + // quantity represents position size in BTC + // With leverage, collateral = (position size in USD) / leverage + const positionSizeUsd = (quantity || 0) * currentPrice; + const collateralAmountUsd = positionSizeUsd / (leverage || 1); + const collateralAmount = BigInt(Math.floor(collateralAmountUsd * 1e6)); // USDC has 6 decimals + + console.log('💰 Collateral calculation:', { + quantity, + currentPrice, + leverage, + positionSizeUsd, + collateralAmountUsd, + collateralAmountRaw: collateralAmountUsd * 1e6, + collateralAmount: collateralAmount.toString(), + collateralAmountUSDC: Number(collateralAmount) / 1e6 + }); + + // Check USDC balance before proceeding + // Use SDK's executeMulticall to get balance (more reliable) + const balanceResult = await sdk.executeMulticall({ + token: { + contractAddress: collateralToken.address, + abiId: "ERC20", + calls: { + balanceOf: { + methodName: "balanceOf", + params: [sdk.account] + } + } + } + }); + const usdcBalance = balanceResult.data.token.balanceOf.returnValues[0] as bigint; + + console.log('💵 USDC Balance check:', { + walletAddress: sdk.account, + usdcBalance: usdcBalance.toString(), + usdcBalanceFormatted: Number(usdcBalance) / 1e6, + requiredAmount: collateralAmount.toString(), + requiredAmountFormatted: Number(collateralAmount) / 1e6, + hasSufficientBalance: usdcBalance >= collateralAmount + }); + + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:835',message:'USDC balance check',data:{usdcBalance:usdcBalance.toString(),requiredAmount:collateralAmount.toString(),hasSufficientBalance:usdcBalance>=collateralAmount,quantity,currentPrice},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'F'})}).catch(()=>{}); + // #endregion + + if (usdcBalance < collateralAmount) { + const errorMsg = `Insufficient USDC balance: need ${Number(collateralAmount) / 1e6} USDC, but only have ${Number(usdcBalance) / 1e6} USDC`; + console.error(`❌ ${errorMsg}`); + throw new Error(errorMsg); + } // Note: Wallet initialization should be done separately before opening positions // This reduces position opening time and allows for better error handling @@ -801,6 +942,54 @@ export const openGmxPositionImpl = async ( console.log('✅ Token allowances verified, proceeding with position opening...'); + // #region agent log + const exchangeRouterAddress = getContract(sdk.chainId, "ExchangeRouter"); + const orderVaultAddress = getContract(sdk.chainId, "OrderVault"); + const syntheticsRouterAddress = getContract(sdk.chainId, "SyntheticsRouter"); + + console.log(`🔍 DEBUG: ExchangeRouter address: ${exchangeRouterAddress}`); + console.log(`🔍 DEBUG: OrderVault address: ${orderVaultAddress}`); + console.log(`🔍 DEBUG: SyntheticsRouter address: ${syntheticsRouterAddress}`); + console.log(`🔍 DEBUG: USDC token address: ${collateralToken.address}`); + console.log(`🔍 DEBUG: Required collateral amount: ${collateralAmount.toString()}`); + + // Force a fresh state read by waiting and checking multiple times + console.log(`⏳ Waiting 3 seconds for state to propagate...`); + await new Promise(resolve => setTimeout(resolve, 3000)); + + // Check allowance using getTokenAllowance (which uses multicall, but we'll verify with multiple reads) + console.log(`🔍 Reading ExchangeRouter allowance...`); + const finalExchangeRouterAllowance = await getTokenAllowance(sdk.account, collateralToken.address, exchangeRouterAddress); + + console.log(`🔍 Reading OrderVault allowance...`); + const finalOrderVaultAllowance = await getTokenAllowance(sdk.account, collateralToken.address, orderVaultAddress); + + console.log(`🔍 Reading SyntheticsRouter allowance...`); + const finalSyntheticsRouterAllowance = await getTokenAllowance(sdk.account, collateralToken.address, syntheticsRouterAddress); + + // Double-check ExchangeRouter with a second read to catch any caching issues + await new Promise(resolve => setTimeout(resolve, 1000)); + const secondExchangeRouterAllowance = await getTokenAllowance(sdk.account, collateralToken.address, exchangeRouterAddress); + console.log(`🔍 Second ExchangeRouter allowance read: ${secondExchangeRouterAllowance.toString()}`); + if (finalExchangeRouterAllowance !== secondExchangeRouterAllowance) { + console.warn(`⚠️ Allowance values differ between reads! First: ${finalExchangeRouterAllowance.toString()}, Second: ${secondExchangeRouterAllowance.toString()}`); + } + + console.log(`🔍 DEBUG: ExchangeRouter allowance (direct read): ${finalExchangeRouterAllowance.toString()}`); + console.log(`🔍 DEBUG: OrderVault allowance (direct read): ${finalOrderVaultAllowance.toString()}`); + console.log(`🔍 DEBUG: SyntheticsRouter allowance (direct read): ${finalSyntheticsRouterAllowance.toString()}`); + console.log(`🔍 DEBUG: ExchangeRouter sufficient: ${finalExchangeRouterAllowance >= collateralAmount}`); + console.log(`🔍 DEBUG: OrderVault sufficient: ${finalOrderVaultAllowance >= collateralAmount}`); + + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:850',message:'Pre-order allowance verification (direct read)',data:{exchangeRouterAddress,orderVaultAddress,syntheticsRouterAddress,exchangeRouterAllowance:finalExchangeRouterAllowance.toString(),orderVaultAllowance:finalOrderVaultAllowance.toString(),syntheticsRouterAllowance:finalSyntheticsRouterAllowance.toString(),requiredAmount:collateralAmount.toString()},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'C'})}).catch(()=>{}); + // #endregion + + // Double-check ExchangeRouter allowance is sufficient before proceeding + if (finalExchangeRouterAllowance < collateralAmount) { + console.error(`❌ CRITICAL: ExchangeRouter allowance ${finalExchangeRouterAllowance.toString()} is insufficient for required ${collateralAmount.toString()}`); + throw new Error(`Insufficient ExchangeRouter allowance: ${finalExchangeRouterAllowance.toString()} < ${collateralAmount.toString()}`); + } + // Check gas fees before opening position console.log('⛽ Checking gas fees before opening position...'); const estimatedGasFee = await estimatePositionGasFee(sdk); @@ -814,11 +1003,35 @@ export const openGmxPositionImpl = async ( console.log('🚀 Executing position order...'); + // Final allowance check RIGHT before transaction execution + // Also check the current block number to ensure we're reading from the latest state + const currentBlock = await sdk.publicClient.getBlockNumber(); + console.log(`🔍 DEBUG: Current block number: ${currentBlock.toString()}`); + + const finalCheckAllowance = await getTokenAllowance(sdk.account, collateralToken.address, exchangeRouterAddress); + console.log(`🔍 DEBUG: Final allowance check RIGHT before order execution: ${finalCheckAllowance.toString()}`); + console.log(`🔍 DEBUG: Required amount: ${collateralAmount.toString()}`); + console.log(`🔍 DEBUG: Is sufficient: ${finalCheckAllowance >= collateralAmount}`); + + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:850',message:'Final allowance check before execution',data:{blockNumber:currentBlock.toString(),finalAllowance:finalCheckAllowance.toString(),requiredAmount:collateralAmount.toString(),isSufficient:finalCheckAllowance>=collateralAmount},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'E'})}).catch(()=>{}); + // #endregion + + if (finalCheckAllowance < collateralAmount) { + console.error(`❌ CRITICAL: ExchangeRouter allowance ${finalCheckAllowance.toString()} is insufficient RIGHT before execution!`); + throw new Error(`Insufficient ExchangeRouter allowance at execution time: ${finalCheckAllowance.toString()} < ${collateralAmount.toString()}`); + } + if (direction === TradeDirection.Long) { await sdk.orders.long(params); } else { await sdk.orders.short(params); } + + // #region agent log + fetch('http://127.0.0.1:7242/ingest/556ee8d6-75a9-41e6-9311-6e6215b38a77',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'gmx.ts:837',message:'Order execution completed',data:{direction},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'D'})}).catch(()=>{}); + // #endregion + console.log('✅ Position order executed successfully'); return ""; diff --git a/src/Managing.Web3Proxy/test/plugins/close-orders.test.ts b/src/Managing.Web3Proxy/test/plugins/close-orders.test.ts index e7e235f7..60ee09d0 100644 --- a/src/Managing.Web3Proxy/test/plugins/close-orders.test.ts +++ b/src/Managing.Web3Proxy/test/plugins/close-orders.test.ts @@ -5,7 +5,7 @@ import {Ticker} from '../../src/generated/ManagingApiTypes' test('GMX Orders Closing', async (t) => { await t.test('should close all orders for BTC', async () => { - const sdk = await getClientForAddress('0x0b4A132cb6ed8fa66953bf61a53D0B91DaCaAd78') + const sdk = await getClientForAddress('0x932167388dD9aad41149b3cA23eBD489E2E2DD78') const result = await cancelGmxOrdersImpl( sdk, diff --git a/src/Managing.Web3Proxy/test/plugins/open-position.test.ts b/src/Managing.Web3Proxy/test/plugins/open-position.test.ts index e11f32ed..84aeb543 100644 --- a/src/Managing.Web3Proxy/test/plugins/open-position.test.ts +++ b/src/Managing.Web3Proxy/test/plugins/open-position.test.ts @@ -5,17 +5,17 @@ import {Ticker, TradeDirection} from '../../src/generated/ManagingApiTypes' test('GMX Position Opening', async (t) => { await t.test('should open a long position for BTC', async () => { - const sdk = await getClientForAddress('0x0b4A132cb6ed8fa66953bf61a53D0B91DaCaAd78') + const sdk = await getClientForAddress('0x932167388dD9aad41149b3cA23eBD489E2E2DD78') const result = await openGmxPositionImpl( sdk, Ticker.BTC, TradeDirection.Long, - 0.00009129924572776991, + 0.00012, // ~5.3 USDC collateral with 2x leverage (fits available balance of 5.69 USDC) 2, - 111350, - 110000, - 114000 + 87856, + undefined, // No stop-loss + undefined // No take-profit ) console.log('Position opening result:', result) assert.ok(result, 'Position opening result should be defined') diff --git a/src/Managing.Web3Proxy/test/plugins/swap-tokens.test.ts b/src/Managing.Web3Proxy/test/plugins/swap-tokens.test.ts index 132c300e..fa192f28 100644 --- a/src/Managing.Web3Proxy/test/plugins/swap-tokens.test.ts +++ b/src/Managing.Web3Proxy/test/plugins/swap-tokens.test.ts @@ -13,9 +13,9 @@ describe('swap tokens implementation', () => { console.log('Account', sdk.account) const result = await swapGmxTokensImpl( sdk, - Ticker.BTC, Ticker.USDC, - 0.00006893, + Ticker.SOL, + 3, 'market', undefined, 0.5