Fix autoswap
This commit is contained in:
@@ -58,7 +58,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
{
|
{
|
||||||
_state.State.AgentName = agentName;
|
_state.State.AgentName = agentName;
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
// Create an empty AgentSummary for the new agent
|
// Create an empty AgentSummary for the new agent
|
||||||
var emptySummary = new AgentSummary
|
var emptySummary = new AgentSummary
|
||||||
{
|
{
|
||||||
@@ -75,7 +75,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
TotalVolume = 0,
|
TotalVolume = 0,
|
||||||
TotalBalance = 0
|
TotalBalance = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
await _agentService.SaveOrUpdateAgentSummary(emptySummary);
|
await _agentService.SaveOrUpdateAgentSummary(emptySummary);
|
||||||
_logger.LogInformation("Agent {UserId} initialized with name {AgentName} and empty summary", userId, agentName);
|
_logger.LogInformation("Agent {UserId} initialized with name {AgentName} and empty summary", userId, agentName);
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("Received agent summary update event for user {UserId}, event type: {EventType}",
|
_logger.LogInformation("Received agent summary update event for user {UserId}, event type: {EventType}",
|
||||||
this.GetPrimaryKeyLong(), updateEvent.EventType);
|
this.GetPrimaryKeyLong(), updateEvent.EventType);
|
||||||
|
|
||||||
// Only update summary if the event is for this agent's bots
|
// Only update summary if the event is for this agent's bots
|
||||||
if (_state.State.BotIds.Contains(updateEvent.BotId))
|
if (_state.State.BotIds.Contains(updateEvent.BotId))
|
||||||
{
|
{
|
||||||
@@ -217,7 +217,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
{
|
{
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
_logger.LogInformation("Bot {BotId} registered to Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
_logger.LogInformation("Bot {BotId} registered to Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
||||||
|
|
||||||
// Update summary after registering bot
|
// Update summary after registering bot
|
||||||
await UpdateSummary();
|
await UpdateSummary();
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
{
|
{
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
_logger.LogInformation("Bot {BotId} unregistered from Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
_logger.LogInformation("Bot {BotId} unregistered from Agent {UserId}", botId, this.GetPrimaryKeyLong());
|
||||||
|
|
||||||
// Update summary after unregistering bot
|
// Update summary after unregistering bot
|
||||||
await UpdateSummary();
|
await UpdateSummary();
|
||||||
}
|
}
|
||||||
@@ -242,7 +242,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
// Check if a swap is already in progress
|
// Check if a swap is already in progress
|
||||||
if (_state.State.IsSwapInProgress)
|
if (_state.State.IsSwapInProgress)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Swap already in progress for agent {UserId}, bot {RequestingBotId} will wait",
|
_logger.LogInformation("Swap already in progress for agent {UserId}, bot {RequestingBotId} will wait",
|
||||||
this.GetPrimaryKeyLong(), requestingBotId);
|
this.GetPrimaryKeyLong(), requestingBotId);
|
||||||
return new BalanceCheckResult
|
return new BalanceCheckResult
|
||||||
{
|
{
|
||||||
@@ -254,10 +254,11 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check cooldown period (5 minutes between swaps)
|
// Check cooldown period (5 minutes between swaps)
|
||||||
if (_state.State.LastSwapTime.HasValue &&
|
if (_state.State.LastSwapTime.HasValue &&
|
||||||
DateTime.UtcNow - _state.State.LastSwapTime.Value < TimeSpan.FromMinutes(5))
|
DateTime.UtcNow - _state.State.LastSwapTime.Value < TimeSpan.FromMinutes(5))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Swap cooldown period active for agent {UserId}, bot {RequestingBotId} will wait",
|
_logger.LogInformation(
|
||||||
|
"Swap cooldown period active for agent {UserId}, bot {RequestingBotId} will wait",
|
||||||
this.GetPrimaryKeyLong(), requestingBotId);
|
this.GetPrimaryKeyLong(), requestingBotId);
|
||||||
return new BalanceCheckResult
|
return new BalanceCheckResult
|
||||||
{
|
{
|
||||||
@@ -272,7 +273,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
var balanceData = await GetOrRefreshBalanceDataAsync(accountName);
|
var balanceData = await GetOrRefreshBalanceDataAsync(accountName);
|
||||||
if (balanceData == null)
|
if (balanceData == null)
|
||||||
{
|
{
|
||||||
_logger.LogError("Failed to get balance data for account {AccountName}, user {UserId}",
|
_logger.LogError("Failed to get balance data for account {AccountName}, user {UserId}",
|
||||||
accountName, this.GetPrimaryKeyLong());
|
accountName, this.GetPrimaryKeyLong());
|
||||||
return new BalanceCheckResult
|
return new BalanceCheckResult
|
||||||
{
|
{
|
||||||
@@ -283,20 +284,23 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Agent {UserId} balance check - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (cached: {IsCached})",
|
_logger.LogInformation(
|
||||||
this.GetPrimaryKeyLong(), balanceData.EthValueInUsd, balanceData.UsdcValue,
|
"Agent {UserId} balance check - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (cached: {IsCached})",
|
||||||
|
this.GetPrimaryKeyLong(), balanceData.EthValueInUsd, balanceData.UsdcValue,
|
||||||
_state.State.CachedBalanceData?.IsValid == true);
|
_state.State.CachedBalanceData?.IsValid == true);
|
||||||
|
|
||||||
// Check USDC minimum balance first (this will stop the bot if insufficient)
|
// Check USDC minimum balance first (this will stop the bot if insufficient)
|
||||||
if (balanceData.UsdcValue < Constants.GMX.Config.MinimumPositionAmount)
|
if (balanceData.UsdcValue < Constants.GMX.Config.MinimumPositionAmount)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("USDC balance is below minimum required amount - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (minimum: {Minimum})",
|
_logger.LogWarning(
|
||||||
|
"USDC balance is below minimum required amount - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (minimum: {Minimum})",
|
||||||
balanceData.EthValueInUsd, balanceData.UsdcValue, Constants.GMX.Config.MinimumPositionAmount);
|
balanceData.EthValueInUsd, balanceData.UsdcValue, Constants.GMX.Config.MinimumPositionAmount);
|
||||||
return new BalanceCheckResult
|
return new BalanceCheckResult
|
||||||
{
|
{
|
||||||
IsSuccessful = false,
|
IsSuccessful = false,
|
||||||
FailureReason = BalanceCheckFailureReason.InsufficientUsdcBelowMinimum,
|
FailureReason = BalanceCheckFailureReason.InsufficientUsdcBelowMinimum,
|
||||||
Message = $"USDC balance below minimum required amount ({Constants.GMX.Config.MinimumPositionAmount} USD)",
|
Message =
|
||||||
|
$"USDC balance below minimum required amount ({Constants.GMX.Config.MinimumPositionAmount} USD)",
|
||||||
ShouldStopBot = true
|
ShouldStopBot = true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -314,9 +318,11 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have enough USDC for swap (need at least 5 USD for swap)
|
// Check if we have enough USDC for swap (need at least 5 USD for swap)
|
||||||
if (balanceData.UsdcValue < (Constants.GMX.Config.MinimumPositionAmount + Constants.GMX.Config.AutoSwapAmount) )
|
if (balanceData.UsdcValue <
|
||||||
|
(Constants.GMX.Config.MinimumPositionAmount + (decimal)Constants.GMX.Config.AutoSwapAmount))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Insufficient USDC balance for swap - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (need {AutoSwapAmount} USD for swap)",
|
_logger.LogWarning(
|
||||||
|
"Insufficient USDC balance for swap - ETH: {EthValue:F2} USD, USDC: {UsdcValue:F2} USD (need {AutoSwapAmount} USD for swap)",
|
||||||
balanceData.EthValueInUsd, balanceData.UsdcValue, Constants.GMX.Config.AutoSwapAmount);
|
balanceData.EthValueInUsd, balanceData.UsdcValue, Constants.GMX.Config.AutoSwapAmount);
|
||||||
return new BalanceCheckResult
|
return new BalanceCheckResult
|
||||||
{
|
{
|
||||||
@@ -333,7 +339,8 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Initiating USDC to ETH swap for agent {UserId} - swapping 5 USDC", this.GetPrimaryKeyLong());
|
_logger.LogInformation("Initiating USDC to ETH swap for agent {UserId} - swapping 5 USDC",
|
||||||
|
this.GetPrimaryKeyLong());
|
||||||
|
|
||||||
// Get user for the swap
|
// Get user for the swap
|
||||||
var userId = (int)this.GetPrimaryKeyLong();
|
var userId = (int)this.GetPrimaryKeyLong();
|
||||||
@@ -351,14 +358,15 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform the swap
|
// Perform the swap
|
||||||
var swapInfo = await _accountService.SwapGmxTokensAsync(user, accountName,
|
var swapInfo = await _accountService.SwapGmxTokensAsync(user, accountName,
|
||||||
Ticker.USDC, Ticker.ETH, 5);
|
Ticker.USDC, Ticker.ETH, Constants.GMX.Config.AutoSwapAmount);
|
||||||
|
|
||||||
if (swapInfo.Success)
|
if (swapInfo.Success)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Successfully swapped 5 USDC to ETH for agent {UserId}, transaction hash: {Hash}",
|
_logger.LogInformation(
|
||||||
|
"Successfully swapped 5 USDC to ETH for agent {UserId}, transaction hash: {Hash}",
|
||||||
userId, swapInfo.Hash);
|
userId, swapInfo.Hash);
|
||||||
|
|
||||||
// Update last swap time and invalidate cache
|
// Update last swap time and invalidate cache
|
||||||
_state.State.LastSwapTime = DateTime.UtcNow;
|
_state.State.LastSwapTime = DateTime.UtcNow;
|
||||||
_state.State.CachedBalanceData = null; // Invalidate cache after successful swap
|
_state.State.CachedBalanceData = null; // Invalidate cache after successful swap
|
||||||
@@ -372,7 +380,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.LogError("Failed to swap USDC to ETH for agent {UserId}: {Error}",
|
_logger.LogError("Failed to swap USDC to ETH for agent {UserId}: {Error}",
|
||||||
userId, swapInfo.Error ?? swapInfo.Message);
|
userId, swapInfo.Error ?? swapInfo.Message);
|
||||||
return new BalanceCheckResult
|
return new BalanceCheckResult
|
||||||
{
|
{
|
||||||
@@ -392,13 +400,13 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error checking/ensuring ETH balance for agent {UserId}, bot {RequestingBotId}",
|
_logger.LogError(ex, "Error checking/ensuring ETH balance for agent {UserId}, bot {RequestingBotId}",
|
||||||
this.GetPrimaryKeyLong(), requestingBotId);
|
this.GetPrimaryKeyLong(), requestingBotId);
|
||||||
|
|
||||||
// Clear swap in progress flag on error
|
// Clear swap in progress flag on error
|
||||||
_state.State.IsSwapInProgress = false;
|
_state.State.IsSwapInProgress = false;
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
return new BalanceCheckResult
|
return new BalanceCheckResult
|
||||||
{
|
{
|
||||||
IsSuccessful = false,
|
IsSuccessful = false,
|
||||||
@@ -417,7 +425,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Check if we have valid cached data for the same account
|
// Check if we have valid cached data for the same account
|
||||||
if (_state.State.CachedBalanceData?.IsValid == true &&
|
if (_state.State.CachedBalanceData?.IsValid == true &&
|
||||||
_state.State.CachedBalanceData.AccountName == accountName)
|
_state.State.CachedBalanceData.AccountName == accountName)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Using cached balance data for account {AccountName}", accountName);
|
_logger.LogDebug("Using cached balance data for account {AccountName}", accountName);
|
||||||
@@ -426,7 +434,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
|
|
||||||
// Fetch fresh balance data
|
// Fetch fresh balance data
|
||||||
_logger.LogInformation("Fetching fresh balance data for account {AccountName}", accountName);
|
_logger.LogInformation("Fetching fresh balance data for account {AccountName}", accountName);
|
||||||
|
|
||||||
var userId = (int)this.GetPrimaryKeyLong();
|
var userId = (int)this.GetPrimaryKeyLong();
|
||||||
var user = await _userService.GetUserByIdAsync(userId);
|
var user = await _userService.GetUserByIdAsync(userId);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
@@ -467,7 +475,7 @@ public class AgentGrain : Grain, IAgentGrain
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error fetching balance data for account {AccountName}, user {UserId}",
|
_logger.LogError(ex, "Error fetching balance data for account {AccountName}, user {UserId}",
|
||||||
accountName, this.GetPrimaryKeyLong());
|
accountName, this.GetPrimaryKeyLong());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,25 +82,25 @@ namespace Managing.Common
|
|||||||
Ticker.WIF,
|
Ticker.WIF,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly Ticker[] SupportedTickers =
|
public static readonly Ticker[] SupportedTickers =
|
||||||
{
|
{
|
||||||
Ticker.BTC,
|
Ticker.BTC,
|
||||||
Ticker.ETH,
|
Ticker.ETH,
|
||||||
Ticker.BNB,
|
Ticker.BNB,
|
||||||
Ticker.DOGE,
|
Ticker.DOGE,
|
||||||
Ticker.ADA,
|
Ticker.ADA,
|
||||||
Ticker.SOL,
|
Ticker.SOL,
|
||||||
Ticker.XRP,
|
Ticker.XRP,
|
||||||
Ticker.LINK,
|
Ticker.LINK,
|
||||||
Ticker.RENDER,
|
Ticker.RENDER,
|
||||||
Ticker.SUI,
|
Ticker.SUI,
|
||||||
Ticker.GMX,
|
Ticker.GMX,
|
||||||
Ticker.ARB,
|
Ticker.ARB,
|
||||||
Ticker.PEPE,
|
Ticker.PEPE,
|
||||||
Ticker.PENDLE,
|
Ticker.PENDLE,
|
||||||
Ticker.AAVE,
|
Ticker.AAVE,
|
||||||
Ticker.HYPE
|
Ticker.HYPE
|
||||||
};
|
};
|
||||||
|
|
||||||
public static class Decimals
|
public static class Decimals
|
||||||
{
|
{
|
||||||
@@ -109,7 +109,7 @@ namespace Managing.Common
|
|||||||
|
|
||||||
public const decimal MinimumPositionAmount = 5m;
|
public const decimal MinimumPositionAmount = 5m;
|
||||||
public const decimal MinimumEthBalance = 2m;
|
public const decimal MinimumEthBalance = 2m;
|
||||||
public const decimal AutoSwapAmount = 3m;
|
public const double AutoSwapAmount = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TokenAddress
|
public class TokenAddress
|
||||||
|
|||||||
@@ -180,14 +180,20 @@ async function init () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the request ID for later use
|
// Store the request ID for later use using a symbol to avoid TypeScript property errors
|
||||||
request.idempotencyKey = requestId as string
|
const IDEMPOTENCY_KEY_SYMBOL = Symbol.for('idempotency-key')
|
||||||
|
// Attach the symbol to the request object
|
||||||
|
;(request as any)[IDEMPOTENCY_KEY_SYMBOL] = requestId as string
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add post-handler hook to store successful responses
|
// Add post-handler hook to store successful responses
|
||||||
app.addHook('onSend', async (request, reply, payload) => {
|
app.addHook('onSend', async (request, reply, payload) => {
|
||||||
if (request.idempotencyKey && request.method === 'POST') {
|
// Retrieve the idempotency key from the symbol
|
||||||
const requestId = request.idempotencyKey
|
const IDEMPOTENCY_KEY_SYMBOL = Symbol.for('idempotency-key')
|
||||||
|
const idempotencyKey = (request as any)[IDEMPOTENCY_KEY_SYMBOL]
|
||||||
|
if (idempotencyKey && request.method === 'POST') {
|
||||||
|
const requestId = idempotencyKey
|
||||||
|
|
||||||
// Only store successful responses (2xx status codes)
|
// Only store successful responses (2xx status codes)
|
||||||
if (reply.statusCode >= 200 && reply.statusCode < 300) {
|
if (reply.statusCode >= 200 && reply.statusCode < 300) {
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
declare module 'fastify' {
|
|
||||||
interface FastifyRequest {
|
|
||||||
idempotencyKey?: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,15 +7,15 @@ describe('swap tokens implementation', () => {
|
|||||||
|
|
||||||
it('should swap SOL to USDC successfully', async () => {
|
it('should swap SOL to USDC successfully', async () => {
|
||||||
try {
|
try {
|
||||||
const testAccount = '0xbBA4eaA534cbD0EcAed5E2fD6036Aec2E7eE309f'
|
const testAccount = '0x932167388dD9aad41149b3cA23eBD489E2E2DD78'
|
||||||
const sdk = await getClientForAddress(testAccount)
|
const sdk = await getClientForAddress(testAccount)
|
||||||
|
|
||||||
console.log('Account', sdk.account)
|
console.log('Account', sdk.account)
|
||||||
const result = await swapGmxTokensImpl(
|
const result = await swapGmxTokensImpl(
|
||||||
sdk,
|
sdk,
|
||||||
Ticker.PENDLE,
|
Ticker.ETH,
|
||||||
Ticker.USDC,
|
Ticker.USDC,
|
||||||
13.339559522
|
0.0042
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.strictEqual(typeof result, 'string')
|
assert.strictEqual(typeof result, 'string')
|
||||||
|
|||||||
Reference in New Issue
Block a user