diff --git a/CoinGecko.Net/Clients/CoinGeckoRestClient.cs b/CoinGecko.Net/Clients/CoinGeckoRestClient.cs index 6916b1d..aaee6b5 100644 --- a/CoinGecko.Net/Clients/CoinGeckoRestClient.cs +++ b/CoinGecko.Net/Clients/CoinGeckoRestClient.cs @@ -10,11 +10,14 @@ namespace CoinGecko.Net.Clients { /// - public class CoinGeckoRestClient: BaseRestClient, ICoinGeckoRestClient + public class CoinGeckoRestClient : BaseRestClient, ICoinGeckoRestClient { /// public ICoinGeckoRestClientApi Api { get; } + /// + public ICoinGeckoRestClientDexApi DexApi { get; } + #region constructor/destructor /// /// Create a new instance of the CoinGeckoClient using provided options @@ -37,6 +40,7 @@ public CoinGeckoRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory Initialize(options.Value); Api = AddApiClient(new CoinGeckoRestClientApi(this, _logger, httpClient, options.Value)); +DexApi = AddApiClient(new CoinGeckoRestClientDexApi(this, _logger, httpClient, options.Value)); } #endregion diff --git a/CoinGecko.Net/Clients/CoinGeckoRestClientDexApi.cs b/CoinGecko.Net/Clients/CoinGeckoRestClientDexApi.cs new file mode 100644 index 0000000..e1c895e --- /dev/null +++ b/CoinGecko.Net/Clients/CoinGeckoRestClientDexApi.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using CoinGecko.Net.Clients.MessageHandlers; +using CoinGecko.Net.Interfaces; +using CoinGecko.Net.Objects.Models; +using CoinGecko.Net.Objects.Options; +using CryptoExchange.Net.Clients; +using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; +using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Objects.Errors; +using CryptoExchange.Net.SharedApis; +using Microsoft.Extensions.Logging; + +namespace CoinGecko.Net.Clients +{ + /// + internal class CoinGeckoRestClientDexApi : RestApiClient, ICoinGeckoRestClientDexApi + { + private static readonly RequestDefinitionCache _definitions = new RequestDefinitionCache(); + private readonly CoinGeckoRestOptions _options; + + protected override IRestMessageHandler MessageHandler { get; } = new CoinGeckoRestMessageHandler(new ErrorMapping([])); + + internal CoinGeckoRestClientDexApi(CoinGeckoRestClient baseClient, ILogger logger, HttpClient? httpClient, CoinGeckoRestOptions options) + : base(logger, httpClient, options.Environment.RestApiAddressPublic, options, options.ApiOptions) + { + _options = options; + StandardRequestHeaders = new Dictionary + { + { "User-Agent", "CryptoExchange.Net/" + baseClient.CryptoExchangeLibVersion.ToString() } + }; + } + + /// + protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(SerializerOptions.WithConverters(CoinGeckoApi.SerializationContext)); + + /// + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) => throw new NotImplementedException(); + + #region Search Pools + + /// + public Task> SearchPoolsAsync(string query, string? network = null, IEnumerable? include = null, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("query", query); + parameters.AddOptional("network", network); + parameters.AddOptionalCommaSeparated("include", include); + + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/onchain/search/pools", CoinGeckoApi.RateLimiter.CoinGecko, 1, false); + return SendAsync(GetBaseAddress(), request, parameters, ct); + } + + #endregion + + #region Get Networks + + /// + public Task> GetDexNetworksAsync(int page = 1, CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.Add("page", page); + + var request = _definitions.GetOrCreate(HttpMethod.Get, "/api/v3/onchain/networks", CoinGeckoApi.RateLimiter.CoinGecko, 1, false); + return SendAsync(GetBaseAddress(), request, parameters, ct); + } + + #endregion + + + + private string GetBaseAddress() + { + if (AuthenticationProvider != null) + { + if (((CoinGeckoAuthenticationProvider)AuthenticationProvider).IsDemo) + return _options.Environment.RestApiAddressPublic; + + return _options.Environment.RestApiAddressPro; + } + + return _options.Environment.RestApiAddressPublic; + } + + /// + protected override CoinGeckoAuthenticationProvider CreateAuthenticationProvider(CoinGeckoCredentials credentials) + => new CoinGeckoAuthenticationProvider(credentials); + } +} diff --git a/CoinGecko.Net/Converters/CoinGeckoSourceGenerationContext.cs b/CoinGecko.Net/Converters/CoinGeckoSourceGenerationContext.cs index 6863ac8..8e2c4cf 100644 --- a/CoinGecko.Net/Converters/CoinGeckoSourceGenerationContext.cs +++ b/CoinGecko.Net/Converters/CoinGeckoSourceGenerationContext.cs @@ -67,6 +67,8 @@ namespace CoinGecko.Net.Converters [JsonSerializable(typeof(CoinGeckoTrendingNftData[]))] [JsonSerializable(typeof(CoinGeckoTrendingCategory[]))] [JsonSerializable(typeof(CoinGeckoTrendingCategoryData[]))] + [JsonSerializable(typeof(CoinGeckoDexNetworksResponse))] + [JsonSerializable(typeof(CoinGeckoDexSearchPoolsResponse))] [JsonSerializable(typeof(string))] [JsonSerializable(typeof(int?))] [JsonSerializable(typeof(int))] diff --git a/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs b/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs index a47ec22..305715e 100644 --- a/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs +++ b/CoinGecko.Net/Interfaces/ICoinGeckoRestClient.cs @@ -13,5 +13,11 @@ public interface ICoinGeckoRestClient : IRestClient /// /// ICoinGeckoRestClientApi Api { get; } + + /// + /// Dex Api endpoints + /// + /// + ICoinGeckoRestClientDexApi DexApi { get; } } } diff --git a/CoinGecko.Net/Interfaces/ICoinGeckoRestClientDexApi.cs b/CoinGecko.Net/Interfaces/ICoinGeckoRestClientDexApi.cs new file mode 100644 index 0000000..dea0eac --- /dev/null +++ b/CoinGecko.Net/Interfaces/ICoinGeckoRestClientDexApi.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using CoinGecko.Net.Objects.Models; +using CryptoExchange.Net.Interfaces.Clients; +using CryptoExchange.Net.Objects; + +namespace CoinGecko.Net.Interfaces +{ + /// + /// CoinGecko API endpoints + /// + public interface ICoinGeckoRestClientDexApi : IRestApiClient + { + /// + /// Get dex networks + /// + /// Docs:
+ ///
+ /// Endpoint:
+ /// GET /api/v3/onchain/networks + ///
+ ///
+ /// Page number + /// Cancellation token + /// + Task> GetDexNetworksAsync(int page = 1, CancellationToken ct = default); + + /// + /// Search pools + /// + /// Docs:
+ ///

+ /// Endpoint:
+ /// GET /api/v3/onchain/search/pools + /// + ///
+ /// Search query, can be pool contract address, token name, token symbol, or token contract address + /// The network id + /// Attributes to include. Available values: base_token, quote_token, dex + /// Cancellation token + /// + Task> SearchPoolsAsync(string query, string? network = null, IEnumerable? include = null, CancellationToken ct = default); + + + } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexItem.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexItem.cs new file mode 100644 index 0000000..ae4cfb8 --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexItem.cs @@ -0,0 +1,49 @@ +using System.Text.Json.Serialization; + +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex item with attributes and relationships + /// + [SerializationModel] + public record CoinGeckoDexItem : CoinGeckoDexItem + { + /// + /// ["relationships"] Relationships + /// + [JsonPropertyName("relationships")] + public TRelationShip? Details { get; set; } + } + + /// + /// Dex item with attributes + /// + [SerializationModel] + public record CoinGeckoDexItem : CoinGeckoDexItem + { + /// + /// ["attributes"] Attributes + /// + [JsonPropertyName("attributes")] + public T? Details { get; set; } + } + + /// + /// Dex item + /// + [SerializationModel] + public record CoinGeckoDexItem + { + /// + /// ["id"] Id + /// + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + /// + /// ["type"] Type + /// + [JsonPropertyName("type")] + public string Type { get; set; } = string.Empty; + } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexNetwork.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexNetwork.cs new file mode 100644 index 0000000..e75bd4c --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexNetwork.cs @@ -0,0 +1,9 @@ +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex network + /// + [SerializationModel] + public record CoinGeckoDexNetwork : CoinGeckoDexItem + { } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexNetworkDetail.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexNetworkDetail.cs new file mode 100644 index 0000000..d7bbdaa --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexNetworkDetail.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex network details + /// + [SerializationModel] + public record CoinGeckoDexNetworkDetail + { + /// + /// ["name"] Name + /// + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// + /// ["coingecko_asset_platform_id"] CoinGecko asset platform id + /// + [JsonPropertyName("coingecko_asset_platform_id")] + public string? CoinGeckoAssetPlatformId { get; set; } + } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexNetworksResponse.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexNetworksResponse.cs new file mode 100644 index 0000000..dde0d75 --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexNetworksResponse.cs @@ -0,0 +1,9 @@ +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex networks response + /// + [SerializationModel] + public record CoinGeckoDexNetworksResponse : CoinGeckoDexResponsePaged + { } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexPageLinks.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexPageLinks.cs new file mode 100644 index 0000000..7714fc2 --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexPageLinks.cs @@ -0,0 +1,35 @@ +using System.Text.Json.Serialization; + +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex pagination links + /// + [SerializationModel] + public record CoinGeckoDexPageLinks + { + /// + /// ["first"] First page link + /// + [JsonPropertyName("first")] + public string First { get; set; } = string.Empty; + + /// + /// ["last"] Last page link + /// + [JsonPropertyName("last")] + public string Last { get; set; } = string.Empty; + + /// + /// ["prev"] Previous page link + /// + [JsonPropertyName("prev")] + public string? Prev { get; set; } + + /// + /// ["next"] Next page link + /// + [JsonPropertyName("next")] + public string? Next { get; set; } + } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexPool.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexPool.cs new file mode 100644 index 0000000..754ffbb --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexPool.cs @@ -0,0 +1,9 @@ +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex pool + /// + [SerializationModel] + public record CoinGeckoDexPool : CoinGeckoDexItem + { } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexPoolDetails.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexPoolDetails.cs new file mode 100644 index 0000000..e4946f5 --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexPoolDetails.cs @@ -0,0 +1,219 @@ +using System; +using System.Text.Json.Serialization; + +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex pool details + /// + [SerializationModel] + public record CoinGeckoDexPoolDetails + { + /// + /// ["base_token_price_usd"] Base token price in USD + /// + [JsonPropertyName("base_token_price_usd")] + public decimal BaseTokenPriceUsd { get; set; } + + /// + /// ["base_token_price_native_currency"] Base token price in native currency + /// + [JsonPropertyName("base_token_price_native_currency"), JsonConverter(typeof(DecimalConverter))] + public decimal? BaseTokenPriceNativeCurrency { get; set; } + + /// + /// ["quote_token_price_usd"] Quote token price in USD + /// + [JsonPropertyName("quote_token_price_usd"), JsonConverter(typeof(DecimalConverter))] + public decimal? QuoteTokenPriceUsd { get; set; } + + /// + /// ["quote_token_price_native_currency"] Quote token price in native currency + /// + [JsonPropertyName("quote_token_price_native_currency"), JsonConverter(typeof(DecimalConverter))] + public decimal? QuoteTokenPriceNativeCurrency { get; set; } + + /// + /// ["base_token_price_quote_token"] Base token price in quote token + /// + [JsonPropertyName("base_token_price_quote_token"), JsonConverter(typeof(DecimalConverter))] + public decimal? BaseTokenPriceQuoteToken { get; set; } + + /// + /// ["quote_token_price_base_token"] Quote token price in base token + /// + [JsonPropertyName("quote_token_price_base_token"), JsonConverter(typeof(DecimalConverter))] + public decimal? QuoteTokenPriceBaseToken { get; set; } + + /// + /// ["address"] Pool address + /// + [JsonPropertyName("address")] + public string Address { get; set; } = string.Empty; + + /// + /// ["name"] Name + /// + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// + /// ["pool_created_at"] Pool creation time + /// + [JsonPropertyName("pool_created_at")] + public DateTime PoolCreatedAt { get; set; } + + /// + /// ["fdv_usd"] Fully diluted valuation in USD + /// + [JsonPropertyName("fdv_usd")] + public decimal? FullyDilutedValuationUsd { get; set; } + + /// + /// ["market_cap_usd"] Market cap in USD + /// + [JsonPropertyName("market_cap_usd")] + public decimal? MarketCapUsd { get; set; } + + /// + /// ["price_change_percentage"] Price change percentage + /// + [JsonPropertyName("price_change_percentage")] + public CoinGeckoDexTimeValues? PriceChangePercentage { get; set; } + + /// + /// ["transactions"] Transactions + /// + [JsonPropertyName("transactions")] + public CoinGeckoDexTransactions? Transactions { get; set; } + + /// + /// ["volume_usd"] Volume in USD + /// + [JsonPropertyName("volume_usd")] + public CoinGeckoDexTimeValues? VolumeUsd { get; set; } + + /// + /// ["reserve_in_usd"] Reserve in USD + /// + [JsonPropertyName("reserve_in_usd")] + public decimal? ReserveInUsd { get; set; } + } + + /// + /// Dex time interval values + /// + [SerializationModel] + public record CoinGeckoDexTimeValues + { + /// + /// ["m5"] Five minutes + /// + [JsonPropertyName("m5")] + public decimal FiveMinutes { get; set; } + + /// + /// ["m15"] Fifteen minutes + /// + [JsonPropertyName("m15")] + public decimal FifteenMinutes { get; set; } + + /// + /// ["m30"] Thirty minutes + /// + [JsonPropertyName("m30")] + public decimal ThirtyMinutes { get; set; } + + /// + /// ["h1"] One hour + /// + [JsonPropertyName("h1")] + public decimal OneHour { get; set; } + + /// + /// ["h6"] Six hours + /// + [JsonPropertyName("h6")] + public decimal SixHours { get; set; } + + /// + /// ["h24"] Twenty four hours + /// + [JsonPropertyName("h24")] + public decimal OneDay { get; set; } + } + + /// + /// Dex transaction counts per time interval + /// + [SerializationModel] + public record CoinGeckoDexTransactions + { + /// + /// ["m5"] Five minutes + /// + [JsonPropertyName("m5")] + public CoinGeckoDexTransactionCounts? FiveMinutes { get; set; } + + /// + /// ["m15"] Fifteen minutes + /// + [JsonPropertyName("m15")] + public CoinGeckoDexTransactionCounts? FifteenMinutes { get; set; } + + /// + /// ["m30"] Thirty minutes + /// + [JsonPropertyName("m30")] + public CoinGeckoDexTransactionCounts? ThirtyMinutes { get; set; } + + /// + /// ["h1"] One hour + /// + [JsonPropertyName("h1")] + public CoinGeckoDexTransactionCounts? OneHour { get; set; } + + /// + /// ["h6"] Six hours + /// + [JsonPropertyName("h6")] + public CoinGeckoDexTransactionCounts? SixHours { get; set; } + + /// + /// ["h24"] Twenty four hours + /// + [JsonPropertyName("h24")] + public CoinGeckoDexTransactionCounts? OneDay { get; set; } + } + + /// + /// Dex transaction counts + /// + [SerializationModel] + public record CoinGeckoDexTransactionCounts + { + /// + /// ["buys"] Number of buys + /// + [JsonPropertyName("buys")] + public int Buys { get; set; } + + /// + /// ["sells"] Number of sells + /// + [JsonPropertyName("sells")] + public int Sells { get; set; } + + /// + /// ["buyers"] Number of buyers + /// + [JsonPropertyName("buyers")] + public int? Buyers { get; set; } + + /// + /// ["sellers"] Number of sellers + /// + [JsonPropertyName("sellers")] + public int? Sellers { get; set; } + } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexPoolRelationShip.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexPoolRelationShip.cs new file mode 100644 index 0000000..aa084bd --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexPoolRelationShip.cs @@ -0,0 +1,43 @@ +using System.Text.Json.Serialization; +using CoinGecko.Net.Objects.Models; + +namespace CoinGecko.Net.Objects +{ + /// + /// Dex pool relationships + /// + [SerializationModel] + public record CoinGeckoDexPoolRelationShip + { + /// + /// ["base_token"] Base token + /// + [JsonPropertyName("base_token")] + public CoinGeckoDexPoolRelationShipItem? BaseToken { get; set; } + + /// + /// ["quote_token"] Quote token + /// + [JsonPropertyName("quote_token")] + public CoinGeckoDexPoolRelationShipItem? QuoteToken { get; set; } + + /// + /// ["dex"] Dex + /// + [JsonPropertyName("dex")] + public CoinGeckoDexPoolRelationShipItem? Dex { get; set; } + } + + /// + /// Dex pool relationship item + /// + [SerializationModel] + public record CoinGeckoDexPoolRelationShipItem + { + /// + /// ["data"] Data + /// + [JsonPropertyName("data")] + public CoinGeckoDexItem? Data { get; set; } + } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexResponse.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexResponse.cs new file mode 100644 index 0000000..117dc2e --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexResponse.cs @@ -0,0 +1,64 @@ +using System.Text.Json.Serialization; +using CoinGecko.Net.Objects.Models; + +namespace CoinGecko.Net.Objects +{ + /// + /// Dex response + /// + [SerializationModel] + public record CoinGeckoDexResponse + where TData : CoinGeckoDexItem + { + /// + /// ["data"] Data + /// + [JsonPropertyName("data")] + public TData[] Data { get; set; } = []; + } + + + /// + /// Dex response with included items + /// + [SerializationModel] + public record CoinGeckoDexResponse : CoinGeckoDexResponse + where TData : CoinGeckoDexItem + where TInclude : CoinGeckoDexItem + { + /// + /// ["included"] Included items + /// + [JsonPropertyName("included")] + public TInclude[] Included { get; set; } = []; + } + + /// + /// Paged dex response + /// + [SerializationModel] + public record CoinGeckoDexResponsePaged : CoinGeckoDexResponse + where TData : CoinGeckoDexItem + { + /// + /// ["links"] Page links + /// + [JsonPropertyName("links")] + public CoinGeckoDexPageLinks PageLinks { get; set; } = new(); + } + + /// + /// Paged dex response with included items + /// + [SerializationModel] + public record CoinGeckoDexResponsePaged : CoinGeckoDexResponse + where TData : CoinGeckoDexItem + where TInclude : CoinGeckoDexItem + { + /// + /// ["links"] Page links + /// + [JsonPropertyName("links")] + public CoinGeckoDexPageLinks PageLinks { get; set; } = new(); + } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexSearchPoolsResponse.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexSearchPoolsResponse.cs new file mode 100644 index 0000000..9bf583a --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexSearchPoolsResponse.cs @@ -0,0 +1,9 @@ +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex search pools response + /// + [SerializationModel] + public record CoinGeckoDexSearchPoolsResponse : CoinGeckoDexResponse + { } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexToken.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexToken.cs new file mode 100644 index 0000000..3619b16 --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexToken.cs @@ -0,0 +1,9 @@ +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex token + /// + [SerializationModel] + public record CoinGeckoDexToken : CoinGeckoDexItem + { } +} diff --git a/CoinGecko.Net/Objects/Models/CoinGeckoDexTokenDetail.cs b/CoinGecko.Net/Objects/Models/CoinGeckoDexTokenDetail.cs new file mode 100644 index 0000000..fb185c9 --- /dev/null +++ b/CoinGecko.Net/Objects/Models/CoinGeckoDexTokenDetail.cs @@ -0,0 +1,47 @@ +using System.Text.Json.Serialization; + +namespace CoinGecko.Net.Objects.Models +{ + /// + /// Dex token details + /// + [SerializationModel] + public record CoinGeckoDexTokenDetail + { + /// + /// ["address"] Address + /// + [JsonPropertyName("address")] + public string Address { get; set; } = string.Empty; + + /// + /// ["name"] Name + /// + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + /// + /// ["symbol"] Symbol + /// + [JsonPropertyName("symbol")] + public string Symbol { get; set; } = string.Empty; + + /// + /// ["icon_url"] Icon URL + /// + [JsonPropertyName("icon_url")] + public string? IconUrl { get; set; } + + /// + /// ["decimals"] Decimals + /// + [JsonPropertyName("decimals")] + public int Decimals { get; set; } + + /// + /// ["coingecko_coin_id"] CoinGecko coin id + /// + [JsonPropertyName("coingecko_coin_id")] + public string? CoinGeckoCoinId { get; set; } + } +}