diff --git a/BTCPayServer.Tests/RateRulesTest.cs b/BTCPayServer.Tests/RateRulesTest.cs
index d82b287d1..f12736855 100644
--- a/BTCPayServer.Tests/RateRulesTest.cs
+++ b/BTCPayServer.Tests/RateRulesTest.cs
@@ -113,12 +113,21 @@ namespace BTCPayServer.Tests
builder.AppendLine("DOGE_BTC = 2000");
Assert.True(RateRules.TryParse(builder.ToString(), out rules));
rules.GlobalMultiplier = 1.1m;
+
rule2 = rules.GetRuleFor(CurrencyPair.Parse("DOGE_USD"));
Assert.Equal("(2000 * (-3 + coinbase(BTC_CAD) + 50 - 5)) * 1.1", rule2.ToString());
rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), 1000m);
Assert.True(rule2.Reevaluate());
Assert.Equal("(2000 * (-3 + 1000 + 50 - 5)) * 1.1", rule2.ToString(true));
Assert.Equal((2000m * (-3m + 1000m + 50m - 5m)) * 1.1m, rule2.Value.Value);
+
+ // Test inverse
+ rule2 = rules.GetRuleFor(CurrencyPair.Parse("USD_DOGE"));
+ Assert.Equal("(1 / (2000 * (-3 + coinbase(BTC_CAD) + 50 - 5))) * 1.1", rule2.ToString());
+ rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_CAD"), 1000m);
+ Assert.True(rule2.Reevaluate());
+ 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);
////////
}
}
diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj
index cd4e8d50f..2b36f82d5 100644
--- a/BTCPayServer/BTCPayServer.csproj
+++ b/BTCPayServer/BTCPayServer.csproj
@@ -2,7 +2,7 @@
Exe
netcoreapp2.0
- 1.0.2.2
+ 1.0.2.3
NU1701,CA1816,CA1308,CA1810,CA2208
diff --git a/BTCPayServer/Rating/CurrencyPair.cs b/BTCPayServer/Rating/CurrencyPair.cs
index 7ba9cfe5a..c9a6c6e9e 100644
--- a/BTCPayServer/Rating/CurrencyPair.cs
+++ b/BTCPayServer/Rating/CurrencyPair.cs
@@ -90,5 +90,10 @@ namespace BTCPayServer.Rating
{
return $"{Left}_{Right}";
}
+
+ public CurrencyPair Inverse()
+ {
+ return new CurrencyPair(Right, Left);
+ }
}
}
diff --git a/BTCPayServer/Rating/RateRules.cs b/BTCPayServer/Rating/RateRules.cs
index 61772a14f..b7c7f20bc 100644
--- a/BTCPayServer/Rating/RateRules.cs
+++ b/BTCPayServer/Rating/RateRules.cs
@@ -133,28 +133,30 @@ namespace BTCPayServer.Rating
if (currencyPair.Left == "X" || currencyPair.Right == "X")
throw new ArgumentException(paramName: nameof(currencyPair), message: "Invalid X currency");
var candidate = FindBestCandidate(currencyPair);
-
if (GlobalMultiplier != decimal.One)
{
candidate = CreateExpression($"({candidate}) * {GlobalMultiplier.ToString(CultureInfo.InvariantCulture)}");
}
return new RateRule(this, currencyPair, candidate);
}
-
+
public ExpressionSyntax FindBestCandidate(CurrencyPair p)
{
- var candidates = new List<(CurrencyPair Pair, int Prioriy, ExpressionSyntax Expression)>();
+ var invP = p.Inverse();
+ var candidates = new List<(CurrencyPair Pair, int Prioriy, ExpressionSyntax Expression, bool Inverse)>();
foreach (var pair in new[]
{
- (Pair: p, Priority: 0),
- (Pair: new CurrencyPair(p.Left, "X"), Priority: 1),
- (Pair: new CurrencyPair("X", p.Right), Priority: 1),
- (Pair: new CurrencyPair("X", "X"), Priority: 2)
+ (Pair: p, Priority: 0, Inverse: false),
+ (Pair: new CurrencyPair(p.Left, "X"), Priority: 1, Inverse: false),
+ (Pair: new CurrencyPair("X", p.Right), Priority: 1, Inverse: false),
+ (Pair: new CurrencyPair(invP.Left, "X"), Priority: 2, Inverse: true),
+ (Pair: new CurrencyPair("X", invP.Right), Priority: 2, Inverse: true),
+ (Pair: new CurrencyPair("X", "X"), Priority: 3, Inverse: false)
})
{
if (ruleList.ExpressionsByPair.TryGetValue(pair.Pair, out var expression))
{
- candidates.Add((pair.Pair, pair.Priority, expression.Expression));
+ candidates.Add((pair.Pair, pair.Priority, expression.Expression, pair.Inverse));
}
}
if (candidates.Count == 0)
@@ -163,8 +165,9 @@ namespace BTCPayServer.Rating
.OrderBy(c => c.Prioriy)
.ThenBy(c => c.Expression.Span.Start)
.First();
-
- return best.Expression;
+ return best.Inverse
+ ? CreateExpression($"1 / {invP}")
+ : best.Expression;
}
internal static ExpressionSyntax CreateExpression(string str)
@@ -364,7 +367,7 @@ namespace BTCPayServer.Rating
string _ExchangeName = null;
public List Errors = new List();
- const int MaxNestedCount = 6;
+ const int MaxNestedCount = 8;
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node)
{
if (CurrencyPair.TryParse(node.Identifier.ValueText, out var currentPair))
diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs
index e30181706..960aca473 100644
--- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs
+++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs
@@ -365,14 +365,14 @@ namespace BTCPayServer.Services.Invoices
var scheme = info.Network.UriScheme;
cryptoInfo.Url = ServerUrl.WithTrailingSlash() + $"i/{paymentId}/{Id}";
-
if (paymentId.PaymentType == PaymentTypes.BTCLike)
{
+ var cryptoSuffix = cryptoInfo.CryptoCode == "BTC" ? "" : "/" + cryptoInfo.CryptoCode;
cryptoInfo.PaymentUrls = new NBitpayClient.InvoicePaymentUrls()
{
- BIP72 = $"{scheme}:{cryptoInfo.Address}?amount={cryptoInfo.Due}&r={cryptoInfo.Url}",
- BIP72b = $"{scheme}:?r={cryptoInfo.Url}",
- BIP73 = cryptoInfo.Url,
+ BIP72 = $"{scheme}:{cryptoInfo.Address}?amount={cryptoInfo.Due}&r={ServerUrl.WithTrailingSlash() + ($"i/{Id}{cryptoSuffix}")}",
+ BIP72b = $"{scheme}:?r={ServerUrl.WithTrailingSlash() + ($"i/{Id}{cryptoSuffix}")}",
+ BIP73 = ServerUrl.WithTrailingSlash() + ($"i/{Id}{cryptoSuffix}"),
BIP21 = $"{scheme}:{cryptoInfo.Address}?amount={cryptoInfo.Due}",
};
}