Skip to content

Commit 06dd960

Browse files
committed
loopout: use asset client for payment
1 parent a25753c commit 06dd960

File tree

1 file changed

+81
-2
lines changed

1 file changed

+81
-2
lines changed

loopout.go

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ import (
2020
"github.com/lightninglabs/loop/sweep"
2121
"github.com/lightninglabs/loop/sweepbatcher"
2222
"github.com/lightninglabs/loop/utils"
23+
"github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
2324
"github.com/lightningnetwork/lnd/chainntnfs"
2425
"github.com/lightningnetwork/lnd/channeldb"
2526
"github.com/lightningnetwork/lnd/lnrpc"
27+
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
2628
"github.com/lightningnetwork/lnd/lntypes"
2729
)
2830

@@ -87,8 +89,9 @@ type loopOutSwap struct {
8789
// to calculate the total cost of the swap.
8890
prepayAmount btcutil.Amount
8991

90-
swapPaymentChan chan paymentResult
91-
prePaymentChan chan paymentResult
92+
swapPaymentChan chan paymentResult
93+
prePaymentChan chan paymentResult
94+
waitForRfqCompletedChan chan interface{}
9295

9396
wg sync.WaitGroup
9497
}
@@ -140,6 +143,11 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig,
140143
log.Infof("Initiating swap request at height %v: amt=%v, expiry=%v",
141144
currentHeight, request.Amount, request.Expiry)
142145

146+
// If we have an asset id, we'll add that to the user agent.
147+
if request.AssetId != nil {
148+
request.Initiator += " asset_out"
149+
}
150+
143151
// The swap deadline will be given to the server for it to use as the
144152
// latest swap publication time.
145153
swapResp, err := cfg.server.NewLoopOutSwap(
@@ -634,13 +642,22 @@ func (s *loopOutSwap) payInvoices(ctx context.Context) {
634642
s.log.Infof("Server recommended routing plugin: %v", pluginType)
635643
}
636644

645+
if s.AssetId != nil {
646+
s.waitForRfqCompletedChan = make(chan interface{})
647+
}
648+
637649
// Use the recommended routing plugin.
638650
s.swapPaymentChan = s.payInvoice(
639651
ctx, s.SwapInvoice, s.MaxSwapRoutingFee,
640652
s.LoopOutContract.OutgoingChanSet,
641653
s.LoopOutContract.PaymentTimeout, pluginType, true,
642654
)
643655

656+
// We'll nee
657+
if s.AssetId != nil {
658+
<-s.waitForRfqCompletedChan
659+
}
660+
644661
// Pay the prepay invoice. Won't use the routing plugin here as the
645662
// prepay is trivially small and shouldn't normally need any help. We
646663
// are sending it over the same channel as the loop out payment.
@@ -717,13 +734,75 @@ func (s *loopOutSwap) payInvoice(ctx context.Context, invoice string,
717734
return resultChan
718735
}
719736

737+
func (s *loopOutSwap) payInvoiceWithAssetClient(ctx context.Context,
738+
invoice string) (*lndclient.PaymentStatus, error) {
739+
740+
totalPaymentTimeout := s.executeConfig.totalPaymentTimeout
741+
742+
sendReq := &routerrpc.SendPaymentRequest{
743+
PaymentRequest: invoice,
744+
TimeoutSeconds: int32(totalPaymentTimeout.Seconds()),
745+
FeeLimitMsat: 1_000_000,
746+
}
747+
748+
paymentStream, err := s.assets.SendPayment(
749+
ctx, &tapchannelrpc.SendPaymentRequest{
750+
AssetId: s.AssetId,
751+
PeerPubkey: s.AssetEdgeNode,
752+
PaymentRequest: sendReq,
753+
})
754+
if err != nil {
755+
return nil, err
756+
}
757+
758+
// We want to receive the accepted quote message first, so we know how
759+
// many assets we're going to pay.
760+
for {
761+
select {
762+
case <-ctx.Done():
763+
return nil, ctx.Err()
764+
default:
765+
msg, err := paymentStream.Recv()
766+
if err != nil {
767+
return nil, err
768+
}
769+
770+
switch msg.GetResult().(type) {
771+
case *tapchannelrpc.SendPaymentResponse_AcceptedSellOrder:
772+
quote := msg.GetAcceptedSellOrder()
773+
log.Infof("Accepted quote: %v", quote.AssetAmount)
774+
if s.waitForRfqCompletedChan != nil {
775+
close(s.waitForRfqCompletedChan)
776+
s.waitForRfqCompletedChan = nil
777+
}
778+
779+
case *tapchannelrpc.SendPaymentResponse_PaymentResult:
780+
payRes := msg.GetPaymentResult()
781+
if payRes.Status == lnrpc.Payment_SUCCEEDED ||
782+
payRes.Status == lnrpc.Payment_FAILED {
783+
784+
return &lndclient.PaymentStatus{
785+
State: payRes.Status,
786+
}, nil
787+
}
788+
}
789+
}
790+
}
791+
}
792+
720793
// payInvoiceAsync is the asynchronously executed part of paying an invoice.
721794
func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
722795
invoice string, maxFee btcutil.Amount,
723796
outgoingChanIds loopdb.ChannelSet, paymentTimeout time.Duration,
724797
pluginType RoutingPluginType, reportPluginResult bool) (
725798
*lndclient.PaymentStatus, error) {
726799

800+
// If we want to use an asset for the payment, we need to use the asset
801+
// client.
802+
if s.AssetId != nil {
803+
return s.payInvoiceWithAssetClient(ctx, invoice)
804+
}
805+
727806
// Extract hash from payment request. Unfortunately the request
728807
// components aren't available directly.
729808
chainParams := s.lnd.ChainParams

0 commit comments

Comments
 (0)