From d31bff7070b522fad6577d475c790f222bbfd676 Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Wed, 19 Feb 2020 09:35:23 +0100 Subject: [PATCH] BPU Prep Work Part2 (#1340) * BPU Prep Work Part2 * Adjust tests to use the hot wallet when registering deriv scheme * Add amount to payment data view for onchain payments * Make zone limits higher when in dev mode (for tests in next PR) * Make IPaymentMethodDetails serialize/deserialize through payment type using the network * Allow named settings through settings repo * Refactor some extensions for next PR * pr changes * use json convert for now --- BTCPayServer.Tests/PSBTTests.cs | 2 +- BTCPayServer.Tests/TestAccount.cs | 42 +++++++++++++------ BTCPayServer.Tests/UnitTest1.cs | 6 ++- .../Configuration/ExternalConnectionString.cs | 4 +- BTCPayServer/Extensions.cs | 20 +++++++-- BTCPayServer/Hosting/BTCPayServerServices.cs | 18 ++++++-- .../InvoicingModels/InvoiceDetailsModel.cs | 2 + BTCPayServer/Payments/PaymentTypes.Bitcoin.cs | 9 +++- .../Payments/PaymentTypes.Lightning.cs | 7 +++- BTCPayServer/Payments/PaymentTypes.cs | 3 +- .../Monero/Payments/MoneroPaymentType.cs | 7 +++- .../Services/Invoices/InvoiceEntity.cs | 5 +-- BTCPayServer/Services/SettingsRepository.cs | 8 ++-- .../Shared/ViewBitcoinLikePaymentData.cshtml | 3 ++ BTCPayServer/wwwroot/js/WalletSend.js | 2 - 15 files changed, 98 insertions(+), 40 deletions(-) diff --git a/BTCPayServer.Tests/PSBTTests.cs b/BTCPayServer.Tests/PSBTTests.cs index 8649bc660..85130c43e 100644 --- a/BTCPayServer.Tests/PSBTTests.cs +++ b/BTCPayServer.Tests/PSBTTests.cs @@ -88,7 +88,7 @@ namespace BTCPayServer.Tests Assert.Equal(vmPSBT.PSBT, vmPSBT2.PSBT); var signedPSBT = unsignedPSBT.Clone(); - signedPSBT.SignAll(user.DerivationScheme, user.ExtKey); + signedPSBT.SignAll(user.DerivationScheme, user.GenerateWalletResponseV.AccountHDKey, user.GenerateWalletResponseV.AccountKeyPath); vmPSBT.PSBT = signedPSBT.ToBase64(); var psbtReady = await walletController.WalletPSBTReady(walletId, new WalletPSBTReadyViewModel() { diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 2d5cbf75f..f73e155cc 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -21,6 +21,7 @@ using BTCPayServer.Data; using OpenIddict.Abstractions; using OpenIddict.Core; using Microsoft.AspNetCore.Identity; +using NBXplorer.Models; namespace BTCPayServer.Tests { @@ -43,18 +44,13 @@ namespace BTCPayServer.Tests var userManager = parent.PayTester.GetService>(); var u = await userManager.FindByIdAsync(UserId); await userManager.AddToRoleAsync(u, Roles.ServerAdmin); + IsAdmin = true; } public void Register() { RegisterAsync().GetAwaiter().GetResult(); } - - public BitcoinExtKey ExtKey - { - get; set; - } - public async Task GrantAccessAsync() { await RegisterAsync(); @@ -100,26 +96,46 @@ namespace BTCPayServer.Tests public BTCPayNetwork SupportedNetwork { get; set; } - public WalletId RegisterDerivationScheme(string crytoCode, bool segwit = false) + public WalletId RegisterDerivationScheme(string crytoCode, bool segwit = false, bool importKeysToNBX = false) { - return RegisterDerivationSchemeAsync(crytoCode, segwit).GetAwaiter().GetResult(); + return RegisterDerivationSchemeAsync(crytoCode, segwit, importKeysToNBX).GetAwaiter().GetResult(); } - public async Task RegisterDerivationSchemeAsync(string cryptoCode, bool segwit = false) + public async Task RegisterDerivationSchemeAsync(string cryptoCode, bool segwit = false, bool importKeysToNBX = false) { SupportedNetwork = parent.NetworkProvider.GetNetwork(cryptoCode); var store = parent.PayTester.GetController(UserId, StoreId); - ExtKey = new ExtKey().GetWif(SupportedNetwork.NBitcoinNetwork); - DerivationScheme = SupportedNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(ExtKey.Neuter().ToString() + (segwit ? "" : "-[legacy]")); + GenerateWalletResponseV = await parent.ExplorerClient.GenerateWalletAsync(new GenerateWalletRequest() + { + ScriptPubKeyType = segwit ? ScriptPubKeyType.Segwit : ScriptPubKeyType.Legacy, + SavePrivateKeys = importKeysToNBX + }); + await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel() { + Enabled = true, + CryptoCode = cryptoCode, + Network = SupportedNetwork, + RootFingerprint = GenerateWalletResponseV.AccountKeyPath.MasterFingerprint.ToString(), + RootKeyPath = SupportedNetwork.GetRootKeyPath(), + Source = "NBXplorer", + AccountKey = GenerateWalletResponseV.AccountHDKey.Neuter().ToWif(), + DerivationSchemeFormat = "BTCPay", + KeyPath = GenerateWalletResponseV.AccountKeyPath.KeyPath.ToString(), DerivationScheme = DerivationScheme.ToString(), Confirmation = true }, cryptoCode); - return new WalletId(StoreId, cryptoCode); } - public DerivationStrategyBase DerivationScheme { get; set; } + public GenerateWalletResponse GenerateWalletResponseV { get; set; } + + public DerivationStrategyBase DerivationScheme + { + get + { + return GenerateWalletResponseV.DerivationScheme; + } + } private async Task RegisterAsync() { diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index d4b7840f4..679cace2b 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -150,17 +150,19 @@ namespace BTCPayServer.Tests new BitcoinLikePaymentHandler(null, networkProvider, null, null), new LightningLikePaymentHandler(null, null, networkProvider, null), }); + var networkBTC = networkProvider.GetNetwork("BTC"); + var networkLTC = networkProvider.GetNetwork("LTC"); InvoiceEntity invoiceEntity = new InvoiceEntity(); invoiceEntity.Networks = networkProvider; invoiceEntity.Payments = new System.Collections.Generic.List(); invoiceEntity.ProductInformation = new ProductInformation() {Price = 100}; PaymentMethodDictionary paymentMethods = new PaymentMethodDictionary(); - paymentMethods.Add(new PaymentMethod() {CryptoCode = "BTC", Rate = 10513.44m,}.SetPaymentMethodDetails( + paymentMethods.Add(new PaymentMethod() {Network = networkBTC, CryptoCode = "BTC", Rate = 10513.44m,}.SetPaymentMethodDetails( new BTCPayServer.Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod() { NextNetworkFee = Money.Coins(0.00000100m), DepositAddress = dummy })); - paymentMethods.Add(new PaymentMethod() {CryptoCode = "LTC", Rate = 216.79m}.SetPaymentMethodDetails( + paymentMethods.Add(new PaymentMethod() {Network = networkLTC, CryptoCode = "LTC", Rate = 216.79m}.SetPaymentMethodDetails( new BTCPayServer.Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod() { NextNetworkFee = Money.Coins(0.00010000m), DepositAddress = dummy diff --git a/BTCPayServer/Configuration/ExternalConnectionString.cs b/BTCPayServer/Configuration/ExternalConnectionString.cs index 8bb83a430..487ce4966 100644 --- a/BTCPayServer/Configuration/ExternalConnectionString.cs +++ b/BTCPayServer/Configuration/ExternalConnectionString.cs @@ -145,9 +145,7 @@ namespace BTCPayServer.Configuration } public bool? IsOnion() { - if (this.Server == null || !this.Server.IsAbsoluteUri) - return null; - return this.Server.DnsSafeHost.EndsWith(".onion", StringComparison.OrdinalIgnoreCase); + return Server?.IsOnion(); } public static bool TryParse(string str, out ExternalConnectionString result, out string error) { diff --git a/BTCPayServer/Extensions.cs b/BTCPayServer/Extensions.cs index 4c300c1b0..19e61beec 100644 --- a/BTCPayServer/Extensions.cs +++ b/BTCPayServer/Extensions.cs @@ -186,11 +186,19 @@ namespace BTCPayServer public static bool IsSegwit(this DerivationStrategyBase derivationStrategyBase) { - if (IsSegwitCore(derivationStrategyBase)) - return true; - return (derivationStrategyBase is P2SHDerivationStrategy p2shStrat && IsSegwitCore(p2shStrat.Inner)); + return ScriptPubKeyType(derivationStrategyBase) != NBitcoin.ScriptPubKeyType.Legacy; } + public static ScriptPubKeyType ScriptPubKeyType(this DerivationStrategyBase derivationStrategyBase) + { + if (IsSegwitCore(derivationStrategyBase)) + { + return NBitcoin.ScriptPubKeyType.Segwit; + } + return (derivationStrategyBase is P2SHDerivationStrategy p2shStrat && IsSegwitCore(p2shStrat.Inner)) + ? NBitcoin.ScriptPubKeyType.SegwitP2SH + : NBitcoin.ScriptPubKeyType.Legacy; + } private static bool IsSegwitCore(DerivationStrategyBase derivationStrategyBase) { return (derivationStrategyBase is P2WSHDerivationStrategy) || @@ -257,6 +265,12 @@ namespace BTCPayServer return false; return request.Host.Host.EndsWith(".onion", StringComparison.OrdinalIgnoreCase); } + + public static bool IsOnion(this Uri uri) + { + return uri?.DnsSafeHost?.EndsWith(".onion", StringComparison.OrdinalIgnoreCase) is true; + } + public static string GetAbsoluteRoot(this HttpRequest request) { diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index 890eb47e9..be19bd8fe 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -260,10 +260,20 @@ namespace BTCPayServer.Hosting { options.AddPolicy(CorsPolicies.All, p => p.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()); }); - - var rateLimits = new RateLimitService(); - rateLimits.SetZone($"zone={ZoneLimits.Login} rate=5r/min burst=3 nodelay"); - services.AddSingleton(rateLimits); + services.AddSingleton(provider => + { + var btcPayEnv = provider.GetService(); + var rateLimits = new RateLimitService(); + if (btcPayEnv.IsDevelopping) + { + rateLimits.SetZone($"zone={ZoneLimits.Login} rate=1000r/min burst=100 nodelay"); + } + else + { + rateLimits.SetZone($"zone={ZoneLimits.Login} rate=5r/min burst=3 nodelay"); + } + return rateLimits; + }); services.AddLogging(logBuilder => diff --git a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs index 9f44b61c4..2fdb72177 100644 --- a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs +++ b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using BTCPayServer.Data; using BTCPayServer.Payments; +using BTCPayServer.Payments.Bitcoin; using BTCPayServer.Services.Invoices; using NBitcoin; using Newtonsoft.Json; @@ -21,6 +22,7 @@ namespace BTCPayServer.Models.InvoicingModels public string TransactionLink { get; set; } public bool Replaced { get; set; } + public BitcoinLikePaymentData CryptoPaymentData { get; set; } } public class OffChainPaymentViewModel diff --git a/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs b/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs index cbbd8c30c..461d189e7 100644 --- a/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs +++ b/BTCPayServer/Payments/PaymentTypes.Bitcoin.cs @@ -31,9 +31,14 @@ namespace BTCPayServer.Payments return ((BTCPayNetwork) network).ToString(paymentData); } - public override IPaymentMethodDetails DeserializePaymentMethodDetails(string str) + public override IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str) { - return JsonConvert.DeserializeObject(str); + return JsonConvert.DeserializeObject(str); + } + + public override string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details) + { + return JsonConvert.SerializeObject(details); } public override ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value) diff --git a/BTCPayServer/Payments/PaymentTypes.Lightning.cs b/BTCPayServer/Payments/PaymentTypes.Lightning.cs index 15388955e..2825fa17f 100644 --- a/BTCPayServer/Payments/PaymentTypes.Lightning.cs +++ b/BTCPayServer/Payments/PaymentTypes.Lightning.cs @@ -29,11 +29,16 @@ namespace BTCPayServer.Payments return ((BTCPayNetwork) network).ToString(paymentData); } - public override IPaymentMethodDetails DeserializePaymentMethodDetails(string str) + public override IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str) { return JsonConvert.DeserializeObject(str); } + public override string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details) + { + return JsonConvert.SerializeObject(details); + } + public override ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value) { return JsonConvert.DeserializeObject(value.ToString()); diff --git a/BTCPayServer/Payments/PaymentTypes.cs b/BTCPayServer/Payments/PaymentTypes.cs index bb5088bc9..229364865 100644 --- a/BTCPayServer/Payments/PaymentTypes.cs +++ b/BTCPayServer/Payments/PaymentTypes.cs @@ -62,7 +62,8 @@ namespace BTCPayServer.Payments public abstract string GetId(); public abstract CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str); public abstract string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData); - public abstract IPaymentMethodDetails DeserializePaymentMethodDetails(string str); + public abstract IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str); + public abstract string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details); public abstract ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value); public abstract string GetTransactionLink(BTCPayNetworkBase network, string txId); public abstract string InvoiceViewPaymentPartialName { get; } diff --git a/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroPaymentType.cs b/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroPaymentType.cs index 0dca0dc10..924d7e07a 100644 --- a/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroPaymentType.cs +++ b/BTCPayServer/Services/Altcoins/Monero/Payments/MoneroPaymentType.cs @@ -24,11 +24,16 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments return JsonConvert.SerializeObject(paymentData); } - public override IPaymentMethodDetails DeserializePaymentMethodDetails(string str) + public override IPaymentMethodDetails DeserializePaymentMethodDetails(BTCPayNetworkBase network, string str) { return JsonConvert.DeserializeObject(str); } + public override string SerializePaymentMethodDetails(BTCPayNetworkBase network, IPaymentMethodDetails details) + { + return JsonConvert.SerializeObject(details); + } + public override ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value) { return JsonConvert.DeserializeObject(value.ToString()); diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 5576eed58..ac82730fb 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -792,7 +792,7 @@ namespace BTCPayServer.Services.Invoices } else { - IPaymentMethodDetails details = GetId().PaymentType.DeserializePaymentMethodDetails(PaymentMethodDetails.ToString()); + IPaymentMethodDetails details = GetId().PaymentType.DeserializePaymentMethodDetails(Network, PaymentMethodDetails.ToString()); if (details is Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod btcLike) { btcLike.NextNetworkFee = NextNetworkFee; @@ -821,8 +821,7 @@ namespace BTCPayServer.Services.Invoices FeeRate = bitcoinPaymentMethod.FeeRate; DepositAddress = bitcoinPaymentMethod.DepositAddress; } - var jobj = JObject.Parse(JsonConvert.SerializeObject(paymentMethod)); - PaymentMethodDetails = jobj; + PaymentMethodDetails = JObject.Parse(paymentMethod.GetPaymentType().SerializePaymentMethodDetails(Network, paymentMethod)); #pragma warning restore CS0618 // Type or member is obsolete return this; diff --git a/BTCPayServer/Services/SettingsRepository.cs b/BTCPayServer/Services/SettingsRepository.cs index fdd76de52..1afef773d 100644 --- a/BTCPayServer/Services/SettingsRepository.cs +++ b/BTCPayServer/Services/SettingsRepository.cs @@ -19,9 +19,9 @@ namespace BTCPayServer.Services _EventAggregator = eventAggregator; } - public async Task GetSettingAsync() + public async Task GetSettingAsync(string name = null) { - var name = typeof(T).FullName; + name ??= typeof(T).FullName; using (var ctx = _ContextFactory.CreateContext()) { var data = await ctx.Settings.Where(s => s.Id == name).FirstOrDefaultAsync(); @@ -31,9 +31,9 @@ namespace BTCPayServer.Services } } - public async Task UpdateSetting(T obj) + public async Task UpdateSetting(T obj, string name = null) { - var name = obj.GetType().FullName; + name ??= obj.GetType().FullName; using (var ctx = _ContextFactory.CreateContext()) { var settings = new SettingData(); diff --git a/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml b/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml index d6626082d..d30391173 100644 --- a/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml +++ b/BTCPayServer/Views/Shared/ViewBitcoinLikePaymentData.cshtml @@ -26,6 +26,7 @@ m.ReceivedTime = payment.ReceivedTime; m.TransactionLink = string.Format(CultureInfo.InvariantCulture, payment.Network.BlockExplorerLink, m.TransactionId); m.Replaced = !payment.Accounted; + m.CryptoPaymentData = onChainPaymentData; return m; }); } @@ -40,6 +41,7 @@ Crypto Deposit address + Amount Transaction Id Confirmations @@ -50,6 +52,7 @@ @payment.Crypto @payment.DepositAddress + @payment.CryptoPaymentData.GetValue()