为什么将返回的 Json 反序列化为类对象在 C# 中失败?
我正在开发一个电报机器人,它可以向频道中的用户报告交易信息。交易信息是通过使用标准“application/json”响应的 HTTP 请求拉取的。
该应用程序执行两次传递:第一个传递返回其检查的代币的当前市场价格。第二个提供了上次检查时间戳之后发生的所有新事务。这是当前代码,减去 API 密钥。出于隐私考虑,API 密钥已被删除。
using Newtonsoft.Json;
using Telegram.Bot;
using Telegram.Bot.Exceptions;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
namespace TelegramBotGeneric
{
class PriceObject
{
public string address { get; set; } = string.Empty;
public double volume_24h { get; set; }
public double liquidity { get; set; }
public double volume_24h_usd { get; set; }
public double liquidty_usd { get; set; }
public double price_usd { get; set; }
public double volume_24h_delta { get; set; }
public double liquidity_24H_delta { get; set; }
public double volume_24h_delta_usd { get; set; }
public double liquidty_24h_delta_usd { get; set; }
public double price_25h_delta_usd{ get; set; }
public double timestamp { get; set; }
public PriceObject()
{
//default CTOR
}
}
class tokensTransfered
{
public string address { get; set; } = string.Empty;
public string symbol { get; set; } = string.Empty;
public string amm { get; set; } = string.Empty;
public string network { get; set; } = string.Empty;
public double price_usd { get; set; }
public double price_eth { get; set; }
public double amount { get; set; }
public double amount_in { get; set; }
public double amount_out { get; set; }
public tokensTransfered()
{
//defaut CTOR
}
}
class returnedTransaction
{
public string amm { get; set; } = string.Empty;
public long chain_id { get; set; }
public string direction { get; set; } = string.Empty;
public string transaction_address { get; set; } = string.Empty;
public double timestamp { get; set; }
public double block_number { get; set; }
public string to { get; set; } = string.Empty;
public string sender { get; set; } = string.Empty;
public double amount_usd { get; set; }
public List<tokensTransfered> tokens_in { get; set; } = new List<tokensTransfered>();
public List<tokensTransfered> tokens_out { get; set; } = new List<tokensTransfered>();
public string pair_address { get; set; } = string.Empty;
public string wallet_address { get; set; } = string.Empty;
public string wallet_category { get; set; } = string.Empty;
public string transaction_type { get; set; } = String.Empty;
public returnedTransaction()
{
//default CTOR
}
}
public class TelegramBot
{
//Readonly Declarators for API Information and Query Strings
private static readonly string TB_BASE_IMAGES_DIRECTORY = @Directory.GetCurrentDirectory() + "\\images";
private static readonly string TB_API_ADDR = "https://api.dev.dex.guru/v1/chain/137/tokens/";
private static readonly string DEXGURU_MARKET_API_KEY =
"/market?api-key=";
private static readonly string DEXGURU_TRANSACTIONS_API_KEY =
"/transactions?api-key=";
private static readonly string TELEGRAM_BOT_API_KEY = "";
private static readonly int TB_MAX_TIME_BETWEEN_POLLING = 10;
private static readonly int TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR = 15;
//declarators for TelegramBot API
private static TelegramBotClient client = new TelegramBotClient(TELEGRAM_BOT_API_KEY);
private static CancellationTokenSource cts = new CancellationTokenSource();
//private static IEnumerable<BotCommand> botCommands;
//storage containers for Image URL and Contract addresses
public static Dictionary<string, string> tbBotCheckableContractAddresses { get; set; } = new Dictionary<string, string>();
public static string[] tbBotImgFileURL { get; set; } = new string[] { };
//variables for time calculation
private static DateTime lastUpdateTime = new();
private static int tbCurrentTimeBetweenPolling = 0;
private static bool tbFirstPassthrough = true;
private static bool tbContinuePolling = true;
private static double tbTransactionLastCheckedTimestamp = 0;
//variables for HTTPRequest Information
private static HttpClient tbHttpClient = new HttpClient();
private static Dictionary<string, double> tbApiReturnedPrices { get; set; } = new Dictionary<string, double>();
private static Dictionary<string, double> tbApiPreviousPrices { get; set; } = new Dictionary<string, double>();
private static string tbCurrentlyPolledAddress = "";
public static async Task Main(string[] args)
{
lastUpdateTime = DateTime.Now;
tbAddAddressesToCheckist();
tbAddDefaultPrices();
tbCurrentTimeBetweenPolling = TB_MAX_TIME_BETWEEN_POLLING;
do
{
if(tbFirstPassthrough)
{
//first we want to check prices
await tbCompletePriceUpdate();
//TEST - output to Telegram the price of TDL
/*Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: "The Current Price of Tidal" + Environment.NewLine +
"**TDL/USD**: $" + Regex.Escape(tbApiReturnedPrices["TDL"].ToString() + " per TDL.")
+ Environment.NewLine + "**TDL/WETH**: "
+ Regex.Escape((tbApiReturnedPrices["WETH"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WETH"])* 100)).ToString() + " WETH per TDL. (WETH = " + tbApiReturnedPrices["WETH"] + ")")
+ Environment.NewLine + "**TDL/WBTC**: "
+ Regex.Escape((tbApiReturnedPrices["WBTC"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WBTC"])* 100)).ToString() + " WBTC per TDL. (WBTC = " + tbApiReturnedPrices["WBTC"] + ")"),
parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
lastUpdateTime = DateTime.Now;*/
await tbFetchNewProcessedOrders(tbBotCheckableContractAddresses["WETH"]);
}
else if((DateTime.Now - lastUpdateTime).Minutes >= TB_MAX_TIME_BETWEEN_POLLING)
{
//first we want to check prices
await tbCompletePriceUpdate();
//TEST - output to Telegram the price of TDL
/*Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: "The Current Price of Tidal" + Environment.NewLine +
"**TDL/USD**: $" + Regex.Escape(tbApiReturnedPrices["TDL"].ToString() + " per TDL.")
+ Environment.NewLine + "**TDL/WETH**: "
+ Regex.Escape((tbApiReturnedPrices["WETH"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WETH"])* 100)).ToString() + " WETH per TDL. (WETH = " + tbApiReturnedPrices["WETH"] + ")")
+ Environment.NewLine + "**TDL/WBTC**: "
+ Regex.Escape((tbApiReturnedPrices["WBTC"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WBTC"])* 100)).ToString() + " WBTC per TDL. (WBTC = " + tbApiReturnedPrices["WBTC"] + ")"),
parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
lastUpdateTime = DateTime.Now;*/
await tbFetchNewProcessedOrders(tbBotCheckableContractAddresses["WETH"]);
}
else
{
//something here
await tbFetchNewProcessedOrders(tbBotCheckableContractAddresses["WETH"]);
}
} while (tbContinuePolling);
}
private static void tbAddAddressesToCheckist()
{
tbBotCheckableContractAddresses.Add("TDL", "0x896219cfa4dF4AB30A418355928724d8B5D25FAC");
//tbBotCheckableContractAddresses.Add("WMATIC", "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270");
//tbBotCheckableContractAddresses.Add("WBNB", "0x3BA4c387f786bFEE076A58914F5Bd38d668B42c3");
tbBotCheckableContractAddresses.Add("WETH", "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619");
tbBotCheckableContractAddresses.Add("WBTC", "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6");
}
public static void tbAddDefaultPrices()
{
tbApiReturnedPrices.Add("TDL", 0);
//tbApiReturnedPrices.Add("WMATIC", 0);
//tbApiReturnedPrices.Add("WBNB", 0);
tbApiReturnedPrices.Add("WETH", 0);
tbApiReturnedPrices.Add("WBTC", 0);
tbApiPreviousPrices = tbApiReturnedPrices;
}
private static void tbHttpClientSetup(string address)
{
tbHttpClient = new HttpClient();
tbHttpClient.DefaultRequestHeaders.Accept.Clear();
tbHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
tbCurrentlyPolledAddress = address;
}
private static async Task tbHttpClientGetPriceData()
{
HttpResponseMessage response = await tbHttpClient.GetAsync(new Uri(TB_API_ADDR + tbCurrentlyPolledAddress + DEXGURU_MARKET_API_KEY));
response.EnsureSuccessStatusCode();
if(response.IsSuccessStatusCode)
{
try
{
PriceObject jsonResponse = JsonConvert.DeserializeObject<PriceObject>(await response.Content.ReadAsStringAsync());
if (jsonResponse == null)
throw new ArgumentException();
tbApiReturnedPrices[(tbBotCheckableContractAddresses.FirstOrDefault(x => x.Value == tbCurrentlyPolledAddress).Key)] = jsonResponse.price_usd;
Console.WriteLine("Retrieved Price Update For Contract " + tbCurrentlyPolledAddress);
}
catch (Exception ex) when(ex is ArgumentException || ex is NullReferenceException)
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Error: "
+ ex.Message);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + ex.HResult), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
else
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Status: "
+ response.StatusCode);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + response.StatusCode), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
private static async Task tbCompletePriceUpdate()
{
foreach(KeyValuePair<string, string> pair in tbBotCheckableContractAddresses)
{
tbHttpClientSetup(pair.Value);
await tbHttpClientGetPriceData();
tbApiPreviousPrices = tbApiReturnedPrices;
}
}
private static async Task tbFetchNewProcessedOrders(string address)
{
//setup the HTTP Client
tbHttpClientSetup(address);
string polledAddress = tbBotCheckableContractAddresses.FirstOrDefault(x => x.Value == address).Key;
returnedTransaction[] transactions;
//get the response
HttpResponseMessage response = await tbHttpClient.GetAsync(new Uri(TB_API_ADDR + tbCurrentlyPolledAddress + DEXGURU_TRANSACTIONS_API_KEY));
response.EnsureSuccessStatusCode();
if (response != null)
{
try
{
//Console.WriteLine(await response.Content.ReadAsStringAsync());
transactions = JsonConvert.DeserializeObject<returnedTransaction[]>(await response.Content.ReadAsStringAsync());
if (transactions == null)
throw new ArgumentException();
foreach(returnedTransaction transaction in transactions)
{
if(tbTransactionLastCheckedTimestamp == 0)
{
tbTransactionLastCheckedTimestamp = transaction.timestamp;
Console.WriteLine(
(transaction.amount_usd / tbApiReturnedPrices[polledAddress]) + " " + polledAddress +
" was purchased for $" + transaction.amount_usd + ".");
Thread.Sleep(2000);
}
else
{
if (tbTransactionLastCheckedTimestamp < transaction.timestamp)
tbTransactionLastCheckedTimestamp = transaction.timestamp;
Console.WriteLine(
((double)transaction.amount_usd / tbApiReturnedPrices[polledAddress]) + " " + polledAddress +
" was purchased for $" + transaction.amount_usd + ".");
Thread.Sleep(2000);
}
}
} catch (Exception ex) when (ex is ArgumentException || ex is NullReferenceException)
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Error: "
+ ex.Message);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + ex.HResult), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
else
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Status: "
+ response.StatusCode);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + response.StatusCode), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
private static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
{
// Only process Message updates: https://core.telegram.org/bots/api#message
if (update.Type != UpdateType.Message)
return;
// Only process text messages
if (update.Message!.Type != MessageType.Text)
return;
var chatId = update.Message.Chat.Id;
var messageText = update.Message.Text;
Console.WriteLine($"Received a '{messageText}' message in chat {chatId}.");
// Echo received message text
Message sentMessage = await botClient.SendTextMessageAsync(
chatId: chatId,
text: "You said:\n" + messageText,
cancellationToken: cancellationToken);
}
private Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
{
var ErrorMessage = exception switch
{
ApiRequestException apiRequestException
=> $"Telegram API Error:\n[{apiRequestException.ErrorCode}]\n{apiRequestException.Message}",
_ => exception.ToString()
};
Console.WriteLine(ErrorMessage);
return Task.CompletedTask;
}
}
}
这里的问题在于上面代码中的函数:
private static async Task tbFetchNewProcessedOrders(string address)
该函数能够从 API 调用中正确返回 json 数据,它还返回 状态代码:200 [OK]
但是,当我尝试将数据反序列化为类对象数组,它会抛出错误:
Newtonsoft.Json.JsonSerializationException:'无法将当前JSON对象(例如{“name”:“value”})反序列化为类型'TelegramBotGeneric.returnedTransaction[]' 因为该类型需要一个 JSON 数组
虽然 HTTP 请求确实返回一个 json 数组,并且该函数
private static async Task tbHttpClientGetPriceData()
也以相同的方式反序列化,但它不需要数组类,因为它每个请求仅返回 1 个代币价格,并且反序列化时不会失败。
对于发生的事情有什么想法吗?我错过了什么吗?任何和所有的帮助将不胜感激。
编辑:Json 结果的副本:
{"total":10000,"data":[{"amm":"waultswap","chain_id":137,"direction":"in","transaction_address":"0xfd8baf557efb178b15fa248ae220d133f0f9fc6d80ca45006eb7f2302fee729c","timestamp":1645650607,"block_number":25270535,"to":"0xcecc7e26d0987281b7da1e3c757161ed6b20af6f","sender":"0x79bafc10542ba08593b2d775d64ed197b0b9a5f9","amount_usd":9.704910550601628,"tokens_in":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"waultswap","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633868277838665,"amount":9.707424,"amount_in":9.707424,"amount_out":0.0}],"tokens_out":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"waultswap","network":"polygon","price_usd":2623.3377574906485,"price_eth":1740.2877131473633,"amount":0.003696525837357276,"amount_in":0.0,"amount_out":0.003696525837357276}],"pair_address":"0xd928ce1d0f2642e44615768761c0f00c23e0d588","wallet_address":"0x779010626fd0c88b6013e802478f07d84de5c4d7","wallet_category":"bot","transaction_type":"swap"},{"amm":"quickswap","chain_id":137,"direction":"out","transaction_address":"0xfd8baf557efb178b15fa248ae220d133f0f9fc6d80ca45006eb7f2302fee729c","timestamp":1645650607,"block_number":25270535,"to":"0xd8d51ea2edca2c2ea15a053a5730f559d79a1570","sender":"0x79bafc10542ba08593b2d775d64ed197b0b9a5f9","amount_usd":9.719504105372957,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"quickswap","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":0.003696525837357276,"amount_in":0.003696525837357276,"amount_out":0.0}],"tokens_out":[{"address":"0x7f426f6dc648e50464a0392e60e1bb465a67e9cf","symbol":"PAUTO","amm":"quickswap","network":"polygon","price_usd":387.73659420086454,"price_eth":257.2194707368818,"amount":0.02503545234060058,"amount_in":0.0,"amount_out":0.02503545234060058}],"pair_address":"0xcecc7e26d0987281b7da1e3c757161ed6b20af6f","wallet_address":"0x779010626fd0c88b6013e802478f07d84de5c4d7","wallet_category":"bot","transaction_type":"swap"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0x5d0bed394c1a35dcc12a70863b499807f1994cd2b3d4f53f3ebadebf4cf02018","timestamp":1645650603,"block_number":25270534,"to":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","sender":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","amount_usd":24187.585904394073,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2622.4290334646125,"price_eth":1739.6856993161678,"amount":9.225,"amount_in":9.225,"amount_out":0.0}],"tokens_out":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"uniswap_v3","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633871411260988,"amount":24193.850184,"amount_in":0.0,"amount_out":24193.850184}],"pair_address":"0x45dda9cb7c25131df268515131f647d726f50608","wallet_address":"0x0dd89655c6ee8d660c00667625434b53112bd32e","wallet_category":"heavy","transaction_type":"swap"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0x5d0bed394c1a35dcc12a70863b499807f1994cd2b3d4f53f3ebadebf4cf02018","timestamp":1645650603,"block_number":25270534,"to":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","sender":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","amount_usd":4839.085854444992,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2623.789185554057,"price_eth":1742.0049634816962,"amount":1.845,"amount_in":1.845,"amount_out":0.0}],"tokens_out":[{"address":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270","symbol":"WMATIC","amm":"uniswap_v3","network":"polygon","price_usd":1.5061892707297249,"price_eth":1.0,"amount":3212.8006409848686,"amount_in":0.0,"amount_out":3212.8006409848686}],"pair_address":"0x86f1d8390222a3691c28938ec7404a1661e618e0","wallet_address":"0x0dd89655c6ee8d660c00667625434b53112bd32e","wallet_category":"heavy","transaction_type":"swap"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0x5d0bed394c1a35dcc12a70863b499807f1994cd2b3d4f53f3ebadebf4cf02018","timestamp":1645650603,"block_number":25270534,"to":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","sender":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","amount_usd":3235.066832050649,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":1.23,"amount_in":1.23,"amount_out":0.0}],"tokens_out":[{"address":"0x769434dca303597c8fc4997bf3dab233e961eda2","symbol":"XSGD","amm":"uniswap_v3","network":"polygon","price_usd":0.7445968945528842,"price_eth":0.4939560051688091,"amount":4344.722434,"amount_in":0.0,"amount_out":4344.722434}],"pair_address":"0x8eb315dbd94469016e84098184dd55c1af2edabb","wallet_address":"0x0dd89655c6ee8d660c00667625434b53112bd32e","wallet_category":"heavy","transaction_type":"swap"},{"amm":"jetswap","chain_id":137,"direction":"in","transaction_address":"0x60f4709e1f7a37033e23106d068fbe248a734211b598a73c86d5c2c0a2ed00a7","timestamp":1645650603,"block_number":25270534,"to":"0x0dfbf1a50bdcb570bd0ff7bb307313b553a02598","sender":"0xd12bcdfb9a39be79da3bdf02557efdcd5ca59e77","amount_usd":40.00789545980349,"tokens_in":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"jetswap","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633871411260988,"amount":40.018257,"amount_in":40.018257,"amount_out":0.0}],"tokens_out":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"jetswap","network":"polygon","price_usd":2632.2662609672825,"price_eth":1746.211589545771,"amount":0.015208203772373943,"amount_in":0.0,"amount_out":0.015208203772373943}],"pair_address":"0xfeff91c350bb564ca5dc7d6f7dcd12ac092f94ff","wallet_address":"0x325a56ae86ccd523beebb3bad693257c60300032","wallet_category":"noob","transaction_type":"swap"},{"amm":"quickswap","chain_id":137,"direction":"out","transaction_address":"0x60f4709e1f7a37033e23106d068fbe248a734211b598a73c86d5c2c0a2ed00a7","timestamp":1645650603,"block_number":25270534,"to":"0xd12bcdfb9a39be79da3bdf02557efdcd5ca59e77","sender":"0xd12bcdfb9a39be79da3bdf02557efdcd5ca59e77","amount_usd":39.94507652391958,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"quickswap","network":"polygon","price_usd":2634.080184385698,"price_eth":1748.8374373491106,"amount":0.015208203772373943,"amount_in":0.015208203772373943,"amount_out":0.0}],"tokens_out":[{"address":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270","symbol":"WMATIC","amm":"quickswap","network":"polygon","price_usd":1.5061892707297249,"price_eth":1.0,"amount":26.52062214237313,"amount_in":0.0,"amount_out":26.52062214237313}],"pair_address":"0x0dfbf1a50bdcb570bd0ff7bb307313b553a02598","wallet_address":"0x325a56ae86ccd523beebb3bad693257c60300032","wallet_category":"noob","transaction_type":"swap"},{"amm":"sushiswap","chain_id":137,"direction":"out","transaction_address":"0xacac09e20049289cce1f5b81f2512e429abdbccca8eb9e84c1c65f09e2a61877","timestamp":1645650603,"block_number":25270534,"to":"0x1b02da8cb0d097eb8d57a175b88c7d8b47997506","sender":"0x1b02da8cb0d097eb8d57a175b88c7d8b47997506","amount_usd":67.53023516550269,"tokens_in":[{"address":"0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39","symbol":"LINK","amm":"sushiswap","network":"polygon","price_usd":13.865995104068453,"price_eth":9.198522850956453,"amount":2.435102373059705,"amount_in":2.435102373059705,"amount_out":0.0},{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"sushiswap","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":0.012841563539959779,"amount_in":0.012841563539959779,"amount_out":0.0}],"tokens_out":[],"pair_address":"0x74d23f21f780ca26b47db16b0504f2e3832b9321","wallet_address":"0x2e822887361d618ad80a4fbe24da7d8521f712c2","wallet_category":null,"transaction_type":"mint"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0xc50d7efd9150cfc9fdd04d31309b601371adb074bf561de09368efd461fcc50a","timestamp":1645650603,"block_number":25270534,"to":"0xeb3d51c1740b71d2c336806e04897b1568bbfd7c","sender":"0xe592427a0aece92de3edee1f18e0157c05861564","amount_usd":2077.9006189538604,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2625.4754887225076,"price_eth":1741.7066785602713,"amount":0.792,"amount_in":0.792,"amount_out":0.0}],"tokens_out":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"uniswap_v3","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633871411260988,"amount":2078.438769,"amount_in":0.0,"amount_out":2078.438769}],"pair_address":"0x45dda9cb7c25131df268515131f647d726f50608","wallet_address":"0x0000000078b7076edd7c78e7873e39c446284480","wallet_category":"bot","transaction_type":"swap"},{"amm":"dfyn","chain_id":137,"direction":"in","transaction_address":"0xd68524a01d4f1a471d165d27665bf82e95e55136b0e70f08a990dc75d0ab0826","timestamp":1645650603,"block_number":25270534,"to":"0x64ac1107923413b6faf0168e2063c1d4cb01bc9b","sender":"0x139b341c75d016a2df262f9babb4f8c794484d41","amount_usd":1.3255504083616483,"tokens_in":[{"address":"0xc168e40227e4ebd8c1cae80f7a55a4f0e6d66c97","symbol":"DFYN","amm":"dfyn","network":"polygon","price_usd":0.09275529258662499,"price_eth":0.06153266837335598,"amount":14.33377439994291,"amount_in":14.33377439994291,"amount_out":0.0}],"tokens_out":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"dfyn","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":0.000504133881739875,"amount_in":0.0,"amount_out":0.000504133881739875}],"pair_address":"0x6fa867bbfdd025780a8cfe988475220aff51fb8b","wallet_address":"0x24a66f8dd7abdbf6f923795a5d4a009ba1b5e011","wallet_category":"heavy","transaction_type":"swap"}]}
I'm working on a telegram bot that reports transaction information to users in a channel. The transaction information is pulled via an HTTP request using standard "application/json" response.
The application does two passthroughs: the first one returns the current market price for tokens it checks. The second one, provides all new transactions that occurred after the last checked timestamp. Here is the current code, minus the API keys. API Keys were removed for privacy.
using Newtonsoft.Json;
using Telegram.Bot;
using Telegram.Bot.Exceptions;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
namespace TelegramBotGeneric
{
class PriceObject
{
public string address { get; set; } = string.Empty;
public double volume_24h { get; set; }
public double liquidity { get; set; }
public double volume_24h_usd { get; set; }
public double liquidty_usd { get; set; }
public double price_usd { get; set; }
public double volume_24h_delta { get; set; }
public double liquidity_24H_delta { get; set; }
public double volume_24h_delta_usd { get; set; }
public double liquidty_24h_delta_usd { get; set; }
public double price_25h_delta_usd{ get; set; }
public double timestamp { get; set; }
public PriceObject()
{
//default CTOR
}
}
class tokensTransfered
{
public string address { get; set; } = string.Empty;
public string symbol { get; set; } = string.Empty;
public string amm { get; set; } = string.Empty;
public string network { get; set; } = string.Empty;
public double price_usd { get; set; }
public double price_eth { get; set; }
public double amount { get; set; }
public double amount_in { get; set; }
public double amount_out { get; set; }
public tokensTransfered()
{
//defaut CTOR
}
}
class returnedTransaction
{
public string amm { get; set; } = string.Empty;
public long chain_id { get; set; }
public string direction { get; set; } = string.Empty;
public string transaction_address { get; set; } = string.Empty;
public double timestamp { get; set; }
public double block_number { get; set; }
public string to { get; set; } = string.Empty;
public string sender { get; set; } = string.Empty;
public double amount_usd { get; set; }
public List<tokensTransfered> tokens_in { get; set; } = new List<tokensTransfered>();
public List<tokensTransfered> tokens_out { get; set; } = new List<tokensTransfered>();
public string pair_address { get; set; } = string.Empty;
public string wallet_address { get; set; } = string.Empty;
public string wallet_category { get; set; } = string.Empty;
public string transaction_type { get; set; } = String.Empty;
public returnedTransaction()
{
//default CTOR
}
}
public class TelegramBot
{
//Readonly Declarators for API Information and Query Strings
private static readonly string TB_BASE_IMAGES_DIRECTORY = @Directory.GetCurrentDirectory() + "\\images";
private static readonly string TB_API_ADDR = "https://api.dev.dex.guru/v1/chain/137/tokens/";
private static readonly string DEXGURU_MARKET_API_KEY =
"/market?api-key=";
private static readonly string DEXGURU_TRANSACTIONS_API_KEY =
"/transactions?api-key=";
private static readonly string TELEGRAM_BOT_API_KEY = "";
private static readonly int TB_MAX_TIME_BETWEEN_POLLING = 10;
private static readonly int TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR = 15;
//declarators for TelegramBot API
private static TelegramBotClient client = new TelegramBotClient(TELEGRAM_BOT_API_KEY);
private static CancellationTokenSource cts = new CancellationTokenSource();
//private static IEnumerable<BotCommand> botCommands;
//storage containers for Image URL and Contract addresses
public static Dictionary<string, string> tbBotCheckableContractAddresses { get; set; } = new Dictionary<string, string>();
public static string[] tbBotImgFileURL { get; set; } = new string[] { };
//variables for time calculation
private static DateTime lastUpdateTime = new();
private static int tbCurrentTimeBetweenPolling = 0;
private static bool tbFirstPassthrough = true;
private static bool tbContinuePolling = true;
private static double tbTransactionLastCheckedTimestamp = 0;
//variables for HTTPRequest Information
private static HttpClient tbHttpClient = new HttpClient();
private static Dictionary<string, double> tbApiReturnedPrices { get; set; } = new Dictionary<string, double>();
private static Dictionary<string, double> tbApiPreviousPrices { get; set; } = new Dictionary<string, double>();
private static string tbCurrentlyPolledAddress = "";
public static async Task Main(string[] args)
{
lastUpdateTime = DateTime.Now;
tbAddAddressesToCheckist();
tbAddDefaultPrices();
tbCurrentTimeBetweenPolling = TB_MAX_TIME_BETWEEN_POLLING;
do
{
if(tbFirstPassthrough)
{
//first we want to check prices
await tbCompletePriceUpdate();
//TEST - output to Telegram the price of TDL
/*Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: "The Current Price of Tidal" + Environment.NewLine +
"**TDL/USD**: quot; + Regex.Escape(tbApiReturnedPrices["TDL"].ToString() + " per TDL.")
+ Environment.NewLine + "**TDL/WETH**: "
+ Regex.Escape((tbApiReturnedPrices["WETH"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WETH"])* 100)).ToString() + " WETH per TDL. (WETH = " + tbApiReturnedPrices["WETH"] + ")")
+ Environment.NewLine + "**TDL/WBTC**: "
+ Regex.Escape((tbApiReturnedPrices["WBTC"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WBTC"])* 100)).ToString() + " WBTC per TDL. (WBTC = " + tbApiReturnedPrices["WBTC"] + ")"),
parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
lastUpdateTime = DateTime.Now;*/
await tbFetchNewProcessedOrders(tbBotCheckableContractAddresses["WETH"]);
}
else if((DateTime.Now - lastUpdateTime).Minutes >= TB_MAX_TIME_BETWEEN_POLLING)
{
//first we want to check prices
await tbCompletePriceUpdate();
//TEST - output to Telegram the price of TDL
/*Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: "The Current Price of Tidal" + Environment.NewLine +
"**TDL/USD**: quot; + Regex.Escape(tbApiReturnedPrices["TDL"].ToString() + " per TDL.")
+ Environment.NewLine + "**TDL/WETH**: "
+ Regex.Escape((tbApiReturnedPrices["WETH"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WETH"])* 100)).ToString() + " WETH per TDL. (WETH = " + tbApiReturnedPrices["WETH"] + ")")
+ Environment.NewLine + "**TDL/WBTC**: "
+ Regex.Escape((tbApiReturnedPrices["WBTC"] * ((tbApiReturnedPrices["TDL"] / tbApiReturnedPrices["WBTC"])* 100)).ToString() + " WBTC per TDL. (WBTC = " + tbApiReturnedPrices["WBTC"] + ")"),
parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
lastUpdateTime = DateTime.Now;*/
await tbFetchNewProcessedOrders(tbBotCheckableContractAddresses["WETH"]);
}
else
{
//something here
await tbFetchNewProcessedOrders(tbBotCheckableContractAddresses["WETH"]);
}
} while (tbContinuePolling);
}
private static void tbAddAddressesToCheckist()
{
tbBotCheckableContractAddresses.Add("TDL", "0x896219cfa4dF4AB30A418355928724d8B5D25FAC");
//tbBotCheckableContractAddresses.Add("WMATIC", "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270");
//tbBotCheckableContractAddresses.Add("WBNB", "0x3BA4c387f786bFEE076A58914F5Bd38d668B42c3");
tbBotCheckableContractAddresses.Add("WETH", "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619");
tbBotCheckableContractAddresses.Add("WBTC", "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6");
}
public static void tbAddDefaultPrices()
{
tbApiReturnedPrices.Add("TDL", 0);
//tbApiReturnedPrices.Add("WMATIC", 0);
//tbApiReturnedPrices.Add("WBNB", 0);
tbApiReturnedPrices.Add("WETH", 0);
tbApiReturnedPrices.Add("WBTC", 0);
tbApiPreviousPrices = tbApiReturnedPrices;
}
private static void tbHttpClientSetup(string address)
{
tbHttpClient = new HttpClient();
tbHttpClient.DefaultRequestHeaders.Accept.Clear();
tbHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
tbCurrentlyPolledAddress = address;
}
private static async Task tbHttpClientGetPriceData()
{
HttpResponseMessage response = await tbHttpClient.GetAsync(new Uri(TB_API_ADDR + tbCurrentlyPolledAddress + DEXGURU_MARKET_API_KEY));
response.EnsureSuccessStatusCode();
if(response.IsSuccessStatusCode)
{
try
{
PriceObject jsonResponse = JsonConvert.DeserializeObject<PriceObject>(await response.Content.ReadAsStringAsync());
if (jsonResponse == null)
throw new ArgumentException();
tbApiReturnedPrices[(tbBotCheckableContractAddresses.FirstOrDefault(x => x.Value == tbCurrentlyPolledAddress).Key)] = jsonResponse.price_usd;
Console.WriteLine("Retrieved Price Update For Contract " + tbCurrentlyPolledAddress);
}
catch (Exception ex) when(ex is ArgumentException || ex is NullReferenceException)
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Error: "
+ ex.Message);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + ex.HResult), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
else
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Status: "
+ response.StatusCode);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + response.StatusCode), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
private static async Task tbCompletePriceUpdate()
{
foreach(KeyValuePair<string, string> pair in tbBotCheckableContractAddresses)
{
tbHttpClientSetup(pair.Value);
await tbHttpClientGetPriceData();
tbApiPreviousPrices = tbApiReturnedPrices;
}
}
private static async Task tbFetchNewProcessedOrders(string address)
{
//setup the HTTP Client
tbHttpClientSetup(address);
string polledAddress = tbBotCheckableContractAddresses.FirstOrDefault(x => x.Value == address).Key;
returnedTransaction[] transactions;
//get the response
HttpResponseMessage response = await tbHttpClient.GetAsync(new Uri(TB_API_ADDR + tbCurrentlyPolledAddress + DEXGURU_TRANSACTIONS_API_KEY));
response.EnsureSuccessStatusCode();
if (response != null)
{
try
{
//Console.WriteLine(await response.Content.ReadAsStringAsync());
transactions = JsonConvert.DeserializeObject<returnedTransaction[]>(await response.Content.ReadAsStringAsync());
if (transactions == null)
throw new ArgumentException();
foreach(returnedTransaction transaction in transactions)
{
if(tbTransactionLastCheckedTimestamp == 0)
{
tbTransactionLastCheckedTimestamp = transaction.timestamp;
Console.WriteLine(
(transaction.amount_usd / tbApiReturnedPrices[polledAddress]) + " " + polledAddress +
" was purchased for quot; + transaction.amount_usd + ".");
Thread.Sleep(2000);
}
else
{
if (tbTransactionLastCheckedTimestamp < transaction.timestamp)
tbTransactionLastCheckedTimestamp = transaction.timestamp;
Console.WriteLine(
((double)transaction.amount_usd / tbApiReturnedPrices[polledAddress]) + " " + polledAddress +
" was purchased for quot; + transaction.amount_usd + ".");
Thread.Sleep(2000);
}
}
} catch (Exception ex) when (ex is ArgumentException || ex is NullReferenceException)
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Error: "
+ ex.Message);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + ex.HResult), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
else
{
Console.WriteLine("Error getting transaction updates For Contract " + tbCurrentlyPolledAddress + ". Status: "
+ response.StatusCode);
Message statusMessage = await client.SendTextMessageAsync(chatId: -765409926,
text: Regex.Escape("Error: An error occured when getting transaction data from source. Trying again in "
+ TB_MAX_TIME_BETWEEN_REFRESH_ON_ERROR + "Minutes. Status: " + response.StatusCode), parseMode: ParseMode.MarkdownV2,
disableNotification: true, cancellationToken: cts.Token);
}
}
private static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
{
// Only process Message updates: https://core.telegram.org/bots/api#message
if (update.Type != UpdateType.Message)
return;
// Only process text messages
if (update.Message!.Type != MessageType.Text)
return;
var chatId = update.Message.Chat.Id;
var messageText = update.Message.Text;
Console.WriteLine(quot;Received a '{messageText}' message in chat {chatId}.");
// Echo received message text
Message sentMessage = await botClient.SendTextMessageAsync(
chatId: chatId,
text: "You said:\n" + messageText,
cancellationToken: cancellationToken);
}
private Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
{
var ErrorMessage = exception switch
{
ApiRequestException apiRequestException
=> quot;Telegram API Error:\n[{apiRequestException.ErrorCode}]\n{apiRequestException.Message}",
_ => exception.ToString()
};
Console.WriteLine(ErrorMessage);
return Task.CompletedTask;
}
}
}
The problem here is with the function in the above code:
private static async Task tbFetchNewProcessedOrders(string address)
This function is able to return the json data correctly from the API call, which also returns Status Code: 200 [OK]
However, when i try to deserialize the data into an array of class objects, it throws an error:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'TelegramBotGeneric.returnedTransaction[]' because the type requires a JSON array
This is although the HTTP request DOES return a json array, and the function
private static async Task tbHttpClientGetPriceData()
also deserializes in the same way, with the exception of it not needing a array of classes as it only returns 1 token price per request, and does not fail when deserializing.
Any ideas as to what is going on? am i missing something? any and all help would be appreciated.
Edit: a copy of the Json results:
{"total":10000,"data":[{"amm":"waultswap","chain_id":137,"direction":"in","transaction_address":"0xfd8baf557efb178b15fa248ae220d133f0f9fc6d80ca45006eb7f2302fee729c","timestamp":1645650607,"block_number":25270535,"to":"0xcecc7e26d0987281b7da1e3c757161ed6b20af6f","sender":"0x79bafc10542ba08593b2d775d64ed197b0b9a5f9","amount_usd":9.704910550601628,"tokens_in":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"waultswap","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633868277838665,"amount":9.707424,"amount_in":9.707424,"amount_out":0.0}],"tokens_out":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"waultswap","network":"polygon","price_usd":2623.3377574906485,"price_eth":1740.2877131473633,"amount":0.003696525837357276,"amount_in":0.0,"amount_out":0.003696525837357276}],"pair_address":"0xd928ce1d0f2642e44615768761c0f00c23e0d588","wallet_address":"0x779010626fd0c88b6013e802478f07d84de5c4d7","wallet_category":"bot","transaction_type":"swap"},{"amm":"quickswap","chain_id":137,"direction":"out","transaction_address":"0xfd8baf557efb178b15fa248ae220d133f0f9fc6d80ca45006eb7f2302fee729c","timestamp":1645650607,"block_number":25270535,"to":"0xd8d51ea2edca2c2ea15a053a5730f559d79a1570","sender":"0x79bafc10542ba08593b2d775d64ed197b0b9a5f9","amount_usd":9.719504105372957,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"quickswap","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":0.003696525837357276,"amount_in":0.003696525837357276,"amount_out":0.0}],"tokens_out":[{"address":"0x7f426f6dc648e50464a0392e60e1bb465a67e9cf","symbol":"PAUTO","amm":"quickswap","network":"polygon","price_usd":387.73659420086454,"price_eth":257.2194707368818,"amount":0.02503545234060058,"amount_in":0.0,"amount_out":0.02503545234060058}],"pair_address":"0xcecc7e26d0987281b7da1e3c757161ed6b20af6f","wallet_address":"0x779010626fd0c88b6013e802478f07d84de5c4d7","wallet_category":"bot","transaction_type":"swap"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0x5d0bed394c1a35dcc12a70863b499807f1994cd2b3d4f53f3ebadebf4cf02018","timestamp":1645650603,"block_number":25270534,"to":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","sender":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","amount_usd":24187.585904394073,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2622.4290334646125,"price_eth":1739.6856993161678,"amount":9.225,"amount_in":9.225,"amount_out":0.0}],"tokens_out":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"uniswap_v3","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633871411260988,"amount":24193.850184,"amount_in":0.0,"amount_out":24193.850184}],"pair_address":"0x45dda9cb7c25131df268515131f647d726f50608","wallet_address":"0x0dd89655c6ee8d660c00667625434b53112bd32e","wallet_category":"heavy","transaction_type":"swap"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0x5d0bed394c1a35dcc12a70863b499807f1994cd2b3d4f53f3ebadebf4cf02018","timestamp":1645650603,"block_number":25270534,"to":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","sender":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","amount_usd":4839.085854444992,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2623.789185554057,"price_eth":1742.0049634816962,"amount":1.845,"amount_in":1.845,"amount_out":0.0}],"tokens_out":[{"address":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270","symbol":"WMATIC","amm":"uniswap_v3","network":"polygon","price_usd":1.5061892707297249,"price_eth":1.0,"amount":3212.8006409848686,"amount_in":0.0,"amount_out":3212.8006409848686}],"pair_address":"0x86f1d8390222a3691c28938ec7404a1661e618e0","wallet_address":"0x0dd89655c6ee8d660c00667625434b53112bd32e","wallet_category":"heavy","transaction_type":"swap"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0x5d0bed394c1a35dcc12a70863b499807f1994cd2b3d4f53f3ebadebf4cf02018","timestamp":1645650603,"block_number":25270534,"to":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","sender":"0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45","amount_usd":3235.066832050649,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":1.23,"amount_in":1.23,"amount_out":0.0}],"tokens_out":[{"address":"0x769434dca303597c8fc4997bf3dab233e961eda2","symbol":"XSGD","amm":"uniswap_v3","network":"polygon","price_usd":0.7445968945528842,"price_eth":0.4939560051688091,"amount":4344.722434,"amount_in":0.0,"amount_out":4344.722434}],"pair_address":"0x8eb315dbd94469016e84098184dd55c1af2edabb","wallet_address":"0x0dd89655c6ee8d660c00667625434b53112bd32e","wallet_category":"heavy","transaction_type":"swap"},{"amm":"jetswap","chain_id":137,"direction":"in","transaction_address":"0x60f4709e1f7a37033e23106d068fbe248a734211b598a73c86d5c2c0a2ed00a7","timestamp":1645650603,"block_number":25270534,"to":"0x0dfbf1a50bdcb570bd0ff7bb307313b553a02598","sender":"0xd12bcdfb9a39be79da3bdf02557efdcd5ca59e77","amount_usd":40.00789545980349,"tokens_in":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"jetswap","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633871411260988,"amount":40.018257,"amount_in":40.018257,"amount_out":0.0}],"tokens_out":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"jetswap","network":"polygon","price_usd":2632.2662609672825,"price_eth":1746.211589545771,"amount":0.015208203772373943,"amount_in":0.0,"amount_out":0.015208203772373943}],"pair_address":"0xfeff91c350bb564ca5dc7d6f7dcd12ac092f94ff","wallet_address":"0x325a56ae86ccd523beebb3bad693257c60300032","wallet_category":"noob","transaction_type":"swap"},{"amm":"quickswap","chain_id":137,"direction":"out","transaction_address":"0x60f4709e1f7a37033e23106d068fbe248a734211b598a73c86d5c2c0a2ed00a7","timestamp":1645650603,"block_number":25270534,"to":"0xd12bcdfb9a39be79da3bdf02557efdcd5ca59e77","sender":"0xd12bcdfb9a39be79da3bdf02557efdcd5ca59e77","amount_usd":39.94507652391958,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"quickswap","network":"polygon","price_usd":2634.080184385698,"price_eth":1748.8374373491106,"amount":0.015208203772373943,"amount_in":0.015208203772373943,"amount_out":0.0}],"tokens_out":[{"address":"0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270","symbol":"WMATIC","amm":"quickswap","network":"polygon","price_usd":1.5061892707297249,"price_eth":1.0,"amount":26.52062214237313,"amount_in":0.0,"amount_out":26.52062214237313}],"pair_address":"0x0dfbf1a50bdcb570bd0ff7bb307313b553a02598","wallet_address":"0x325a56ae86ccd523beebb3bad693257c60300032","wallet_category":"noob","transaction_type":"swap"},{"amm":"sushiswap","chain_id":137,"direction":"out","transaction_address":"0xacac09e20049289cce1f5b81f2512e429abdbccca8eb9e84c1c65f09e2a61877","timestamp":1645650603,"block_number":25270534,"to":"0x1b02da8cb0d097eb8d57a175b88c7d8b47997506","sender":"0x1b02da8cb0d097eb8d57a175b88c7d8b47997506","amount_usd":67.53023516550269,"tokens_in":[{"address":"0x53e0bca35ec356bd5dddfebbd1fc0fd03fabad39","symbol":"LINK","amm":"sushiswap","network":"polygon","price_usd":13.865995104068453,"price_eth":9.198522850956453,"amount":2.435102373059705,"amount_in":2.435102373059705,"amount_out":0.0},{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"sushiswap","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":0.012841563539959779,"amount_in":0.012841563539959779,"amount_out":0.0}],"tokens_out":[],"pair_address":"0x74d23f21f780ca26b47db16b0504f2e3832b9321","wallet_address":"0x2e822887361d618ad80a4fbe24da7d8521f712c2","wallet_category":null,"transaction_type":"mint"},{"amm":"uniswap_v3","chain_id":137,"direction":"out","transaction_address":"0xc50d7efd9150cfc9fdd04d31309b601371adb074bf561de09368efd461fcc50a","timestamp":1645650603,"block_number":25270534,"to":"0xeb3d51c1740b71d2c336806e04897b1568bbfd7c","sender":"0xe592427a0aece92de3edee1f18e0157c05861564","amount_usd":2077.9006189538604,"tokens_in":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"uniswap_v3","network":"polygon","price_usd":2625.4754887225076,"price_eth":1741.7066785602713,"amount":0.792,"amount_in":0.792,"amount_out":0.0}],"tokens_out":[{"address":"0x2791bca1f2de4661ed88a30c99a7a9449aa84174","symbol":"USDC","amm":"uniswap_v3","network":"polygon","price_usd":0.9997410796727977,"price_eth":0.6633871411260988,"amount":2078.438769,"amount_in":0.0,"amount_out":2078.438769}],"pair_address":"0x45dda9cb7c25131df268515131f647d726f50608","wallet_address":"0x0000000078b7076edd7c78e7873e39c446284480","wallet_category":"bot","transaction_type":"swap"},{"amm":"dfyn","chain_id":137,"direction":"in","transaction_address":"0xd68524a01d4f1a471d165d27665bf82e95e55136b0e70f08a990dc75d0ab0826","timestamp":1645650603,"block_number":25270534,"to":"0x64ac1107923413b6faf0168e2063c1d4cb01bc9b","sender":"0x139b341c75d016a2df262f9babb4f8c794484d41","amount_usd":1.3255504083616483,"tokens_in":[{"address":"0xc168e40227e4ebd8c1cae80f7a55a4f0e6d66c97","symbol":"DFYN","amm":"dfyn","network":"polygon","price_usd":0.09275529258662499,"price_eth":0.06153266837335598,"amount":14.33377439994291,"amount_in":14.33377439994291,"amount_out":0.0}],"tokens_out":[{"address":"0x7ceb23fd6bc0add59e62ac25578270cff1b9f619","symbol":"WETH","amm":"dfyn","network":"polygon","price_usd":2629.3618746410916,"price_eth":1744.2848570041135,"amount":0.000504133881739875,"amount_in":0.0,"amount_out":0.000504133881739875}],"pair_address":"0x6fa867bbfdd025780a8cfe988475220aff51fb8b","wallet_address":"0x24a66f8dd7abdbf6f923795a5d4a009ba1b5e011","wallet_category":"heavy","transaction_type":"swap"}]}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我解决了。没有反序列化上层类和数组。现在它正在工作。感谢您的帮助。
I solved it. Was not deserializing the upper class and array. It is now working. thanks for your help.