Fix: Inverse rule was not found in BTCPay with X_X

This commit is contained in:
nicolas.dorier
2018-07-27 18:04:41 +09:00
parent a2b039f983
commit 0dcda0f289
9 changed files with 29 additions and 26 deletions

View File

@@ -104,7 +104,7 @@ namespace BTCPayServer.Tests
rule2.Reevaluate(); rule2.Reevaluate();
Assert.False(rule2.HasError); Assert.False(rule2.HasError);
Assert.Equal("5000 * 2000.4 * 1.1", rule2.ToString(true)); Assert.Equal("5000 * 2000.4 * 1.1", rule2.ToString(true));
Assert.Equal(rule2.Value, 5000m * 2000.4m * 1.1m); Assert.Equal(rule2.BidAsk.Bid, 5000m * 2000.4m * 1.1m);
//////// ////////
// Make sure parenthesis are correctly calculated // Make sure parenthesis are correctly calculated
@@ -120,7 +120,7 @@ namespace BTCPayServer.Tests
rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), new BidAsk(1000m)); rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), new BidAsk(1000m));
Assert.True(rule2.Reevaluate()); Assert.True(rule2.Reevaluate());
Assert.Equal("(2000 * (-3 + 1000 + 50 - 5)) * 1.1", rule2.ToString(true)); Assert.Equal("(2000 * (-3 + 1000 + 50 - 5)) * 1.1", rule2.ToString(true));
Assert.Equal((2000m * (-3m + 1000m + 50m - 5m)) * 1.1m, rule2.Value.Value); Assert.Equal((2000m * (-3m + 1000m + 50m - 5m)) * 1.1m, rule2.BidAsk.Bid);
// Test inverse // Test inverse
rule2 = rules.GetRuleFor(CurrencyPair.Parse("USD_DOGE")); rule2 = rules.GetRuleFor(CurrencyPair.Parse("USD_DOGE"));
@@ -128,7 +128,7 @@ namespace BTCPayServer.Tests
rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), new BidAsk(1000m)); rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), new BidAsk(1000m));
Assert.True(rule2.Reevaluate()); Assert.True(rule2.Reevaluate());
Assert.Equal("(1 / (2000 * (-3 + 1000 + 50 - 5))) * 1.1", rule2.ToString(true)); Assert.Equal("(1 / (2000 * (-3 + 1000 + 50 - 5))) * 1.1", rule2.ToString(true));
Assert.Equal((1.0m / (2000m * (-3m + 1000m + 50m - 5m))) * 1.1m, rule2.Value.Value); Assert.Equal((1.0m / (2000m * (-3m + 1000m + 50m - 5m))) * 1.1m, rule2.BidAsk.Bid);
//////// ////////
// Make sure kraken is not converted to CurrencyPair // Make sure kraken is not converted to CurrencyPair
@@ -147,12 +147,12 @@ namespace BTCPayServer.Tests
rule2.ExchangeRates.SetRate("kraken", CurrencyPair.Parse("BTC_USD"), new BidAsk(6000m, 6100m)); rule2.ExchangeRates.SetRate("kraken", CurrencyPair.Parse("BTC_USD"), new BidAsk(6000m, 6100m));
Assert.True(rule2.Reevaluate()); Assert.True(rule2.Reevaluate());
Assert.Equal("(6000, 6100)", rule2.ToString(true)); Assert.Equal("(6000, 6100)", rule2.ToString(true));
Assert.Equal(6000m, rule2.Value.Value); Assert.Equal(6000m, rule2.BidAsk.Bid);
rule2 = rules.GetRuleFor(CurrencyPair.Parse("USD_BTC")); rule2 = rules.GetRuleFor(CurrencyPair.Parse("USD_BTC"));
rule2.ExchangeRates.SetRate("kraken", CurrencyPair.Parse("BTC_USD"), new BidAsk(6000m, 6100m)); rule2.ExchangeRates.SetRate("kraken", CurrencyPair.Parse("BTC_USD"), new BidAsk(6000m, 6100m));
Assert.True(rule2.Reevaluate()); Assert.True(rule2.Reevaluate());
Assert.Equal("1 / (6000, 6100)", rule2.ToString(true)); Assert.Equal("1 / (6000, 6100)", rule2.ToString(true));
Assert.Equal(1m / 6100m, rule2.Value.Value); Assert.Equal(1m / 6100m, rule2.BidAsk.Bid);
// Make sure the inverse has more priority than X_X or CDNT_X // Make sure the inverse has more priority than X_X or CDNT_X
builder = new StringBuilder(); builder = new StringBuilder();

View File

@@ -1592,7 +1592,7 @@ namespace BTCPayServer.Tests
foreach (var value in result) foreach (var value in result)
{ {
var rateResult = value.Value.GetAwaiter().GetResult(); var rateResult = value.Value.GetAwaiter().GetResult();
Assert.NotNull(rateResult.Value); Assert.NotNull(rateResult.BidAsk);
} }
} }
@@ -1629,7 +1629,7 @@ namespace BTCPayServer.Tests
// Should cache at exchange level so this should hit the cache // Should cache at exchange level so this should hit the cache
var fetchedRate2 = factory.FetchRate(CurrencyPair.Parse("LTC_USD"), rateRules).GetAwaiter().GetResult(); var fetchedRate2 = factory.FetchRate(CurrencyPair.Parse("LTC_USD"), rateRules).GetAwaiter().GetResult();
Assert.True(fetchedRate.Cached); Assert.True(fetchedRate.Cached);
Assert.NotEqual(fetchedRate.Value.Value, fetchedRate2.Value.Value); Assert.NotEqual(fetchedRate.BidAsk.Bid, fetchedRate2.BidAsk.Bid);
// Should cache at exchange level this should not hit the cache as it is different exchange // Should cache at exchange level this should not hit the cache as it is different exchange
RateRules.TryParse("X_X = bittrex(X_X);", out rateRules); RateRules.TryParse("X_X = bittrex(X_X);", out rateRules);

View File

@@ -209,7 +209,7 @@ namespace BTCPayServer.Controllers
{ {
var storeBlob = store.GetStoreBlob(); var storeBlob = store.GetStoreBlob();
var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.ProductInformation.Currency)]; var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.ProductInformation.Currency)];
if (rate.Value == null) if (rate.BidAsk == null)
{ {
return null; return null;
} }
@@ -217,7 +217,7 @@ namespace BTCPayServer.Controllers
paymentMethod.ParentEntity = entity; paymentMethod.ParentEntity = entity;
paymentMethod.Network = network; paymentMethod.Network = network;
paymentMethod.SetId(supportedPaymentMethod.PaymentId); paymentMethod.SetId(supportedPaymentMethod.PaymentId);
paymentMethod.Rate = rate.Value.Value; paymentMethod.Rate = rate.BidAsk.Bid;
var paymentDetails = await handler.CreatePaymentMethodDetails(supportedPaymentMethod, paymentMethod, store, network); var paymentDetails = await handler.CreatePaymentMethodDetails(supportedPaymentMethod, paymentMethod, store, network);
if (storeBlob.NetworkFeeDisabled) if (storeBlob.NetworkFeeDisabled)
paymentDetails.SetNoTxFee(); paymentDetails.SetNoTxFee();
@@ -244,9 +244,9 @@ namespace BTCPayServer.Controllers
if (compare != null) if (compare != null)
{ {
var limitValueRate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, limitValue.Currency)]; var limitValueRate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, limitValue.Currency)];
if (limitValueRate.Value.HasValue) if (limitValueRate.BidAsk != null)
{ {
var limitValueCrypto = Money.Coins(limitValue.Value / limitValueRate.Value.Value); var limitValueCrypto = Money.Coins(limitValue.Value / limitValueRate.BidAsk.Bid);
if (compare(paymentMethod.Calculate().Due, limitValueCrypto)) if (compare(paymentMethod.Calculate().Due, limitValueCrypto))
{ {
logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: {errorMessage}"); logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: {errorMessage}");

View File

@@ -81,7 +81,7 @@ namespace BTCPayServer.Controllers
var fetching = _RateProviderFactory.FetchRates(pairs, rules); var fetching = _RateProviderFactory.FetchRates(pairs, rules);
await Task.WhenAll(fetching.Select(f => f.Value).ToArray()); await Task.WhenAll(fetching.Select(f => f.Value).ToArray());
return Json(pairs return Json(pairs
.Select(r => (Pair: r, Value: fetching[r].GetAwaiter().GetResult().Value)) .Select(r => (Pair: r, Value: fetching[r].GetAwaiter().GetResult().BidAsk?.Bid))
.Where(r => r.Value.HasValue) .Where(r => r.Value.HasValue)
.Select(r => .Select(r =>
new Rate() new Rate()

View File

@@ -262,7 +262,7 @@ namespace BTCPayServer.Controllers
{ {
CurrencyPair = fetch.Key.ToString(), CurrencyPair = fetch.Key.ToString(),
Error = testResult.Errors.Count != 0, Error = testResult.Errors.Count != 0,
Rule = testResult.Errors.Count == 0 ? testResult.Rule + " = " + testResult.Value.Value.ToString(CultureInfo.InvariantCulture) Rule = testResult.Errors.Count == 0 ? testResult.Rule + " = " + testResult.BidAsk.Bid.ToString(CultureInfo.InvariantCulture)
: testResult.EvaluatedRule : testResult.EvaluatedRule
}); });
} }

View File

@@ -162,9 +162,9 @@ namespace BTCPayServer.Controllers
{ {
cts.CancelAfter(TimeSpan.FromSeconds(5)); cts.CancelAfter(TimeSpan.FromSeconds(5));
var result = await _RateProvider.FetchRate(currencyPair, rateRules).WithCancellation(cts.Token); var result = await _RateProvider.FetchRate(currencyPair, rateRules).WithCancellation(cts.Token);
if (result.Value != null) if (result.BidAsk != null)
{ {
model.Rate = result.Value; model.Rate = result.BidAsk.Center;
model.Divisibility = _currencyTable.GetNumberFormatInfo(currencyPair.Right, true).CurrencyDecimalDigits; model.Divisibility = _currencyTable.GetNumberFormatInfo(currencyPair.Right, true).CurrencyDecimalDigits;
model.Fiat = currencyPair.Right; model.Fiat = currencyPair.Right;
} }

View File

@@ -138,6 +138,9 @@ namespace BTCPayServer.Rating
return _Ask; return _Ask;
} }
} }
public decimal Center => (Ask + Bid) / 2.0m;
public BidAsk Inverse() public BidAsk Inverse()
{ {
return new BidAsk(1.0m / Ask, 1.0m / Bid); return new BidAsk(1.0m / Ask, 1.0m / Bid);

View File

@@ -504,7 +504,7 @@ namespace BTCPayServer.Rating
public bool Reevaluate() public bool Reevaluate()
{ {
_Value = null; _BidAsk = null;
_EvaluatedNode = null; _EvaluatedNode = null;
_Evaluated = null; _Evaluated = null;
Errors.Clear(); Errors.Clear();
@@ -524,7 +524,7 @@ namespace BTCPayServer.Rating
Errors.AddRange(calculate.Errors); Errors.AddRange(calculate.Errors);
return false; return false;
} }
_Value = calculate.Values.Pop().Bid; _BidAsk = calculate.Values.Pop();
_EvaluatedNode = result; _EvaluatedNode = result;
return true; return true;
} }
@@ -563,12 +563,12 @@ namespace BTCPayServer.Rating
return expression.NormalizeWhitespace("", "\n").ToString(); return expression.NormalizeWhitespace("", "\n").ToString();
} }
decimal? _Value; BidAsk _BidAsk;
public decimal? Value public BidAsk BidAsk
{ {
get get
{ {
return _Value; return _BidAsk;
} }
} }
} }

View File

@@ -22,7 +22,7 @@ namespace BTCPayServer.Services.Rates
public string Rule { get; set; } public string Rule { get; set; }
public string EvaluatedRule { get; set; } public string EvaluatedRule { get; set; }
public HashSet<RateRulesErrors> Errors { get; set; } public HashSet<RateRulesErrors> Errors { get; set; }
public decimal? Value { get; set; } public BidAsk BidAsk { get; set; }
public bool Cached { get; internal set; } public bool Cached { get; internal set; }
} }
@@ -172,11 +172,11 @@ namespace BTCPayServer.Services.Rates
result.ExchangeExceptions.AddRange(query.Exceptions); result.ExchangeExceptions.AddRange(query.Exceptions);
foreach (var rule in query.ExchangeRates) foreach (var rule in query.ExchangeRates)
{ {
rateRule.ExchangeRates.Add(rule); rateRule.ExchangeRates.SetRate(rule.Exchange, rule.CurrencyPair, rule.BidAsk);
} }
} }
rateRule.Reevaluate(); rateRule.Reevaluate();
result.Value = rateRule.Value; result.BidAsk = rateRule.BidAsk;
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);