Fix BTCPay Server integration for production deployment

- Fixed invoice creation to use GBP (fiat) instead of cryptocurrency amounts
- BTCPay Server now handles automatic crypto conversion
- Updated payment flow to use checkout links instead of raw wallet addresses
- Added comprehensive logging for debugging payment issues
- Created diagnostic endpoints for testing BTCPay connection and payments
- Added documentation for deployment and troubleshooting

The key issue was that BTCPay v2 manages wallet addresses internally and provides checkout links for customers to complete payments, rather than exposing raw crypto addresses.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
SilverLabs DevTeam
2025-09-19 10:21:04 +01:00
parent 54618348ab
commit 6f0efa6252
4 changed files with 329 additions and 45 deletions

View File

@@ -13,15 +13,18 @@ public class CryptoPaymentService : ICryptoPaymentService
private readonly LittleShopContext _context;
private readonly IBTCPayServerService _btcPayService;
private readonly ILogger<CryptoPaymentService> _logger;
private readonly IConfiguration _configuration;
public CryptoPaymentService(
LittleShopContext context,
LittleShopContext context,
IBTCPayServerService btcPayService,
ILogger<CryptoPaymentService> logger)
ILogger<CryptoPaymentService> logger,
IConfiguration configuration)
{
_context = context;
_btcPayService = btcPayService;
_logger = logger;
_configuration = configuration;
}
public async Task<CryptoPaymentDto> CreatePaymentAsync(Guid orderId, CryptoCurrency currency)
@@ -45,15 +48,46 @@ public class CryptoPaymentService : ICryptoPaymentService
// Create BTCPay Server invoice
var invoiceId = await _btcPayService.CreateInvoiceAsync(
order.TotalAmount,
currency,
order.TotalAmount,
currency,
order.Id.ToString(),
$"Order #{order.Id} - {order.Items.Count} items"
);
// For now, generate a placeholder wallet address
// In a real implementation, this would come from BTCPay Server
var walletAddress = GenerateWalletAddress(currency);
// Get the real wallet address from BTCPay Server
var invoice = await _btcPayService.GetInvoiceAsync(invoiceId);
if (invoice == null)
{
throw new InvalidOperationException($"Failed to retrieve invoice {invoiceId} from BTCPay Server");
}
// Extract the wallet address from the invoice
string walletAddress;
decimal cryptoAmount = 0;
try
{
// BTCPay Server v2 uses CheckoutLink for payment
// The actual wallet addresses are managed internally by BTCPay
// Customers should use the CheckoutLink to make payments
walletAddress = invoice.CheckoutLink ?? $"https://{_configuration["BTCPayServer:BaseUrl"]}/i/{invoiceId}";
// For display purposes, we can show the checkout link
// BTCPay handles all the wallet address generation internally
_logger.LogInformation("Created payment for {Currency} - Invoice: {InvoiceId}, Checkout: {CheckoutLink}",
currency, invoiceId, walletAddress);
// Set the amount from the invoice (will be in fiat)
cryptoAmount = invoice.Amount > 0 ? invoice.Amount : order.TotalAmount;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing invoice {InvoiceId}", invoiceId);
// Fallback to a generated checkout link
walletAddress = $"https://{_configuration["BTCPayServer:BaseUrl"]}/i/{invoiceId}";
cryptoAmount = order.TotalAmount;
}
var cryptoPayment = new CryptoPayment
{
@@ -61,7 +95,7 @@ public class CryptoPaymentService : ICryptoPaymentService
OrderId = orderId,
Currency = currency,
WalletAddress = walletAddress,
RequiredAmount = order.TotalAmount, // This should be converted to crypto amount
RequiredAmount = cryptoAmount > 0 ? cryptoAmount : order.TotalAmount, // Use crypto amount if available
PaidAmount = 0,
Status = PaymentStatus.Pending,
BTCPayInvoiceId = invoiceId, // This is the actual BTCPay invoice ID
@@ -160,21 +194,19 @@ public class CryptoPaymentService : ICryptoPaymentService
};
}
private static string GenerateWalletAddress(CryptoCurrency currency)
private static string GetPaymentMethodId(CryptoCurrency currency)
{
// Placeholder wallet addresses - in production these would come from BTCPay Server
var guid = Guid.NewGuid().ToString("N"); // 32 characters
return currency switch
{
CryptoCurrency.BTC => "bc1q" + guid[..26],
CryptoCurrency.XMR => "4" + guid + guid[..32], // XMR needs ~95 chars, use double GUID
CryptoCurrency.USDT => "0x" + guid[..32], // ERC-20 address
CryptoCurrency.LTC => "ltc1q" + guid[..26],
CryptoCurrency.ETH => "0x" + guid[..32],
CryptoCurrency.ZEC => "zs1" + guid + guid[..29], // Shielded address
CryptoCurrency.DASH => "X" + guid[..30],
CryptoCurrency.DOGE => "D" + guid[..30],
_ => "placeholder_" + guid[..20]
CryptoCurrency.BTC => "BTC",
CryptoCurrency.XMR => "XMR",
CryptoCurrency.USDT => "USDT",
CryptoCurrency.LTC => "LTC",
CryptoCurrency.ETH => "ETH",
CryptoCurrency.ZEC => "ZEC",
CryptoCurrency.DASH => "DASH",
CryptoCurrency.DOGE => "DOGE",
_ => "BTC"
};
}
}