Add Lightning payout support (#2517)

* Add Lightning payout support

* Adjust Greenfield API to allow other payment types for Payouts

* Pull payment view: Improve payment method select

* Pull payments view: Update JS

* Pull payments view: Table improvements

* Pull payment form: Remove duplicate name field

* Cleanup Lightning branch after rebasing

* Update swagger documnetation for Lightning support

* Remove required requirement for amount in pull payments

* Adapt Refund endpoint to support multiple playment methods

* Support LNURL Pay for Pull Payments

* Revert "Remove required requirement for amount in pull payments"

This reverts commit 96cb78939d43b7be61ee2d257800ccd1cce45c4c.

* Support Lightning address payout claims

* Fix lightning claim handling and provide better error messages

* Fix tests

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
This commit is contained in:
Andrew Camilleri
2021-10-18 05:37:59 +02:00
committed by GitHub
parent 5ac4135a13
commit cf206e64a7
33 changed files with 925 additions and 172 deletions

View File

@@ -85,6 +85,7 @@ namespace BTCPayServer.Controllers
Currency = blob.Currency,
Status = entity.Entity.State,
Destination = entity.Blob.Destination,
PaymentMethod = PaymentMethodId.Parse(entity.Entity.PaymentMethodId),
Link = entity.ProofBlob?.Link,
TransactionId = entity.ProofBlob?.Id
}).ToList()
@@ -105,14 +106,31 @@ namespace BTCPayServer.Controllers
}
var ppBlob = pp.GetBlob();
var network = _networkProvider.GetNetwork<BTCPayNetwork>(ppBlob.SupportedPaymentMethods.Single().CryptoCode);
var paymentMethodId = ppBlob.SupportedPaymentMethods.Single();
var payoutHandler = _payoutHandlers.FirstOrDefault(handler => handler.CanHandle(paymentMethodId));
IClaimDestination destination = await payoutHandler?.ParseClaimDestination(paymentMethodId, vm.Destination);
if (destination is null)
var paymentMethodId = ppBlob.SupportedPaymentMethods.FirstOrDefault(id => vm.SelectedPaymentMethod == id.ToString());
var payoutHandler = paymentMethodId is null? null: _payoutHandlers.FirstOrDefault(handler => handler.CanHandle(paymentMethodId));
if (payoutHandler is null)
{
ModelState.AddModelError(nameof(vm.Destination), $"Invalid destination");
ModelState.AddModelError(nameof(vm.SelectedPaymentMethod), $"Invalid destination with selected payment method");
return await ViewPullPayment(pullPaymentId);
}
var destination = await payoutHandler?.ParseClaimDestination(paymentMethodId, vm.Destination, true);
if (destination.destination is null)
{
ModelState.AddModelError(nameof(vm.Destination), destination.error??"Invalid destination with selected payment method");
return await ViewPullPayment(pullPaymentId);
}
if (vm.ClaimedAmount == 0)
{
ModelState.AddModelError(nameof(vm.ClaimedAmount),
$"Amount is required");
}
else if (vm.ClaimedAmount != 0 && destination.destination.Amount != null && vm.ClaimedAmount != destination.destination.Amount)
{
ModelState.AddModelError(nameof(vm.ClaimedAmount),
$"Amount is implied in destination ({destination.destination.Amount}) that does not match the payout amount provided {vm.ClaimedAmount})");
}
if (!ModelState.IsValid)
@@ -122,10 +140,10 @@ namespace BTCPayServer.Controllers
var result = await _pullPaymentHostedService.Claim(new ClaimRequest()
{
Destination = destination,
Destination = destination.destination,
PullPaymentId = pullPaymentId,
Value = vm.ClaimedAmount,
PaymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike)
PaymentMethodId = paymentMethodId
});
if (result.Result != ClaimRequest.ClaimResult.Ok)
@@ -150,12 +168,5 @@ namespace BTCPayServer.Controllers
}
return RedirectToAction(nameof(ViewPullPayment), new { pullPaymentId = pullPaymentId });
}
string GetTransactionLink(BTCPayNetworkBase network, string txId)
{
if (txId is null)
return string.Empty;
return string.Format(CultureInfo.InvariantCulture, network.BlockExplorerLink, txId);
}
}
}