mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Do not roundup rates
This commit is contained in:
@@ -265,7 +265,7 @@ namespace BTCPayServer.Tests
|
|||||||
var user = tester.NewAccount();
|
var user = tester.NewAccount();
|
||||||
user.GrantAccess();
|
user.GrantAccess();
|
||||||
user.RegisterDerivationScheme("BTC");
|
user.RegisterDerivationScheme("BTC");
|
||||||
|
|
||||||
// Set tolerance to 50%
|
// Set tolerance to 50%
|
||||||
var stores = user.GetController<StoresController>();
|
var stores = user.GetController<StoresController>();
|
||||||
var vm = Assert.IsType<StoreViewModel>(Assert.IsType<ViewResult>(stores.UpdateStore()).Model);
|
var vm = Assert.IsType<StoreViewModel>(Assert.IsType<ViewResult>(stores.UpdateStore()).Model);
|
||||||
@@ -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()
|
||||||
{
|
{
|
||||||
@@ -617,7 +633,7 @@ namespace BTCPayServer.Tests
|
|||||||
ItemDesc = "Some description",
|
ItemDesc = "Some description",
|
||||||
FullNotifications = true
|
FullNotifications = true
|
||||||
}, Facade.Merchant);
|
}, Facade.Merchant);
|
||||||
|
|
||||||
var cashCow = tester.ExplorerNode;
|
var cashCow = tester.ExplorerNode;
|
||||||
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
|
var invoiceAddress = BitcoinAddress.Create(invoice.CryptoInfo[0].Address, cashCow.Network);
|
||||||
var firstPayment = invoice.CryptoInfo[0].TotalDue - Money.Satoshis(10);
|
var firstPayment = invoice.CryptoInfo[0].TotalDue - Money.Satoshis(10);
|
||||||
@@ -1411,7 +1427,7 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
var provider = new BTCPayNetworkProvider(NetworkType.Mainnet);
|
var provider = new BTCPayNetworkProvider(NetworkType.Mainnet);
|
||||||
var factory = CreateBTCPayRateFactory(provider);
|
var factory = CreateBTCPayRateFactory(provider);
|
||||||
|
|
||||||
foreach (var result in factory
|
foreach (var result in factory
|
||||||
.DirectProviders
|
.DirectProviders
|
||||||
.Select(p => (ExpectedName: p.Key, ResultAsync: p.Value.GetRatesAsync()))
|
.Select(p => (ExpectedName: p.Key, ResultAsync: p.Value.GetRatesAsync()))
|
||||||
@@ -1423,8 +1439,8 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.NotEmpty(exchangeRates.ByExchange[result.ExpectedName]);
|
Assert.NotEmpty(exchangeRates.ByExchange[result.ExpectedName]);
|
||||||
|
|
||||||
// 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]
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace BTCPayServer.Controllers
|
|||||||
StoreLink = Url.Action(nameof(StoresController.UpdateStore), "Stores", new { storeId = store.Id }),
|
StoreLink = Url.Action(nameof(StoresController.UpdateStore), "Stores", new { storeId = store.Id }),
|
||||||
Id = invoice.Id,
|
Id = invoice.Id,
|
||||||
Status = invoice.Status,
|
Status = invoice.Status,
|
||||||
TransactionSpeed = invoice.SpeedPolicy == SpeedPolicy.HighSpeed ? "high" :
|
TransactionSpeed = invoice.SpeedPolicy == SpeedPolicy.HighSpeed ? "high" :
|
||||||
invoice.SpeedPolicy == SpeedPolicy.MediumSpeed ? "medium" :
|
invoice.SpeedPolicy == SpeedPolicy.MediumSpeed ? "medium" :
|
||||||
invoice.SpeedPolicy == SpeedPolicy.LowMediumSpeed ? "low-medium" :
|
invoice.SpeedPolicy == SpeedPolicy.LowMediumSpeed ? "low-medium" :
|
||||||
"low",
|
"low",
|
||||||
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user