mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 22:25:28 +01:00
Further abstract payment data by encapsulating bitcoin related logic into BitcoinLikePaymentData
This commit is contained in:
parent
b898cc030c
commit
a1ee09cd85
6 changed files with 125 additions and 69 deletions
|
@ -66,7 +66,7 @@ namespace BTCPayServer
|
||||||
|
|
||||||
public BTCPayDefaultSettings DefaultSettings { get; set; }
|
public BTCPayDefaultSettings DefaultSettings { get; set; }
|
||||||
public KeyPath CoinType { get; internal set; }
|
public KeyPath CoinType { get; internal set; }
|
||||||
public int MaxTrackedConfirmation { get; internal set; } = 7;
|
public int MaxTrackedConfirmation { get; internal set; } = 6;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,14 +80,34 @@ namespace BTCPayServer.Controllers
|
||||||
|
|
||||||
var payments = invoice
|
var payments = invoice
|
||||||
.GetPayments()
|
.GetPayments()
|
||||||
|
.Where(p => p.GetCryptoPaymentData() is BitcoinLikePaymentData)
|
||||||
.Select(async payment =>
|
.Select(async payment =>
|
||||||
{
|
{
|
||||||
|
var paymentData = (BitcoinLikePaymentData)payment.GetCryptoPaymentData();
|
||||||
var m = new InvoiceDetailsModel.Payment();
|
var m = new InvoiceDetailsModel.Payment();
|
||||||
var paymentNetwork = _NetworkProvider.GetNetwork(payment.GetCryptoCode());
|
var paymentNetwork = _NetworkProvider.GetNetwork(payment.GetCryptoCode());
|
||||||
m.CryptoCode = payment.GetCryptoCode();
|
m.CryptoCode = payment.GetCryptoCode();
|
||||||
m.DepositAddress = payment.GetScriptPubKey().GetDestinationAddress(paymentNetwork.NBitcoinNetwork);
|
m.DepositAddress = payment.GetScriptPubKey().GetDestinationAddress(paymentNetwork.NBitcoinNetwork);
|
||||||
m.Confirmations = (await _ExplorerClients.GetExplorerClient(payment.GetCryptoCode())?.GetTransactionAsync(payment.Outpoint.Hash))?.Confirmations ?? 0;
|
|
||||||
m.TransactionId = payment.Outpoint.Hash.ToString();
|
int confirmationCount = 0;
|
||||||
|
if(paymentData.Legacy) // The confirmation count in the paymentData is not up to date
|
||||||
|
{
|
||||||
|
confirmationCount = (await _ExplorerClients.GetExplorerClient(payment.GetCryptoCode())?.GetTransactionAsync(paymentData.Outpoint.Hash))?.Confirmations ?? 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
confirmationCount = paymentData.ConfirmationCount;
|
||||||
|
}
|
||||||
|
if(confirmationCount >= paymentNetwork.MaxTrackedConfirmation)
|
||||||
|
{
|
||||||
|
m.Confirmations = "At least " + (paymentNetwork.MaxTrackedConfirmation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m.Confirmations = confirmationCount.ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.TransactionId = paymentData.Outpoint.Hash.ToString();
|
||||||
m.ReceivedTime = payment.ReceivedTime;
|
m.ReceivedTime = payment.ReceivedTime;
|
||||||
m.TransactionLink = string.Format(CultureInfo.InvariantCulture, paymentNetwork.BlockExplorerLink, m.TransactionId);
|
m.TransactionLink = string.Format(CultureInfo.InvariantCulture, paymentNetwork.BlockExplorerLink, m.TransactionId);
|
||||||
m.Replaced = !payment.Accounted;
|
m.Replaced = !payment.Accounted;
|
||||||
|
|
|
@ -165,10 +165,11 @@ namespace BTCPayServer.HostedServices
|
||||||
var invoice = await _InvoiceRepository.GetInvoiceFromScriptPubKey(output.ScriptPubKey, network.CryptoCode);
|
var invoice = await _InvoiceRepository.GetInvoiceFromScriptPubKey(output.ScriptPubKey, network.CryptoCode);
|
||||||
if (invoice != null)
|
if (invoice != null)
|
||||||
{
|
{
|
||||||
var payment = invoice.GetPayments().FirstOrDefault(p => p.Outpoint == txCoin.Outpoint);
|
var paymentData = new BitcoinLikePaymentData(txCoin, evt.TransactionData.Transaction.RBF);
|
||||||
if (payment == null)
|
var alreadyExist = GetAllBitcoinPaymentData(invoice).Where(c => c.GetPaymentId() == paymentData.GetPaymentId()).Any();
|
||||||
|
if (!alreadyExist)
|
||||||
{
|
{
|
||||||
payment = await _InvoiceRepository.AddPayment(invoice.Id, DateTimeOffset.UtcNow, txCoin, network.CryptoCode);
|
var payment = await _InvoiceRepository.AddPayment(invoice.Id, DateTimeOffset.UtcNow, paymentData, network.CryptoCode);
|
||||||
await ReceivedPayment(wallet, invoice.Id, payment, evt.DerivationStrategy);
|
await ReceivedPayment(wallet, invoice.Id, payment, evt.DerivationStrategy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -205,17 +206,27 @@ namespace BTCPayServer.HostedServices
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerable<BitcoinLikePaymentData> GetAllBitcoinPaymentData(InvoiceEntity invoice)
|
||||||
|
{
|
||||||
|
return invoice.GetPayments()
|
||||||
|
.Select(p => p.GetCryptoPaymentData() as BitcoinLikePaymentData)
|
||||||
|
.Where(p => p != null);
|
||||||
|
}
|
||||||
|
|
||||||
async Task<InvoiceEntity> UpdatePaymentStates(BTCPayWallet wallet, string invoiceId)
|
async Task<InvoiceEntity> UpdatePaymentStates(BTCPayWallet wallet, string invoiceId)
|
||||||
{
|
{
|
||||||
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId, false);
|
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId, false);
|
||||||
List<PaymentEntity> updatedPaymentEntities = new List<PaymentEntity>();
|
List<PaymentEntity> updatedPaymentEntities = new List<PaymentEntity>();
|
||||||
var transactions = await wallet.GetTransactions(invoice.GetPayments(wallet.Network)
|
var transactions = await wallet.GetTransactions(GetAllBitcoinPaymentData(invoice)
|
||||||
.Select(t => t.Outpoint.Hash)
|
.Select(p => p.Outpoint.Hash)
|
||||||
.ToArray());
|
.ToArray());
|
||||||
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 (!transactions.TryGetValue(payment.Outpoint.Hash, out TransactionResult tx))
|
var paymentData = payment.GetCryptoPaymentData() as BitcoinLikePaymentData;
|
||||||
|
if (paymentData == null)
|
||||||
|
continue;
|
||||||
|
if (!transactions.TryGetValue(paymentData.Outpoint.Hash, out TransactionResult tx))
|
||||||
continue;
|
continue;
|
||||||
var txId = tx.Transaction.GetHash();
|
var txId = tx.Transaction.GetHash();
|
||||||
var txConflict = conflicts.GetConflict(txId);
|
var txConflict = conflicts.GetConflict(txId);
|
||||||
|
@ -228,27 +239,12 @@ namespace BTCPayServer.HostedServices
|
||||||
payment.Accounted = accounted;
|
payment.Accounted = accounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bitcoinLike = payment.GetCryptoPaymentData() as BitcoinLikePaymentData;
|
if (paymentData.ConfirmationCount != tx.Confirmations)
|
||||||
|
|
||||||
// Legacy
|
|
||||||
if (bitcoinLike == null)
|
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
if(wallet.Network.MaxTrackedConfirmation >= paymentData.ConfirmationCount)
|
||||||
payment.CryptoPaymentDataType = "BTCLike";
|
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
|
||||||
bitcoinLike = new BitcoinLikePaymentData();
|
|
||||||
bitcoinLike.ConfirmationCount = tx.Confirmations;
|
|
||||||
bitcoinLike.RBF = tx.Transaction.RBF;
|
|
||||||
payment.SetCryptoPaymentData(bitcoinLike);
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bitcoinLike.ConfirmationCount != tx.Confirmations)
|
|
||||||
{
|
|
||||||
if(wallet.Network.MaxTrackedConfirmation >= bitcoinLike.ConfirmationCount)
|
|
||||||
{
|
{
|
||||||
bitcoinLike.ConfirmationCount = tx.Confirmations;
|
paymentData.ConfirmationCount = tx.Confirmations;
|
||||||
payment.SetCryptoPaymentData(bitcoinLike);
|
payment.SetCryptoPaymentData(paymentData);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +324,7 @@ namespace BTCPayServer.HostedServices
|
||||||
foreach (var invoiceId in invoices)
|
foreach (var invoiceId in invoices)
|
||||||
{
|
{
|
||||||
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId, true);
|
var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId, true);
|
||||||
var alreadyAccounted = new HashSet<OutPoint>(invoice.GetPayments(network).Select(p => p.Outpoint));
|
var alreadyAccounted = GetAllBitcoinPaymentData(invoice).Select(p => p.Outpoint).ToHashSet();
|
||||||
var strategy = invoice.GetDerivationStrategy(network);
|
var strategy = invoice.GetDerivationStrategy(network);
|
||||||
if (strategy == null)
|
if (strategy == null)
|
||||||
continue;
|
continue;
|
||||||
|
@ -337,7 +333,9 @@ namespace BTCPayServer.HostedServices
|
||||||
.ToArray();
|
.ToArray();
|
||||||
foreach (var coin in coins.Where(c => !alreadyAccounted.Contains(c.Coin.Outpoint)))
|
foreach (var coin in coins.Where(c => !alreadyAccounted.Contains(c.Coin.Outpoint)))
|
||||||
{
|
{
|
||||||
var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin.Timestamp, coin.Coin, network.CryptoCode).ConfigureAwait(false);
|
var transaction = await wallet.GetTransactionAsync(coin.Coin.Outpoint.Hash);
|
||||||
|
var paymentData = new BitcoinLikePaymentData(coin.Coin, transaction.Transaction.RBF);
|
||||||
|
var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin.Timestamp, paymentData, network.CryptoCode).ConfigureAwait(false);
|
||||||
alreadyAccounted.Add(coin.Coin.Outpoint);
|
alreadyAccounted.Add(coin.Coin.Outpoint);
|
||||||
invoice = await ReceivedPayment(wallet, invoice.Id, payment, strategy);
|
invoice = await ReceivedPayment(wallet, invoice.Id, payment, strategy);
|
||||||
totalPayment++;
|
totalPayment++;
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||||
public class Payment
|
public class Payment
|
||||||
{
|
{
|
||||||
public string CryptoCode { get; set; }
|
public string CryptoCode { get; set; }
|
||||||
public int Confirmations
|
public string Confirmations
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
|
@ -537,7 +537,7 @@ namespace BTCPayServer.Services.Invoices
|
||||||
|
|
||||||
public BitcoinAddress GetDepositAddress()
|
public BitcoinAddress GetDepositAddress()
|
||||||
{
|
{
|
||||||
if(string.IsNullOrEmpty(DepositAddress))
|
if (string.IsNullOrEmpty(DepositAddress))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -604,12 +604,14 @@ namespace BTCPayServer.Services.Invoices
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use ((BitcoinLikePaymentData)GetCryptoPaymentData()).Outpoint")]
|
||||||
public OutPoint Outpoint
|
public OutPoint Outpoint
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use GetValue() or GetScriptPubKey() instead")]
|
[Obsolete("Use ((BitcoinLikePaymentData)GetCryptoPaymentData()).Output")]
|
||||||
public TxOut Output
|
public TxOut Output
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
|
@ -627,6 +629,7 @@ namespace BTCPayServer.Services.Invoices
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Obsolete("Use GetCryptoCode() instead")]
|
[Obsolete("Use GetCryptoCode() instead")]
|
||||||
public string CryptoCode
|
public string CryptoCode
|
||||||
{
|
{
|
||||||
|
@ -644,23 +647,38 @@ namespace BTCPayServer.Services.Invoices
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
if (string.IsNullOrEmpty(CryptoPaymentDataType))
|
if (string.IsNullOrEmpty(CryptoPaymentDataType))
|
||||||
{
|
{
|
||||||
return NullPaymentData.Instance;
|
// In case this is a payment done before this update, consider it unconfirmed with RBF for safety
|
||||||
|
var paymentData = new BitcoinLikePaymentData();
|
||||||
|
paymentData.Outpoint = Outpoint;
|
||||||
|
paymentData.Output = Output;
|
||||||
|
paymentData.RBF = true;
|
||||||
|
paymentData.ConfirmationCount = 0;
|
||||||
|
paymentData.Legacy = true;
|
||||||
|
return paymentData;
|
||||||
}
|
}
|
||||||
if (CryptoPaymentDataType == "BTCLike")
|
if (CryptoPaymentDataType == "BTCLike")
|
||||||
{
|
{
|
||||||
return JsonConvert.DeserializeObject<BitcoinLikePaymentData>(CryptoPaymentData);
|
var paymentData = JsonConvert.DeserializeObject<BitcoinLikePaymentData>(CryptoPaymentData);
|
||||||
|
// legacy
|
||||||
|
paymentData.Output = Output;
|
||||||
|
paymentData.Outpoint = Outpoint;
|
||||||
|
return paymentData;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return NullPaymentData.Instance;
|
throw new NotSupportedException(nameof(CryptoPaymentDataType) + " does not support " + CryptoPaymentDataType);
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCryptoPaymentData(CryptoPaymentData cryptoPaymentData)
|
public void SetCryptoPaymentData(CryptoPaymentData cryptoPaymentData)
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
if (cryptoPaymentData is BitcoinLikePaymentData)
|
if (cryptoPaymentData is BitcoinLikePaymentData paymentData)
|
||||||
{
|
{
|
||||||
CryptoPaymentDataType = "BTCLike";
|
CryptoPaymentDataType = "BTCLike";
|
||||||
|
// Legacy
|
||||||
|
Outpoint = paymentData.Outpoint;
|
||||||
|
Output = paymentData.Output;
|
||||||
|
///
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new NotSupportedException(cryptoPaymentData.ToString());
|
throw new NotSupportedException(cryptoPaymentData.ToString());
|
||||||
|
@ -701,41 +719,60 @@ namespace BTCPayServer.Services.Invoices
|
||||||
|
|
||||||
public interface CryptoPaymentData
|
public interface CryptoPaymentData
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an identifier which uniquely identify the payment
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The payment id</returns>
|
||||||
|
string GetPaymentId();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns terms which will be indexed and searchable in the search bar of invoice
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The search terms</returns>
|
||||||
|
string[] GetSearchTerms();
|
||||||
bool PaymentCompleted(PaymentEntity entity, BTCPayNetwork network);
|
bool PaymentCompleted(PaymentEntity entity, BTCPayNetwork network);
|
||||||
bool PaymentConfirmed(PaymentEntity entity, SpeedPolicy speedPolicy, BTCPayNetwork network);
|
bool PaymentConfirmed(PaymentEntity entity, SpeedPolicy speedPolicy, BTCPayNetwork network);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NullPaymentData : CryptoPaymentData
|
|
||||||
{
|
|
||||||
|
|
||||||
private static readonly NullPaymentData _Instance = new NullPaymentData();
|
|
||||||
public static NullPaymentData Instance
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _Instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool PaymentCompleted(PaymentEntity entity, BTCPayNetwork network)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PaymentConfirmed(PaymentEntity entity, SpeedPolicy speedPolicy, BTCPayNetwork network)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BitcoinLikePaymentData : CryptoPaymentData
|
public class BitcoinLikePaymentData : CryptoPaymentData
|
||||||
{
|
{
|
||||||
|
public BitcoinLikePaymentData()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public BitcoinLikePaymentData(Coin coin, bool rbf)
|
||||||
|
{
|
||||||
|
Outpoint = coin.Outpoint;
|
||||||
|
Output = coin.TxOut;
|
||||||
|
ConfirmationCount = 0;
|
||||||
|
RBF = rbf;
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public OutPoint Outpoint { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
|
public TxOut Output { get; set; }
|
||||||
public int ConfirmationCount { get; set; }
|
public int ConfirmationCount { get; set; }
|
||||||
public bool RBF { get; set; }
|
public bool RBF { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is set to true if the payment was created before CryptoPaymentData existed in BTCPayServer
|
||||||
|
/// </summary>
|
||||||
|
public bool Legacy { get; set; }
|
||||||
|
|
||||||
|
public string GetPaymentId()
|
||||||
|
{
|
||||||
|
return Outpoint.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetSearchTerms()
|
||||||
|
{
|
||||||
|
return new[] { Outpoint.Hash.ToString() };
|
||||||
|
}
|
||||||
|
|
||||||
public bool PaymentCompleted(PaymentEntity entity, BTCPayNetwork network)
|
public bool PaymentCompleted(PaymentEntity entity, BTCPayNetwork network)
|
||||||
{
|
{
|
||||||
return ConfirmationCount >= 6;
|
return ConfirmationCount >= network.MaxTrackedConfirmation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool PaymentConfirmed(PaymentEntity entity, SpeedPolicy speedPolicy, BTCPayNetwork network)
|
public bool PaymentConfirmed(PaymentEntity entity, SpeedPolicy speedPolicy, BTCPayNetwork network)
|
||||||
|
|
|
@ -443,24 +443,24 @@ namespace BTCPayServer.Services.Invoices
|
||||||
AddToTextSearch(invoiceId, addresses.Select(a => a.ToString()).ToArray());
|
AddToTextSearch(invoiceId, addresses.Select(a => a.ToString()).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PaymentEntity> AddPayment(string invoiceId, DateTimeOffset date, Coin receivedCoin, string cryptoCode)
|
public async Task<PaymentEntity> AddPayment(string invoiceId, DateTimeOffset date, CryptoPaymentData paymentData, string cryptoCode)
|
||||||
{
|
{
|
||||||
using (var context = _ContextFactory.CreateContext())
|
using (var context = _ContextFactory.CreateContext())
|
||||||
{
|
{
|
||||||
PaymentEntity entity = new PaymentEntity
|
PaymentEntity entity = new PaymentEntity
|
||||||
{
|
{
|
||||||
Outpoint = receivedCoin.Outpoint,
|
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
Output = receivedCoin.TxOut,
|
|
||||||
CryptoCode = cryptoCode,
|
CryptoCode = cryptoCode,
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
ReceivedTime = date.UtcDateTime,
|
ReceivedTime = date.UtcDateTime,
|
||||||
Accounted = false
|
Accounted = false
|
||||||
};
|
};
|
||||||
entity.SetCryptoPaymentData(new BitcoinLikePaymentData());
|
entity.SetCryptoPaymentData(paymentData);
|
||||||
|
|
||||||
|
|
||||||
PaymentData data = new PaymentData
|
PaymentData data = new PaymentData
|
||||||
{
|
{
|
||||||
Id = receivedCoin.Outpoint.ToString(),
|
Id = paymentData.GetPaymentId(),
|
||||||
Blob = ToBytes(entity, null),
|
Blob = ToBytes(entity, null),
|
||||||
InvoiceDataId = invoiceId,
|
InvoiceDataId = invoiceId,
|
||||||
Accounted = false
|
Accounted = false
|
||||||
|
@ -469,7 +469,7 @@ namespace BTCPayServer.Services.Invoices
|
||||||
context.Payments.Add(data);
|
context.Payments.Add(data);
|
||||||
|
|
||||||
await context.SaveChangesAsync().ConfigureAwait(false);
|
await context.SaveChangesAsync().ConfigureAwait(false);
|
||||||
AddToTextSearch(invoiceId, receivedCoin.Outpoint.Hash.ToString());
|
AddToTextSearch(invoiceId, paymentData.GetSearchTerms());
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,8 +482,9 @@ namespace BTCPayServer.Services.Invoices
|
||||||
{
|
{
|
||||||
foreach (var payment in payments)
|
foreach (var payment in payments)
|
||||||
{
|
{
|
||||||
|
var paymentData = payment.GetCryptoPaymentData();
|
||||||
var data = new PaymentData();
|
var data = new PaymentData();
|
||||||
data.Id = payment.Outpoint.ToString();
|
data.Id = paymentData.GetPaymentId();
|
||||||
data.Accounted = payment.Accounted;
|
data.Accounted = payment.Accounted;
|
||||||
data.Blob = ToBytes(payment, null);
|
data.Blob = ToBytes(payment, null);
|
||||||
context.Attach(data);
|
context.Attach(data);
|
||||||
|
|
Loading…
Add table
Reference in a new issue