Add agent balance fetch from proxy

This commit is contained in:
2025-08-15 20:52:37 +07:00
parent b178f15beb
commit 289fd25dc3
9 changed files with 1622 additions and 43 deletions

View File

@@ -325,15 +325,59 @@ public class EvmManager : IEvmManager
public async Task<List<EvmBalance>> GetAllBalancesOnAllChain(string publicAddress)
{
var chainBalances = new List<EvmBalance>();
var chains = ChainService.GetChains();
foreach (var chain in chains)
try
{
chainBalances.AddRange(await GetAllBalances(chain, publicAddress));
}
// Define the assets and chains we want to query
var assets = new[] { Ticker.USDC, Ticker.ETH };
var chains = new[] { "arbitrum", "ethereum" };
return chainBalances;
// Get balances from Web3Proxy service
var balances = await _web3ProxyService.GetWalletBalanceAsync(publicAddress, assets, chains);
// Convert Balance objects to EvmBalance objects
var evmBalances = new List<EvmBalance>();
foreach (var balance in balances)
{
if (balance.Amount > 0)
{
var evmBalance = new EvmBalance
{
Balance = balance.Amount,
TokenName = balance.TokenName ?? "Unknown",
TokenAddress = balance.TokenAdress ?? "",
TokenImage = balance.TokenImage ?? "",
Price = balance.Price,
Value = balance.Value,
Chain = new Chain
{
Id = balance.Chain?.Id ?? "",
Name = balance.Chain?.Name ?? "Unknown",
ChainId = balance.Chain?.ChainId ?? 0,
RpcUrl = balance.Chain?.RpcUrl ?? ""
}
};
evmBalances.Add(evmBalance);
}
}
return evmBalances;
}
catch (Exception ex)
{
// Log the exception and fallback to original implementation if Web3Proxy fails
Console.WriteLine($"Web3Proxy balance retrieval failed: {ex.Message}");
var chainBalances = new List<EvmBalance>();
var chains = ChainService.GetChains();
foreach (var chain in chains)
{
chainBalances.AddRange(await GetAllBalances(chain, publicAddress));
}
return chainBalances;
}
}
public async Task<List<Candle>> GetCandles(Ticker ticker, DateTime startDate, Timeframe timeframe,

View File

@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using Managing.Domain.Accounts;
namespace Managing.Infrastructure.Evm.Models.Proxy
{
@@ -138,4 +139,16 @@ namespace Managing.Infrastructure.Evm.Models.Proxy
[JsonPropertyName("hash")]
public string Hash { get; set; }
}
/// <summary>
/// Response for wallet balance operations
/// </summary>
public class Web3ProxyBalanceResponse : Web3ProxyResponse
{
/// <summary>
/// List of wallet balances if successful
/// </summary>
[JsonPropertyName("balances")]
public List<Balance> Balances { get; set; }
}
}

View File

@@ -1,3 +1,4 @@
using System.Collections;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
@@ -181,19 +182,20 @@ namespace Managing.Infrastructure.Evm.Services
};
}
public async Task<SwapInfos> SwapGmxTokensAsync(string account, Ticker fromTicker, Ticker toTicker, double amount, string orderType = "market", double? triggerRatio = null, double allowedSlippage = 0.5)
public async Task<SwapInfos> SwapGmxTokensAsync(string account, Ticker fromTicker, Ticker toTicker,
double amount, string orderType = "market", double? triggerRatio = null, double allowedSlippage = 0.5)
{
var payload = new
{
account,
fromTicker = fromTicker.ToString(),
toTicker = toTicker.ToString(),
amount,
orderType,
triggerRatio,
allowedSlippage
var payload = new
{
account,
fromTicker = fromTicker.ToString(),
toTicker = toTicker.ToString(),
amount,
orderType,
triggerRatio,
allowedSlippage
};
var response = await CallGmxServiceAsync<GmxSwapResponse>("/swap-tokens", payload);
if (response == null)
@@ -213,17 +215,18 @@ namespace Managing.Infrastructure.Evm.Services
};
}
public async Task<SwapInfos> SendTokenAsync(string senderAddress, string recipientAddress, Ticker ticker, decimal amount, int? chainId = null)
public async Task<SwapInfos> SendTokenAsync(string senderAddress, string recipientAddress, Ticker ticker,
decimal amount, int? chainId = null)
{
var payload = new
{
senderAddress,
recipientAddress,
ticker = ticker.ToString(),
var payload = new
{
senderAddress,
recipientAddress,
ticker = ticker.ToString(),
amount = amount.ToString(), // Convert decimal to string for bigint compatibility
chainId
chainId
};
var response = await CallPrivyServiceAsync<Web3ProxyTokenSendResponse>("/send-token", payload);
if (response == null)
@@ -243,6 +246,30 @@ namespace Managing.Infrastructure.Evm.Services
};
}
public async Task<List<Balance>> GetWalletBalanceAsync(string address, Ticker[] assets, string[] chains)
{
var payload = new
{
address,
asset = assets,
chain = chains
};
var response = await GetPrivyServiceAsync<Web3ProxyBalanceResponse>("/wallet-balance", payload);
if (response == null)
{
throw new Web3ProxyException("Wallet balance response is null");
}
if (!response.Success)
{
throw new Web3ProxyException($"Wallet balance request failed: {response.Error}");
}
return response.Balances ?? new List<Balance>();
}
private async Task HandleErrorResponse(HttpResponseMessage response)
{
var statusCode = (int)response.StatusCode;
@@ -303,20 +330,42 @@ namespace Managing.Infrastructure.Evm.Services
var value = prop.GetValue(payload);
if (value != null)
{
if (!isFirst)
{
queryString.Append("&");
}
var paramName = prop.Name;
// Apply camelCase to match JSON property naming
paramName = char.ToLowerInvariant(paramName[0]) + paramName.Substring(1);
queryString.Append(HttpUtility.UrlEncode(paramName));
queryString.Append("=");
queryString.Append(HttpUtility.UrlEncode(value.ToString()));
// Check if the value is an array or enumerable (but not string)
if (value is IEnumerable enumerable && !(value is string))
{
// Handle arrays by creating multiple query parameters with the same name
foreach (var item in enumerable)
{
if (!isFirst)
{
queryString.Append("&");
}
isFirst = false;
queryString.Append(HttpUtility.UrlEncode(paramName));
queryString.Append("=");
queryString.Append(HttpUtility.UrlEncode(item?.ToString() ?? ""));
isFirst = false;
}
}
else
{
// Handle single values
if (!isFirst)
{
queryString.Append("&");
}
queryString.Append(HttpUtility.UrlEncode(paramName));
queryString.Append("=");
queryString.Append(HttpUtility.UrlEncode(value.ToString()));
isFirst = false;
}
}
}