Big refactoring renaming cryptoData => PaymentMethod

This commit is contained in:
nicolas.dorier 2018-02-19 15:09:05 +09:00
parent af94de93d1
commit a634593903
17 changed files with 269 additions and 230 deletions

View file

@ -51,81 +51,81 @@ namespace BTCPayServer.Tests
entity.ProductInformation = new ProductInformation() { Price = 5000 }; entity.ProductInformation = new ProductInformation() { Price = 5000 };
// Some check that handling legacy stuff does not break things // Some check that handling legacy stuff does not break things
var cryptoData = entity.GetCryptoData(null, true).TryGet("BTC", PaymentTypes.BTCLike); var paymentMethod = entity.GetPaymentMethods(null, true).TryGet("BTC", PaymentTypes.BTCLike);
cryptoData.Calculate(); paymentMethod.Calculate();
Assert.NotNull(cryptoData); Assert.NotNull(paymentMethod);
Assert.Null(entity.GetCryptoData(null, false).TryGet("BTC", PaymentTypes.BTCLike)); Assert.Null(entity.GetPaymentMethods(null, false).TryGet("BTC", PaymentTypes.BTCLike));
entity.SetCryptoData(new CryptoData() { ParentEntity = entity, Rate = entity.Rate, CryptoCode = "BTC", TxFee = entity.TxFee }); entity.SetPaymentMethod(new PaymentMethod() { ParentEntity = entity, Rate = entity.Rate, CryptoCode = "BTC", TxFee = entity.TxFee });
Assert.NotNull(entity.GetCryptoData(null, false).TryGet("BTC", PaymentTypes.BTCLike)); Assert.NotNull(entity.GetPaymentMethods(null, false).TryGet("BTC", PaymentTypes.BTCLike));
Assert.NotNull(entity.GetCryptoData(null, true).TryGet("BTC", PaymentTypes.BTCLike)); Assert.NotNull(entity.GetPaymentMethods(null, true).TryGet("BTC", PaymentTypes.BTCLike));
//////////////////// ////////////////////
var accounting = cryptoData.Calculate(); var accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(1.1m), accounting.Due); Assert.Equal(Money.Coins(1.1m), accounting.Due);
Assert.Equal(Money.Coins(1.1m), accounting.TotalDue); Assert.Equal(Money.Coins(1.1m), accounting.TotalDue);
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.5m), new Key()), Accounted = true });
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
//Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1 //Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1
Assert.Equal(Money.Coins(0.7m), accounting.Due); Assert.Equal(Money.Coins(0.7m), accounting.Due);
Assert.Equal(Money.Coins(1.2m), accounting.TotalDue); Assert.Equal(Money.Coins(1.2m), accounting.TotalDue);
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()), Accounted = true });
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(0.6m), accounting.Due); Assert.Equal(Money.Coins(0.6m), accounting.Due);
Assert.Equal(Money.Coins(1.3m), accounting.TotalDue); Assert.Equal(Money.Coins(1.3m), accounting.TotalDue);
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.6m), new Key()), Accounted = true });
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Zero, accounting.Due); Assert.Equal(Money.Zero, accounting.Due);
Assert.Equal(Money.Coins(1.3m), accounting.TotalDue); Assert.Equal(Money.Coins(1.3m), accounting.TotalDue);
entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { Output = new TxOut(Money.Coins(0.2m), new Key()), Accounted = true });
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Zero, accounting.Due); Assert.Equal(Money.Zero, accounting.Due);
Assert.Equal(Money.Coins(1.3m), accounting.TotalDue); Assert.Equal(Money.Coins(1.3m), accounting.TotalDue);
entity = new InvoiceEntity(); entity = new InvoiceEntity();
entity.ProductInformation = new ProductInformation() { Price = 5000 }; entity.ProductInformation = new ProductInformation() { Price = 5000 };
CryptoDataDictionary cryptoDatas = new CryptoDataDictionary(); PaymentMethodDictionary paymentMethods = new PaymentMethodDictionary();
cryptoDatas.Add(new CryptoData() paymentMethods.Add(new PaymentMethod()
{ {
CryptoCode = "BTC", CryptoCode = "BTC",
Rate = 1000, Rate = 1000,
TxFee = Money.Coins(0.1m) TxFee = Money.Coins(0.1m)
}); });
cryptoDatas.Add(new CryptoData() paymentMethods.Add(new PaymentMethod()
{ {
CryptoCode = "LTC", CryptoCode = "LTC",
Rate = 500, Rate = 500,
TxFee = Money.Coins(0.01m) TxFee = Money.Coins(0.01m)
}); });
entity.SetCryptoData(cryptoDatas); entity.SetPaymentMethods(paymentMethods);
entity.Payments = new List<PaymentEntity>(); entity.Payments = new List<PaymentEntity>();
cryptoData = entity.GetCryptoData(new CryptoDataId("BTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(5.1m), accounting.Due); Assert.Equal(Money.Coins(5.1m), accounting.Due);
cryptoData = entity.GetCryptoData(new CryptoDataId("LTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("LTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(10.01m), accounting.TotalDue); Assert.Equal(Money.Coins(10.01m), accounting.TotalDue);
entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true });
cryptoData = entity.GetCryptoData(new CryptoDataId("BTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(4.2m), accounting.Due); Assert.Equal(Money.Coins(4.2m), accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
Assert.Equal(Money.Coins(1.0m), accounting.Paid); Assert.Equal(Money.Coins(1.0m), accounting.Paid);
Assert.Equal(Money.Coins(5.2m), accounting.TotalDue); Assert.Equal(Money.Coins(5.2m), accounting.TotalDue);
Assert.Equal(2, accounting.TxCount); Assert.Equal(2, accounting.TxCount);
cryptoData = entity.GetCryptoData(new CryptoDataId("LTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("LTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(10.01m + 0.1m * 2 - 2.0m /* 8.21m */), accounting.Due); Assert.Equal(Money.Coins(10.01m + 0.1m * 2 - 2.0m /* 8.21m */), accounting.Due);
Assert.Equal(Money.Coins(0.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(0.0m), accounting.CryptoPaid);
Assert.Equal(Money.Coins(2.0m), accounting.Paid); Assert.Equal(Money.Coins(2.0m), accounting.Paid);
@ -134,16 +134,16 @@ namespace BTCPayServer.Tests
entity.Payments.Add(new PaymentEntity() { CryptoCode = "LTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { CryptoCode = "LTC", Output = new TxOut(Money.Coins(1.0m), new Key()), Accounted = true });
cryptoData = entity.GetCryptoData(new CryptoDataId("BTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(4.2m - 0.5m + 0.01m / 2), accounting.Due); Assert.Equal(Money.Coins(4.2m - 0.5m + 0.01m / 2), accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
Assert.Equal(Money.Coins(1.5m), accounting.Paid); Assert.Equal(Money.Coins(1.5m), accounting.Paid);
Assert.Equal(Money.Coins(5.2m + 0.01m / 2), accounting.TotalDue); // The fee for LTC added Assert.Equal(Money.Coins(5.2m + 0.01m / 2), accounting.TotalDue); // The fee for LTC added
Assert.Equal(2, accounting.TxCount); Assert.Equal(2, accounting.TxCount);
cryptoData = entity.GetCryptoData(new CryptoDataId("LTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("LTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Coins(8.21m - 1.0m + 0.01m), accounting.Due); Assert.Equal(Money.Coins(8.21m - 1.0m + 0.01m), accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
Assert.Equal(Money.Coins(3.0m), accounting.Paid); Assert.Equal(Money.Coins(3.0m), accounting.Paid);
@ -153,8 +153,8 @@ namespace BTCPayServer.Tests
var remaining = Money.Coins(4.2m - 0.5m + 0.01m / 2); var remaining = Money.Coins(4.2m - 0.5m + 0.01m / 2);
entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(remaining, new Key()), Accounted = true }); entity.Payments.Add(new PaymentEntity() { CryptoCode = "BTC", Output = new TxOut(remaining, new Key()), Accounted = true });
cryptoData = entity.GetCryptoData(new CryptoDataId("BTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("BTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Zero, accounting.Due); Assert.Equal(Money.Zero, accounting.Due);
Assert.Equal(Money.Coins(1.0m) + remaining, accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m) + remaining, accounting.CryptoPaid);
Assert.Equal(Money.Coins(1.5m) + remaining, accounting.Paid); Assert.Equal(Money.Coins(1.5m) + remaining, accounting.Paid);
@ -162,8 +162,8 @@ namespace BTCPayServer.Tests
Assert.Equal(accounting.Paid, accounting.TotalDue); Assert.Equal(accounting.Paid, accounting.TotalDue);
Assert.Equal(2, accounting.TxCount); Assert.Equal(2, accounting.TxCount);
cryptoData = entity.GetCryptoData(new CryptoDataId("LTC", PaymentTypes.BTCLike), null); paymentMethod = entity.GetPaymentMethod(new PaymentMethodId("LTC", PaymentTypes.BTCLike), null);
accounting = cryptoData.Calculate(); accounting = paymentMethod.Calculate();
Assert.Equal(Money.Zero, accounting.Due); Assert.Equal(Money.Zero, accounting.Due);
Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid); Assert.Equal(Money.Coins(1.0m), accounting.CryptoPaid);
Assert.Equal(Money.Coins(3.0m) + remaining * 2, accounting.Paid); Assert.Equal(Money.Coins(3.0m) + remaining * 2, accounting.Paid);
@ -334,8 +334,8 @@ namespace BTCPayServer.Tests
Currency = "USD" Currency = "USD"
}, Facade.Merchant); }, Facade.Merchant);
var payment1 = Money.Coins(0.04m); var payment1 = invoice.BtcDue + Money.Coins(0.0001m);
var payment2 = Money.Coins(0.08m); var payment2 = invoice.BtcDue;
var tx1 = new uint256(tester.ExplorerNode.SendCommand("sendtoaddress", new object[] var tx1 = new uint256(tester.ExplorerNode.SendCommand("sendtoaddress", new object[]
{ {
invoice.BitcoinAddress, invoice.BitcoinAddress,
@ -351,6 +351,8 @@ namespace BTCPayServer.Tests
{ {
invoice = user.BitPay.GetInvoice(invoice.Id); invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal(payment1, invoice.BtcPaid); Assert.Equal(payment1, invoice.BtcPaid);
Assert.Equal("paid", invoice.Status);
Assert.Equal("paidOver", invoice.ExceptionStatus.ToString());
invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, user.SupportedNetwork.NBitcoinNetwork); invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, user.SupportedNetwork.NBitcoinNetwork);
}); });
@ -359,11 +361,9 @@ namespace BTCPayServer.Tests
{ {
input.ScriptSig = Script.Empty; //Strip signatures input.ScriptSig = Script.Empty; //Strip signatures
} }
var change = tx.Outputs.First(o => o.Value != payment1);
var output = tx.Outputs.First(o => o.Value == payment1); var output = tx.Outputs.First(o => o.Value == payment1);
output.Value = payment2; output.Value = payment2;
output.ScriptPubKey = invoiceAddress.ScriptPubKey; output.ScriptPubKey = invoiceAddress.ScriptPubKey;
change.Value -= (payment2 - payment1) * 2; //Add more fees
var replaced = tester.ExplorerNode.SignRawTransaction(tx); var replaced = tester.ExplorerNode.SignRawTransaction(tx);
tester.ExplorerNode.SendRawTransaction(replaced); tester.ExplorerNode.SendRawTransaction(replaced);
var test = tester.ExplorerClient.GetUTXOs(user.DerivationScheme, null); var test = tester.ExplorerClient.GetUTXOs(user.DerivationScheme, null);
@ -371,6 +371,7 @@ namespace BTCPayServer.Tests
{ {
invoice = user.BitPay.GetInvoice(invoice.Id); invoice = user.BitPay.GetInvoice(invoice.Id);
Assert.Equal(payment2, invoice.BtcPaid); Assert.Equal(payment2, invoice.BtcPaid);
Assert.Equal("False", invoice.ExceptionStatus.ToString());
}); });
} }
} }

View file

@ -24,12 +24,12 @@ namespace BTCPayServer.Controllers
cryptoCode = "BTC"; cryptoCode = "BTC";
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId); var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId);
var network = _NetworkProvider.GetNetwork(cryptoCode); var network = _NetworkProvider.GetNetwork(cryptoCode);
var cryptoId = new CryptoDataId(cryptoCode, Payments.PaymentTypes.BTCLike); var paymentMethodId = new PaymentMethodId(cryptoCode, Payments.PaymentTypes.BTCLike);
if (invoice == null || invoice.IsExpired() || network == null || !invoice.Support(cryptoId)) if (invoice == null || invoice.IsExpired() || network == null || !invoice.Support(paymentMethodId))
return NotFound(); return NotFound();
var dto = invoice.EntityToDTO(_NetworkProvider); var dto = invoice.EntityToDTO(_NetworkProvider);
var cryptoData = dto.CryptoInfo.First(c => c.GetCryptoDataId() == cryptoId); var paymentMethod = dto.CryptoInfo.First(c => c.GetpaymentMethodId() == paymentMethodId);
PaymentRequest request = new PaymentRequest PaymentRequest request = new PaymentRequest
{ {
DetailsVersion = 1 DetailsVersion = 1
@ -37,7 +37,7 @@ namespace BTCPayServer.Controllers
request.Details.Expires = invoice.ExpirationTime; request.Details.Expires = invoice.ExpirationTime;
request.Details.Memo = invoice.ProductInformation.ItemDesc; request.Details.Memo = invoice.ProductInformation.ItemDesc;
request.Details.Network = network.NBitcoinNetwork; request.Details.Network = network.NBitcoinNetwork;
request.Details.Outputs.Add(new PaymentOutput() { Amount = cryptoData.Due, Script = BitcoinAddress.Create(cryptoData.Address, network.NBitcoinNetwork).ScriptPubKey }); request.Details.Outputs.Add(new PaymentOutput() { Amount = paymentMethod.Due, Script = BitcoinAddress.Create(paymentMethod.Address, network.NBitcoinNetwork).ScriptPubKey });
request.Details.MerchantData = Encoding.UTF8.GetBytes(invoice.Id); request.Details.MerchantData = Encoding.UTF8.GetBytes(invoice.Id);
request.Details.Time = DateTimeOffset.UtcNow; request.Details.Time = DateTimeOffset.UtcNow;
request.Details.PaymentUrl = new Uri(invoice.ServerUrl.WithTrailingSlash() + ($"i/{invoice.Id}"), UriKind.Absolute); request.Details.PaymentUrl = new Uri(invoice.ServerUrl.WithTrailingSlash() + ($"i/{invoice.Id}"), UriKind.Absolute);
@ -71,7 +71,7 @@ namespace BTCPayServer.Controllers
if (cryptoCode == null) if (cryptoCode == null)
cryptoCode = "BTC"; cryptoCode = "BTC";
var network = _NetworkProvider.GetNetwork(cryptoCode); var network = _NetworkProvider.GetNetwork(cryptoCode);
if (network == null || invoice == null || invoice.IsExpired() || !invoice.Support(new Services.Invoices.CryptoDataId(cryptoCode, Payments.PaymentTypes.BTCLike))) if (network == null || invoice == null || invoice.IsExpired() || !invoice.Support(new Services.Invoices.PaymentMethodId(cryptoCode, Payments.PaymentTypes.BTCLike)))
return NotFound(); return NotFound();
var wallet = _WalletProvider.GetWallet(network); var wallet = _WalletProvider.GetWallet(network);

View file

@ -64,9 +64,9 @@ namespace BTCPayServer.Controllers
Events = invoice.Events Events = invoice.Events
}; };
foreach (var data in invoice.GetCryptoData(null)) foreach (var data in invoice.GetPaymentMethods(null))
{ {
var cryptoInfo = dto.CryptoInfo.First(o => o.GetCryptoDataId() == data.GetId()); var cryptoInfo = dto.CryptoInfo.First(o => o.GetpaymentMethodId() == data.GetId());
var accounting = data.Calculate(); var accounting = data.Calculate();
var paymentNetwork = _NetworkProvider.GetNetwork(data.GetId().CryptoCode); var paymentNetwork = _NetworkProvider.GetNetwork(data.GetId().CryptoCode);
var cryptoPayment = new InvoiceDetailsModel.CryptoPayment(); var cryptoPayment = new InvoiceDetailsModel.CryptoPayment();
@ -74,7 +74,7 @@ namespace BTCPayServer.Controllers
cryptoPayment.Due = accounting.Due.ToString() + $" {paymentNetwork.CryptoCode}"; cryptoPayment.Due = accounting.Due.ToString() + $" {paymentNetwork.CryptoCode}";
cryptoPayment.Paid = accounting.CryptoPaid.ToString() + $" {paymentNetwork.CryptoCode}"; cryptoPayment.Paid = accounting.CryptoPaid.ToString() + $" {paymentNetwork.CryptoCode}";
var onchainMethod = data.GetPaymentMethod() as Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod; var onchainMethod = data.GetPaymentMethodDetails() as Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod;
if(onchainMethod != null) if(onchainMethod != null)
{ {
cryptoPayment.Address = onchainMethod.DepositAddress.ToString(); cryptoPayment.Address = onchainMethod.DepositAddress.ToString();
@ -86,7 +86,7 @@ namespace BTCPayServer.Controllers
var payments = invoice var payments = invoice
.GetPayments() .GetPayments()
.Where(p => p.GetCryptoDataId().PaymentType == PaymentTypes.BTCLike) .Where(p => p.GetpaymentMethodId().PaymentType == PaymentTypes.BTCLike)
.Select(async payment => .Select(async payment =>
{ {
var paymentData = (Payments.Bitcoin.BitcoinLikePaymentData)payment.GetCryptoPaymentData(); var paymentData = (Payments.Bitcoin.BitcoinLikePaymentData)payment.GetCryptoPaymentData();
@ -129,65 +129,65 @@ namespace BTCPayServer.Controllers
[HttpGet] [HttpGet]
[Route("i/{invoiceId}")] [Route("i/{invoiceId}")]
[Route("i/{invoiceId}/{cryptoDataId}")] [Route("i/{invoiceId}/{paymentMethodId}")]
[Route("invoice")] [Route("invoice")]
[AcceptMediaTypeConstraint("application/bitcoin-paymentrequest", false)] [AcceptMediaTypeConstraint("application/bitcoin-paymentrequest", false)]
[XFrameOptionsAttribute(null)] [XFrameOptionsAttribute(null)]
public async Task<IActionResult> Checkout(string invoiceId, string id = null, string cryptoDataId = null) public async Task<IActionResult> Checkout(string invoiceId, string id = null, string paymentMethodId = null)
{ {
//Keep compatibility with Bitpay //Keep compatibility with Bitpay
invoiceId = invoiceId ?? id; invoiceId = invoiceId ?? id;
id = invoiceId; id = invoiceId;
//// ////
var model = await GetInvoiceModel(invoiceId, cryptoDataId); var model = await GetInvoiceModel(invoiceId, paymentMethodId);
if (model == null) if (model == null)
return NotFound(); return NotFound();
return View(nameof(Checkout), model); return View(nameof(Checkout), model);
} }
private async Task<PaymentModel> GetInvoiceModel(string invoiceId, string cryptoDataId) private async Task<PaymentModel> GetInvoiceModel(string invoiceId, string paymentMethodIdStr)
{ {
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId); var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId);
if (invoice == null) if (invoice == null)
return null; return null;
var store = await _StoreRepository.FindStore(invoice.StoreId); var store = await _StoreRepository.FindStore(invoice.StoreId);
bool isDefaultCrypto = false; bool isDefaultCrypto = false;
if (cryptoDataId == null) if (paymentMethodIdStr == null)
{ {
cryptoDataId = store.GetDefaultCrypto(); paymentMethodIdStr = store.GetDefaultCrypto();
isDefaultCrypto = true; isDefaultCrypto = true;
} }
var cryptoId = CryptoDataId.Parse(cryptoDataId); var paymentMethodId = PaymentMethodId.Parse(paymentMethodIdStr);
var network = _NetworkProvider.GetNetwork(cryptoId.CryptoCode); var network = _NetworkProvider.GetNetwork(paymentMethodId.CryptoCode);
if (invoice == null || network == null) if (invoice == null || network == null)
return null; return null;
if (!invoice.Support(cryptoId)) if (!invoice.Support(paymentMethodId))
{ {
if(!isDefaultCrypto) if(!isDefaultCrypto)
return null; return null;
var firstCryptoData = invoice.GetCryptoData(_NetworkProvider).First(); var paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider).First();
network = firstCryptoData.Network; network = paymentMethodTemp.Network;
cryptoId = firstCryptoData.GetId(); paymentMethodId = paymentMethodTemp.GetId();
} }
var cryptoData = invoice.GetCryptoData(cryptoId, _NetworkProvider); var paymentMethod = invoice.GetPaymentMethod(paymentMethodId, _NetworkProvider);
var paymentMethod = cryptoData.GetPaymentMethod(); var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails();
var dto = invoice.EntityToDTO(_NetworkProvider); var dto = invoice.EntityToDTO(_NetworkProvider);
var cryptoInfo = dto.CryptoInfo.First(o => o.GetCryptoDataId() == cryptoId); var cryptoInfo = dto.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
var currency = invoice.ProductInformation.Currency; var currency = invoice.ProductInformation.Currency;
var accounting = cryptoData.Calculate(); var accounting = paymentMethod.Calculate();
var model = new PaymentModel() var model = new PaymentModel()
{ {
CryptoCode = network.CryptoCode, CryptoCode = network.CryptoCode,
CryptoDataId = cryptoId.ToString(), paymentMethodId = paymentMethodId.ToString(),
ServerUrl = HttpContext.Request.GetAbsoluteRoot(), ServerUrl = HttpContext.Request.GetAbsoluteRoot(),
OrderId = invoice.OrderId, OrderId = invoice.OrderId,
InvoiceId = invoice.Id, InvoiceId = invoice.Id,
BtcAddress = paymentMethod.GetPaymentDestination(), BtcAddress = paymentMethodDetails.GetPaymentDestination(),
OrderAmount = (accounting.TotalDue - accounting.NetworkFee).ToString(), OrderAmount = (accounting.TotalDue - accounting.NetworkFee).ToString(),
BtcDue = accounting.Due.ToString(), BtcDue = accounting.Due.ToString(),
CustomerEmail = invoice.RefundMail, CustomerEmail = invoice.RefundMail,
@ -195,7 +195,7 @@ namespace BTCPayServer.Controllers
MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds, MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds,
MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes, MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes,
ItemDesc = invoice.ProductInformation.ItemDesc, ItemDesc = invoice.ProductInformation.ItemDesc,
Rate = FormatCurrency(cryptoData), Rate = FormatCurrency(paymentMethod),
MerchantRefLink = invoice.RedirectURL ?? "/", MerchantRefLink = invoice.RedirectURL ?? "/",
StoreName = store.StoreName, StoreName = store.StoreName,
InvoiceBitcoinUrl = cryptoInfo.PaymentUrls.BIP21, InvoiceBitcoinUrl = cryptoInfo.PaymentUrls.BIP21,
@ -203,14 +203,14 @@ namespace BTCPayServer.Controllers
BtcPaid = accounting.Paid.ToString(), BtcPaid = accounting.Paid.ToString(),
Status = invoice.Status, Status = invoice.Status,
CryptoImage = "/" + Url.Content(network.CryptoImagePath), CryptoImage = "/" + Url.Content(network.CryptoImagePath),
NetworkFeeDescription = $"{accounting.TxCount} transaction{(accounting.TxCount > 1 ? "s" : "")} x {paymentMethod.GetTxFee()} {network.CryptoCode}", NetworkFeeDescription = $"{accounting.TxCount} transaction{(accounting.TxCount > 1 ? "s" : "")} x {paymentMethodDetails.GetTxFee()} {network.CryptoCode}",
AvailableCryptos = invoice.GetCryptoData(_NetworkProvider) AvailableCryptos = invoice.GetPaymentMethods(_NetworkProvider)
.Where(i => i.Network != null) .Where(i => i.Network != null)
.Select(kv=> new PaymentModel.AvailableCrypto() .Select(kv=> new PaymentModel.AvailableCrypto()
{ {
CryptoDataId = kv.GetId().ToString(), paymentMethodId = kv.GetId().ToString(),
CryptoImage = "/" + kv.Network.CryptoImagePath, CryptoImage = "/" + kv.Network.CryptoImagePath,
Link = Url.Action(nameof(Checkout), new { invoiceId = invoiceId, cryptoDataId = kv.GetId().ToString() }) Link = Url.Action(nameof(Checkout), new { invoiceId = invoiceId, paymentMethodId = kv.GetId().ToString() })
}).Where(c => c.CryptoImage != "/") }).Where(c => c.CryptoImage != "/")
.ToList() .ToList()
}; };
@ -224,10 +224,10 @@ namespace BTCPayServer.Controllers
return model; return model;
} }
private string FormatCurrency(CryptoData cryptoData) private string FormatCurrency(PaymentMethod paymentMethod)
{ {
string currency = cryptoData.ParentEntity.ProductInformation.Currency; string currency = paymentMethod.ParentEntity.ProductInformation.Currency;
return FormatCurrency(cryptoData.Rate, currency); return FormatCurrency(paymentMethod.Rate, currency);
} }
public string FormatCurrency(decimal price, string currency) public string FormatCurrency(decimal price, string currency)
{ {
@ -247,10 +247,10 @@ namespace BTCPayServer.Controllers
[HttpGet] [HttpGet]
[Route("i/{invoiceId}/status")] [Route("i/{invoiceId}/status")]
[Route("i/{invoiceId}/{cryptoDataId}/status")] [Route("i/{invoiceId}/{paymentMethodId}/status")]
public async Task<IActionResult> GetStatus(string invoiceId, string cryptoDataId = null) public async Task<IActionResult> GetStatus(string invoiceId, string paymentMethodId = null)
{ {
var model = await GetInvoiceModel(invoiceId, cryptoDataId); var model = await GetInvoiceModel(invoiceId, paymentMethodId);
if (model == null) if (model == null)
return NotFound(); return NotFound();
return Json(model); return Json(model);

View file

@ -137,27 +137,27 @@ namespace BTCPayServer.Controllers
}); });
bool legacyBTCisSet = false; bool legacyBTCisSet = false;
var cryptoDatas = new CryptoDataDictionary(); var paymentMethods = new PaymentMethodDictionary();
foreach (var q in queries) foreach (var q in queries)
{ {
CryptoData cryptoData = new CryptoData(); PaymentMethod paymentMethod = new PaymentMethod();
cryptoData.SetId(new CryptoDataId(q.network.CryptoCode, PaymentTypes.BTCLike)); paymentMethod.SetId(new PaymentMethodId(q.network.CryptoCode, PaymentTypes.BTCLike));
Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod onchainMethod = new Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod(); Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod onchainMethod = new Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod();
onchainMethod.FeeRate = (await q.getFeeRate); onchainMethod.FeeRate = (await q.getFeeRate);
onchainMethod.TxFee = GetTxFee(storeBlob, onchainMethod.FeeRate); // assume price for 100 bytes onchainMethod.TxFee = GetTxFee(storeBlob, onchainMethod.FeeRate); // assume price for 100 bytes
cryptoData.Rate = await q.getRate; paymentMethod.Rate = await q.getRate;
onchainMethod.DepositAddress = (await q.getAddress); onchainMethod.DepositAddress = (await q.getAddress);
cryptoData.SetPaymentMethod(onchainMethod); paymentMethod.SetPaymentMethodDetails(onchainMethod);
#pragma warning disable CS0618 #pragma warning disable CS0618
if (q.network.IsBTC) if (q.network.IsBTC)
{ {
legacyBTCisSet = true; legacyBTCisSet = true;
entity.TxFee = cryptoData.TxFee; entity.TxFee = paymentMethod.TxFee;
entity.Rate = cryptoData.Rate; entity.Rate = paymentMethod.Rate;
entity.DepositAddress = cryptoData.DepositAddress; entity.DepositAddress = paymentMethod.DepositAddress;
} }
#pragma warning restore CS0618 #pragma warning restore CS0618
cryptoDatas.Add(cryptoData); paymentMethods.Add(paymentMethod);
} }
if (!legacyBTCisSet) if (!legacyBTCisSet)
@ -177,7 +177,7 @@ namespace BTCPayServer.Controllers
#pragma warning restore CS0618 #pragma warning restore CS0618
} }
entity.SetCryptoData(cryptoDatas); entity.SetPaymentMethods(paymentMethods);
entity.PosData = invoice.PosData; entity.PosData = invoice.PosData;
entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, _NetworkProvider); entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, _NetworkProvider);
_EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, "invoice_created")); _EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, "invoice_created"));

View file

@ -30,21 +30,21 @@ namespace BTCPayServer.Data
return Address; return Address;
return Address.Substring(0, index); return Address.Substring(0, index);
} }
public AddressInvoiceData Set(string address, CryptoDataId cryptoDataId) public AddressInvoiceData Set(string address, PaymentMethodId paymentMethodId)
{ {
Address = address + "#" + cryptoDataId?.ToString(); Address = address + "#" + paymentMethodId?.ToString();
return this; return this;
} }
public CryptoDataId GetCryptoDataId() public PaymentMethodId GetpaymentMethodId()
{ {
if (Address == null) if (Address == null)
return null; return null;
var index = Address.LastIndexOf("#", StringComparison.InvariantCulture); var index = Address.LastIndexOf("#", StringComparison.InvariantCulture);
// Legacy AddressInvoiceData does not have the CryptoDataId attached to the Address // Legacy AddressInvoiceData does not have the paymentMethodId attached to the Address
if (index == -1) if (index == -1)
return CryptoDataId.Parse("BTC"); return PaymentMethodId.Parse("BTC");
///////////////////////// /////////////////////////
return CryptoDataId.Parse(Address.Substring(index + 1)); return PaymentMethodId.Parse(Address.Substring(index + 1));
} }
#pragma warning restore CS0618 #pragma warning restore CS0618

View file

@ -30,9 +30,9 @@ namespace BTCPayServer
{ {
public static class Extensions public static class Extensions
{ {
public static CryptoDataId GetCryptoDataId(this InvoiceCryptoInfo info) public static PaymentMethodId GetpaymentMethodId(this InvoiceCryptoInfo info)
{ {
return new CryptoDataId(info.CryptoCode, Enum.Parse<PaymentTypes>(info.PaymentType)); return new PaymentMethodId(info.CryptoCode, Enum.Parse<PaymentTypes>(info.PaymentType));
} }
public static async Task CloseSocket(this WebSocket webSocket) public static async Task CloseSocket(this WebSocket webSocket)
{ {

View file

@ -201,7 +201,7 @@ namespace BTCPayServer.HostedServices
// We keep backward compatibility with bitpay by passing BTC info to the notification // We keep backward compatibility with bitpay by passing BTC info to the notification
// we don't pass other info, as it is a bad idea to use IPN data for logic processing (can be faked) // we don't pass other info, as it is a bad idea to use IPN data for logic processing (can be faked)
var btcCryptoInfo = dto.CryptoInfo.FirstOrDefault(c => c.GetCryptoDataId() == new CryptoDataId("BTC", Payments.PaymentTypes.BTCLike)); var btcCryptoInfo = dto.CryptoInfo.FirstOrDefault(c => c.GetpaymentMethodId() == new PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike));
if (btcCryptoInfo != null) if (btcCryptoInfo != null)
{ {
#pragma warning disable CS0618 #pragma warning disable CS0618

View file

@ -72,16 +72,16 @@ namespace BTCPayServer.HostedServices
var derivationStrategies = invoice.GetDerivationStrategies(_NetworkProvider).ToArray(); var derivationStrategies = invoice.GetDerivationStrategies(_NetworkProvider).ToArray();
var payments = invoice.GetPayments().Where(p => p.Accounted).ToArray(); var payments = invoice.GetPayments().Where(p => p.Accounted).ToArray();
var cryptoDataAll = invoice.GetCryptoData(_NetworkProvider); var allPaymentMethods = invoice.GetPaymentMethods(_NetworkProvider);
foreach (var cryptoData in cryptoDataAll.Select(c => c)) foreach (var paymentMethod in allPaymentMethods.Select(c => c))
{ {
var accounting = cryptoData.Calculate(); var accounting = paymentMethod.Calculate();
var network = _NetworkProvider.GetNetwork(cryptoData.GetId().CryptoCode); var network = _NetworkProvider.GetNetwork(paymentMethod.GetId().CryptoCode);
if (network == null) if (network == null)
continue; continue;
var totalPaid = payments.Select(p => p.GetValue(allPaymentMethods, paymentMethod.GetId())).Sum();
if (invoice.Status == "new" || invoice.Status == "expired") if (invoice.Status == "new" || invoice.Status == "expired")
{ {
var totalPaid = payments.Select(p => p.GetValue(cryptoDataAll, cryptoData.GetId())).Sum();
if (totalPaid >= accounting.TotalDue) if (totalPaid >= accounting.TotalDue)
{ {
if (invoice.Status == "new") if (invoice.Status == "new")
@ -107,11 +107,34 @@ namespace BTCPayServer.HostedServices
} }
} }
// Just make sure RBF did not cancelled a payment
if (invoice.Status == "paid")
{
if (totalPaid == accounting.TotalDue && invoice.ExceptionStatus == "paidOver")
{
invoice.ExceptionStatus = null;
context.MarkDirty();
}
if (totalPaid > accounting.TotalDue && invoice.ExceptionStatus != "paidOver")
{
invoice.ExceptionStatus = "paidOver";
context.MarkDirty();
}
if (totalPaid < accounting.TotalDue)
{
invoice.Status = "new";
invoice.ExceptionStatus = totalPaid == Money.Zero ? null : "paidPartial";
context.MarkDirty();
}
}
if (invoice.Status == "paid") if (invoice.Status == "paid")
{ {
var transactions = payments.Where(p => p.GetCryptoPaymentData().PaymentConfirmed(p, invoice.SpeedPolicy, network)); var transactions = payments.Where(p => p.GetCryptoPaymentData().PaymentConfirmed(p, invoice.SpeedPolicy, network));
var totalConfirmed = transactions.Select(t => t.GetValue(cryptoDataAll, cryptoData.GetId())).Sum(); var totalConfirmed = transactions.Select(t => t.GetValue(allPaymentMethods, paymentMethod.GetId())).Sum();
if (// Is after the monitoring deadline if (// Is after the monitoring deadline
(invoice.MonitoringExpiration < DateTimeOffset.UtcNow) (invoice.MonitoringExpiration < DateTimeOffset.UtcNow)
@ -136,7 +159,7 @@ namespace BTCPayServer.HostedServices
if (invoice.Status == "confirmed") if (invoice.Status == "confirmed")
{ {
var transactions = payments.Where(p => p.GetCryptoPaymentData().PaymentCompleted(p, network)); var transactions = payments.Where(p => p.GetCryptoPaymentData().PaymentCompleted(p, network));
var totalConfirmed = transactions.Select(t => t.GetValue(cryptoDataAll, cryptoData.GetId())).Sum(); var totalConfirmed = transactions.Select(t => t.GetValue(allPaymentMethods, paymentMethod.GetId())).Sum();
if (totalConfirmed >= accounting.TotalDue) if (totalConfirmed >= accounting.TotalDue)
{ {
context.Events.Add(new InvoiceEvent(invoice, 1006, "invoice_completed")); context.Events.Add(new InvoiceEvent(invoice, 1006, "invoice_completed"));

View file

@ -9,7 +9,7 @@ namespace BTCPayServer.Models.InvoicingModels
{ {
public class AvailableCrypto public class AvailableCrypto
{ {
public string CryptoDataId { get; set; } public string paymentMethodId { get; set; }
public string CryptoImage { get; set; } public string CryptoImage { get; set; }
public string Link { get; set; } public string Link { get; set; }
} }
@ -41,6 +41,6 @@ namespace BTCPayServer.Models.InvoicingModels
public string NetworkFeeDescription { get; internal set; } public string NetworkFeeDescription { get; internal set; }
public int MaxTimeMinutes { get; internal set; } public int MaxTimeMinutes { get; internal set; }
public string PaymentType { get; internal set; } public string PaymentType { get; internal set; }
public string CryptoDataId { get; internal set; } public string paymentMethodId { get; internal set; }
} }
} }

View file

@ -8,7 +8,7 @@ using Newtonsoft.Json;
namespace BTCPayServer.Payments.Bitcoin namespace BTCPayServer.Payments.Bitcoin
{ {
public class BitcoinLikeOnChainPaymentMethod : IPaymentMethod public class BitcoinLikeOnChainPaymentMethod : IPaymentMethodDetails
{ {
public PaymentTypes GetPaymentType() public PaymentTypes GetPaymentType()
{ {

View file

@ -211,7 +211,7 @@ namespace BTCPayServer.Payments.Bitcoin
IEnumerable<BitcoinLikePaymentData> GetAllBitcoinPaymentData(InvoiceEntity invoice) IEnumerable<BitcoinLikePaymentData> GetAllBitcoinPaymentData(InvoiceEntity invoice)
{ {
return invoice.GetPayments() return invoice.GetPayments()
.Where(p => p.GetCryptoDataId().PaymentType == PaymentTypes.BTCLike) .Where(p => p.GetpaymentMethodId().PaymentType == PaymentTypes.BTCLike)
.Select(p => (BitcoinLikePaymentData)p.GetCryptoPaymentData()); .Select(p => (BitcoinLikePaymentData)p.GetCryptoPaymentData());
} }
@ -225,7 +225,7 @@ namespace BTCPayServer.Payments.Bitcoin
var conflicts = GetConflicts(transactions.Select(t => t.Value)); var conflicts = GetConflicts(transactions.Select(t => t.Value));
foreach (var payment in invoice.GetPayments(wallet.Network)) foreach (var payment in invoice.GetPayments(wallet.Network))
{ {
if (payment.GetCryptoDataId().PaymentType != PaymentTypes.BTCLike) if (payment.GetpaymentMethodId().PaymentType != PaymentTypes.BTCLike)
continue; continue;
var paymentData = (BitcoinLikePaymentData)payment.GetCryptoPaymentData(); var paymentData = (BitcoinLikePaymentData)payment.GetCryptoPaymentData();
if (!transactions.TryGetValue(paymentData.Outpoint.Hash, out TransactionResult tx)) if (!transactions.TryGetValue(paymentData.Outpoint.Hash, out TransactionResult tx))
@ -330,7 +330,7 @@ namespace BTCPayServer.Payments.Bitcoin
var strategy = invoice.GetDerivationStrategy(network); var strategy = invoice.GetDerivationStrategy(network);
if (strategy == null) if (strategy == null)
continue; continue;
var cryptoId = new CryptoDataId(network.CryptoCode, PaymentTypes.BTCLike); var cryptoId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
if (!invoice.Support(cryptoId)) if (!invoice.Support(cryptoId))
continue; continue;
var coins = (await wallet.GetUnspentCoins(strategy)) var coins = (await wallet.GetUnspentCoins(strategy))
@ -353,16 +353,18 @@ namespace BTCPayServer.Payments.Bitcoin
{ {
var paymentData = (BitcoinLikePaymentData)payment.GetCryptoPaymentData(); var paymentData = (BitcoinLikePaymentData)payment.GetCryptoPaymentData();
var invoice = (await UpdatePaymentStates(wallet, invoiceId)); var invoice = (await UpdatePaymentStates(wallet, invoiceId));
var cryptoData = invoice.GetCryptoData(wallet.Network, PaymentTypes.BTCLike, _ExplorerClients.NetworkProviders); var paymentMethod = invoice.GetPaymentMethod(wallet.Network, PaymentTypes.BTCLike, _ExplorerClients.NetworkProviders);
var method = cryptoData.GetPaymentMethod() as BitcoinLikeOnChainPaymentMethod; if (paymentMethod != null &&
if (method.DepositAddress.ScriptPubKey == paymentData.Output.ScriptPubKey && cryptoData.Calculate().Due > Money.Zero) paymentMethod.GetPaymentMethodDetails() is BitcoinLikeOnChainPaymentMethod btc &&
btc.DepositAddress.ScriptPubKey == paymentData.Output.ScriptPubKey &&
paymentMethod.Calculate().Due > Money.Zero)
{ {
var address = await wallet.ReserveAddressAsync(strategy); var address = await wallet.ReserveAddressAsync(strategy);
method.DepositAddress = address; btc.DepositAddress = address;
await _InvoiceRepository.NewAddress(invoiceId, method, wallet.Network); await _InvoiceRepository.NewAddress(invoiceId, btc, wallet.Network);
_Aggregator.Publish(new InvoiceNewAddressEvent(invoiceId, address.ToString(), wallet.Network)); _Aggregator.Publish(new InvoiceNewAddressEvent(invoiceId, address.ToString(), wallet.Network));
cryptoData.SetPaymentMethod(method); paymentMethod.SetPaymentMethodDetails(btc);
invoice.SetCryptoData(cryptoData); invoice.SetPaymentMethod(paymentMethod);
} }
wallet.InvalidateCache(strategy); wallet.InvalidateCache(strategy);
_Aggregator.Publish(new InvoiceEvent(invoiceId, 1002, "invoice_receivedPayment")); _Aggregator.Publish(new InvoiceEvent(invoiceId, 1002, "invoice_receivedPayment"));

View file

@ -6,7 +6,7 @@ using NBitcoin;
namespace BTCPayServer.Payments namespace BTCPayServer.Payments
{ {
public interface IPaymentMethod public interface IPaymentMethodDetails
{ {
string GetPaymentDestination(); string GetPaymentDestination();
PaymentTypes GetPaymentType(); PaymentTypes GetPaymentType();

View file

@ -7,15 +7,22 @@ using BTCPayServer.Payments;
namespace BTCPayServer.Services.Invoices namespace BTCPayServer.Services.Invoices
{ {
public class CryptoDataDictionary : IEnumerable<CryptoData> public class PaymentMethodDictionary : IEnumerable<PaymentMethod>
{ {
Dictionary<CryptoDataId, CryptoData> _Inner = new Dictionary<CryptoDataId, CryptoData>(); Dictionary<PaymentMethodId, PaymentMethod> _Inner = new Dictionary<PaymentMethodId, PaymentMethod>();
public CryptoDataDictionary() public PaymentMethodDictionary()
{ {
} }
public CryptoData this[CryptoDataId index] public PaymentMethodDictionary(BTCPayNetworkProvider networkProvider)
{
NetworkProvider = networkProvider;
}
public BTCPayNetworkProvider NetworkProvider { get; set; }
public PaymentMethod this[PaymentMethodId index]
{ {
get get
{ {
@ -23,30 +30,30 @@ namespace BTCPayServer.Services.Invoices
} }
} }
public void Add(CryptoData cryptoData) public void Add(PaymentMethod paymentMethod)
{ {
_Inner.Add(cryptoData.GetId(), cryptoData); _Inner.Add(paymentMethod.GetId(), paymentMethod);
} }
public void Remove(CryptoData cryptoData) public void Remove(PaymentMethod paymentMethod)
{ {
_Inner.Remove(cryptoData.GetId()); _Inner.Remove(paymentMethod.GetId());
} }
public bool TryGetValue(CryptoDataId cryptoDataId, out CryptoData data) public bool TryGetValue(PaymentMethodId paymentMethodId, out PaymentMethod data)
{ {
if (cryptoDataId == null) if (paymentMethodId == null)
throw new ArgumentNullException(nameof(cryptoDataId)); throw new ArgumentNullException(nameof(paymentMethodId));
return _Inner.TryGetValue(cryptoDataId, out data); return _Inner.TryGetValue(paymentMethodId, out data);
} }
public void AddOrReplace(CryptoData cryptoData) public void AddOrReplace(PaymentMethod paymentMethod)
{ {
var key = cryptoData.GetId(); var key = paymentMethod.GetId();
_Inner.Remove(key); _Inner.Remove(key);
_Inner.Add(key, cryptoData); _Inner.Add(key, paymentMethod);
} }
public IEnumerator<CryptoData> GetEnumerator() public IEnumerator<PaymentMethod> GetEnumerator()
{ {
return _Inner.Values.GetEnumerator(); return _Inner.Values.GetEnumerator();
} }
@ -56,18 +63,18 @@ namespace BTCPayServer.Services.Invoices
return GetEnumerator(); return GetEnumerator();
} }
public CryptoData TryGet(CryptoDataId cryptoDataId) public PaymentMethod TryGet(PaymentMethodId paymentMethodId)
{ {
if (cryptoDataId == null) if (paymentMethodId == null)
throw new ArgumentNullException(nameof(cryptoDataId)); throw new ArgumentNullException(nameof(paymentMethodId));
_Inner.TryGetValue(cryptoDataId, out var value); _Inner.TryGetValue(paymentMethodId, out var value);
return value; return value;
} }
public CryptoData TryGet(string network, PaymentTypes paymentType) public PaymentMethod TryGet(string network, PaymentTypes paymentType)
{ {
if (network == null) if (network == null)
throw new ArgumentNullException(nameof(network)); throw new ArgumentNullException(nameof(network));
var id = new CryptoDataId(network, paymentType); var id = new PaymentMethodId(network, paymentType);
return TryGet(id); return TryGet(id);
} }
} }

View file

@ -122,7 +122,7 @@ namespace BTCPayServer.Services.Invoices
{ {
get; set; get; set;
} }
[Obsolete("Use GetCryptoData(network).Rate instead")] [Obsolete("Use GetPaymentMethod(network) instead")]
public decimal Rate public decimal Rate
{ {
get; set; get; set;
@ -136,7 +136,7 @@ namespace BTCPayServer.Services.Invoices
get; set; get; set;
} }
[Obsolete("Use GetCryptoData(network).DepositAddress instead")] [Obsolete("Use GetPaymentMethod(network).GetPaymentMethodDetails().GetDestinationAddress() instead")]
public string DepositAddress public string DepositAddress
{ {
get; set; get; set;
@ -282,7 +282,7 @@ namespace BTCPayServer.Services.Invoices
set; set;
} }
[Obsolete("Use GetCryptoData(network).TxFee instead")] [Obsolete("Use GetPaymentMethod(network).GetTxFee() instead")]
public Money TxFee public Money TxFee
{ {
get; get;
@ -304,8 +304,9 @@ namespace BTCPayServer.Services.Invoices
set; set;
} }
[Obsolete("Use Set/GetCryptoData() instead")] [Obsolete("Use Set/GetPaymentMethod() instead")]
public JObject CryptoData { get; set; } [JsonProperty(PropertyName = "cryptoData")]
public JObject PaymentMethod { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public DateTimeOffset MonitoringExpiration public DateTimeOffset MonitoringExpiration
@ -350,7 +351,7 @@ namespace BTCPayServer.Services.Invoices
}; };
dto.CryptoInfo = new List<NBitpayClient.InvoiceCryptoInfo>(); dto.CryptoInfo = new List<NBitpayClient.InvoiceCryptoInfo>();
foreach (var info in this.GetCryptoData(networkProvider, true)) foreach (var info in this.GetPaymentMethods(networkProvider, true))
{ {
var accounting = info.Calculate(); var accounting = info.Calculate();
var cryptoInfo = new NBitpayClient.InvoiceCryptoInfo(); var cryptoInfo = new NBitpayClient.InvoiceCryptoInfo();
@ -366,7 +367,7 @@ namespace BTCPayServer.Services.Invoices
cryptoInfo.TxCount = accounting.TxCount; cryptoInfo.TxCount = accounting.TxCount;
cryptoInfo.CryptoPaid = accounting.CryptoPaid.ToString(); cryptoInfo.CryptoPaid = accounting.CryptoPaid.ToString();
cryptoInfo.Address = info.GetPaymentMethod()?.GetPaymentDestination(); cryptoInfo.Address = info.GetPaymentMethodDetails()?.GetPaymentDestination();
cryptoInfo.ExRates = new Dictionary<string, double> cryptoInfo.ExRates = new Dictionary<string, double>
{ {
{ ProductInformation.Currency, (double)cryptoInfo.Rate } { ProductInformation.Currency, (double)cryptoInfo.Rate }
@ -417,48 +418,50 @@ namespace BTCPayServer.Services.Invoices
JsonConvert.PopulateObject(str, dest); JsonConvert.PopulateObject(str, dest);
} }
internal bool Support(CryptoDataId cryptoDataId) internal bool Support(PaymentMethodId paymentMethodId)
{ {
var rates = GetCryptoData(null); var rates = GetPaymentMethods(null);
return rates.TryGet(cryptoDataId) != null; return rates.TryGet(paymentMethodId) != null;
} }
public CryptoData GetCryptoData(CryptoDataId cryptoDataId, BTCPayNetworkProvider networkProvider) public PaymentMethod GetPaymentMethod(PaymentMethodId paymentMethodId, BTCPayNetworkProvider networkProvider)
{ {
GetCryptoData(networkProvider).TryGetValue(cryptoDataId, out var data); GetPaymentMethods(networkProvider).TryGetValue(paymentMethodId, out var data);
return data; return data;
} }
public CryptoData GetCryptoData(BTCPayNetwork network, PaymentTypes paymentType, BTCPayNetworkProvider networkProvider) public PaymentMethod GetPaymentMethod(BTCPayNetwork network, PaymentTypes paymentType, BTCPayNetworkProvider networkProvider)
{ {
return GetCryptoData(new CryptoDataId(network.CryptoCode, paymentType), networkProvider); return GetPaymentMethod(new PaymentMethodId(network.CryptoCode, paymentType), networkProvider);
} }
public CryptoDataDictionary GetCryptoData(BTCPayNetworkProvider networkProvider, bool alwaysIncludeBTC = false) public PaymentMethodDictionary GetPaymentMethods(BTCPayNetworkProvider networkProvider, bool alwaysIncludeBTC = false)
{ {
CryptoDataDictionary rates = new CryptoDataDictionary(); PaymentMethodDictionary rates = new PaymentMethodDictionary(networkProvider);
var serializer = new Serializer(Dummy); var serializer = new Serializer(Dummy);
CryptoData phantom = null; PaymentMethod phantom = null;
#pragma warning disable CS0618 #pragma warning disable CS0618
// Legacy // Legacy
if (alwaysIncludeBTC) if (alwaysIncludeBTC)
{ {
var btcNetwork = networkProvider?.GetNetwork("BTC"); var btcNetwork = networkProvider?.GetNetwork("BTC");
phantom = new CryptoData() { ParentEntity = this, IsPhantomBTC = true, Rate = Rate, CryptoCode = "BTC", TxFee = TxFee, FeeRate = new FeeRate(TxFee, 100), DepositAddress = DepositAddress, Network = btcNetwork }; phantom = new PaymentMethod() { ParentEntity = this, IsPhantomBTC = true, Rate = Rate, CryptoCode = "BTC", TxFee = TxFee, FeeRate = new FeeRate(TxFee, 100), DepositAddress = DepositAddress, Network = btcNetwork };
rates.Add(phantom); if (btcNetwork != null || networkProvider == null)
rates.Add(phantom);
} }
if (CryptoData != null) if (PaymentMethod != null)
{ {
foreach (var prop in CryptoData.Properties()) foreach (var prop in PaymentMethod.Properties())
{ {
if (prop.Name == "BTC" && phantom != null) if (prop.Name == "BTC" && phantom != null)
rates.Remove(phantom); rates.Remove(phantom);
var r = serializer.ToObject<CryptoData>(prop.Value.ToString()); var r = serializer.ToObject<PaymentMethod>(prop.Value.ToString());
var cryptoDataId = CryptoDataId.Parse(prop.Name); var paymentMethodId = PaymentMethodId.Parse(prop.Name);
r.CryptoCode = cryptoDataId.CryptoCode; r.CryptoCode = paymentMethodId.CryptoCode;
r.PaymentType = cryptoDataId.PaymentType.ToString(); r.PaymentType = paymentMethodId.PaymentType.ToString();
r.ParentEntity = this; r.ParentEntity = this;
r.Network = networkProvider?.GetNetwork(r.CryptoCode); r.Network = networkProvider?.GetNetwork(r.CryptoCode);
rates.Add(r); if(r.Network != null || networkProvider == null)
rates.Add(r);
} }
} }
#pragma warning restore CS0618 #pragma warning restore CS0618
@ -467,31 +470,33 @@ namespace BTCPayServer.Services.Invoices
Network Dummy = Network.Main; Network Dummy = Network.Main;
public void SetCryptoData(CryptoData cryptoData) public void SetPaymentMethod(PaymentMethod paymentMethod)
{ {
var dict = GetCryptoData(null); var dict = GetPaymentMethods(null);
dict.AddOrReplace(cryptoData); dict.AddOrReplace(paymentMethod);
SetCryptoData(dict); SetPaymentMethods(dict);
} }
public void SetCryptoData(CryptoDataDictionary cryptoData) public void SetPaymentMethods(PaymentMethodDictionary paymentMethods)
{ {
if (paymentMethods.NetworkProvider != null)
throw new InvalidOperationException($"{nameof(paymentMethods)} should have NetworkProvider to null");
var obj = new JObject(); var obj = new JObject();
var serializer = new Serializer(Dummy); var serializer = new Serializer(Dummy);
#pragma warning disable CS0618 #pragma warning disable CS0618
foreach (var v in cryptoData) foreach (var v in paymentMethods)
{ {
var clone = serializer.ToObject<CryptoData>(serializer.ToString(v)); var clone = serializer.ToObject<PaymentMethod>(serializer.ToString(v));
clone.CryptoCode = null; clone.CryptoCode = null;
clone.PaymentType = null; clone.PaymentType = null;
obj.Add(new JProperty(v.GetId().ToString(), JObject.Parse(serializer.ToString(clone)))); obj.Add(new JProperty(v.GetId().ToString(), JObject.Parse(serializer.ToString(clone))));
} }
CryptoData = obj; PaymentMethod = obj;
#pragma warning restore CS0618 #pragma warning restore CS0618
} }
} }
public class CryptoDataAccounting public class PaymentMethodAccounting
{ {
/// <summary> /// <summary>
/// Total amount of this invoice /// Total amount of this invoice
@ -523,9 +528,9 @@ namespace BTCPayServer.Services.Invoices
public Money NetworkFee { get; set; } public Money NetworkFee { get; set; }
} }
public class CryptoDataId public class PaymentMethodId
{ {
public CryptoDataId(string cryptoCode, PaymentTypes paymentType) public PaymentMethodId(string cryptoCode, PaymentTypes paymentType)
{ {
if (cryptoCode == null) if (cryptoCode == null)
throw new ArgumentNullException(nameof(cryptoCode)); throw new ArgumentNullException(nameof(cryptoCode));
@ -538,12 +543,12 @@ namespace BTCPayServer.Services.Invoices
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
CryptoDataId item = obj as CryptoDataId; PaymentMethodId item = obj as PaymentMethodId;
if (item == null) if (item == null)
return false; return false;
return ToString().Equals(item.ToString(), StringComparison.InvariantCulture); return ToString().Equals(item.ToString(), StringComparison.InvariantCulture);
} }
public static bool operator ==(CryptoDataId a, CryptoDataId b) public static bool operator ==(PaymentMethodId a, PaymentMethodId b)
{ {
if (System.Object.ReferenceEquals(a, b)) if (System.Object.ReferenceEquals(a, b))
return true; return true;
@ -552,7 +557,7 @@ namespace BTCPayServer.Services.Invoices
return a.ToString() == b.ToString(); return a.ToString() == b.ToString();
} }
public static bool operator !=(CryptoDataId a, CryptoDataId b) public static bool operator !=(PaymentMethodId a, PaymentMethodId b)
{ {
return !(a == b); return !(a == b);
} }
@ -571,14 +576,14 @@ namespace BTCPayServer.Services.Invoices
return CryptoCode + "_" + PaymentType.ToString(); return CryptoCode + "_" + PaymentType.ToString();
} }
public static CryptoDataId Parse(string str) public static PaymentMethodId Parse(string str)
{ {
var parts = str.Split('_'); var parts = str.Split('_');
return new CryptoDataId(parts[0], parts.Length == 1 ? PaymentTypes.BTCLike : Enum.Parse<PaymentTypes>(parts[1])); return new PaymentMethodId(parts[0], parts.Length == 1 ? PaymentTypes.BTCLike : Enum.Parse<PaymentTypes>(parts[1]));
} }
} }
public class CryptoData public class PaymentMethod
{ {
[JsonIgnore] [JsonIgnore]
public InvoiceEntity ParentEntity { get; set; } public InvoiceEntity ParentEntity { get; set; }
@ -592,14 +597,14 @@ namespace BTCPayServer.Services.Invoices
public string PaymentType { get; set; } public string PaymentType { get; set; }
public CryptoDataId GetId() public PaymentMethodId GetId()
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
return new CryptoDataId(CryptoCode, string.IsNullOrEmpty(PaymentType) ? PaymentTypes.BTCLike : Enum.Parse<PaymentTypes>(PaymentType)); return new PaymentMethodId(CryptoCode, string.IsNullOrEmpty(PaymentType) ? PaymentTypes.BTCLike : Enum.Parse<PaymentTypes>(PaymentType));
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
} }
public void SetId(CryptoDataId id) public void SetId(PaymentMethodId id)
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
CryptoCode = id.CryptoCode; CryptoCode = id.CryptoCode;
@ -610,13 +615,14 @@ namespace BTCPayServer.Services.Invoices
[JsonProperty(PropertyName = "rate")] [JsonProperty(PropertyName = "rate")]
public decimal Rate { get; set; } public decimal Rate { get; set; }
[Obsolete("Use GetPaymentMethod() instead")] [Obsolete("Use GetPaymentMethodDetails() instead")]
public JObject PaymentMethod { get; set; } [JsonProperty(PropertyName = "paymentMethod")]
public IPaymentMethod GetPaymentMethod() public JObject PaymentMethodDetails { get; set; }
public IPaymentMethodDetails GetPaymentMethodDetails()
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
// Legacy, old code does not have PaymentMethods // Legacy, old code does not have PaymentMethods
if (string.IsNullOrEmpty(PaymentType) || PaymentMethod == null) if (string.IsNullOrEmpty(PaymentType) || PaymentMethodDetails == null)
{ {
return new Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod() return new Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod()
{ {
@ -630,7 +636,7 @@ namespace BTCPayServer.Services.Invoices
if (GetId().PaymentType == PaymentTypes.BTCLike) if (GetId().PaymentType == PaymentTypes.BTCLike)
{ {
var method = DeserializePaymentMethod<Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod>(PaymentMethod); var method = DeserializePaymentMethodDetails<Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod>(PaymentMethodDetails);
method.TxFee = TxFee; method.TxFee = TxFee;
method.DepositAddress = BitcoinAddress.Create(DepositAddress, Network?.NBitcoinNetwork); method.DepositAddress = BitcoinAddress.Create(DepositAddress, Network?.NBitcoinNetwork);
method.FeeRate = FeeRate; method.FeeRate = FeeRate;
@ -641,12 +647,12 @@ namespace BTCPayServer.Services.Invoices
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
} }
private T DeserializePaymentMethod<T>(JObject jobj) where T : class, IPaymentMethod private T DeserializePaymentMethodDetails<T>(JObject jobj) where T : class, IPaymentMethodDetails
{ {
return JsonConvert.DeserializeObject<T>(jobj.ToString()); return JsonConvert.DeserializeObject<T>(jobj.ToString());
} }
public void SetPaymentMethod(IPaymentMethod paymentMethod) public void SetPaymentMethodDetails(IPaymentMethodDetails paymentMethod)
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
// Legacy, need to fill the old fields // Legacy, need to fill the old fields
@ -663,7 +669,7 @@ namespace BTCPayServer.Services.Invoices
DepositAddress = bitcoinPaymentMethod.DepositAddress.ToString(); DepositAddress = bitcoinPaymentMethod.DepositAddress.ToString();
} }
var jobj = JObject.Parse(JsonConvert.SerializeObject(paymentMethod)); var jobj = JObject.Parse(JsonConvert.SerializeObject(paymentMethod));
PaymentMethod = jobj; PaymentMethodDetails = jobj;
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
} }
@ -681,9 +687,9 @@ namespace BTCPayServer.Services.Invoices
[JsonIgnore] [JsonIgnore]
public bool IsPhantomBTC { get; set; } public bool IsPhantomBTC { get; set; }
public CryptoDataAccounting Calculate() public PaymentMethodAccounting Calculate()
{ {
var cryptoData = ParentEntity.GetCryptoData(null, IsPhantomBTC); var paymentMethods = ParentEntity.GetPaymentMethods(null, IsPhantomBTC);
var totalDue = Money.Coins(ParentEntity.ProductInformation.Price / Rate); var totalDue = Money.Coins(ParentEntity.ProductInformation.Price / Rate);
var paid = Money.Zero; var paid = Money.Zero;
var cryptoPaid = Money.Zero; var cryptoPaid = Money.Zero;
@ -697,15 +703,15 @@ namespace BTCPayServer.Services.Invoices
.OrderBy(p => p.ReceivedTime) .OrderBy(p => p.ReceivedTime)
.Select(_ => .Select(_ =>
{ {
var txFee = _.GetValue(cryptoData, GetId(), cryptoData[_.GetCryptoDataId()].GetTxFee()); var txFee = _.GetValue(paymentMethods, GetId(), paymentMethods[_.GetpaymentMethodId()].GetTxFee());
paid += _.GetValue(cryptoData, GetId()); paid += _.GetValue(paymentMethods, GetId());
if (!paidEnough) if (!paidEnough)
{ {
totalDue += txFee; totalDue += txFee;
paidTxFee += txFee; paidTxFee += txFee;
} }
paidEnough |= totalDue <= paid; paidEnough |= totalDue <= paid;
if (GetId() == _.GetCryptoDataId()) if (GetId() == _.GetpaymentMethodId())
{ {
cryptoPaid += _.GetCryptoPaymentData().GetValue(); cryptoPaid += _.GetCryptoPaymentData().GetValue();
txCount++; txCount++;
@ -720,7 +726,7 @@ namespace BTCPayServer.Services.Invoices
totalDue += GetTxFee(); totalDue += GetTxFee();
paidTxFee += GetTxFee(); paidTxFee += GetTxFee();
} }
var accounting = new CryptoDataAccounting(); var accounting = new PaymentMethodAccounting();
accounting.TotalDue = totalDue; accounting.TotalDue = totalDue;
accounting.Paid = paid; accounting.Paid = paid;
accounting.TxCount = txCount; accounting.TxCount = txCount;
@ -732,7 +738,7 @@ namespace BTCPayServer.Services.Invoices
private Money GetTxFee() private Money GetTxFee()
{ {
var method = GetPaymentMethod(); var method = GetPaymentMethodDetails();
if (method == null) if (method == null)
return Money.Zero; return Money.Zero;
return method.GetTxFee(); return method.GetTxFee();
@ -764,7 +770,7 @@ namespace BTCPayServer.Services.Invoices
} }
[Obsolete("Use GetCryptoDataId().CryptoCode instead")] [Obsolete("Use GetpaymentMethodId().CryptoCode instead")]
public string CryptoCode public string CryptoCode
{ {
get; get;
@ -773,7 +779,7 @@ namespace BTCPayServer.Services.Invoices
[Obsolete("Use GetCryptoPaymentData() instead")] [Obsolete("Use GetCryptoPaymentData() instead")]
public string CryptoPaymentData { get; set; } public string CryptoPaymentData { get; set; }
[Obsolete("Use GetCryptoDataId().PaymentType instead")] [Obsolete("Use GetpaymentMethodId().PaymentType instead")]
public string CryptoPaymentDataType { get; set; } public string CryptoPaymentDataType { get; set; }
@ -791,7 +797,7 @@ namespace BTCPayServer.Services.Invoices
paymentData.Legacy = true; paymentData.Legacy = true;
return paymentData; return paymentData;
} }
if (GetCryptoDataId().PaymentType == PaymentTypes.BTCLike) if (GetpaymentMethodId().PaymentType == PaymentTypes.BTCLike)
{ {
var paymentData = JsonConvert.DeserializeObject<Payments.Bitcoin.BitcoinLikePaymentData>(CryptoPaymentData); var paymentData = JsonConvert.DeserializeObject<Payments.Bitcoin.BitcoinLikePaymentData>(CryptoPaymentData);
// legacy // legacy
@ -820,27 +826,27 @@ namespace BTCPayServer.Services.Invoices
CryptoPaymentData = JsonConvert.SerializeObject(cryptoPaymentData); CryptoPaymentData = JsonConvert.SerializeObject(cryptoPaymentData);
#pragma warning restore CS0618 #pragma warning restore CS0618
} }
public Money GetValue(CryptoDataDictionary cryptoData, CryptoDataId cryptoDataId, Money value = null) public Money GetValue(PaymentMethodDictionary paymentMethods, PaymentMethodId paymentMethodId, Money value = null)
{ {
#pragma warning disable CS0618 #pragma warning disable CS0618
value = value ?? Output.Value; value = value ?? Output.Value;
#pragma warning restore CS0618 #pragma warning restore CS0618
var to = cryptoDataId; var to = paymentMethodId;
var from = this.GetCryptoDataId(); var from = this.GetpaymentMethodId();
if (to == from) if (to == from)
return value; return value;
var fromRate = cryptoData[from].Rate; var fromRate = paymentMethods[from].Rate;
var toRate = cryptoData[to].Rate; var toRate = paymentMethods[to].Rate;
var fiatValue = fromRate * value.ToDecimal(MoneyUnit.BTC); var fiatValue = fromRate * value.ToDecimal(MoneyUnit.BTC);
var otherCurrencyValue = toRate == 0 ? 0.0m : fiatValue / toRate; var otherCurrencyValue = toRate == 0 ? 0.0m : fiatValue / toRate;
return Money.Coins(otherCurrencyValue); return Money.Coins(otherCurrencyValue);
} }
public CryptoDataId GetCryptoDataId() public PaymentMethodId GetpaymentMethodId()
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
return new CryptoDataId(CryptoCode ?? "BTC", string.IsNullOrEmpty(CryptoPaymentDataType) ? PaymentTypes.BTCLike : Enum.Parse<PaymentTypes>(CryptoPaymentDataType)); return new PaymentMethodId(CryptoCode ?? "BTC", string.IsNullOrEmpty(CryptoPaymentDataType) ? PaymentTypes.BTCLike : Enum.Parse<PaymentTypes>(CryptoPaymentDataType));
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
} }

View file

@ -124,26 +124,26 @@ namespace BTCPayServer.Services.Invoices
CustomerEmail = invoice.RefundMail CustomerEmail = invoice.RefundMail
}); });
foreach (var cryptoData in invoice.GetCryptoData(networkProvider)) foreach (var paymentMethod in invoice.GetPaymentMethods(networkProvider))
{ {
if (cryptoData.Network == null) if (paymentMethod.Network == null)
throw new InvalidOperationException("CryptoCode unsupported"); throw new InvalidOperationException("CryptoCode unsupported");
var paymentDestination = cryptoData.GetPaymentMethod().GetPaymentDestination(); var paymentDestination = paymentMethod.GetPaymentMethodDetails().GetPaymentDestination();
string address = GetDestination(cryptoData); string address = GetDestination(paymentMethod);
context.AddressInvoices.Add(new AddressInvoiceData() context.AddressInvoices.Add(new AddressInvoiceData()
{ {
InvoiceDataId = invoice.Id, InvoiceDataId = invoice.Id,
CreatedTime = DateTimeOffset.UtcNow, CreatedTime = DateTimeOffset.UtcNow,
}.Set(address, cryptoData.GetId())); }.Set(address, paymentMethod.GetId()));
context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData() context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData()
{ {
InvoiceDataId = invoice.Id, InvoiceDataId = invoice.Id,
Assigned = DateTimeOffset.UtcNow Assigned = DateTimeOffset.UtcNow
}.SetAddress(paymentDestination, cryptoData.GetId().ToString())); }.SetAddress(paymentDestination, paymentMethod.GetId().ToString()));
textSearch.Add(paymentDestination); textSearch.Add(paymentDestination);
textSearch.Add(cryptoData.Calculate().TotalDue.ToString()); textSearch.Add(paymentMethod.Calculate().TotalDue.ToString());
} }
context.PendingInvoices.Add(new PendingInvoiceData() { Id = invoice.Id }); context.PendingInvoices.Add(new PendingInvoiceData() { Id = invoice.Id });
await context.SaveChangesAsync().ConfigureAwait(false); await context.SaveChangesAsync().ConfigureAwait(false);
@ -162,18 +162,18 @@ namespace BTCPayServer.Services.Invoices
return invoice; return invoice;
} }
private static string GetDestination(CryptoData cryptoData) private static string GetDestination(PaymentMethod paymentMethod)
{ {
// For legacy reason, BitcoinLikeOnChain is putting the hashes of addresses in database // For legacy reason, BitcoinLikeOnChain is putting the hashes of addresses in database
if (cryptoData.GetId().PaymentType == Payments.PaymentTypes.BTCLike) if (paymentMethod.GetId().PaymentType == Payments.PaymentTypes.BTCLike)
{ {
return ((Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod)cryptoData.GetPaymentMethod()).DepositAddress.ScriptPubKey.Hash.ToString(); return ((Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod)paymentMethod.GetPaymentMethodDetails()).DepositAddress.ScriptPubKey.Hash.ToString();
} }
/////////////// ///////////////
return cryptoData.GetPaymentMethod().GetPaymentDestination(); return paymentMethod.GetPaymentMethodDetails().GetPaymentDestination();
} }
public async Task<bool> NewAddress(string invoiceId, IPaymentMethod paymentMethod, BTCPayNetwork network) public async Task<bool> NewAddress(string invoiceId, IPaymentMethodDetails paymentMethod, BTCPayNetwork network)
{ {
using (var context = _ContextFactory.CreateContext()) using (var context = _ContextFactory.CreateContext())
{ {
@ -182,11 +182,11 @@ namespace BTCPayServer.Services.Invoices
return false; return false;
var invoiceEntity = ToObject<InvoiceEntity>(invoice.Blob, network.NBitcoinNetwork); var invoiceEntity = ToObject<InvoiceEntity>(invoice.Blob, network.NBitcoinNetwork);
var currencyData = invoiceEntity.GetCryptoData(network, paymentMethod.GetPaymentType(), null); var currencyData = invoiceEntity.GetPaymentMethod(network, paymentMethod.GetPaymentType(), null);
if (currencyData == null) if (currencyData == null)
return false; return false;
var existingPaymentMethod = currencyData.GetPaymentMethod(); var existingPaymentMethod = currencyData.GetPaymentMethodDetails();
if (existingPaymentMethod.GetPaymentDestination() != null) if (existingPaymentMethod.GetPaymentDestination() != null)
{ {
MarkUnassigned(invoiceId, invoiceEntity, context, currencyData.GetId()); MarkUnassigned(invoiceId, invoiceEntity, context, currencyData.GetId());
@ -194,14 +194,14 @@ namespace BTCPayServer.Services.Invoices
existingPaymentMethod.SetPaymentDestination(paymentMethod.GetPaymentDestination()); existingPaymentMethod.SetPaymentDestination(paymentMethod.GetPaymentDestination());
currencyData.SetPaymentMethod(existingPaymentMethod); currencyData.SetPaymentMethodDetails(existingPaymentMethod);
#pragma warning disable CS0618 #pragma warning disable CS0618
if (network.IsBTC) if (network.IsBTC)
{ {
invoiceEntity.DepositAddress = currencyData.DepositAddress; invoiceEntity.DepositAddress = currencyData.DepositAddress;
} }
#pragma warning restore CS0618 #pragma warning restore CS0618
invoiceEntity.SetCryptoData(currencyData); invoiceEntity.SetPaymentMethod(currencyData);
invoice.Blob = ToBytes(invoiceEntity, network.NBitcoinNetwork); invoice.Blob = ToBytes(invoiceEntity, network.NBitcoinNetwork);
context.AddressInvoices.Add(new AddressInvoiceData() context.AddressInvoices.Add(new AddressInvoiceData()
@ -237,15 +237,15 @@ namespace BTCPayServer.Services.Invoices
} }
} }
private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, CryptoDataId cryptoDataId) private static void MarkUnassigned(string invoiceId, InvoiceEntity entity, ApplicationDbContext context, PaymentMethodId paymentMethodId)
{ {
foreach (var address in entity.GetCryptoData(null)) foreach (var address in entity.GetPaymentMethods(null))
{ {
if (cryptoDataId != null && cryptoDataId != address.GetId()) if (paymentMethodId != null && paymentMethodId != address.GetId())
continue; continue;
var historical = new HistoricalAddressInvoiceData(); var historical = new HistoricalAddressInvoiceData();
historical.InvoiceDataId = invoiceId; historical.InvoiceDataId = invoiceId;
historical.SetAddress(address.GetPaymentMethod().GetPaymentDestination(), address.GetId().ToString()); historical.SetAddress(address.GetPaymentMethodDetails().GetPaymentDestination(), address.GetId().ToString());
historical.UnAssigned = DateTimeOffset.UtcNow; historical.UnAssigned = DateTimeOffset.UtcNow;
context.Attach(historical); context.Attach(historical);
context.Entry(historical).Property(o => o.UnAssigned).IsModified = true; context.Entry(historical).Property(o => o.UnAssigned).IsModified = true;
@ -361,7 +361,7 @@ namespace BTCPayServer.Services.Invoices
} }
if (invoice.AddressInvoices != null) if (invoice.AddressInvoices != null)
{ {
entity.AvailableAddressHashes = invoice.AddressInvoices.Select(a => a.GetAddress() + a.GetCryptoDataId().ToString()).ToHashSet(); entity.AvailableAddressHashes = invoice.AddressInvoices.Select(a => a.GetAddress() + a.GetpaymentMethodId().ToString()).ToHashSet();
} }
if(invoice.Events != null) if(invoice.Events != null)
{ {

View file

@ -613,7 +613,7 @@
<div style="text-align:center"> <div style="text-align:center">
@foreach(var crypto in Model.AvailableCryptos) @foreach(var crypto in Model.AvailableCryptos)
{ {
<a style="text-decoration:none;" href="@crypto.Link" onclick="srvModel.cryptoDataId='@crypto.CryptoDataId'; fetchStatus(); return false;"><img style="height:32px; margin-right:5px; margin-left:5px;" alt="@crypto.CryptoDataId" src="@crypto.CryptoImage" /></a> <a style="text-decoration:none;" href="@crypto.Link" onclick="srvModel.paymentMethodId='@crypto.paymentMethodId'; fetchStatus(); return false;"><img style="height:32px; margin-right:5px; margin-left:5px;" alt="@crypto.paymentMethodId" src="@crypto.CryptoImage" /></a>
} }
</div> </div>
} }

View file

@ -198,7 +198,7 @@ function onDataCallback(jsonData) {
} }
function fetchStatus() { function fetchStatus() {
var path = srvModel.serverUrl + "/i/" + srvModel.invoiceId + "/" + srvModel.cryptoDataId + "/status"; var path = srvModel.serverUrl + "/i/" + srvModel.invoiceId + "/" + srvModel.paymentMethodId + "/status";
$.ajax({ $.ajax({
url: path, url: path,
type: "GET" type: "GET"