From 5e469ff9c05b7e3ad9a1eb38ab86970ecc828294 Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Mon, 10 Jul 2023 10:31:48 +0200 Subject: [PATCH] Improve rates (#5166) * Removes Chaincoin shitcoin which is so dead even its website is gone * Add ExchangeRateHost and FreeCurrencyRates as new rate providers * Add recommended rate providers for UGX and RSD * Fix BTX rate by switching to graviex * Fix BTC rate by switching to exmo * Fix LCAD rate script --- .../Altcoins/BTCPayNetworkProvider.BGold.cs | 2 +- .../Altcoins/BTCPayNetworkProvider.Bitcore.cs | 2 +- .../BTCPayNetworkProvider.Chaincoin.cs | 32 --------------- .../BTCPayNetworkProvider.LiquidAssets.cs | 1 + BTCPayServer.Common/BTCPayNetworkProvider.cs | 1 - .../Providers/ExchangeRateHostRateProvider.cs | 40 +++++++++++++++++++ .../FreeCurrencyRatesRateProvider.cs | 36 +++++++++++++++++ BTCPayServer.Tests/ThirdPartyTests.cs | 29 +++++++++++--- BTCPayServer/Data/StoreBlob.cs | 4 +- BTCPayServer/Hosting/BTCPayServerServices.cs | 2 + 10 files changed, 108 insertions(+), 41 deletions(-) delete mode 100644 BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Chaincoin.cs create mode 100644 BTCPayServer.Rating/Providers/ExchangeRateHostRateProvider.cs create mode 100644 BTCPayServer.Rating/Providers/FreeCurrencyRatesRateProvider.cs diff --git a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.BGold.cs b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.BGold.cs index f96cf6b02..797587791 100644 --- a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.BGold.cs +++ b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.BGold.cs @@ -16,7 +16,7 @@ namespace BTCPayServer DefaultRateRules = new[] { "BTG_X = BTG_BTC * BTC_X", - "BTG_BTC = bitfinex(BTG_BTC)", + "BTG_BTC = exmo(BTG_BTC)", }, CryptoImagePath = "imlegacy/btg.svg", LightningImagePath = "imlegacy/btg-lightning.svg", diff --git a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcore.cs b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcore.cs index e1dbad24b..6d7b9e9f6 100644 --- a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcore.cs +++ b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcore.cs @@ -17,7 +17,7 @@ namespace BTCPayServer DefaultRateRules = new[] { "BTX_X = BTX_BTC * BTC_X", - "BTX_BTC = hitbtc(BTX_BTC)" + "BTX_BTC = graviex(BTX_BTC)" }, CryptoImagePath = "imlegacy/bitcore.svg", LightningImagePath = "imlegacy/bitcore-lightning.svg", diff --git a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Chaincoin.cs b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Chaincoin.cs deleted file mode 100644 index 0547e03f0..000000000 --- a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Chaincoin.cs +++ /dev/null @@ -1,32 +0,0 @@ -using NBitcoin; - -namespace BTCPayServer -{ - public partial class BTCPayNetworkProvider - { - public void InitChaincoin() - { - var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("CHC"); - Add(new BTCPayNetwork() - { - CryptoCode = nbxplorerNetwork.CryptoCode, - DisplayName = "Chaincoin", - BlockExplorerLink = NetworkType == ChainName.Mainnet - ? "https://explorer.chaincoin.org/Explorer/Transaction/{0}" - : "https://test.explorer.chaincoin.org/Explorer/Transaction/tx/{0}", - NBXplorerNetwork = nbxplorerNetwork, - DefaultRateRules = new[] - { - "CHC_X = CHC_BTC * BTC_X", - "CHC_BTC = txbit(CHC_X)" - }, - CryptoImagePath = "imlegacy/chaincoin.png", - DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType), - //https://github.com/satoshilabs/slips/blob/master/slip-0044.md - CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("711'") - : new KeyPath("1'") - }); - } - } -} - diff --git a/BTCPayServer.Common/Altcoins/Liquid/BTCPayNetworkProvider.LiquidAssets.cs b/BTCPayServer.Common/Altcoins/Liquid/BTCPayNetworkProvider.LiquidAssets.cs index 0f49aafc5..d257e8b72 100644 --- a/BTCPayServer.Common/Altcoins/Liquid/BTCPayNetworkProvider.LiquidAssets.cs +++ b/BTCPayServer.Common/Altcoins/Liquid/BTCPayNetworkProvider.LiquidAssets.cs @@ -63,6 +63,7 @@ namespace BTCPayServer "LCAD_CAD = 1", "LCAD_X = CAD_BTC * BTC_X", "LCAD_BTC = bylls(CAD_BTC)", + "CAD_BTC = LCAD_BTC" }, AssetId = new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"), DisplayName = "Liquid CAD", diff --git a/BTCPayServer.Common/BTCPayNetworkProvider.cs b/BTCPayServer.Common/BTCPayNetworkProvider.cs index 1d587afa1..2888d9bac 100644 --- a/BTCPayServer.Common/BTCPayNetworkProvider.cs +++ b/BTCPayServer.Common/BTCPayNetworkProvider.cs @@ -56,7 +56,6 @@ namespace BTCPayServer InitViacoin(); InitMonero(); InitZcash(); - InitChaincoin(); // InitArgoneum();//their rate source is down 9/15/20. // InitMonetaryUnit(); Not supported from Bittrex from 11/23/2022, dead shitcoin diff --git a/BTCPayServer.Rating/Providers/ExchangeRateHostRateProvider.cs b/BTCPayServer.Rating/Providers/ExchangeRateHostRateProvider.cs new file mode 100644 index 000000000..96497199e --- /dev/null +++ b/BTCPayServer.Rating/Providers/ExchangeRateHostRateProvider.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using BTCPayServer.Rating; +using Newtonsoft.Json.Linq; + +namespace BTCPayServer.Services.Rates; + + +public class ExchangeRateHostRateProvider : IRateProvider +{ + public RateSourceInfo RateSourceInfo => new("exchangeratehost", "Yadio", "https://api.exchangerate.host/latest?base=BTC"); + private readonly HttpClient _httpClient; + public ExchangeRateHostRateProvider(HttpClient httpClient) + { + _httpClient = httpClient ?? new HttpClient(); + } + + public async Task GetRatesAsync(CancellationToken cancellationToken) + { + var response = await _httpClient.GetAsync(RateSourceInfo.Url, cancellationToken); + response.EnsureSuccessStatusCode(); + var jobj = await response.Content.ReadAsAsync(cancellationToken); + if(jobj["success"].Value() is not true || !jobj["base"].Value().Equals("BTC", StringComparison.InvariantCulture)) + throw new Exception("exchangerate.host returned a non success response or the base currency was not the requested one (BTC)"); + var results = (JObject) jobj["rates"] ; + //key value is currency code to rate value + var list = new List(); + foreach (var item in results) + { + string name = item.Key; + var value = item.Value.Value(); + list.Add(new PairRate(new CurrencyPair("BTC", name), new BidAsk(value))); + } + + return list.ToArray(); + } +} diff --git a/BTCPayServer.Rating/Providers/FreeCurrencyRatesRateProvider.cs b/BTCPayServer.Rating/Providers/FreeCurrencyRatesRateProvider.cs new file mode 100644 index 000000000..29f342f29 --- /dev/null +++ b/BTCPayServer.Rating/Providers/FreeCurrencyRatesRateProvider.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using BTCPayServer.Rating; +using Newtonsoft.Json.Linq; + +namespace BTCPayServer.Services.Rates; + +public class FreeCurrencyRatesRateProvider : IRateProvider +{ + public RateSourceInfo RateSourceInfo => new("free-currency-rates", "Free Currency Rates", "https://cdn.jsdelivr.net/gh/fawazahmed0/currency-api@1/latest/currencies/btc.min.json"); + private readonly HttpClient _httpClient; + public FreeCurrencyRatesRateProvider(HttpClient httpClient) + { + _httpClient = httpClient ?? new HttpClient(); + } + + public async Task GetRatesAsync(CancellationToken cancellationToken) + { + var response = await _httpClient.GetAsync(RateSourceInfo.Url, cancellationToken); + response.EnsureSuccessStatusCode(); + var jobj = await response.Content.ReadAsAsync(cancellationToken); + var results = (JObject) jobj["btc"] ; + //key value is currency code to rate value + var list = new List(); + foreach (var item in results) + { + string name = item.Key; + var value = item.Value.Value(); + list.Add(new PairRate(new CurrencyPair("BTC", name), new BidAsk(value))); + } + + return list.ToArray(); + } +} diff --git a/BTCPayServer.Tests/ThirdPartyTests.cs b/BTCPayServer.Tests/ThirdPartyTests.cs index 0a92d3ccc..b0fd0f116 100644 --- a/BTCPayServer.Tests/ThirdPartyTests.cs +++ b/BTCPayServer.Tests/ThirdPartyTests.cs @@ -290,9 +290,9 @@ retry: } [Fact] - public void CanGetRateCryptoCurrenciesByDefault() + public async Task CanGetRateCryptoCurrenciesByDefault() { - string[] brokenShitcoins = { "BTX_USD", "CHC_USD" }; + string[] brokenShitcoins = { }; var provider = new BTCPayNetworkProvider(ChainName.Mainnet); var factory = FastTests.CreateBTCPayRateFactory(); var fetcher = new RateFetcher(factory); @@ -305,14 +305,33 @@ retry: var result = fetcher.FetchRates(pairs, rules, default); foreach ((CurrencyPair key, Task value) in result) { - var rateResult = value.GetAwaiter().GetResult(); - if (key.ToString() == "BTG_USD") - continue; // shitcoin not supported by bitfinex anymore + var rateResult = await value; TestLogs.LogInformation($"Testing {key}"); if (brokenShitcoins.Contains(key.ToString())) continue; Assert.True(rateResult.BidAsk != null, $"Impossible to get the rate {rateResult.EvaluatedRule}"); } + + var b = new StoreBlob(); + foreach (var k in StoreBlob.RecommendedExchanges) + { + b.DefaultCurrency = k.Key; + rules = b.GetDefaultRateRules(provider); + pairs = + provider.GetAll() + .Select(c => new CurrencyPair(c.CryptoCode, k.Key)) + .ToHashSet(); + result = fetcher.FetchRates(pairs, rules, default); + foreach ((CurrencyPair key, Task value) in result) + { + var rateResult = await value; + TestLogs.LogInformation($"Testing {key} when default currency is {k.Key}"); + if (brokenShitcoins.Contains(key.ToString())) + continue; + Assert.True(rateResult.BidAsk != null, $"Impossible to get the rate {rateResult.EvaluatedRule}"); + } + } + } [Fact] diff --git a/BTCPayServer/Data/StoreBlob.cs b/BTCPayServer/Data/StoreBlob.cs index 320cec3ec..110e7aae3 100644 --- a/BTCPayServer/Data/StoreBlob.cs +++ b/BTCPayServer/Data/StoreBlob.cs @@ -199,7 +199,9 @@ namespace BTCPayServer.Data { "GTQ", "bitpay" }, { "COP", "yadio" }, { "JPY", "bitbank" }, - { "TRY", "btcturk" } + { "TRY", "btcturk" }, + { "UGX", "exchangeratehost"}, + { "RSD", "bitpay"} }; public string GetRecommendedExchange() => diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index 987ebcfde..a69bcdeb0 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -520,6 +520,8 @@ namespace BTCPayServer.Hosting services.AddRateProvider(); services.AddRateProvider(); services.AddRateProvider(); + services.AddRateProvider(); + services.AddRateProvider(); // Broken // Providers.Add("argoneum", new ArgoneumRateProvider(_httpClientFactory?.CreateClient("EXCHANGE_ARGONEUM")));