Fix get Gas fees + position direction list
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
|
using Managing.Domain.Evm;
|
||||||
using static Managing.Common.Enums;
|
using static Managing.Common.Enums;
|
||||||
|
|
||||||
namespace Managing.Application.Abstractions.Services
|
namespace Managing.Application.Abstractions.Services
|
||||||
@@ -19,5 +20,7 @@ namespace Managing.Application.Abstractions.Services
|
|||||||
Task<List<Balance>> GetWalletBalanceAsync(string address, Ticker[] assets, string[] chains);
|
Task<List<Balance>> GetWalletBalanceAsync(string address, Ticker[] assets, string[] chains);
|
||||||
|
|
||||||
Task<decimal> GetEstimatedGasFeeUsdAsync();
|
Task<decimal> GetEstimatedGasFeeUsdAsync();
|
||||||
|
|
||||||
|
Task<GasFeeData> GetGasFeeDataAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -614,6 +614,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (positionForSignal.TakeProfit2 != null)
|
if (positionForSignal.TakeProfit2 != null)
|
||||||
{
|
{
|
||||||
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
||||||
@@ -679,6 +680,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
positionForSignal.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (positionForSignal.TakeProfit2 != null)
|
if (positionForSignal.TakeProfit2 != null)
|
||||||
{
|
{
|
||||||
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
positionForSignal.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
||||||
@@ -1138,7 +1140,8 @@ public class TradingBotBase : ITradingBot
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var command = new ClosePositionCommand(position, position.AccountId, lastPrice, isForBacktest: Config.IsForBacktest);
|
var command = new ClosePositionCommand(position, position.AccountId, lastPrice,
|
||||||
|
isForBacktest: Config.IsForBacktest);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Position closedPosition = null;
|
Position closedPosition = null;
|
||||||
@@ -1277,6 +1280,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
position.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
position.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position.TakeProfit2 != null)
|
if (position.TakeProfit2 != null)
|
||||||
{
|
{
|
||||||
position.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
position.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
||||||
@@ -1349,6 +1353,7 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
position.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
position.TakeProfit1.SetStatus(TradeStatus.Cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (position.TakeProfit2 != null)
|
if (position.TakeProfit2 != null)
|
||||||
{
|
{
|
||||||
position.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
position.TakeProfit2.SetStatus(TradeStatus.Cancelled);
|
||||||
@@ -2163,7 +2168,8 @@ public class TradingBotBase : ITradingBot
|
|||||||
PositionIdentifier = position.Identifier,
|
PositionIdentifier = position.Identifier,
|
||||||
Ticker = position.Ticker,
|
Ticker = position.Ticker,
|
||||||
Volume = position.Open.Price * position.Open.Quantity * position.Open.Leverage,
|
Volume = position.Open.Price * position.Open.Quantity * position.Open.Leverage,
|
||||||
Fee = position.Open.Fee
|
Fee = position.GasFees + position.UiFees,
|
||||||
|
Direction = position.OriginDirection
|
||||||
};
|
};
|
||||||
await platformGrain.OnPositionOpenAsync(positionOpenEvent);
|
await platformGrain.OnPositionOpenAsync(positionOpenEvent);
|
||||||
break;
|
break;
|
||||||
|
|||||||
70
src/Managing.Domain/Evm/GasFeeData.cs
Normal file
70
src/Managing.Domain/Evm/GasFeeData.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Managing.Domain.Evm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gas fee data model
|
||||||
|
/// </summary>
|
||||||
|
public class GasFeeData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Estimated gas fee in Wei
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("estimatedGasFeeWei")]
|
||||||
|
public string? EstimatedGasFeeWei { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estimated gas fee in ETH
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("estimatedGasFeeEth")]
|
||||||
|
public string? EstimatedGasFeeEth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estimated gas fee in USD
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("estimatedGasFeeUsd")]
|
||||||
|
public double? EstimatedGasFeeUsd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ETH balance of the account
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("ethBalance")]
|
||||||
|
public string? EthBalance { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current ETH price in USD
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("ethPrice")]
|
||||||
|
public double? EthPrice { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the account has sufficient balance for gas fees
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("hasSufficientBalance")]
|
||||||
|
public bool? HasSufficientBalance { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error message if insufficient balance
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("errorMessage")]
|
||||||
|
public string? ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum allowed gas fee in USD
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("maxAllowedUsd")]
|
||||||
|
public double? MaxAllowedUsd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gas price in Wei
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("gasPrice")]
|
||||||
|
public string? GasPrice { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gas limit
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("gasLimit")]
|
||||||
|
public string? GasLimit { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
|
using Managing.Domain.Evm;
|
||||||
|
|
||||||
namespace Managing.Infrastructure.Evm.Models.Proxy
|
namespace Managing.Infrastructure.Evm.Models.Proxy
|
||||||
{
|
{
|
||||||
@@ -158,21 +159,10 @@ namespace Managing.Infrastructure.Evm.Models.Proxy
|
|||||||
public class GasFeeResponse : Web3ProxyResponse
|
public class GasFeeResponse : Web3ProxyResponse
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Estimated gas fee in USD
|
/// Gas fee data object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("estimatedGasFeeUsd")]
|
[JsonPropertyName("data")]
|
||||||
public double? EstimatedGasFeeUsd { get; set; }
|
public GasFeeData? Data { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Current ETH price in USD
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("ethPrice")]
|
|
||||||
public double? EthPrice { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gas price in Gwei
|
|
||||||
/// </summary>
|
|
||||||
[JsonPropertyName("gasPriceGwei")]
|
|
||||||
public double? GasPriceGwei { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ using System.Web;
|
|||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Core.Exceptions;
|
using Managing.Core.Exceptions;
|
||||||
using Managing.Domain.Accounts;
|
using Managing.Domain.Accounts;
|
||||||
|
using Managing.Domain.Evm;
|
||||||
using Managing.Infrastructure.Evm.Models.Proxy;
|
using Managing.Infrastructure.Evm.Models.Proxy;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
@@ -408,7 +409,34 @@ namespace Managing.Infrastructure.Evm.Services
|
|||||||
throw new Web3ProxyException($"Gas fee request failed: {response.Error}");
|
throw new Web3ProxyException($"Gas fee request failed: {response.Error}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (decimal)(response.EstimatedGasFeeUsd ?? 0);
|
if (response.Data is null)
|
||||||
|
{
|
||||||
|
throw new Web3ProxyException("Gas fee data is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (decimal)(response.Data.EstimatedGasFeeUsd ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GasFeeData> GetGasFeeDataAsync()
|
||||||
|
{
|
||||||
|
var response = await GetGmxServiceAsync<GasFeeResponse>("/gas-fee", null);
|
||||||
|
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
throw new Web3ProxyException("Gas fee response is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.Success)
|
||||||
|
{
|
||||||
|
throw new Web3ProxyException($"Gas fee request failed: {response.Error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.Data is null)
|
||||||
|
{
|
||||||
|
throw new Web3ProxyException("Gas fee data is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleErrorResponse(HttpResponseMessage response)
|
private async Task HandleErrorResponse(HttpResponseMessage response)
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ function checkMemoryUsage() {
|
|||||||
* @param estimatedGasFee The estimated gas fee in wei
|
* @param estimatedGasFee The estimated gas fee in wei
|
||||||
* @returns Object with balance check result and details
|
* @returns Object with balance check result and details
|
||||||
*/
|
*/
|
||||||
async function checkGasFeeBalance(
|
export async function checkGasFeeBalance(
|
||||||
sdk: GmxSdk,
|
sdk: GmxSdk,
|
||||||
estimatedGasFee: bigint
|
estimatedGasFee: bigint
|
||||||
): Promise<{
|
): Promise<{
|
||||||
@@ -151,9 +151,8 @@ async function checkGasFeeBalance(
|
|||||||
* @param params The position increase parameters
|
* @param params The position increase parameters
|
||||||
* @returns Estimated gas fee in wei
|
* @returns Estimated gas fee in wei
|
||||||
*/
|
*/
|
||||||
async function estimatePositionGasFee(
|
export async function estimatePositionGasFee(
|
||||||
sdk: GmxSdk,
|
sdk: GmxSdk,
|
||||||
params: PositionIncreaseParams
|
|
||||||
): Promise<bigint> {
|
): Promise<bigint> {
|
||||||
try {
|
try {
|
||||||
// Estimate gas for the position opening transaction
|
// Estimate gas for the position opening transaction
|
||||||
@@ -440,6 +439,7 @@ declare module 'fastify' {
|
|||||||
getGmxTrade: typeof getGmxTrade;
|
getGmxTrade: typeof getGmxTrade;
|
||||||
getGmxPositions: typeof getGmxPositions;
|
getGmxPositions: typeof getGmxPositions;
|
||||||
swapGmxTokens: typeof swapGmxTokens;
|
swapGmxTokens: typeof swapGmxTokens;
|
||||||
|
estimatePositionGasFee: typeof estimatePositionGasFee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,7 +633,7 @@ export const openGmxPositionImpl = async (
|
|||||||
|
|
||||||
// Check gas fees before opening position
|
// Check gas fees before opening position
|
||||||
console.log('⛽ Checking gas fees before opening position...');
|
console.log('⛽ Checking gas fees before opening position...');
|
||||||
const estimatedGasFee = await estimatePositionGasFee(sdk, params);
|
const estimatedGasFee = await estimatePositionGasFee(sdk);
|
||||||
const gasFeeCheck = await checkGasFeeBalance(sdk, estimatedGasFee);
|
const gasFeeCheck = await checkGasFeeBalance(sdk, estimatedGasFee);
|
||||||
|
|
||||||
if (!gasFeeCheck.hasSufficientBalance) {
|
if (!gasFeeCheck.hasSufficientBalance) {
|
||||||
@@ -1417,6 +1417,7 @@ export default fp(async (fastify) => {
|
|||||||
fastify.decorateRequest('claimGmxUiFees', claimGmxUiFees)
|
fastify.decorateRequest('claimGmxUiFees', claimGmxUiFees)
|
||||||
fastify.decorateRequest('swapGmxTokens', swapGmxTokens)
|
fastify.decorateRequest('swapGmxTokens', swapGmxTokens)
|
||||||
fastify.decorateRequest('checkGmxTokenAllowances', checkGmxTokenAllowances)
|
fastify.decorateRequest('checkGmxTokenAllowances', checkGmxTokenAllowances)
|
||||||
|
fastify.decorateRequest('estimatePositionGasFee', estimatePositionGasFee)
|
||||||
|
|
||||||
// Set up cache refresh without blocking plugin registration
|
// Set up cache refresh without blocking plugin registration
|
||||||
setupCacheRefresh();
|
setupCacheRefresh();
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import {FastifyPluginAsyncTypebox} from '@fastify/type-provider-typebox'
|
|||||||
import {Type} from '@sinclair/typebox'
|
import {Type} from '@sinclair/typebox'
|
||||||
import {TradeDirection} from '../../../generated/ManagingApiTypes.js'
|
import {TradeDirection} from '../../../generated/ManagingApiTypes.js'
|
||||||
import {
|
import {
|
||||||
|
checkGasFeeBalance,
|
||||||
|
estimatePositionGasFee,
|
||||||
getClaimableFundingFeesImpl,
|
getClaimableFundingFeesImpl,
|
||||||
getClaimableUiFeesImpl,
|
getClaimableUiFeesImpl,
|
||||||
getGmxRebateStatsImpl
|
getGmxRebateStatsImpl
|
||||||
} from '../../../plugins/custom/gmx.js'
|
} from '../../../plugins/custom/gmx.js'
|
||||||
|
|
||||||
|
const MAX_GAS_FEE_USD = 1.5; // Maximum gas fee in USD
|
||||||
|
|
||||||
const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
||||||
// Define route to open a position
|
// Define route to open a position
|
||||||
fastify.post('/open-position', {
|
fastify.post('/open-position', {
|
||||||
@@ -194,6 +198,67 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Define route to get gas fee estimation for opening a position
|
||||||
|
fastify.get('/gas-fee', {
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: Type.Object({
|
||||||
|
success: Type.Boolean(),
|
||||||
|
data: Type.Optional(Type.Object({
|
||||||
|
estimatedGasFeeWei: Type.String(),
|
||||||
|
estimatedGasFeeEth: Type.String(),
|
||||||
|
estimatedGasFeeUsd: Type.Number(),
|
||||||
|
ethBalance: Type.String(),
|
||||||
|
ethPrice: Type.Number(),
|
||||||
|
hasSufficientBalance: Type.Boolean(),
|
||||||
|
errorMessage: Type.Optional(Type.String()),
|
||||||
|
maxAllowedUsd: Type.Number(),
|
||||||
|
gasPrice: Type.String(),
|
||||||
|
gasLimit: Type.String()
|
||||||
|
})),
|
||||||
|
error: Type.Optional(Type.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, async (request, reply) => {
|
||||||
|
try {
|
||||||
|
// Use a default address for gas fee estimation
|
||||||
|
const defaultAccount = "0x0000000000000000000000000000000000000000"
|
||||||
|
|
||||||
|
// Get GMX client for the default account
|
||||||
|
const sdk = await request.getClientForAddress(defaultAccount)
|
||||||
|
|
||||||
|
// Call the two methods as mentioned
|
||||||
|
const estimatedGasFee = await estimatePositionGasFee(sdk);
|
||||||
|
const gasFeeCheck = await checkGasFeeBalance(sdk, estimatedGasFee);
|
||||||
|
|
||||||
|
// Format the response data
|
||||||
|
const data = {
|
||||||
|
estimatedGasFeeWei: estimatedGasFee.toString(),
|
||||||
|
estimatedGasFeeEth: (Number(estimatedGasFee) / 1e18).toFixed(6),
|
||||||
|
estimatedGasFeeUsd: gasFeeCheck.estimatedGasFeeUsd,
|
||||||
|
ethBalance: gasFeeCheck.ethBalance,
|
||||||
|
ethPrice: gasFeeCheck.ethPrice,
|
||||||
|
hasSufficientBalance: gasFeeCheck.hasSufficientBalance,
|
||||||
|
errorMessage: gasFeeCheck.errorMessage,
|
||||||
|
maxAllowedUsd: MAX_GAS_FEE_USD,
|
||||||
|
gasPrice: (Number(estimatedGasFee) / 500000).toString(), // Approximate gas price
|
||||||
|
gasLimit: "500000" // Base gas limit used in estimation
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error estimating gas fee:', error)
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `Failed to estimate gas fee: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Define route to get all claimable fees and rebate stats
|
// Define route to get all claimable fees and rebate stats
|
||||||
fastify.get('/claimable-summary', {
|
fastify.get('/claimable-summary', {
|
||||||
schema: {
|
schema: {
|
||||||
|
|||||||
Reference in New Issue
Block a user