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

View file

@ -24,12 +24,12 @@ namespace BTCPayServer.Controllers
cryptoCode = "BTC";
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId);
var network = _NetworkProvider.GetNetwork(cryptoCode);
var cryptoId = new CryptoDataId(cryptoCode, Payments.PaymentTypes.BTCLike);
if (invoice == null || invoice.IsExpired() || network == null || !invoice.Support(cryptoId))
var paymentMethodId = new PaymentMethodId(cryptoCode, Payments.PaymentTypes.BTCLike);
if (invoice == null || invoice.IsExpired() || network == null || !invoice.Support(paymentMethodId))
return NotFound();
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
{
DetailsVersion = 1
@ -37,7 +37,7 @@ namespace BTCPayServer.Controllers
request.Details.Expires = invoice.ExpirationTime;
request.Details.Memo = invoice.ProductInformation.ItemDesc;
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.Time = DateTimeOffset.UtcNow;
request.Details.PaymentUrl = new Uri(invoice.ServerUrl.WithTrailingSlash() + ($"i/{invoice.Id}"), UriKind.Absolute);
@ -71,7 +71,7 @@ namespace BTCPayServer.Controllers
if (cryptoCode == null)
cryptoCode = "BTC";
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();
var wallet = _WalletProvider.GetWallet(network);

View file

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

View file

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

View file

@ -30,21 +30,21 @@ namespace BTCPayServer.Data
return Address;
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;
}
public CryptoDataId GetCryptoDataId()
public PaymentMethodId GetpaymentMethodId()
{
if (Address == null)
return null;
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)
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

View file

@ -30,9 +30,9 @@ namespace BTCPayServer
{
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)
{

View file

@ -201,7 +201,7 @@ namespace BTCPayServer.HostedServices
// 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)
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)
{
#pragma warning disable CS0618

View file

@ -72,16 +72,16 @@ namespace BTCPayServer.HostedServices
var derivationStrategies = invoice.GetDerivationStrategies(_NetworkProvider).ToArray();
var payments = invoice.GetPayments().Where(p => p.Accounted).ToArray();
var cryptoDataAll = invoice.GetCryptoData(_NetworkProvider);
foreach (var cryptoData in cryptoDataAll.Select(c => c))
var allPaymentMethods = invoice.GetPaymentMethods(_NetworkProvider);
foreach (var paymentMethod in allPaymentMethods.Select(c => c))
{
var accounting = cryptoData.Calculate();
var network = _NetworkProvider.GetNetwork(cryptoData.GetId().CryptoCode);
var accounting = paymentMethod.Calculate();
var network = _NetworkProvider.GetNetwork(paymentMethod.GetId().CryptoCode);
if (network == null)
continue;
var totalPaid = payments.Select(p => p.GetValue(allPaymentMethods, paymentMethod.GetId())).Sum();
if (invoice.Status == "new" || invoice.Status == "expired")
{
var totalPaid = payments.Select(p => p.GetValue(cryptoDataAll, cryptoData.GetId())).Sum();
if (totalPaid >= accounting.TotalDue)
{
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")
{
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
(invoice.MonitoringExpiration < DateTimeOffset.UtcNow)
@ -136,7 +159,7 @@ namespace BTCPayServer.HostedServices
if (invoice.Status == "confirmed")
{
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)
{
context.Events.Add(new InvoiceEvent(invoice, 1006, "invoice_completed"));

View file

@ -9,7 +9,7 @@ namespace BTCPayServer.Models.InvoicingModels
{
public class AvailableCrypto
{
public string CryptoDataId { get; set; }
public string paymentMethodId { get; set; }
public string CryptoImage { get; set; }
public string Link { get; set; }
}
@ -41,6 +41,6 @@ namespace BTCPayServer.Models.InvoicingModels
public string NetworkFeeDescription { get; internal set; }
public int MaxTimeMinutes { 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
{
public class BitcoinLikeOnChainPaymentMethod : IPaymentMethod
public class BitcoinLikeOnChainPaymentMethod : IPaymentMethodDetails
{
public PaymentTypes GetPaymentType()
{

View file

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

View file

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

View file

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

View file

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

View file

@ -124,26 +124,26 @@ namespace BTCPayServer.Services.Invoices
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");
var paymentDestination = cryptoData.GetPaymentMethod().GetPaymentDestination();
var paymentDestination = paymentMethod.GetPaymentMethodDetails().GetPaymentDestination();
string address = GetDestination(cryptoData);
string address = GetDestination(paymentMethod);
context.AddressInvoices.Add(new AddressInvoiceData()
{
InvoiceDataId = invoice.Id,
CreatedTime = DateTimeOffset.UtcNow,
}.Set(address, cryptoData.GetId()));
}.Set(address, paymentMethod.GetId()));
context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData()
{
InvoiceDataId = invoice.Id,
Assigned = DateTimeOffset.UtcNow
}.SetAddress(paymentDestination, cryptoData.GetId().ToString()));
}.SetAddress(paymentDestination, paymentMethod.GetId().ToString()));
textSearch.Add(paymentDestination);
textSearch.Add(cryptoData.Calculate().TotalDue.ToString());
textSearch.Add(paymentMethod.Calculate().TotalDue.ToString());
}
context.PendingInvoices.Add(new PendingInvoiceData() { Id = invoice.Id });
await context.SaveChangesAsync().ConfigureAwait(false);
@ -162,18 +162,18 @@ namespace BTCPayServer.Services.Invoices
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
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())
{
@ -182,11 +182,11 @@ namespace BTCPayServer.Services.Invoices
return false;
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)
return false;
var existingPaymentMethod = currencyData.GetPaymentMethod();
var existingPaymentMethod = currencyData.GetPaymentMethodDetails();
if (existingPaymentMethod.GetPaymentDestination() != null)
{
MarkUnassigned(invoiceId, invoiceEntity, context, currencyData.GetId());
@ -194,14 +194,14 @@ namespace BTCPayServer.Services.Invoices
existingPaymentMethod.SetPaymentDestination(paymentMethod.GetPaymentDestination());
currencyData.SetPaymentMethod(existingPaymentMethod);
currencyData.SetPaymentMethodDetails(existingPaymentMethod);
#pragma warning disable CS0618
if (network.IsBTC)
{
invoiceEntity.DepositAddress = currencyData.DepositAddress;
}
#pragma warning restore CS0618
invoiceEntity.SetCryptoData(currencyData);
invoiceEntity.SetPaymentMethod(currencyData);
invoice.Blob = ToBytes(invoiceEntity, network.NBitcoinNetwork);
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;
var historical = new HistoricalAddressInvoiceData();
historical.InvoiceDataId = invoiceId;
historical.SetAddress(address.GetPaymentMethod().GetPaymentDestination(), address.GetId().ToString());
historical.SetAddress(address.GetPaymentMethodDetails().GetPaymentDestination(), address.GetId().ToString());
historical.UnAssigned = DateTimeOffset.UtcNow;
context.Attach(historical);
context.Entry(historical).Property(o => o.UnAssigned).IsModified = true;
@ -361,7 +361,7 @@ namespace BTCPayServer.Services.Invoices
}
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)
{

View file

@ -613,7 +613,7 @@
<div style="text-align:center">
@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>
}

View file

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