diff --git a/client.go b/client.go index 70309a6..3724e7b 100644 --- a/client.go +++ b/client.go @@ -397,7 +397,7 @@ func (s *Client) LoopOut(globalCtx context.Context, } // Calculate htlc expiry height. - terms, err := s.Server.GetLoopOutTerms(globalCtx) + terms, err := s.Server.GetLoopOutTerms(globalCtx, request.Initiator) if err != nil { return nil, err } @@ -456,7 +456,7 @@ func (s *Client) getExpiry(height int32, terms *LoopOutTerms, func (s *Client) LoopOutQuote(ctx context.Context, request *LoopOutQuoteRequest) (*LoopOutQuote, error) { - terms, err := s.Server.GetLoopOutTerms(ctx) + terms, err := s.Server.GetLoopOutTerms(ctx, request.Initiator) if err != nil { return nil, err } @@ -477,6 +477,7 @@ func (s *Client) LoopOutQuote(ctx context.Context, quote, err := s.Server.GetLoopOutQuote( ctx, request.Amount, expiry, request.SwapPublicationDeadline, + request.Initiator, ) if err != nil { return nil, err @@ -528,10 +529,10 @@ func (s *Client) getLoopOutSweepFee(ctx context.Context, confTarget int32) ( } // LoopOutTerms returns the terms on which the server executes swaps. -func (s *Client) LoopOutTerms(ctx context.Context) ( +func (s *Client) LoopOutTerms(ctx context.Context, initiator string) ( *LoopOutTerms, error) { - return s.Server.GetLoopOutTerms(ctx) + return s.Server.GetLoopOutTerms(ctx, initiator) } // waitForInitialized for swaps to be resumed and executor ready. @@ -601,7 +602,7 @@ func (s *Client) LoopInQuote(ctx context.Context, request *LoopInQuoteRequest) (*LoopInQuote, error) { // Retrieve current server terms to calculate swap fee. - terms, err := s.Server.GetLoopInTerms(ctx) + terms, err := s.Server.GetLoopInTerms(ctx, request.Initiator) if err != nil { return nil, err } @@ -641,7 +642,7 @@ func (s *Client) LoopInQuote(ctx context.Context, quote, err := s.Server.GetLoopInQuote( ctx, request.Amount, s.lndServices.NodePubkey, request.LastHop, - request.RouteHints, + request.RouteHints, request.Initiator, ) if err != nil { return nil, err @@ -721,10 +722,10 @@ func (s *Client) estimateFee(ctx context.Context, amt btcutil.Amount, } // LoopInTerms returns the terms on which the server executes swaps. -func (s *Client) LoopInTerms(ctx context.Context) ( +func (s *Client) LoopInTerms(ctx context.Context, initiator string) ( *LoopInTerms, error) { - return s.Server.GetLoopInTerms(ctx) + return s.Server.GetLoopInTerms(ctx, initiator) } // wrapGrpcError wraps the non-nil error provided with a message providing diff --git a/interface.go b/interface.go index 790a907..3476fd7 100644 --- a/interface.go +++ b/interface.go @@ -129,6 +129,11 @@ type LoopOutQuoteRequest struct { // available routes and off-chain fee estimates. To apply these maximum // values properly, the server needs to be queried for its required // final cltv delta values for the off-chain payments. + + // Initiator is an optional string that identifies what software + // initiated the swap (loop CLI, autolooper, LiT UI and so on) and is + // appended to the user agent string. + Initiator string } // LoopOutTerms are the server terms on which it executes swaps. @@ -267,6 +272,11 @@ type LoopInQuoteRequest struct { // private. In which case, loop will generate hophints to assist with // probing and payment. Private bool + + // Initiator is an optional string that identifies what software + // initiated the swap (loop CLI, autolooper, LiT UI and so on) and is + // appended to the user agent string. + Initiator string } // LoopInQuote contains estimates for the fees making up the total swap cost diff --git a/liquidity/liquidity.go b/liquidity/liquidity.go index 7556117..bd84922 100644 --- a/liquidity/liquidity.go +++ b/liquidity/liquidity.go @@ -178,8 +178,8 @@ type Config struct { // Restrictions returns the restrictions that the server applies to // swaps. - Restrictions func(ctx context.Context, swapType swap.Type) ( - *Restrictions, error) + Restrictions func(ctx context.Context, swapType swap.Type, + initiator string) (*Restrictions, error) // Lnd provides us with access to lnd's rpc servers. Lnd *lndclient.LndServices @@ -212,10 +212,12 @@ type Config struct { request *loop.LoopInRequest) (*loop.LoopInSwapInfo, error) // LoopInTerms returns the terms for a loop in swap. - LoopInTerms func(ctx context.Context) (*loop.LoopInTerms, error) + LoopInTerms func(ctx context.Context, + initiator string) (*loop.LoopInTerms, error) // LoopOutTerms returns the terms for a loop out swap. - LoopOutTerms func(ctx context.Context) (*loop.LoopOutTerms, error) + LoopOutTerms func(ctx context.Context, + initiator string) (*loop.LoopOutTerms, error) // Clock allows easy mocking of time in unit tests. Clock clock.Clock @@ -355,7 +357,9 @@ func (m *Manager) SetParameters(ctx context.Context, func (m *Manager) setParameters(ctx context.Context, params Parameters) error { - restrictions, err := m.cfg.Restrictions(ctx, swap.TypeOut) + restrictions, err := m.cfg.Restrictions( + ctx, swap.TypeOut, getInitiator(m.params), + ) if err != nil { return err } @@ -566,7 +570,9 @@ func (m *Manager) dispatchBestEasyAutoloopSwap(ctx context.Context) error { return nil } - restrictions, err := m.cfg.Restrictions(ctx, swap.TypeOut) + restrictions, err := m.cfg.Restrictions( + ctx, swap.TypeOut, getInitiator(m.params), + ) if err != nil { return err } @@ -999,7 +1005,9 @@ func (m *Manager) suggestSwap(ctx context.Context, traffic *swapTraffic, func (m *Manager) getSwapRestrictions(ctx context.Context, swapType swap.Type) ( *Restrictions, error) { - restrictions, err := m.cfg.Restrictions(ctx, swapType) + restrictions, err := m.cfg.Restrictions( + ctx, swapType, getInitiator(m.params), + ) if err != nil { return nil, err } @@ -1487,6 +1495,14 @@ func (m *Manager) checkSummaryInflight( return allowedSwaps, nil } +func getInitiator(params Parameters) string { + if params.EasyAutoloop { + return "easy-autoloop" + } + + return "autoloop" +} + // isAutoloopLabel is a helper function that returns a flag indicating whether // the provided label corresponds to an autoloop swap. func isAutoloopLabel(label string) bool { diff --git a/liquidity/loopin_builder.go b/liquidity/loopin_builder.go index b94fca7..f887719 100644 --- a/liquidity/loopin_builder.go +++ b/liquidity/loopin_builder.go @@ -90,6 +90,7 @@ func (b *loopInBuilder) buildSwap(ctx context.Context, pubkey route.Vertex, Amount: amount, LastHop: &pubkey, HtlcConfTarget: params.HtlcConfTarget, + Initiator: getInitiator(params), }) if err != nil { // If the server fails our quote, we're not reachable right @@ -113,7 +114,7 @@ func (b *loopInBuilder) buildSwap(ctx context.Context, pubkey route.Vertex, MaxMinerFee: quote.MinerFee, HtlcConfTarget: params.HtlcConfTarget, LastHop: &pubkey, - Initiator: autoloopSwapInitiator, + Initiator: getInitiator(params), } if params.Autoloop { diff --git a/liquidity/loopout_builder.go b/liquidity/loopout_builder.go index 062b1f3..658c940 100644 --- a/liquidity/loopout_builder.go +++ b/liquidity/loopout_builder.go @@ -101,6 +101,7 @@ func (b *loopOutBuilder) buildSwap(ctx context.Context, pubkey route.Vertex, Amount: amount, SweepConfTarget: params.SweepConfTarget, SwapPublicationDeadline: b.cfg.Clock.Now(), + Initiator: getInitiator(params), }, ) if err != nil { @@ -144,7 +145,7 @@ func (b *loopOutBuilder) buildSwap(ctx context.Context, pubkey route.Vertex, MaxSwapFee: quote.SwapFee, MaxPrepayAmount: quote.PrepayAmount, SweepConfTarget: params.SweepConfTarget, - Initiator: autoloopSwapInitiator, + Initiator: getInitiator(params), } if params.Autoloop { diff --git a/loopd/swapclient_server.go b/loopd/swapclient_server.go index dd826cc..d463f80 100644 --- a/loopd/swapclient_server.go +++ b/loopd/swapclient_server.go @@ -38,6 +38,8 @@ const ( // to specify. This is driven by the minimum confirmation target allowed // by the backing fee estimator. minConfTarget = 2 + + defaultLoopdInitiator = "loopd" ) var ( @@ -511,7 +513,7 @@ func (s *swapClientServer) LoopOutTerms(ctx context.Context, log.Infof("Loop out terms request received") - terms, err := s.impl.LoopOutTerms(ctx) + terms, err := s.impl.LoopOutTerms(ctx, defaultLoopdInitiator) if err != nil { log.Errorf("Terms request: %v", err) return nil, err @@ -542,6 +544,7 @@ func (s *swapClientServer) LoopOutQuote(ctx context.Context, SwapPublicationDeadline: time.Unix( int64(req.SwapPublicationDeadline), 0, ), + Initiator: defaultLoopdInitiator, }) if err != nil { return nil, err @@ -562,7 +565,7 @@ func (s *swapClientServer) GetLoopInTerms(ctx context.Context, log.Infof("Loop in terms request received") - terms, err := s.impl.LoopInTerms(ctx) + terms, err := s.impl.LoopInTerms(ctx, defaultLoopdInitiator) if err != nil { log.Errorf("Terms request: %v", err) return nil, err @@ -616,6 +619,7 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context, LastHop: lastHop, RouteHints: routeHints, Private: req.Private, + Initiator: defaultLoopdInitiator, }) if err != nil { return nil, err diff --git a/loopd/utils.go b/loopd/utils.go index 46457c2..cac86d6 100644 --- a/loopd/utils.go +++ b/loopd/utils.go @@ -75,11 +75,11 @@ func getLiquidityManager(client *loop.Client) *liquidity.Manager { AutoloopTicker: ticker.NewForce(liquidity.DefaultAutoloopTicker), LoopOut: client.LoopOut, LoopIn: client.LoopIn, - Restrictions: func(ctx context.Context, - swapType swap.Type) (*liquidity.Restrictions, error) { + Restrictions: func(ctx context.Context, swapType swap.Type, + initiator string) (*liquidity.Restrictions, error) { if swapType == swap.TypeOut { - outTerms, err := client.Server.GetLoopOutTerms(ctx) + outTerms, err := client.Server.GetLoopOutTerms(ctx, initiator) if err != nil { return nil, err } @@ -89,7 +89,7 @@ func getLiquidityManager(client *loop.Client) *liquidity.Manager { ), nil } - inTerms, err := client.Server.GetLoopInTerms(ctx) + inTerms, err := client.Server.GetLoopInTerms(ctx, initiator) if err != nil { return nil, err } diff --git a/loopin.go b/loopin.go index b74d177..c061fce 100644 --- a/loopin.go +++ b/loopin.go @@ -121,7 +121,7 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig, // hints. quote, err := cfg.server.GetLoopInQuote( globalCtx, request.Amount, cfg.lnd.NodePubkey, request.LastHop, - request.RouteHints, + request.RouteHints, request.Initiator, ) if err != nil { return nil, wrapGrpcError("loop in terms", err) diff --git a/swap_server_client.go b/swap_server_client.go index 1a752a5..5ca1141 100644 --- a/swap_server_client.go +++ b/swap_server_client.go @@ -68,19 +68,20 @@ func (r RoutingPluginType) String() string { } type swapServerClient interface { - GetLoopOutTerms(ctx context.Context) ( + GetLoopOutTerms(ctx context.Context, initiator string) ( *LoopOutTerms, error) GetLoopOutQuote(ctx context.Context, amt btcutil.Amount, expiry int32, - swapPublicationDeadline time.Time) ( + swapPublicationDeadline time.Time, initiator string) ( *LoopOutQuote, error) - GetLoopInTerms(ctx context.Context) ( + GetLoopInTerms(ctx context.Context, initiator string) ( *LoopInTerms, error) GetLoopInQuote(ctx context.Context, amt btcutil.Amount, pubKey route.Vertex, lastHop *route.Vertex, - routeHints [][]zpay32.HopHint) (*LoopInQuote, error) + routeHints [][]zpay32.HopHint, + initiator string) (*LoopInQuote, error) Probe(ctx context.Context, amt btcutil.Amount, target route.Vertex, lastHop *route.Vertex, routeHints [][]zpay32.HopHint) error @@ -180,14 +181,15 @@ func newSwapServerClient(cfg *ClientConfig, lsatStore lsat.Store) ( }, nil } -func (s *grpcSwapServerClient) GetLoopOutTerms(ctx context.Context) ( - *LoopOutTerms, error) { +func (s *grpcSwapServerClient) GetLoopOutTerms(ctx context.Context, + initiator string) (*LoopOutTerms, error) { rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout) defer rpcCancel() terms, err := s.server.LoopOutTerms(rpcCtx, &looprpc.ServerLoopOutTermsRequest{ ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), + UserAgent: UserAgent(initiator), }, ) if err != nil { @@ -203,8 +205,8 @@ func (s *grpcSwapServerClient) GetLoopOutTerms(ctx context.Context) ( } func (s *grpcSwapServerClient) GetLoopOutQuote(ctx context.Context, - amt btcutil.Amount, expiry int32, swapPublicationDeadline time.Time) ( - *LoopOutQuote, error) { + amt btcutil.Amount, expiry int32, swapPublicationDeadline time.Time, + initiator string) (*LoopOutQuote, error) { rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout) defer rpcCancel() @@ -214,6 +216,7 @@ func (s *grpcSwapServerClient) GetLoopOutQuote(ctx context.Context, SwapPublicationDeadline: swapPublicationDeadline.Unix(), ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), Expiry: expiry, + UserAgent: UserAgent(initiator), }, ) if err != nil { @@ -237,14 +240,15 @@ func (s *grpcSwapServerClient) GetLoopOutQuote(ctx context.Context, }, nil } -func (s *grpcSwapServerClient) GetLoopInTerms(ctx context.Context) ( - *LoopInTerms, error) { +func (s *grpcSwapServerClient) GetLoopInTerms(ctx context.Context, + initiator string) (*LoopInTerms, error) { rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout) defer rpcCancel() terms, err := s.server.LoopInTerms(rpcCtx, &looprpc.ServerLoopInTermsRequest{ ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), + UserAgent: UserAgent(initiator), }, ) if err != nil { @@ -259,7 +263,7 @@ func (s *grpcSwapServerClient) GetLoopInTerms(ctx context.Context) ( func (s *grpcSwapServerClient) GetLoopInQuote(ctx context.Context, amt btcutil.Amount, pubKey route.Vertex, lastHop *route.Vertex, - routeHints [][]zpay32.HopHint) (*LoopInQuote, error) { + routeHints [][]zpay32.HopHint, initiator string) (*LoopInQuote, error) { err := s.Probe(ctx, amt, pubKey, lastHop, routeHints) if err != nil && status.Code(err) != codes.Unavailable { @@ -273,6 +277,7 @@ func (s *grpcSwapServerClient) GetLoopInQuote(ctx context.Context, Amt: uint64(amt), ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), Pubkey: pubKey[:], + UserAgent: UserAgent(initiator), } if lastHop != nil {