Do not roundup rates

This commit is contained in:
nicolas.dorier
2018-05-13 15:09:17 +09:00
parent 449738414b
commit f7fe855274
3 changed files with 47 additions and 23 deletions

View File

@@ -296,6 +296,22 @@ namespace BTCPayServer.Tests
} }
} }
[Fact]
public void RoundupCurrenciesCorrectly()
{
foreach(var test in new[]
{
(0.0005m, "$0.0005 (USD)"),
(0.001m, "$0.001 (USD)"),
(0.01m, "$0.01 (USD)"),
(0.1m, "$0.10 (USD)"),
})
{
var actual = InvoiceController.FormatCurrency(test.Item1, "USD", new CurrencyNameTable());
Assert.Equal(test.Item2, actual);
}
}
[Fact] [Fact]
public void CanPayUsingBIP70() public void CanPayUsingBIP70()
{ {
@@ -1424,7 +1440,7 @@ namespace BTCPayServer.Tests
// This check if the currency pair is using right currency pair // This check if the currency pair is using right currency pair
Assert.Contains(exchangeRates.ByExchange[result.ExpectedName], Assert.Contains(exchangeRates.ByExchange[result.ExpectedName],
e => ( e.CurrencyPair == new CurrencyPair("BTC", "USD") || e => (e.CurrencyPair == new CurrencyPair("BTC", "USD") ||
e.CurrencyPair == new CurrencyPair("BTC", "EUR") || e.CurrencyPair == new CurrencyPair("BTC", "EUR") ||
e.CurrencyPair == new CurrencyPair("BTC", "USDT")) e.CurrencyPair == new CurrencyPair("BTC", "USDT"))
&& e.Value > 1.0m // 1BTC will always be more than 1USD && e.Value > 1.0m // 1BTC will always be more than 1USD
@@ -1454,7 +1470,7 @@ namespace BTCPayServer.Tests
private static BTCPayRateProviderFactory CreateBTCPayRateFactory(BTCPayNetworkProvider provider) private static BTCPayRateProviderFactory CreateBTCPayRateFactory(BTCPayNetworkProvider provider)
{ {
return new BTCPayRateProviderFactory(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromSeconds(1.0) }, provider, null, new CoinAverageSettings()); return new BTCPayRateProviderFactory(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromSeconds(1.0) }, provider, new CoinAverageSettings());
} }
[Fact] [Fact]

View File

@@ -61,7 +61,7 @@ namespace BTCPayServer.Controllers
MonitoringDate = invoice.MonitoringExpiration, MonitoringDate = invoice.MonitoringExpiration,
OrderId = invoice.OrderId, OrderId = invoice.OrderId,
BuyerInformation = invoice.BuyerInformation, BuyerInformation = invoice.BuyerInformation,
Fiat = FormatCurrency((decimal)dto.Price, dto.Currency), Fiat = FormatCurrency((decimal)dto.Price, dto.Currency, _CurrencyNameTable),
NotificationUrl = invoice.NotificationURL, NotificationUrl = invoice.NotificationURL,
RedirectUrl = invoice.RedirectURL, RedirectUrl = invoice.RedirectURL,
ProductInformation = invoice.ProductInformation, ProductInformation = invoice.ProductInformation,
@@ -291,11 +291,29 @@ namespace BTCPayServer.Controllers
private string FormatCurrency(PaymentMethod paymentMethod) private string FormatCurrency(PaymentMethod paymentMethod)
{ {
string currency = paymentMethod.ParentEntity.ProductInformation.Currency; string currency = paymentMethod.ParentEntity.ProductInformation.Currency;
return FormatCurrency(paymentMethod.Rate, currency); return FormatCurrency(paymentMethod.Rate, currency, _CurrencyNameTable);
} }
public string FormatCurrency(decimal price, string currency) public static string FormatCurrency(decimal price, string currency, CurrencyNameTable currencies)
{ {
return price.ToString("C", _CurrencyNameTable.GetCurrencyProvider(currency)) + $" ({currency})"; var provider = ((CultureInfo)currencies.GetCurrencyProvider(currency)).NumberFormat;
var currencyData = currencies.GetCurrencyData(currency);
var divisibility = currencyData.Divisibility;
while (true)
{
var rounded = decimal.Round(price, divisibility, MidpointRounding.AwayFromZero);
if ((Math.Abs(rounded - price) / price) < 0.001m)
{
price = rounded;
break;
}
divisibility++;
}
if(divisibility != provider.CurrencyDecimalDigits)
{
provider = (NumberFormatInfo)provider.Clone();
provider.CurrencyDecimalDigits = divisibility;
}
return price.ToString("C", provider) + $" ({currency})";
} }
[HttpGet] [HttpGet]
@@ -430,7 +448,7 @@ namespace BTCPayServer.Controllers
var stores = await _StoreRepository.GetStoresByUserId(GetUserId()); var stores = await _StoreRepository.GetStoresByUserId(GetUserId());
model.Stores = new SelectList(stores, nameof(StoreData.Id), nameof(StoreData.StoreName), model.StoreId); model.Stores = new SelectList(stores, nameof(StoreData.Id), nameof(StoreData.StoreName), model.StoreId);
var store = stores.FirstOrDefault(s => s.Id == model.StoreId); var store = stores.FirstOrDefault(s => s.Id == model.StoreId);
if(store == null) if (store == null)
{ {
ModelState.AddModelError(nameof(model.StoreId), "Store not found"); ModelState.AddModelError(nameof(model.StoreId), "Store not found");
} }

View File

@@ -36,7 +36,6 @@ namespace BTCPayServer.Services.Rates
} }
IMemoryCache _Cache; IMemoryCache _Cache;
private IOptions<MemoryCacheOptions> _CacheOptions; private IOptions<MemoryCacheOptions> _CacheOptions;
CurrencyNameTable _CurrencyTable;
public IMemoryCache Cache public IMemoryCache Cache
{ {
get get
@@ -47,12 +46,10 @@ namespace BTCPayServer.Services.Rates
CoinAverageSettings _CoinAverageSettings; CoinAverageSettings _CoinAverageSettings;
public BTCPayRateProviderFactory(IOptions<MemoryCacheOptions> cacheOptions, public BTCPayRateProviderFactory(IOptions<MemoryCacheOptions> cacheOptions,
BTCPayNetworkProvider btcpayNetworkProvider, BTCPayNetworkProvider btcpayNetworkProvider,
CurrencyNameTable currencyTable,
CoinAverageSettings coinAverageSettings) CoinAverageSettings coinAverageSettings)
{ {
if (cacheOptions == null) if (cacheOptions == null)
throw new ArgumentNullException(nameof(cacheOptions)); throw new ArgumentNullException(nameof(cacheOptions));
_CurrencyTable = currencyTable;
_CoinAverageSettings = coinAverageSettings; _CoinAverageSettings = coinAverageSettings;
_Cache = new MemoryCache(cacheOptions); _Cache = new MemoryCache(cacheOptions);
_CacheOptions = cacheOptions; _CacheOptions = cacheOptions;
@@ -90,7 +87,7 @@ namespace BTCPayServer.Services.Rates
public CoinAverageExchanges GetSupportedExchanges() public CoinAverageExchanges GetSupportedExchanges()
{ {
CoinAverageExchanges exchanges = new CoinAverageExchanges(); CoinAverageExchanges exchanges = new CoinAverageExchanges();
foreach(var exchange in _CoinAverageSettings.AvailableExchanges) foreach (var exchange in _CoinAverageSettings.AvailableExchanges)
{ {
exchanges.Add(exchange.Value); exchanges.Add(exchange.Value);
} }
@@ -180,13 +177,6 @@ namespace BTCPayServer.Services.Rates
} }
rateRule.Reevaluate(); rateRule.Reevaluate();
result.Value = rateRule.Value; result.Value = rateRule.Value;
var currencyData = _CurrencyTable?.GetCurrencyData(rateRule.CurrencyPair.Right);
if(currencyData != null && result.Value.HasValue)
{
result.Value = decimal.Round(result.Value.Value, currencyData.Divisibility, MidpointRounding.AwayFromZero);
}
result.Errors = rateRule.Errors; result.Errors = rateRule.Errors;
result.EvaluatedRule = rateRule.ToString(true); result.EvaluatedRule = rateRule.ToString(true);
result.Rule = rateRule.ToString(false); result.Rule = rateRule.ToString(false);