@@ -17,6 +17,7 @@ import (
1717 "github.com/lightninglabs/aperture/lsat"
1818 "github.com/lightninglabs/loop/loopdb"
1919 "github.com/lightninglabs/loop/looprpc"
20+ "github.com/lightningnetwork/lnd/lnrpc"
2021 "github.com/lightningnetwork/lnd/lntypes"
2122 "github.com/lightningnetwork/lnd/routing/route"
2223 "github.com/lightningnetwork/lnd/tor"
@@ -74,6 +75,10 @@ type swapServerClient interface {
7475 // SubscribeLoopInUpdates subscribes to loop in server state.
7576 SubscribeLoopInUpdates (ctx context.Context ,
7677 hash lntypes.Hash ) (<- chan * ServerUpdate , <- chan error , error )
78+
79+ // CancelLoopOutSwap cancels a loop out swap.
80+ CancelLoopOutSwap (ctx context.Context ,
81+ details * outCancelDetails ) error
7782}
7883
7984type grpcSwapServerClient struct {
@@ -456,6 +461,104 @@ func (s *grpcSwapServerClient) makeServerUpdate(ctx context.Context,
456461 return updateChan , errChan
457462}
458463
464+ // paymentType is an enum representing different types of off-chain payments
465+ // made by a swap.
466+ type paymentType uint8
467+
468+ const (
469+ // paymentTypePrepay indicates that we could not route the prepay.
470+ paymentTypePrepay paymentType = iota
471+
472+ // paymentTypeInvoice indicates that we could not route the swap
473+ // invoice.
474+ paymentTypeInvoice
475+ )
476+
477+ // routeCancelMetadata contains cancelation information for swaps that are
478+ // canceled because the client could not route off-chain to the server.
479+ type routeCancelMetadata struct {
480+ // paymentType is the type of payment that failed.
481+ paymentType paymentType
482+
483+ // attempts is the set of htlc attempts made by the client, reporting
484+ // the distance from the invoice's destination node that a failure
485+ // occurred.
486+ attempts []uint32
487+
488+ // failureReason is the reason that the payment failed.
489+ failureReason lnrpc.PaymentFailureReason
490+ }
491+
492+ // outCancelDetails contains the informaton required to cancel a loop out swap.
493+ type outCancelDetails struct {
494+ // Hash is the swap's hash.
495+ hash lntypes.Hash
496+
497+ // paymentAddr is the payment address for the swap's invoice.
498+ paymentAddr [32 ]byte
499+
500+ // metadata contains additional information about the swap.
501+ metadata routeCancelMetadata
502+ }
503+
504+ // CancelLoopOutSwap sends an instruction to the server to cancel a loop out
505+ // swap.
506+ func (s * grpcSwapServerClient ) CancelLoopOutSwap (ctx context.Context ,
507+ details * outCancelDetails ) error {
508+
509+ req := & looprpc.CancelLoopOutSwapRequest {
510+ ProtocolVersion : loopdb .CurrentRPCProtocolVersion ,
511+ SwapHash : details .hash [:],
512+ PaymentAddress : details .paymentAddr [:],
513+ }
514+
515+ var err error
516+ req .CancelInfo , err = rpcRouteCancel (details )
517+ if err != nil {
518+ return err
519+ }
520+
521+ _ , err = s .server .CancelLoopOutSwap (ctx , req )
522+ return err
523+ }
524+
525+ func rpcRouteCancel (details * outCancelDetails ) (
526+ * looprpc.CancelLoopOutSwapRequest_RouteCancel , error ) {
527+
528+ attempts := make ([]* looprpc.HtlcAttempt , len (details .metadata .attempts ))
529+ for i , remaining := range details .metadata .attempts {
530+ attempts [i ] = & looprpc.HtlcAttempt {
531+ RemainingHops : remaining ,
532+ }
533+ }
534+
535+ resp := & looprpc.CancelLoopOutSwapRequest_RouteCancel {
536+ RouteCancel : & looprpc.RouteCancel {
537+ Attempts : attempts ,
538+ // We can cast our lnd failure reason to a loop payment
539+ // failure reason because these values are copied 1:1
540+ // from lnd.
541+ Failure : looprpc .PaymentFailureReason (
542+ details .metadata .failureReason ,
543+ ),
544+ },
545+ }
546+
547+ switch details .metadata .paymentType {
548+ case paymentTypePrepay :
549+ resp .RouteCancel .RouteType = looprpc .RoutePaymentType_PREPAY_ROUTE
550+
551+ case paymentTypeInvoice :
552+ resp .RouteCancel .RouteType = looprpc .RoutePaymentType_INVOICE_ROUTE
553+
554+ default :
555+ return nil , fmt .Errorf ("unknown payment type: %v" ,
556+ details .metadata .paymentType )
557+ }
558+
559+ return resp , nil
560+ }
561+
459562// getSwapServerConn returns a connection to the swap server. A non-empty
460563// proxyAddr indicates that a SOCKS proxy found at the address should be used to
461564// establish the connection.
0 commit comments