From 71671b9e164e5a181781774e22bdee68d1ed4fc5 Mon Sep 17 00:00:00 2001 From: Kukks Date: Wed, 18 Sep 2019 18:26:24 +0300 Subject: [PATCH 1/7] Add sats as a native currency This will allow you to create an invoice where its primary currency is denominated in sats --- .../Altcoins/BTCPayNetworkProvider.Bitcoin.cs | 5 +++++ .../Lightning/LightningLikePaymentHandler.cs | 1 + BTCPayServer/Services/Rates/CurrencyNameTable.cs | 15 +++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs index f03652ceb..10abe336a 100644 --- a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs +++ b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs @@ -21,6 +21,11 @@ namespace BTCPayServer UriScheme = "bitcoin", CryptoImagePath = "imlegacy/bitcoin.svg", LightningImagePath = "imlegacy/bitcoin-lightning.svg", + DefaultRateRules = new[] + { + "SATS_X = SATS_BTC * BTC_X", + "BTC_SATS = sats(BTC_SATS);", + }, DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType), CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("0'") : new KeyPath("1'"), SupportRBF = true, diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs index ca085c4f6..6668e2d17 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; diff --git a/BTCPayServer/Services/Rates/CurrencyNameTable.cs b/BTCPayServer/Services/Rates/CurrencyNameTable.cs index ee3a72a09..54098c094 100644 --- a/BTCPayServer/Services/Rates/CurrencyNameTable.cs +++ b/BTCPayServer/Services/Rates/CurrencyNameTable.cs @@ -98,6 +98,12 @@ namespace BTCPayServer.Services.Rates { AddCurrency(_CurrencyProviders, network.CryptoCode, 8, network.CryptoCode); } + + _CurrencyProviders.TryAdd("SATS", + new NumberFormatInfo() + { + CurrencySymbol = "sats", CurrencyDecimalDigits = 0, CurrencyPositivePattern = 3 + }); } return _CurrencyProviders.TryGet(currency.ToUpperInvariant()); } @@ -189,6 +195,15 @@ namespace BTCPayServer.Services.Rates } } + dico.TryAdd("SATS", new CurrencyData() + { + Code = "SATS", + Crypto = true, + Divisibility = 0, + Name = "Satoshis", + Symbol = "Sats", + }); + return dico.Values.ToArray(); } From 27a61b7afdc2ab3b544fbca1e55c5c3181125cc2 Mon Sep 17 00:00:00 2001 From: Kukks Date: Sun, 22 Sep 2019 13:46:02 +0200 Subject: [PATCH 2/7] fix test --- BTCPayServer.Tests/UnitTest1.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 3b6b0fcb3..1959cd912 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -2702,6 +2702,12 @@ noninventoryitem: Assert.Contains(exchangeRates.ByExchange[result.ExpectedName], e => e.CurrencyPair == new CurrencyPair("BTC", "JPY") && e.BidAsk.Bid > 100m); // 1BTC will always be more than 100JPY } + else if (result.ExpectedName == "sats") + { + Assert.Contains(exchangeRates.ByExchange[result.ExpectedName], + e => e.CurrencyPair == new CurrencyPair("SATS", "BTC") && + e.BidAsk.Bid == 0.00000001m); + } else { // This check if the currency pair is using right currency pair From f8139a9156170b3d3fa91c29370062ef9cdf4cd5 Mon Sep 17 00:00:00 2001 From: Kukks Date: Mon, 23 Sep 2019 12:09:08 +0200 Subject: [PATCH 3/7] cleanup (remove sats rate provider and just use rate scripting) --- .../Altcoins/BTCPayNetworkProvider.Bitcoin.cs | 2 +- BTCPayServer.Tests/UnitTest1.cs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs index 10abe336a..f1278b7b3 100644 --- a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs +++ b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs @@ -24,7 +24,7 @@ namespace BTCPayServer DefaultRateRules = new[] { "SATS_X = SATS_BTC * BTC_X", - "BTC_SATS = sats(BTC_SATS);", + "SATS_BTC = 0.00000001" }, DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType), CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("0'") : new KeyPath("1'"), diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 1959cd912..3b6b0fcb3 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -2702,12 +2702,6 @@ noninventoryitem: Assert.Contains(exchangeRates.ByExchange[result.ExpectedName], e => e.CurrencyPair == new CurrencyPair("BTC", "JPY") && e.BidAsk.Bid > 100m); // 1BTC will always be more than 100JPY } - else if (result.ExpectedName == "sats") - { - Assert.Contains(exchangeRates.ByExchange[result.ExpectedName], - e => e.CurrencyPair == new CurrencyPair("SATS", "BTC") && - e.BidAsk.Bid == 0.00000001m); - } else { // This check if the currency pair is using right currency pair From a78dff5931c5872c3677503efb148b24652c4ba5 Mon Sep 17 00:00:00 2001 From: Kukks Date: Sun, 12 Jan 2020 13:53:31 +0100 Subject: [PATCH 4/7] remove padding --- BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs index 6668e2d17..ca085c4f6 100644 --- a/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs +++ b/BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; From f5cbf6672ab5533e000318221d1f9263eb4608da Mon Sep 17 00:00:00 2001 From: Kukks Date: Sun, 12 Jan 2020 13:53:48 +0100 Subject: [PATCH 5/7] remove default rate rule for sats --- .../Altcoins/BTCPayNetworkProvider.Bitcoin.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs index f1278b7b3..f03652ceb 100644 --- a/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs +++ b/BTCPayServer.Common/Altcoins/BTCPayNetworkProvider.Bitcoin.cs @@ -21,11 +21,6 @@ namespace BTCPayServer UriScheme = "bitcoin", CryptoImagePath = "imlegacy/bitcoin.svg", LightningImagePath = "imlegacy/bitcoin-lightning.svg", - DefaultRateRules = new[] - { - "SATS_X = SATS_BTC * BTC_X", - "SATS_BTC = 0.00000001" - }, DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType), CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("0'") : new KeyPath("1'"), SupportRBF = true, From a63502873ca12aa2c1764c3e58a6f6af433dc06b Mon Sep 17 00:00:00 2001 From: Kukks Date: Sun, 12 Jan 2020 13:54:06 +0100 Subject: [PATCH 6/7] Add implicit hidden rate rule for sats in parser --- BTCPayServer.Rating/RateRules.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BTCPayServer.Rating/RateRules.cs b/BTCPayServer.Rating/RateRules.cs index 2b47b34fa..c91c90d77 100644 --- a/BTCPayServer.Rating/RateRules.cs +++ b/BTCPayServer.Rating/RateRules.cs @@ -99,6 +99,8 @@ namespace BTCPayServer.Rating RuleList ruleList; decimal _Spread; + private const string ImplicitSatsRule = "SATS_X = SATS_BTC * BTC_X;\nSATS_BTC = 0.00000001;\n"; + public decimal Spread { get @@ -126,6 +128,7 @@ namespace BTCPayServer.Rating } public static bool TryParse(string str, out RateRules rules, out List errors) { + str = ImplicitSatsRule + str; rules = null; errors = null; var expression = CSharpSyntaxTree.ParseText(str, new CSharpParseOptions(LanguageVersion.Default).WithKind(SourceCodeKind.Script)); @@ -195,6 +198,7 @@ namespace BTCPayServer.Rating { return root.NormalizeWhitespace("", "\n") .ToFullString() + .Replace(ImplicitSatsRule, string.Empty, StringComparison.OrdinalIgnoreCase) .Replace("{\n", string.Empty, StringComparison.OrdinalIgnoreCase) .Replace("\n}", string.Empty, StringComparison.OrdinalIgnoreCase); } From a08d5be35c654dd2338cb6003afc1706a958bb74 Mon Sep 17 00:00:00 2001 From: rockstardev Date: Wed, 29 Jan 2020 22:31:43 -0600 Subject: [PATCH 7/7] Expanding tests to check implicit conversion of Sats to BTC --- BTCPayServer.Tests/RateRulesTest.cs | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/BTCPayServer.Tests/RateRulesTest.cs b/BTCPayServer.Tests/RateRulesTest.cs index 8a508cede..66fd9bade 100644 --- a/BTCPayServer.Tests/RateRulesTest.cs +++ b/BTCPayServer.Tests/RateRulesTest.cs @@ -56,6 +56,8 @@ namespace BTCPayServer.Tests (Pair: "BTC_CAD", Expected: "coinbase(BTC_CAD)"), (Pair: "DOGE_CAD", Expected: "bittrex(DOGE_BTC) * coinbase(BTC_CAD) * 1.1"), (Pair: "LTC_CAD", Expected: "coinaverage(LTC_CAD) * 1.02"), + (Pair: "SATS_CAD", Expected: "0.00000001 * coinbase(BTC_CAD)"), + (Pair: "Sats_USD", Expected: "0.00000001 * kraken(BTC_USD)") }; foreach (var test in tests) { @@ -102,6 +104,8 @@ namespace BTCPayServer.Tests (Pair: "BTC_CAD", Expected: "coinbase(BTC_CAD)", ExpectedExchangeRates: "coinbase(BTC_CAD)"), (Pair: "DOGE_CAD", Expected: "bittrex(DOGE_BTC) * coinbase(BTC_CAD) * 1.1", ExpectedExchangeRates: "bittrex(DOGE_BTC),coinbase(BTC_CAD)"), (Pair: "LTC_CAD", Expected: "coinaverage(LTC_CAD) * 1.02", ExpectedExchangeRates: "coinaverage(LTC_CAD)"), + (Pair: "SATS_USD", Expected: "0.00000001 * kraken(BTC_USD)", ExpectedExchangeRates: "kraken(BTC_USD)"), + (Pair: "SATS_EUR", Expected: "0.00000001 * coinbase(BTC_EUR)", ExpectedExchangeRates: "coinbase(BTC_EUR)") }; foreach (var test in tests2) { @@ -189,6 +193,37 @@ namespace BTCPayServer.Tests rule2.ExchangeRates.SetRate("coinaverage", CurrencyPair.Parse("BTC_USD"), new BidAsk(6000m, 6100m)); Assert.True(rule2.Reevaluate()); Assert.Equal($"({(1m / 6100m).ToString(CultureInfo.InvariantCulture)}, {(1m / 6000m).ToString(CultureInfo.InvariantCulture)})", rule2.ToString(true)); + + // Make sure defining value in sats works + builder = new StringBuilder(); + builder.AppendLine("BTC_USD = kraken(BTC_USD)"); + builder.AppendLine("BTC_X = coinbase(BTC_X)"); + Assert.True(RateRules.TryParse(builder.ToString(), out rules)); + rule2 = rules.GetRuleFor(CurrencyPair.Parse("SATS_USD")); + rule2.ExchangeRates.SetRate("kraken", CurrencyPair.Parse("BTC_USD"), new BidAsk(6000m, 6100m)); + Assert.True(rule2.Reevaluate()); + Assert.Equal("0.00000001 * (6000, 6100)", rule2.ToString(true)); + Assert.Equal(0.00006m, rule2.BidAsk.Bid); + rule2 = rules.GetRuleFor(CurrencyPair.Parse("USD_SATS")); + rule2.ExchangeRates.SetRate("kraken", CurrencyPair.Parse("BTC_USD"), new BidAsk(6000m, 6100m)); + Assert.True(rule2.Reevaluate()); + Assert.Equal("1 / (0.00000001 * (6000, 6100))", rule2.ToString(true)); + Assert.Equal(1m / 0.000061m, rule2.BidAsk.Bid); + + // testing rounding + rule2 = rules.GetRuleFor(CurrencyPair.Parse("Sats_EUR")); + rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_EUR"), new BidAsk(1.23m, 2.34m)); + Assert.True(rule2.Reevaluate()); + Assert.Equal("0.00000001 * (1.23, 2.34)", rule2.ToString(true)); + Assert.Equal(0.0000000234m, rule2.BidAsk.Ask); + Assert.Equal(0.0000000123m, rule2.BidAsk.Bid); + + rule2 = rules.GetRuleFor(CurrencyPair.Parse("EUR_Sats")); + rule2.ExchangeRates.SetRate("coinbase", CurrencyPair.Parse("BTC_EUR"), new BidAsk(1.23m, 2.34m)); + Assert.True(rule2.Reevaluate()); + Assert.Equal("1 / (0.00000001 * (1.23, 2.34))", rule2.ToString(true)); + Assert.Equal(1m / 0.0000000123m, rule2.BidAsk.Ask); + Assert.Equal(1m / 0.0000000234m, rule2.BidAsk.Bid); } } }