Do not crash UI and background services after switching to BItcoin Only when you have altcoin payments

This commit is contained in:
Kukks 2020-08-09 14:43:13 +02:00
parent a80146e894
commit 26aac6c45d
18 changed files with 79 additions and 35 deletions

View file

@ -135,7 +135,7 @@ namespace BTCPayServer.Controllers
else else
{ {
var paymentMethods = invoice.GetBlob(_NetworkProvider).GetPaymentMethods(); var paymentMethods = invoice.GetBlob(_NetworkProvider).GetPaymentMethods();
var options = invoice.GetBlob(_NetworkProvider).GetPaymentMethods() var options = paymentMethods
.Select(o => o.GetId()) .Select(o => o.GetId())
.Select(o => o.CryptoCode) .Select(o => o.CryptoCode)
.Where(o => _NetworkProvider.GetNetwork<BTCPayNetwork>(o) is BTCPayNetwork n && !n.ReadonlyWallet) .Where(o => _NetworkProvider.GetNetwork<BTCPayNetwork>(o) is BTCPayNetwork n && !n.ReadonlyWallet)
@ -143,14 +143,15 @@ namespace BTCPayServer.Controllers
.OrderBy(o => o) .OrderBy(o => o)
.Select(o => new PaymentMethodId(o, PaymentTypes.BTCLike)) .Select(o => new PaymentMethodId(o, PaymentTypes.BTCLike))
.ToList(); .ToList();
var defaultRefund = invoice.Payments.Select(p => p.GetBlob(_NetworkProvider)) var defaultRefund = invoice.Payments
.Select(p => p.GetPaymentMethodId().CryptoCode) .Select(p => p.GetBlob(_NetworkProvider))
.FirstOrDefault(); .Select(p => p.GetPaymentMethodId())
.FirstOrDefault(p => p != null && p.PaymentType == BitcoinPaymentType.Instance);
// TODO: What if no option? // TODO: What if no option?
var refund = new RefundModel(); var refund = new RefundModel();
refund.Title = "Select a payment method"; refund.Title = "Select a payment method";
refund.AvailablePaymentMethods = new SelectList(options, nameof(PaymentMethodId.CryptoCode), nameof(PaymentMethodId.CryptoCode)); refund.AvailablePaymentMethods = new SelectList(options, nameof(PaymentMethodId.CryptoCode), nameof(PaymentMethodId.CryptoCode));
refund.SelectedPaymentMethod = defaultRefund ?? options.Select(o => o.CryptoCode).First(); refund.SelectedPaymentMethod = defaultRefund?.ToString() ?? options.Select(o => o.CryptoCode).First();
// Nothing to select, skip to next // Nothing to select, skip to next
if (refund.AvailablePaymentMethods.Count() == 1) if (refund.AvailablePaymentMethods.Count() == 1)

View file

@ -15,8 +15,7 @@ namespace BTCPayServer.Data
public static PaymentMethodId GetDefaultPaymentId(this StoreData storeData, BTCPayNetworkProvider networks) public static PaymentMethodId GetDefaultPaymentId(this StoreData storeData, BTCPayNetworkProvider networks)
{ {
PaymentMethodId[] paymentMethodIds = storeData.GetEnabledPaymentIds(networks); PaymentMethodId[] paymentMethodIds = storeData.GetEnabledPaymentIds(networks);
PaymentMethodId.TryParse(storeData.DefaultCrypto, out var defaultPaymentId);
var defaultPaymentId = string.IsNullOrEmpty(storeData.DefaultCrypto) ? null : PaymentMethodId.Parse(storeData.DefaultCrypto);
var chosen = paymentMethodIds.FirstOrDefault(f => f == defaultPaymentId) ?? var chosen = paymentMethodIds.FirstOrDefault(f => f == defaultPaymentId) ??
paymentMethodIds.FirstOrDefault(f => f.CryptoCode == defaultPaymentId?.CryptoCode) ?? paymentMethodIds.FirstOrDefault(f => f.CryptoCode == defaultPaymentId?.CryptoCode) ??
paymentMethodIds.FirstOrDefault(); paymentMethodIds.FirstOrDefault();
@ -80,7 +79,10 @@ namespace BTCPayServer.Data
JObject strategies = JObject.Parse(storeData.DerivationStrategies); JObject strategies = JObject.Parse(storeData.DerivationStrategies);
foreach (var strat in strategies.Properties()) foreach (var strat in strategies.Properties())
{ {
var paymentMethodId = PaymentMethodId.Parse(strat.Name); if (!PaymentMethodId.TryParse(strat.Name, out var paymentMethodId))
{
continue;
}
var network = networks.GetNetwork<BTCPayNetworkBase>(paymentMethodId.CryptoCode); var network = networks.GetNetwork<BTCPayNetworkBase>(paymentMethodId.CryptoCode);
if (network != null) if (network != null)
{ {

View file

@ -117,8 +117,9 @@ namespace BTCPayServer
public static IEnumerable<BitcoinLikePaymentData> GetAllBitcoinPaymentData(this InvoiceEntity invoice) public static IEnumerable<BitcoinLikePaymentData> GetAllBitcoinPaymentData(this InvoiceEntity invoice)
{ {
return invoice.GetPayments() return invoice.GetPayments()
.Where(p => p.GetPaymentMethodId().PaymentType == PaymentTypes.BTCLike) .Where(p => p.GetPaymentMethodId()?.PaymentType == PaymentTypes.BTCLike)
.Select(p => (BitcoinLikePaymentData)p.GetCryptoPaymentData()); .Select(p => (BitcoinLikePaymentData)p.GetCryptoPaymentData())
.Where(data => data != null);
} }
public static async Task<Dictionary<uint256, TransactionResult>> GetTransactions(this BTCPayWallet client, uint256[] hashes, bool includeOffchain = false, CancellationToken cts = default(CancellationToken)) public static async Task<Dictionary<uint256, TransactionResult>> GetTransactions(this BTCPayWallet client, uint256[] hashes, bool includeOffchain = false, CancellationToken cts = default(CancellationToken))

View file

@ -33,7 +33,7 @@ namespace BTCPayServer.HostedServices
protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken) protected override async Task ProcessEvent(object evt, CancellationToken cancellationToken)
{ {
if (evt is InvoiceEvent invoiceEvent && invoiceEvent.Name == InvoiceEvent.ReceivedPayment && if (evt is InvoiceEvent invoiceEvent && invoiceEvent.Name == InvoiceEvent.ReceivedPayment &&
invoiceEvent.Payment.GetPaymentMethodId().PaymentType == BitcoinPaymentType.Instance && invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType == BitcoinPaymentType.Instance &&
invoiceEvent.Payment.GetCryptoPaymentData() is BitcoinLikePaymentData bitcoinLikePaymentData) invoiceEvent.Payment.GetCryptoPaymentData() is BitcoinLikePaymentData bitcoinLikePaymentData)
{ {
var walletId = new WalletId(invoiceEvent.Invoice.StoreId, invoiceEvent.Payment.GetCryptoCode()); var walletId = new WalletId(invoiceEvent.Invoice.StoreId, invoiceEvent.Payment.GetCryptoCode());

View file

@ -55,7 +55,7 @@ namespace BTCPayServer.Models.AppViewModels
} }
public class Contribution public class Contribution
{ {
public PaymentMethodId PaymentMehtodId { get; set; } public PaymentMethodId PaymentMethodId { get; set; }
public decimal Value { get; set; } public decimal Value { get; set; }
public decimal CurrencyValue { get; set; } public decimal CurrencyValue { get; set; }
} }

View file

@ -159,7 +159,7 @@ namespace BTCPayServer.PaymentRequest
{ {
data.GetValue(), data.GetValue(),
invoiceEvent.Payment.GetCryptoCode(), invoiceEvent.Payment.GetCryptoCode(),
invoiceEvent.Payment.GetPaymentMethodId().PaymentType.ToString() invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType?.ToString()
}); });
} }

View file

@ -104,10 +104,16 @@ namespace BTCPayServer.PaymentRequest
Currency = entity.ProductInformation.Currency, Currency = entity.ProductInformation.Currency,
ExpiryDate = entity.ExpirationTime.DateTime, ExpiryDate = entity.ExpirationTime.DateTime,
Status = entity.GetInvoiceState().ToString(), Status = entity.GetInvoiceState().ToString(),
Payments = entity.GetPayments().Select(paymentEntity => Payments = entity
.GetPayments()
.Select(paymentEntity =>
{ {
var paymentData = paymentEntity.GetCryptoPaymentData(); var paymentData = paymentEntity.GetCryptoPaymentData();
var paymentMethodId = paymentEntity.GetPaymentMethodId(); var paymentMethodId = paymentEntity.GetPaymentMethodId();
if (paymentData is null || paymentMethodId is null)
{
return null;
}
string txId = paymentData.GetPaymentId(); string txId = paymentData.GetPaymentId();
string link = GetTransactionLink(paymentMethodId, txId); string link = GetTransactionLink(paymentMethodId, txId);
@ -118,7 +124,9 @@ namespace BTCPayServer.PaymentRequest
Link = link, Link = link,
Id = txId Id = txId
}; };
}).ToList() })
.Where(payment => payment != null)
.ToList()
}).ToList() }).ToList()
}; };
} }

View file

@ -222,7 +222,7 @@ namespace BTCPayServer.Payments.Bitcoin
var paymentEntitiesByPrevOut = new Dictionary<OutPoint, PaymentEntity>(); var paymentEntitiesByPrevOut = new Dictionary<OutPoint, PaymentEntity>();
foreach (var payment in invoice.GetPayments(wallet.Network)) foreach (var payment in invoice.GetPayments(wallet.Network))
{ {
if (payment.GetPaymentMethodId().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))

View file

@ -72,6 +72,7 @@ namespace BTCPayServer.Payments
public static bool TryParse(string str, out PaymentMethodId paymentMethodId) public static bool TryParse(string str, out PaymentMethodId paymentMethodId)
{ {
str ??= "";
paymentMethodId = null; paymentMethodId = null;
var parts = str.Split('_', StringSplitOptions.RemoveEmptyEntries); var parts = str.Split('_', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0 || parts.Length > 2) if (parts.Length == 0 || parts.Length > 2)

View file

@ -22,7 +22,7 @@ namespace BTCPayServer.Payments
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str) public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
{ {
return ((BTCPayNetwork)network).ToObject<BitcoinLikePaymentData>(str); return ((BTCPayNetwork)network)?.ToObject<BitcoinLikePaymentData>(str);
} }
public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData) public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)

View file

@ -20,7 +20,7 @@ namespace BTCPayServer.Payments
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str) public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
{ {
return ((BTCPayNetwork)network).ToObject<LightningLikePaymentData>(str); return ((BTCPayNetwork)network)?.ToObject<LightningLikePaymentData>(str);
} }
public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData) public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)

View file

@ -39,7 +39,7 @@ namespace BTCPayServer.Services.Apps
{ {
data.GetValue(), data.GetValue(),
invoiceEvent.Payment.GetCryptoCode(), invoiceEvent.Payment.GetCryptoCode(),
invoiceEvent.Payment.GetPaymentMethodId().PaymentType.ToString() invoiceEvent.Payment.GetPaymentMethodId()?.PaymentType?.ToString()
}, cancellationToken); }, cancellationToken);
} }
await InfoUpdated(appId); await InfoUpdated(appId);

View file

@ -333,7 +333,7 @@ namespace BTCPayServer.Services.Apps
.SelectMany(p => .SelectMany(p =>
{ {
var contribution = new Contribution(); var contribution = new Contribution();
contribution.PaymentMehtodId = new PaymentMethodId(p.ProductInformation.Currency, PaymentTypes.BTCLike); contribution.PaymentMethodId = new PaymentMethodId(p.ProductInformation.Currency, PaymentTypes.BTCLike);
contribution.CurrencyValue = p.ProductInformation.Price; contribution.CurrencyValue = p.ProductInformation.Price;
contribution.Value = contribution.CurrencyValue; contribution.Value = contribution.CurrencyValue;
@ -363,18 +363,18 @@ namespace BTCPayServer.Services.Apps
.Select(pay => .Select(pay =>
{ {
var paymentMethodContribution = new Contribution(); var paymentMethodContribution = new Contribution();
paymentMethodContribution.PaymentMehtodId = pay.GetPaymentMethodId(); paymentMethodContribution.PaymentMethodId = pay.GetPaymentMethodId();
paymentMethodContribution.Value = pay.GetCryptoPaymentData().GetValue() - pay.NetworkFee; paymentMethodContribution.Value = pay.GetCryptoPaymentData().GetValue() - pay.NetworkFee;
var rate = p.GetPaymentMethod(paymentMethodContribution.PaymentMehtodId).Rate; var rate = p.GetPaymentMethod(paymentMethodContribution.PaymentMethodId).Rate;
paymentMethodContribution.CurrencyValue = rate * paymentMethodContribution.Value; paymentMethodContribution.CurrencyValue = rate * paymentMethodContribution.Value;
return paymentMethodContribution; return paymentMethodContribution;
}) })
.ToArray(); .ToArray();
}) })
.GroupBy(p => p.PaymentMehtodId) .GroupBy(p => p.PaymentMethodId)
.ToDictionary(p => p.Key, p => new Contribution() .ToDictionary(p => p.Key, p => new Contribution()
{ {
PaymentMehtodId = p.Key, PaymentMethodId = p.Key,
Value = p.Select(v => v.Value).Sum(), Value = p.Select(v => v.Value).Sum(),
CurrencyValue = p.Select(v => v.CurrencyValue).Sum() CurrencyValue = p.Select(v => v.CurrencyValue).Sum()
}); });

View file

@ -267,11 +267,11 @@ namespace BTCPayServer.Services.Invoices
#pragma warning disable CS0618 #pragma warning disable CS0618
public List<PaymentEntity> GetPayments() public List<PaymentEntity> GetPayments()
{ {
return Payments?.ToList() ?? new List<PaymentEntity>(); return Payments?.Where(entity => entity.GetPaymentMethodId() != null).ToList() ?? new List<PaymentEntity>();
} }
public List<PaymentEntity> GetPayments(string cryptoCode) public List<PaymentEntity> GetPayments(string cryptoCode)
{ {
return Payments.Where(p => p.CryptoCode == cryptoCode).ToList(); return GetPayments().Where(p => p.CryptoCode == cryptoCode).ToList();
} }
public List<PaymentEntity> GetPayments(BTCPayNetworkBase network) public List<PaymentEntity> GetPayments(BTCPayNetworkBase network)
{ {
@ -551,7 +551,10 @@ namespace BTCPayServer.Services.Invoices
foreach (var prop in PaymentMethod.Properties()) foreach (var prop in PaymentMethod.Properties())
{ {
var r = serializer.ToObject<PaymentMethod>(prop.Value.ToString()); var r = serializer.ToObject<PaymentMethod>(prop.Value.ToString());
var paymentMethodId = PaymentMethodId.Parse(prop.Name); if (!PaymentMethodId.TryParse(prop.Name, out var paymentMethodId))
{
continue;
}
r.CryptoCode = paymentMethodId.CryptoCode; r.CryptoCode = paymentMethodId.CryptoCode;
r.PaymentType = paymentMethodId.PaymentType.ToString(); r.PaymentType = paymentMethodId.PaymentType.ToString();
r.ParentEntity = this; r.ParentEntity = this;
@ -1006,7 +1009,18 @@ namespace BTCPayServer.Services.Invoices
} }
else else
{ {
paymentData = GetPaymentMethodId().PaymentType.DeserializePaymentData(Network, CryptoPaymentData); var paymentMethodId = GetPaymentMethodId();
if (paymentMethodId is null)
{
return null;
}
paymentData = paymentMethodId.PaymentType.DeserializePaymentData(Network, CryptoPaymentData);
if (paymentData is null)
{
return null;
}
paymentData.Network = Network; paymentData.Network = Network;
if (paymentData is BitcoinLikePaymentData bitcoin) if (paymentData is BitcoinLikePaymentData bitcoin)
{ {
@ -1051,7 +1065,16 @@ namespace BTCPayServer.Services.Invoices
public PaymentMethodId GetPaymentMethodId() public PaymentMethodId GetPaymentMethodId()
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
return new PaymentMethodId(CryptoCode ?? "BTC", string.IsNullOrEmpty(CryptoPaymentDataType) ? PaymentTypes.BTCLike : PaymentTypes.Parse(CryptoPaymentDataType)); PaymentType paymentType;
if (string.IsNullOrEmpty(CryptoPaymentDataType))
{
paymentType = BitcoinPaymentType.Instance;;
}
else if(!PaymentTypes.TryParse(CryptoPaymentDataType, out paymentType))
{
return null;
}
return new PaymentMethodId(CryptoCode ?? "BTC", paymentType);
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
} }

View file

@ -701,7 +701,7 @@ retry:
Accounted = accounted Accounted = accounted
}; };
context.Payments.Add(data); await context.Payments.AddAsync(data);
try try
{ {

View file

@ -47,7 +47,7 @@
</div> </div>
</div> </div>
@{ @{
var grouped = invoice.Payments.GroupBy(payment => payment.GetPaymentMethodId().PaymentType); var grouped = invoice.Payments.GroupBy(payment => payment.GetPaymentMethodId()?.PaymentType).Where(entities => entities.Key!= null);
} }
@foreach (var paymentGroup in grouped) @foreach (var paymentGroup in grouped)
{ {

View file

@ -5,10 +5,14 @@
@{ @{
PayjoinInformation payjoinIformation = null; PayjoinInformation payjoinIformation = null;
var onchainPayments = Model.Where(entity => entity.GetPaymentMethodId().PaymentType == BitcoinPaymentType.Instance).Select(payment => var onchainPayments = Model.Where(entity => entity.GetPaymentMethodId()?.PaymentType == BitcoinPaymentType.Instance).Select(payment =>
{ {
var m = new OnchainPaymentViewModel(); var m = new OnchainPaymentViewModel();
var onChainPaymentData = payment.GetCryptoPaymentData() as BitcoinLikePaymentData; var onChainPaymentData = payment.GetCryptoPaymentData() as BitcoinLikePaymentData;
if (onChainPaymentData is null)
{
return null;
}
m.Crypto = payment.GetPaymentMethodId().CryptoCode; m.Crypto = payment.GetPaymentMethodId().CryptoCode;
m.DepositAddress = onChainPaymentData.GetDestination(); m.DepositAddress = onChainPaymentData.GetDestination();
@ -38,7 +42,7 @@
m.Replaced = !payment.Accounted; m.Replaced = !payment.Accounted;
m.CryptoPaymentData = onChainPaymentData; m.CryptoPaymentData = onChainPaymentData;
return m; return m;
}); }).Where(model => model != null);
} }
@if (onchainPayments.Any()) @if (onchainPayments.Any())

View file

@ -3,15 +3,19 @@
@model IEnumerable<BTCPayServer.Services.Invoices.PaymentEntity> @model IEnumerable<BTCPayServer.Services.Invoices.PaymentEntity>
@{ @{
var offchainPayments = Model.Where(entity => entity.GetPaymentMethodId().PaymentType == LightningPaymentType.Instance).Select(payment => var offchainPayments = Model.Where(entity => entity.GetPaymentMethodId()?.PaymentType == LightningPaymentType.Instance).Select(payment =>
{ {
var offChainPaymentData = payment.GetCryptoPaymentData() as LightningLikePaymentData; var offChainPaymentData = payment.GetCryptoPaymentData() as LightningLikePaymentData;
if (offChainPaymentData is null)
{
return null;
}
return new OffChainPaymentViewModel() return new OffChainPaymentViewModel()
{ {
Crypto = payment.Network.CryptoCode, Crypto = payment.Network.CryptoCode,
BOLT11 = offChainPaymentData.BOLT11 BOLT11 = offChainPaymentData.BOLT11
}; };
}); }).Where(model => model != null);
} }