Show index of payment address for onchain payments

This commit is contained in:
Kukks 2020-08-09 16:00:58 +02:00
parent 2711f2cb2f
commit 8e8415515d
15 changed files with 92 additions and 97 deletions

View file

@ -600,7 +600,7 @@ namespace BTCPayServer.Controllers
try
{
leases.Add(_EventAggregator.Subscribe<Events.InvoiceDataChangedEvent>(async o => await NotifySocket(webSocket, o.InvoiceId, invoiceId)));
leases.Add(_EventAggregator.Subscribe<Events.InvoiceNewAddressEvent>(async o => await NotifySocket(webSocket, o.InvoiceId, invoiceId)));
leases.Add(_EventAggregator.Subscribe<Events.InvoiceNewPaymentDetailsEvent>(async o => await NotifySocket(webSocket, o.InvoiceId, invoiceId)));
leases.Add(_EventAggregator.Subscribe<Events.InvoiceEvent>(async o => await NotifySocket(webSocket, o.Invoice.Id, invoiceId)));
while (true)
{

View file

@ -1,20 +0,0 @@
namespace BTCPayServer.Events
{
public class InvoiceNewAddressEvent
{
public InvoiceNewAddressEvent(string invoiceId, string address, BTCPayNetworkBase network)
{
Address = address;
InvoiceId = invoiceId;
Network = network;
}
public string Address { get; set; }
public string InvoiceId { get; set; }
public BTCPayNetworkBase Network { get; set; }
public override string ToString()
{
return $"{Network.CryptoCode}: New address {Address} for invoice {InvoiceId}";
}
}
}

View file

@ -0,0 +1,24 @@
using BTCPayServer.Payments;
namespace BTCPayServer.Events
{
public class InvoiceNewPaymentDetailsEvent
{
public InvoiceNewPaymentDetailsEvent(string invoiceId, IPaymentMethodDetails details, PaymentMethodId paymentMethodId)
{
InvoiceId = invoiceId;
Details = details;
PaymentMethodId = paymentMethodId;
}
public string Address { get; set; }
public string InvoiceId { get; set; }
public IPaymentMethodDetails Details { get; }
public PaymentMethodId PaymentMethodId { get; }
public override string ToString()
{
return $"{PaymentMethodId.ToPrettyString()}: New payment details {Details.GetPaymentDestination()} for invoice {InvoiceId}";
}
}
}

View file

@ -1,4 +1,5 @@
using System;
using System.Linq;
using BTCPayServer.Client.Models;
using NBitcoin;
using Newtonsoft.Json;
@ -24,9 +25,10 @@ namespace BTCPayServer.Payments.Bitcoin
return FeeRate.SatoshiPerByte;
}
public void SetPaymentDestination(string newPaymentDestination)
public void SetPaymentDetails(IPaymentMethodDetails newPaymentMethodDetails)
{
DepositAddress = newPaymentDestination;
DepositAddress = newPaymentMethodDetails.GetPaymentDestination();
KeyPath = (newPaymentMethodDetails as BitcoinLikeOnChainPaymentMethod)?.KeyPath;
}
public NetworkFeeMode NetworkFeeMode { get; set; }
@ -51,7 +53,9 @@ namespace BTCPayServer.Payments.Bitcoin
[JsonIgnore]
public Money NextNetworkFee { get; set; }
[JsonIgnore]
public String DepositAddress { get; set; }
public String DepositAddress { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.KeyPathJsonConverter))]
public KeyPath KeyPath { get; set; }
public BitcoinAddress GetDepositAddress(Network network)
{

View file

@ -17,13 +17,14 @@ namespace BTCPayServer.Payments.Bitcoin
}
public BitcoinLikePaymentData(BitcoinAddress address, IMoney value, OutPoint outpoint, bool rbf)
public BitcoinLikePaymentData(BitcoinAddress address, IMoney value, OutPoint outpoint, bool rbf, KeyPath keyPath)
{
Address = address;
Value = value;
Outpoint = outpoint;
ConfirmationCount = 0;
RBF = rbf;
KeyPath = keyPath;
}
[JsonIgnore]
public BTCPayNetworkBase Network { get; set; }
@ -34,6 +35,8 @@ namespace BTCPayServer.Payments.Bitcoin
public int ConfirmationCount { get; set; }
public bool RBF { get; set; }
public BitcoinAddress Address { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.KeyPathJsonConverter))]
public KeyPath KeyPath { get; set; }
public IMoney Value { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]

View file

@ -159,7 +159,9 @@ namespace BTCPayServer.Payments.Bitcoin
break;
}
onchainMethod.DepositAddress = (await prepare.ReserveAddress).Address.ToString();
var reserved = await prepare.ReserveAddress;
onchainMethod.DepositAddress = reserved.Address.ToString();
onchainMethod.KeyPath = reserved.KeyPath;
onchainMethod.PayjoinEnabled = blob.PayJoinEnabled &&
PayjoinClient.SupportedFormats.Contains(supportedPaymentMethod
.AccountDerivation.ScriptPubKeyType()) &&

View file

@ -157,7 +157,7 @@ namespace BTCPayServer.Payments.Bitcoin
var paymentData = new BitcoinLikePaymentData(address,
output.matchedOutput.Value, output.outPoint,
evt.TransactionData.Transaction.RBF);
evt.TransactionData.Transaction.RBF, output.Item1.KeyPath);
var alreadyExist = invoice.GetAllBitcoinPaymentData().Where(c => c.GetPaymentId() == paymentData.GetPaymentId()).Any();
if (!alreadyExist)
@ -363,7 +363,7 @@ namespace BTCPayServer.Payments.Bitcoin
var address = network.NBXplorerNetwork.CreateAddress(strategy, coin.KeyPath, coin.ScriptPubKey);
var paymentData = new BitcoinLikePaymentData(address, coin.Value, coin.OutPoint,
transaction.Transaction.RBF);
transaction.Transaction.RBF, coin.KeyPath);
var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin.Timestamp, paymentData, network).ConfigureAwait(false);
alreadyAccounted.Add(coin.OutPoint);
@ -400,8 +400,9 @@ namespace BTCPayServer.Payments.Bitcoin
{
var address = await wallet.ReserveAddressAsync(strategy);
btc.DepositAddress = address.Address.ToString();
await _InvoiceRepository.NewAddress(invoice.Id, btc, wallet.Network);
_Aggregator.Publish(new InvoiceNewAddressEvent(invoice.Id, btc.DepositAddress, wallet.Network));
btc.KeyPath = address.KeyPath;
await _InvoiceRepository.NewPaymentDetails(invoice.Id, btc, wallet.Network);
_Aggregator.Publish(new InvoiceNewPaymentDetailsEvent(invoice.Id, btc, paymentMethod.GetId()));
paymentMethod.SetPaymentMethodDetails(btc);
invoice.SetPaymentMethod(paymentMethod);
}

View file

@ -21,10 +21,5 @@ namespace BTCPayServer.Payments
/// </summary>
/// <returns></returns>
decimal GetFeeRate();
/// <summary>
/// Change the payment destination (internal plumbing)
/// </summary>
/// <param name="newPaymentDestination"></param>
void SetPaymentDestination(string newPaymentDestination);
}
}

View file

@ -26,9 +26,9 @@ namespace BTCPayServer.Payments.Lightning
return 0.0m;
}
public void SetPaymentDestination(string newPaymentDestination)
public void SetPaymentDetails(IPaymentMethodDetails newPaymentMethodDetails)
{
BOLT11 = newPaymentDestination;
BOLT11 = newPaymentMethodDetails.GetPaymentDestination();
}
}
}

View file

@ -238,6 +238,7 @@ namespace BTCPayServer.Payments.PayJoin
Dictionary<OutPoint, UTXO> selectedUTXOs = new Dictionary<OutPoint, UTXO>();
PSBTOutput originalPaymentOutput = null;
BitcoinAddress paymentAddress = null;
KeyPath paymentAddressIndex = null;
InvoiceEntity invoice = null;
DerivationSchemeSettings derivationSchemeSettings = null;
foreach (var output in psbt.Outputs)
@ -300,6 +301,7 @@ namespace BTCPayServer.Payments.PayJoin
ctx.LockedUTXOs = selectedUTXOs.Select(u => u.Key).ToArray();
originalPaymentOutput = output;
paymentAddress = paymentDetails.GetDepositAddress(network.NBitcoinNetwork);
paymentAddressIndex = paymentDetails.KeyPath;
break;
}
@ -440,7 +442,7 @@ namespace BTCPayServer.Payments.PayJoin
var originalPaymentData = new BitcoinLikePaymentData(paymentAddress,
originalPaymentOutput.Value,
new OutPoint(ctx.OriginalTransaction.GetHash(), originalPaymentOutput.Index),
ctx.OriginalTransaction.RBF);
ctx.OriginalTransaction.RBF, paymentAddressIndex);
originalPaymentData.ConfirmationCount = -1;
originalPaymentData.PayjoinInformation = new PayjoinInformation()
{

View file

@ -25,6 +25,11 @@ namespace BTCPayServer.Services.Altcoins.Ethereum.Payments
return 0;
}
public void SetPaymentDetails(IPaymentMethodDetails newPaymentMethodDetails)
{
throw new System.NotImplementedException();
}
public void SetPaymentDestination(string newPaymentDestination)
{
DepositAddress = newPaymentDestination;

View file

@ -25,10 +25,6 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
return 0.0m;
}
public void SetPaymentDestination(string newPaymentDestination)
{
DepositAddress = newPaymentDestination;
}
public long AccountIndex { get; set; }
public long AddressIndex { get; set; }
public string DepositAddress { get; set; }

View file

@ -135,9 +135,9 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
});
monero.DepositAddress = address.Address;
monero.AddressIndex = address.AddressIndex;
await _invoiceRepository.NewAddress(invoice.Id, monero, payment.Network);
await _invoiceRepository.NewPaymentDetails(invoice.Id, monero, payment.Network);
_eventAggregator.Publish(
new InvoiceNewAddressEvent(invoice.Id, address.Address, payment.Network));
new InvoiceNewPaymentDetailsEvent(invoice.Id, monero, payment.GetPaymentMethodId()));
paymentMethod.SetPaymentMethodDetails(monero);
invoice.SetPaymentMethod(paymentMethod);
}

View file

@ -245,67 +245,48 @@ retry:
return paymentMethod.GetPaymentMethodDetails().GetPaymentDestination();
}
public async Task<bool> NewAddress(string invoiceId, IPaymentMethodDetails paymentMethod, BTCPayNetworkBase network)
public async Task<bool> NewPaymentDetails(string invoiceId, IPaymentMethodDetails paymentMethodDetails, BTCPayNetworkBase network)
{
using (var context = _ContextFactory.CreateContext())
await using var context = _ContextFactory.CreateContext();
var invoice = (await context.Invoices.Where(i => i.Id == invoiceId).ToListAsync()).FirstOrDefault();
if (invoice == null)
return false;
var invoiceEntity = invoice.GetBlob(_Networks);
var paymentMethod = invoiceEntity.GetPaymentMethod(network, paymentMethodDetails.GetPaymentType());
if (paymentMethod == null)
return false;
var existingPaymentMethod = paymentMethod.GetPaymentMethodDetails();
if (existingPaymentMethod.GetPaymentDestination() != null)
{
var invoice = (await context.Invoices.Where(i => i.Id == invoiceId).ToListAsync()).FirstOrDefault();
if (invoice == null)
return false;
var invoiceEntity = invoice.GetBlob(_Networks);
var currencyData = invoiceEntity.GetPaymentMethod(network, paymentMethod.GetPaymentType());
if (currencyData == null)
return false;
var existingPaymentMethod = currencyData.GetPaymentMethodDetails();
if (existingPaymentMethod.GetPaymentDestination() != null)
{
MarkUnassigned(invoiceId, invoiceEntity, context, currencyData.GetId());
}
existingPaymentMethod.SetPaymentDestination(paymentMethod.GetPaymentDestination());
currencyData.SetPaymentMethodDetails(existingPaymentMethod);
MarkUnassigned(invoiceId, invoiceEntity, context, paymentMethod.GetId());
}
paymentMethod.SetPaymentMethodDetails(paymentMethodDetails);
#pragma warning disable CS0618
if (network.IsBTC)
{
invoiceEntity.DepositAddress = currencyData.DepositAddress;
}
if (network.IsBTC)
{
invoiceEntity.DepositAddress = paymentMethod.DepositAddress;
}
#pragma warning restore CS0618
invoiceEntity.SetPaymentMethod(currencyData);
invoice.Blob = ToBytes(invoiceEntity, network);
invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = ToBytes(invoiceEntity, network);
context.AddressInvoices.Add(new AddressInvoiceData()
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
{
InvoiceDataId = invoiceId,
CreatedTime = DateTimeOffset.UtcNow
}
.Set(GetDestination(currencyData), currencyData.GetId()));
context.HistoricalAddressInvoices.Add(new HistoricalAddressInvoiceData()
{
InvoiceDataId = invoiceId,
Assigned = DateTimeOffset.UtcNow
}.SetAddress(paymentMethod.GetPaymentDestination(), network.CryptoCode));
await context.SaveChangesAsync();
AddToTextSearch(invoice.Id, paymentMethod.GetPaymentDestination());
return true;
}
}
public async Task UpdateInvoicePaymentMethod(string invoiceId, PaymentMethod paymentMethod)
{
using (var context = _ContextFactory.CreateContext())
.Set(GetDestination(paymentMethod), paymentMethod.GetId()));
await context.HistoricalAddressInvoices.AddAsync(new HistoricalAddressInvoiceData()
{
var invoice = await context.Invoices.FindAsync(invoiceId);
if (invoice == null)
return;
var network = paymentMethod.Network;
var invoiceEntity = invoice.GetBlob(_Networks);
invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = ToBytes(invoiceEntity, network);
await context.SaveChangesAsync();
}
InvoiceDataId = invoiceId,
Assigned = DateTimeOffset.UtcNow
}.SetAddress(paymentMethodDetails.GetPaymentDestination(), network.CryptoCode));
await context.SaveChangesAsync();
AddToTextSearch(invoice.Id, paymentMethodDetails.GetPaymentDestination());
return true;
}
public async Task AddPendingInvoiceIfNotPresent(string invoiceId)

View file

@ -54,6 +54,7 @@
<thead class="thead-inverse">
<tr>
<th>Crypto</th>
<th>Index</th>
<th>Deposit address</th>
<th>Amount</th>
<th>Transaction Id</th>
@ -65,9 +66,10 @@
{
<tr style="@(payment.Replaced ? "text-decoration: line-through" : "")">
<td>@payment.Crypto</td>
<td>@payment.DepositAddress</td>
<td>@(payment.CryptoPaymentData.Index?.ToString()?? "Unknown")</td>
<td style="max-width:300px;" data-toggle="tooltip" class="text-truncate" title="@payment.DepositAddress">@payment.DepositAddress</td>
<td class="payment-value">@payment.CryptoPaymentData.GetValue() @Safe.Raw(payment.AdditionalInformation is string i ? $"<br/>({i})" : string.Empty)</td>
<td>
<td style="max-width:300px;" data-toggle="tooltip" class="text-truncate" title="@payment.TransactionId">
<div class="wraptextAuto">
<a href="@payment.TransactionLink" target="_blank">
@payment.TransactionId