@@ -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.
721794func (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