From da385f9295a6b4fce53d09a2fab338bc157c1c5b Mon Sep 17 00:00:00 2001 From: lepipele Date: Fri, 20 Oct 2017 14:00:38 -0500 Subject: [PATCH 1/6] Adding Unit Test for generating test Bitpay checkout page --- BTCPayServer.Tests/UnitTest1.cs | 579 +++++++++++++++++--------------- 1 file changed, 301 insertions(+), 278 deletions(-) diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index a629012fc..af969e396 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -16,333 +16,356 @@ using Newtonsoft.Json.Linq; using BTCPayServer.Controllers; using Microsoft.AspNetCore.Mvc; using BTCPayServer.Authentication; +using System.Diagnostics; namespace BTCPayServer.Tests { - public class UnitTest1 - { - public UnitTest1(ITestOutputHelper helper) - { - Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; - Logs.LogProvider = new XUnitLogProvider(helper); - } + public class UnitTest1 + { + public UnitTest1(ITestOutputHelper helper) + { + Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; + Logs.LogProvider = new XUnitLogProvider(helper); + } - [Fact] - public void CanCalculateCryptoDue() - { - var entity = new InvoiceEntity(); - entity.TxFee = Money.Coins(0.1m); - entity.Rate = 5000; - entity.Payments = new System.Collections.Generic.List(); - entity.ProductInformation = new ProductInformation() { Price = 5000 }; + [Fact] + public void CanCalculateCryptoDue() + { + var entity = new InvoiceEntity(); + entity.TxFee = Money.Coins(0.1m); + entity.Rate = 5000; + entity.Payments = new System.Collections.Generic.List(); + entity.ProductInformation = new ProductInformation() { Price = 5000 }; - Assert.Equal(Money.Coins(1.1m), entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.1m), entity.GetTotalCryptoDue()); + Assert.Equal(Money.Coins(1.1m), entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.1m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()) }); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()) }); - //Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1 - Assert.Equal(Money.Coins(0.7m), entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.2m), entity.GetTotalCryptoDue()); + //Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1 + Assert.Equal(Money.Coins(0.7m), entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.2m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); - Assert.Equal(Money.Coins(0.6m), entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); + Assert.Equal(Money.Coins(0.6m), entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()) }); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()) }); - Assert.Equal(Money.Zero, entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); + Assert.Equal(Money.Zero, entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); - entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); + entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()) }); - Assert.Equal(Money.Zero, entity.GetCryptoDue()); - Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); - } + Assert.Equal(Money.Zero, entity.GetCryptoDue()); + Assert.Equal(Money.Coins(1.3m), entity.GetTotalCryptoDue()); + } - [Fact] - public void CanPayUsingBIP70() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var user = tester.NewAccount(); - user.GrantAccess(); - var invoice = user.BitPay.CreateInvoice(new Invoice() - { - Buyer = new Buyer() { email = "test@fwf.com" }, - Price = 5000.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - //RedirectURL = redirect + "redirect", - //NotificationURL = CallbackUri + "/notification", - ItemDesc = "Some description", - FullNotifications = true - }, Facade.Merchant); + [Fact] + public void CanPayUsingBIP70() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var user = tester.NewAccount(); + user.GrantAccess(); + var invoice = user.BitPay.CreateInvoice(new Invoice() + { + Buyer = new Buyer() { email = "test@fwf.com" }, + Price = 5000.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + //RedirectURL = redirect + "redirect", + //NotificationURL = CallbackUri + "/notification", + ItemDesc = "Some description", + FullNotifications = true + }, Facade.Merchant); - Assert.False(invoice.Refundable); + Assert.False(invoice.Refundable); - var url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP72); - var request = url.GetPaymentRequest(); - var payment = request.CreatePayment(); + var url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP72); + var request = url.GetPaymentRequest(); + var payment = request.CreatePayment(); - Transaction tx = new Transaction(); - tx.Outputs.AddRange(request.Details.Outputs.Select(o => new TxOut(o.Amount, o.Script))); - var cashCow = tester.ExplorerNode; - tx = cashCow.FundRawTransaction(tx).Transaction; - tx = cashCow.SignRawTransaction(tx); + Transaction tx = new Transaction(); + tx.Outputs.AddRange(request.Details.Outputs.Select(o => new TxOut(o.Amount, o.Script))); + var cashCow = tester.ExplorerNode; + tx = cashCow.FundRawTransaction(tx).Transaction; + tx = cashCow.SignRawTransaction(tx); - payment.Transactions.Add(tx); + payment.Transactions.Add(tx); - payment.RefundTo.Add(new PaymentOutput(Money.Coins(1.0m), new Key().ScriptPubKey)); - var ack = payment.SubmitPayment(); - Assert.NotNull(ack); + payment.RefundTo.Add(new PaymentOutput(Money.Coins(1.0m), new Key().ScriptPubKey)); + var ack = payment.SubmitPayment(); + Assert.NotNull(ack); - Eventually(() => - { - tester.SimulateCallback(url.Address); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paid", localInvoice.Status); - Assert.True(localInvoice.Refundable); - }); - } - } + Eventually(() => + { + tester.SimulateCallback(url.Address); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paid", localInvoice.Status); + Assert.True(localInvoice.Refundable); + }); + } + } - [Fact] - public void CanUseServerInitiatedPairingCode() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var acc = tester.NewAccount(); - acc.Register(); - acc.CreateStore(); - - var controller = tester.PayTester.GetController(acc.UserId); - var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel() - { - Facade = Facade.Merchant.ToString(), - Label = "bla", - PublicKey = null - }).GetAwaiter().GetResult(); + [Fact] + public void CanUseServerInitiatedPairingCode() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var acc = tester.NewAccount(); + acc.Register(); + acc.CreateStore(); - var pairingCode = (string)token.RouteValues["pairingCode"]; + var controller = tester.PayTester.GetController(acc.UserId); + var token = (RedirectToActionResult)controller.CreateToken(acc.StoreId, new Models.StoreViewModels.CreateTokenViewModel() + { + Facade = Facade.Merchant.ToString(), + Label = "bla", + PublicKey = null + }).GetAwaiter().GetResult(); - acc.BitPay.AuthorizeClient(new PairingCode(pairingCode)).GetAwaiter().GetResult(); - Assert.True(acc.BitPay.TestAccess(Facade.Merchant)); - } - } + var pairingCode = (string)token.RouteValues["pairingCode"]; - [Fact] - public void CanSendIPN() - { - using(var callbackServer = new CustomServer()) - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var acc = tester.NewAccount(); - acc.GrantAccess(); - var invoice = acc.BitPay.CreateInvoice(new Invoice() - { - Price = 5.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - NotificationURL = callbackServer.GetUri().AbsoluteUri, - ItemDesc = "Some description", - FullNotifications = true - }); - BitcoinUrlBuilder url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP21); - tester.ExplorerNode.SendToAddress(url.Address, url.Amount); - Thread.Sleep(5000); - tester.SimulateCallback(url.Address); - callbackServer.ProcessNextRequest((ctx) => - { - var ipn = new StreamReader(ctx.Request.Body).ReadToEnd(); - JsonConvert.DeserializeObject(ipn); //can deserialize - }); - var invoice2 = acc.BitPay.GetInvoice(invoice.Id); - Assert.NotNull(invoice2); - } - } - } + acc.BitPay.AuthorizeClient(new PairingCode(pairingCode)).GetAwaiter().GetResult(); + Assert.True(acc.BitPay.TestAccess(Facade.Merchant)); + } + } - [Fact] - public void CantPairTwiceWithSamePubkey() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var acc = tester.NewAccount(); - acc.Register(); - var store = acc.CreateStore(); - var pairingCode = acc.BitPay.RequestClientAuthorization("test", Facade.Merchant); - Assert.IsType(store.Pair(pairingCode.ToString(), acc.StoreId).GetAwaiter().GetResult()); + [Fact] + public void CanSendIPN() + { + using (var callbackServer = new CustomServer()) + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var acc = tester.NewAccount(); + acc.GrantAccess(); + var invoice = acc.BitPay.CreateInvoice(new Invoice() + { + Price = 5.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + NotificationURL = callbackServer.GetUri().AbsoluteUri, + ItemDesc = "Some description", + FullNotifications = true + }); + BitcoinUrlBuilder url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP21); + tester.ExplorerNode.SendToAddress(url.Address, url.Amount); + Thread.Sleep(5000); + tester.SimulateCallback(url.Address); + callbackServer.ProcessNextRequest((ctx) => + { + var ipn = new StreamReader(ctx.Request.Body).ReadToEnd(); + JsonConvert.DeserializeObject(ipn); //can deserialize + }); + var invoice2 = acc.BitPay.GetInvoice(invoice.Id); + Assert.NotNull(invoice2); + } + } + } - pairingCode = acc.BitPay.RequestClientAuthorization("test1", Facade.Merchant); - var store2 = acc.CreateStore(); - store2.Pair(pairingCode.ToString(), store2.CreatedStoreId).GetAwaiter().GetResult(); - Assert.Contains(nameof(PairingResult.ReusedKey), store2.StatusMessage); - } - } + [Fact] + public void CantPairTwiceWithSamePubkey() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var acc = tester.NewAccount(); + acc.Register(); + var store = acc.CreateStore(); + var pairingCode = acc.BitPay.RequestClientAuthorization("test", Facade.Merchant); + Assert.IsType(store.Pair(pairingCode.ToString(), acc.StoreId).GetAwaiter().GetResult()); - [Fact] - public void InvoiceFlowThroughDifferentStatesCorrectly() - { - using(var tester = ServerTester.Create()) - { - tester.Start(); - var user = tester.NewAccount(); - Assert.False(user.BitPay.TestAccess(Facade.Merchant)); - user.GrantAccess(); - Assert.True(user.BitPay.TestAccess(Facade.Merchant)); - var invoice = user.BitPay.CreateInvoice(new Invoice() - { - Price = 5000.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - //RedirectURL = redirect + "redirect", - //NotificationURL = CallbackUri + "/notification", - ItemDesc = "Some description", - FullNotifications = true - }, Facade.Merchant); + pairingCode = acc.BitPay.RequestClientAuthorization("test1", Facade.Merchant); + var store2 = acc.CreateStore(); + store2.Pair(pairingCode.ToString(), store2.CreatedStoreId).GetAwaiter().GetResult(); + Assert.Contains(nameof(PairingResult.ReusedKey), store2.StatusMessage); + } + } - var textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() - { - StoreId = user.StoreId, - TextSearch = invoice.OrderId - }).GetAwaiter().GetResult(); + [Fact] + public void InvoiceFlowThroughDifferentStatesCorrectly() + { + using (var tester = ServerTester.Create()) + { + tester.Start(); + var user = tester.NewAccount(); + Assert.False(user.BitPay.TestAccess(Facade.Merchant)); + user.GrantAccess(); + Assert.True(user.BitPay.TestAccess(Facade.Merchant)); + var invoice = user.BitPay.CreateInvoice(new Invoice() + { + Price = 5000.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + //RedirectURL = redirect + "redirect", + //NotificationURL = CallbackUri + "/notification", + ItemDesc = "Some description", + FullNotifications = true + }, Facade.Merchant); - Assert.Equal(1, textSearchResult.Length); + var textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() + { + StoreId = user.StoreId, + TextSearch = invoice.OrderId + }).GetAwaiter().GetResult(); - textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() - { - StoreId = user.StoreId, - TextSearch = invoice.Id - }).GetAwaiter().GetResult(); + Assert.Equal(1, textSearchResult.Length); - Assert.Equal(1, textSearchResult.Length); + textSearchResult = tester.PayTester.Runtime.InvoiceRepository.GetInvoices(new InvoiceQuery() + { + StoreId = user.StoreId, + TextSearch = invoice.Id + }).GetAwaiter().GetResult(); - invoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal(Money.Coins(0), invoice.BtcPaid); - Assert.Equal("new", invoice.Status); - Assert.Equal(false, (bool)((JValue)invoice.ExceptionStatus).Value); + Assert.Equal(1, textSearchResult.Length); - Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime).Length); - Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime + TimeSpan.FromDays(1)).Length); - Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5)).Length); - Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime).Length); - Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime - TimeSpan.FromDays(1)).Length); + invoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal(Money.Coins(0), invoice.BtcPaid); + Assert.Equal("new", invoice.Status); + Assert.Equal(false, (bool)((JValue)invoice.ExceptionStatus).Value); + + Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime).Length); + Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime + TimeSpan.FromDays(1)).Length); + Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5)).Length); + Assert.Equal(1, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime).Length); + Assert.Equal(0, user.BitPay.GetInvoices(invoice.InvoiceTime.DateTime - TimeSpan.FromDays(5), invoice.InvoiceTime.DateTime - TimeSpan.FromDays(1)).Length); - var firstPayment = Money.Coins(0.04m); + var firstPayment = Money.Coins(0.04m); - var txFee = Money.Zero; + var txFee = Money.Zero; - var rate = user.BitPay.GetRates(); + var rate = user.BitPay.GetRates(); - var cashCow = tester.ExplorerNode; - var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); - cashCow.SendToAddress(invoiceAddress, firstPayment); + var cashCow = tester.ExplorerNode; + var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); + cashCow.SendToAddress(invoiceAddress, firstPayment); - Money secondPayment = Money.Zero; + Money secondPayment = Money.Zero; - Eventually(() => - { - tester.SimulateCallback(invoiceAddress); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paidPartial", localInvoice.Status); - Assert.Equal(firstPayment, localInvoice.BtcPaid); - txFee = localInvoice.BtcDue - invoice.BtcDue; - Assert.Equal("paidPartial", localInvoice.ExceptionStatus); - secondPayment = localInvoice.BtcDue; - }); + Eventually(() => + { + tester.SimulateCallback(invoiceAddress); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paidPartial", localInvoice.Status); + Assert.Equal(firstPayment, localInvoice.BtcPaid); + txFee = localInvoice.BtcDue - invoice.BtcDue; + Assert.Equal("paidPartial", localInvoice.ExceptionStatus); + secondPayment = localInvoice.BtcDue; + }); - cashCow.SendToAddress(invoiceAddress, secondPayment); + cashCow.SendToAddress(invoiceAddress, secondPayment); - Eventually(() => - { - tester.SimulateCallback(invoiceAddress); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paid", localInvoice.Status); - Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid); - Assert.Equal(Money.Zero, localInvoice.BtcDue); - Assert.Equal(false, (bool)((JValue)localInvoice.ExceptionStatus).Value); - }); + Eventually(() => + { + tester.SimulateCallback(invoiceAddress); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paid", localInvoice.Status); + Assert.Equal(firstPayment + secondPayment, localInvoice.BtcPaid); + Assert.Equal(Money.Zero, localInvoice.BtcDue); + Assert.Equal(false, (bool)((JValue)localInvoice.ExceptionStatus).Value); + }); - cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed + cashCow.Generate(1); //The user has medium speed settings, so 1 conf is enough to be confirmed - Eventually(() => - { - tester.SimulateCallback(); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("confirmed", localInvoice.Status); - }); + Eventually(() => + { + tester.SimulateCallback(); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("confirmed", localInvoice.Status); + }); - cashCow.Generate(5); //Now should be complete + cashCow.Generate(5); //Now should be complete - Eventually(() => - { - tester.SimulateCallback(); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("complete", localInvoice.Status); - }); + Eventually(() => + { + tester.SimulateCallback(); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("complete", localInvoice.Status); + }); - invoice = user.BitPay.CreateInvoice(new Invoice() - { - Price = 5000.0, - Currency = "USD", - PosData = "posData", - OrderId = "orderId", - //RedirectURL = redirect + "redirect", - //NotificationURL = CallbackUri + "/notification", - ItemDesc = "Some description", - FullNotifications = true - }, Facade.Merchant); - invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); + invoice = user.BitPay.CreateInvoice(new Invoice() + { + Price = 5000.0, + Currency = "USD", + PosData = "posData", + OrderId = "orderId", + //RedirectURL = redirect + "redirect", + //NotificationURL = CallbackUri + "/notification", + ItemDesc = "Some description", + FullNotifications = true + }, Facade.Merchant); + invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); - cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1)); + cashCow.SendToAddress(invoiceAddress, invoice.BtcDue + Money.Coins(1)); - Eventually(() => - { - tester.SimulateCallback(invoiceAddress); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("paidOver", localInvoice.Status); - Assert.Equal(Money.Zero, localInvoice.BtcDue); - Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); - }); + Eventually(() => + { + tester.SimulateCallback(invoiceAddress); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("paidOver", localInvoice.Status); + Assert.Equal(Money.Zero, localInvoice.BtcDue); + Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); + }); - cashCow.Generate(1); + cashCow.Generate(1); - Eventually(() => - { - tester.SimulateCallback(); - var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); - Assert.Equal("confirmed", localInvoice.Status); - Assert.Equal(Money.Zero, localInvoice.BtcDue); - Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); - }); - } - } + Eventually(() => + { + tester.SimulateCallback(); + var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant); + Assert.Equal("confirmed", localInvoice.Status); + Assert.Equal(Money.Zero, localInvoice.BtcDue); + Assert.Equal("paidOver", (string)((JValue)localInvoice.ExceptionStatus).Value); + }); + } + } - private void Eventually(Action act) - { - CancellationTokenSource cts = new CancellationTokenSource(10000); - while(true) - { - try - { - act(); - break; - } - catch(XunitException) when(!cts.Token.IsCancellationRequested) - { - cts.Token.WaitHandle.WaitOne(500); - } - } - } - } + private void Eventually(Action act) + { + CancellationTokenSource cts = new CancellationTokenSource(10000); + while (true) + { + try + { + act(); + break; + } + catch (XunitException) when (!cts.Token.IsCancellationRequested) + { + cts.Token.WaitHandle.WaitOne(500); + } + } + } + + // NOTE: Unit test that generates temorary checkout Bitpay page + // https://forkbitpay.slack.com/archives/C7M093Z55/p1508293682000217 + //[Fact] + //public void Test() + //{ + // var key = new Key(Encoders.Hex.DecodeData("7b70a06f35562873e3dcb46005ed0fe78e1991ad906e56adaaafa40ba861e056")); + // var url = new Uri("https://test.bitpay.com/"); + // var btcpay = new Bitpay(key, url); + // var invoice = btcpay.CreateInvoice(new Invoice() + // { + + // Price = 5.0, + // Currency = "USD", + // PosData = "posData", + // OrderId = "cdfd8a5f-6928-4c3b-ba9b-ddf438029e73", + // ItemDesc = "Hello from the otherside" + // }, Facade.Merchant); + + // // go to invoice.Url + // Trace.WriteLine(invoice.Url); + //} + } } From 45b0991841cae768c01fd3b2249e84f65d3d086a Mon Sep 17 00:00:00 2001 From: lepipele Date: Fri, 20 Oct 2017 14:06:37 -0500 Subject: [PATCH 2/6] Fixing typo in namespace --- BTCPayServer.Tests/BTCPayServerTester.cs | 2 +- BTCPayServer.Tests/TestAccount.cs | 2 +- BTCPayServer.Tests/UnitTest1.cs | 2 +- BTCPayServer/Configuration/BTCPayServerRuntime.cs | 2 +- BTCPayServer/Controllers/CallbackController.cs | 2 +- BTCPayServer/Controllers/InvoiceController.API.cs | 2 +- BTCPayServer/Controllers/InvoiceController.UI.cs | 2 +- BTCPayServer/Controllers/InvoiceController.cs | 2 +- BTCPayServer/Data/StoreData.cs | 2 +- BTCPayServer/Hosting/BTCPayServerServices.cs | 2 +- BTCPayServer/Migrations/20170926073744_Settings.Designer.cs | 2 +- .../20170926084408_RequiresEmailConfirmation.Designer.cs | 2 +- .../Migrations/20171006013443_AddressMapping.Designer.cs | 2 +- BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs | 2 +- .../Migrations/20171012020112_PendingInvoices.Designer.cs | 2 +- BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs | 2 +- BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs | 2 +- BTCPayServer/Models/StoreViewModels/StoreViewModel.cs | 2 +- BTCPayServer/Services/Invoices/InvoiceEntity.cs | 2 +- BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs | 2 +- BTCPayServer/Services/Invoices/InvoiceRepository.cs | 2 +- BTCPayServer/Services/Invoices/InvoiceWatcher.cs | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/BTCPayServer.Tests/BTCPayServerTester.cs b/BTCPayServer.Tests/BTCPayServerTester.cs index 88a666fd4..b2baa5c7e 100644 --- a/BTCPayServer.Tests/BTCPayServerTester.cs +++ b/BTCPayServer.Tests/BTCPayServerTester.cs @@ -1,6 +1,6 @@ using BTCPayServer.Configuration; using BTCPayServer.Hosting; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Rates; using BTCPayServer.Tests.Logging; using BTCPayServer.Tests.Mocks; diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index b7b2c8804..b22b19a0b 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -1,7 +1,7 @@ using BTCPayServer.Controllers; using BTCPayServer.Models.AccountViewModels; using BTCPayServer.Models.StoreViewModels; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.AspNetCore.Mvc; using NBitcoin; using NBitpayClient; diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index af969e396..c4bc49608 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -9,7 +9,7 @@ using System.Threading; using Xunit; using Xunit.Abstractions; using Xunit.Sdk; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Newtonsoft.Json; using System.IO; using Newtonsoft.Json.Linq; diff --git a/BTCPayServer/Configuration/BTCPayServerRuntime.cs b/BTCPayServer/Configuration/BTCPayServerRuntime.cs index 568b266e2..7ef6b61af 100644 --- a/BTCPayServer/Configuration/BTCPayServerRuntime.cs +++ b/BTCPayServer/Configuration/BTCPayServerRuntime.cs @@ -13,7 +13,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Wallets; namespace BTCPayServer.Configuration diff --git a/BTCPayServer/Controllers/CallbackController.cs b/BTCPayServer/Controllers/CallbackController.cs index f14697010..b3455b73c 100644 --- a/BTCPayServer/Controllers/CallbackController.cs +++ b/BTCPayServer/Controllers/CallbackController.cs @@ -1,5 +1,5 @@ using BTCPayServer.Logging; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services; using BTCPayServer.Services.Wallets; using Microsoft.AspNetCore.Http; diff --git a/BTCPayServer/Controllers/InvoiceController.API.cs b/BTCPayServer/Controllers/InvoiceController.API.cs index 00d750e87..b5009f30b 100644 --- a/BTCPayServer/Controllers/InvoiceController.API.cs +++ b/BTCPayServer/Controllers/InvoiceController.API.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.AspNetCore.Cors; using BTCPayServer.Services.Stores; diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 8d6ab411b..9cdc6e66e 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -1,7 +1,7 @@ using BTCPayServer.Data; using BTCPayServer.Filters; using BTCPayServer.Models.InvoicingModels; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index 67abb5fec..4f94968a6 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -29,7 +29,7 @@ using BTCPayServer.Services; using System.ComponentModel.DataAnnotations; using System.Text.RegularExpressions; using BTCPayServer.Services.Stores; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Rates; using BTCPayServer.Services.Wallets; using BTCPayServer.Validations; diff --git a/BTCPayServer/Data/StoreData.cs b/BTCPayServer/Data/StoreData.cs index f330a984c..8c3a6e401 100644 --- a/BTCPayServer/Data/StoreData.cs +++ b/BTCPayServer/Data/StoreData.cs @@ -1,5 +1,5 @@ using BTCPayServer.Models; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index c8aaba0e0..d9dc7073e 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -16,7 +16,7 @@ using NBXplorer; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; using BTCPayServer.Services; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Rates; using BTCPayServer.Services.Stores; using BTCPayServer.Services.Fees; diff --git a/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs b/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs index 8f27c3b37..400730f1c 100644 --- a/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs +++ b/BTCPayServer/Migrations/20170926073744_Settings.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs b/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs index c9c90ec1f..b5c9d23fd 100644 --- a/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs +++ b/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs b/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs index c2b8f6bc6..ee5867766 100644 --- a/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs +++ b/BTCPayServer/Migrations/20171006013443_AddressMapping.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs b/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs index af6f94745..c9cee961b 100644 --- a/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs +++ b/BTCPayServer/Migrations/20171010082424_Tokens.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs b/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs index fe3429d46..8ac5e3cc0 100644 --- a/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs +++ b/BTCPayServer/Migrations/20171012020112_PendingInvoices.Designer.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs b/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs index b0ec6b352..65d4da025 100644 --- a/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/BTCPayServer/Migrations/ApplicationDbContextModelSnapshot.cs @@ -1,6 +1,6 @@ // using BTCPayServer.Data; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; diff --git a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs index 4c0e47790..320c4d4e9 100644 --- a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs +++ b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using NBitcoin; namespace BTCPayServer.Models.InvoicingModels diff --git a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs index 59f0aba51..e2cafc12d 100644 --- a/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs +++ b/BTCPayServer/Models/StoreViewModels/StoreViewModel.cs @@ -1,4 +1,4 @@ -using BTCPayServer.Servcices.Invoices; +using BTCPayServer.Services.Invoices; using BTCPayServer.Validations; using System; using System.Collections.Generic; diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 1b4daae16..2c690bdde 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -9,7 +9,7 @@ using NBitpayClient; using Newtonsoft.Json.Linq; using NBitcoin.DataEncoders; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class BuyerInformation { diff --git a/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs b/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs index 0fae0c2bb..054c425d8 100644 --- a/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs +++ b/BTCPayServer/Services/Invoices/InvoiceNotificationManager.cs @@ -16,7 +16,7 @@ using Newtonsoft.Json.Linq; using Newtonsoft.Json; using System.Collections.Concurrent; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class InvoiceNotificationManager { diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs index b313d5ea7..7de919e39 100644 --- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs +++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs @@ -17,7 +17,7 @@ using BTCPayServer.Data; using System.Globalization; using BTCPayServer.Models.InvoicingModels; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class InvoiceRepository { diff --git a/BTCPayServer/Services/Invoices/InvoiceWatcher.cs b/BTCPayServer/Services/Invoices/InvoiceWatcher.cs index 9257b0bd3..98ab9f859 100644 --- a/BTCPayServer/Services/Invoices/InvoiceWatcher.cs +++ b/BTCPayServer/Services/Invoices/InvoiceWatcher.cs @@ -14,7 +14,7 @@ using System.Collections.Concurrent; using Hangfire; using BTCPayServer.Services.Wallets; -namespace BTCPayServer.Servcices.Invoices +namespace BTCPayServer.Services.Invoices { public class InvoiceWatcher : IHostedService { From 28ea694791c4de21daef308b307b50a17fd0bf3f Mon Sep 17 00:00:00 2001 From: lepipele Date: Fri, 20 Oct 2017 16:49:13 -0500 Subject: [PATCH 3/6] Extracting my tests to separate class, adding test for generating ExtPubKey --- BTCPayServer.Tests/UnitTest1.cs | 22 ------------- BTCPayServer.Tests/UnitTestPeusa.cs | 50 +++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 BTCPayServer.Tests/UnitTestPeusa.cs diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index c4bc49608..ad7fa5847 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -345,27 +345,5 @@ namespace BTCPayServer.Tests } } } - - // NOTE: Unit test that generates temorary checkout Bitpay page - // https://forkbitpay.slack.com/archives/C7M093Z55/p1508293682000217 - //[Fact] - //public void Test() - //{ - // var key = new Key(Encoders.Hex.DecodeData("7b70a06f35562873e3dcb46005ed0fe78e1991ad906e56adaaafa40ba861e056")); - // var url = new Uri("https://test.bitpay.com/"); - // var btcpay = new Bitpay(key, url); - // var invoice = btcpay.CreateInvoice(new Invoice() - // { - - // Price = 5.0, - // Currency = "USD", - // PosData = "posData", - // OrderId = "cdfd8a5f-6928-4c3b-ba9b-ddf438029e73", - // ItemDesc = "Hello from the otherside" - // }, Facade.Merchant); - - // // go to invoice.Url - // Trace.WriteLine(invoice.Url); - //} } } diff --git a/BTCPayServer.Tests/UnitTestPeusa.cs b/BTCPayServer.Tests/UnitTestPeusa.cs new file mode 100644 index 000000000..363f0a3d5 --- /dev/null +++ b/BTCPayServer.Tests/UnitTestPeusa.cs @@ -0,0 +1,50 @@ +using NBitcoin; +using NBitcoin.DataEncoders; +using NBitpayClient; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace BTCPayServer.Tests +{ + // Helper class for testing functionality and generating data needed during coding/debuging + public class UnitTestPeusa + { + // Unit test that generates temorary checkout Bitpay page + // https://forkbitpay.slack.com/archives/C7M093Z55/p1508293682000217 + [Fact] + public void BitpayCheckout() + { + var key = new Key(Encoders.Hex.DecodeData("7b70a06f35562873e3dcb46005ed0fe78e1991ad906e56adaaafa40ba861e056")); + var url = new Uri("https://test.bitpay.com/"); + var btcpay = new Bitpay(key, url); + var invoice = btcpay.CreateInvoice(new Invoice() + { + + Price = 5.0, + Currency = "USD", + PosData = "posData", + OrderId = "cdfd8a5f-6928-4c3b-ba9b-ddf438029e73", + ItemDesc = "Hello from the otherside" + }, Facade.Merchant); + + // go to invoice.Url + Console.WriteLine(invoice.Url); + } + + // Generating Extended public key to use on http://localhost:14142/stores/{storeId} + [Fact] + public void GeneratePubkey() + { + var network = Network.RegTest; + + ExtKey masterKey = new ExtKey(); + Console.WriteLine("Master key : " + masterKey.ToString(network)); + ExtPubKey masterPubKey = masterKey.Neuter(); + + ExtPubKey pubkey = masterPubKey.Derive(0); + Console.WriteLine("PubKey " + 0 + " : " + pubkey.ToString(network)); + } + } +} From 5fed7a3a0ce6945aaea84a5d43d483bfdfb4621f Mon Sep 17 00:00:00 2001 From: lepipele Date: Fri, 20 Oct 2017 17:14:43 -0500 Subject: [PATCH 4/6] Linking back to Invoices after expiry --- BTCPayServer/Views/Invoice/Checkout.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BTCPayServer/Views/Invoice/Checkout.cshtml b/BTCPayServer/Views/Invoice/Checkout.cshtml index 07993d88a..66a16f201 100644 --- a/BTCPayServer/Views/Invoice/Checkout.cshtml +++ b/BTCPayServer/Views/Invoice/Checkout.cshtml @@ -543,13 +543,13 @@ - + From 8fe5835e09a6d283b7530c1d841538833cf5762c Mon Sep 17 00:00:00 2001 From: lepipele Date: Fri, 20 Oct 2017 17:15:25 -0500 Subject: [PATCH 5/6] Adding text overflow protection on td when invoice is displayed Responsive layout better maintained this way --- BTCPayServer/Views/Invoice/Invoice.cshtml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/BTCPayServer/Views/Invoice/Invoice.cshtml b/BTCPayServer/Views/Invoice/Invoice.cshtml index 6e15aa2b4..6781d8803 100644 --- a/BTCPayServer/Views/Invoice/Invoice.cshtml +++ b/BTCPayServer/Views/Invoice/Invoice.cshtml @@ -3,6 +3,15 @@ ViewData["Title"] = "Invoice " + Model.Id; } + +
@@ -86,7 +95,7 @@ Payment Url - @Model.PaymentUrl + @Model.PaymentUrl
From 0f603ffb0a1c7afff0b6061b748a697de63828f9 Mon Sep 17 00:00:00 2001 From: lepipele Date: Fri, 20 Oct 2017 17:32:52 -0500 Subject: [PATCH 6/6] Allowing customization of expiry time for easier debugging --- BTCPayServer/Controllers/InvoiceController.UI.cs | 2 +- BTCPayServer/Controllers/InvoiceController.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 9cdc6e66e..34c57f70e 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -268,7 +268,7 @@ namespace BTCPayServer.Controllers ItemDesc = model.ItemDesc, FullNotifications = true, BuyerEmail = model.BuyerEmail, - }, store, HttpContext.Request.GetAbsoluteRoot()); + }, store, HttpContext.Request.GetAbsoluteRoot(), 120); StatusMessage = $"Invoice {result.Data.Id} just created!"; return RedirectToAction(nameof(ListInvoices)); diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index 4f94968a6..69d4ac9c3 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -75,7 +75,7 @@ namespace BTCPayServer.Controllers _FeeProvider = feeProvider ?? throw new ArgumentNullException(nameof(feeProvider)); } - internal async Task> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl) + internal async Task> CreateInvoiceCore(Invoice invoice, StoreData store, string serverUrl, double expiryMinutes = 15) { var derivationStrategy = store.DerivationStrategy; var entity = new InvoiceEntity @@ -87,7 +87,7 @@ namespace BTCPayServer.Controllers if(notificationUri == null || (notificationUri.Scheme != "http" && notificationUri.Scheme != "https")) //TODO: Filer non routable addresses ? notificationUri = null; EmailAddressAttribute emailValidator = new EmailAddressAttribute(); - entity.ExpirationTime = entity.InvoiceTime + TimeSpan.FromMinutes(15.0); + entity.ExpirationTime = entity.InvoiceTime.AddMinutes(expiryMinutes); entity.ServerUrl = serverUrl; entity.FullNotifications = invoice.FullNotifications; entity.NotificationURL = notificationUri?.AbsoluteUri;