public async Task CheckPendingTransaction(Transaction transaction, CancellationToken cancellationToken = default(CancellationToken)) { var invoice = await _btcpayService.GetLightningInvoice(transaction.InvoiceId, cancellationToken); if (invoice.Status == LightningInvoiceStatus.Paid) { await MarkTransactionPaid(transaction, invoice.AmountReceived, invoice.PaidAt); } }
public async Task <Transaction> UpdateTransaction(Transaction transaction) { await using var dbContext = _dbContextFactory.CreateDbContext(); var entry = dbContext.Entry(transaction); entry.State = EntityState.Modified; await dbContext.SaveChangesAsync(); return(entry.Entity); }
private async Task MarkTransactionPaid(Transaction transaction, LightMoney amountSettled, DateTimeOffset?date) { _logger.LogInformation($"Marking transaction {transaction.TransactionId} as paid."); transaction.AmountSettled = amountSettled; transaction.PaidAt = date; await UpdateTransaction(transaction); await _transactionHub.Clients.All.SendAsync("transaction-update", new { transaction.TransactionId, transaction.InvoiceId, transaction.WalletId, transaction.Status, transaction.IsPaid, transaction.IsExpired, Event = "paid" }); }
public async Task RemoveTransaction(Transaction transaction) { await using var dbContext = _dbContextFactory.CreateDbContext(); dbContext.Transactions.Remove(transaction); await dbContext.SaveChangesAsync(); }
public async Task <Transaction> Send(Wallet wallet, BOLT11PaymentRequest bolt11, string paymentRequest) { await using var dbContext = _dbContextFactory.CreateDbContext(); var amount = bolt11.MinimumAmount; if (bolt11.ExpiryDate <= DateTimeOffset.UtcNow) { throw new Exception($"Payment request already expired at {bolt11.ExpiryDate}."); } if (wallet.Balance < amount) { var balanceSats = wallet.Balance.ToUnit(LightMoneyUnit.Satoshi); var amountSats = amount.ToUnit(LightMoneyUnit.Satoshi); throw new Exception($"Insufficient balance: {balanceSats} sats, tried to send {amountSats} sats."); } // pay via the node and fall back to internal payment Transaction internalReceivingTransaction = null; try { await _btcpayService.PayLightningInvoice(new LightningInvoicePayRequest { PaymentRequest = paymentRequest }); } catch (GreenFieldAPIException ex) when(ex.APIError.Code == "could-not-find-route") { internalReceivingTransaction = await GetTransaction(new TransactionQuery { PaymentRequest = paymentRequest, HasInvoiceId = true }); if (internalReceivingTransaction == null) { throw; } } if (internalReceivingTransaction != null) { if (internalReceivingTransaction.IsExpired) { throw new Exception($"Payment request already expired at {internalReceivingTransaction.ExpiresAt}."); } if (internalReceivingTransaction.IsPaid) { throw new Exception($"Payment request has already been paid."); } } // https://docs.microsoft.com/en-us/ef/core/saving/transactions#controlling-transactions await using var dbTransaction = await dbContext.Database.BeginTransactionAsync(); var now = DateTimeOffset.UtcNow; var entry = await dbContext.Transactions.AddAsync(new Transaction { WalletId = wallet.WalletId, PaymentRequest = paymentRequest, Amount = amount, AmountSettled = new LightMoney(amount.MilliSatoshi * -1), ExpiresAt = bolt11.ExpiryDate, Description = bolt11.ShortDescription, PaidAt = now }); await dbContext.SaveChangesAsync(); if (internalReceivingTransaction != null) { await MarkTransactionPaid(internalReceivingTransaction, amount, now); } await dbTransaction.CommitAsync(); return(entry.Entity); }