diff --git a/client.go b/client.go index 4f32173..27f7e6a 100644 --- a/client.go +++ b/client.go @@ -79,8 +79,8 @@ type Client struct { // NewClient returns a new instance to initiate swaps with. func NewClient(dbDir string, serverAddress string, insecure bool, - tlsPathServer string, lnd *lndclient.LndServices) (*Client, func(), - error) { + tlsPathServer string, lnd *lndclient.LndServices, maxLSATCost, + maxLSATFee btcutil.Amount) (*Client, func(), error) { store, err := loopdb.NewBoltSwapStore(dbDir, lnd.ChainParams) if err != nil { @@ -93,6 +93,7 @@ func NewClient(dbDir string, serverAddress string, insecure bool, swapServerClient, err := newSwapServerClient( serverAddress, insecure, tlsPathServer, lsatStore, lnd, + maxLSATCost, maxLSATFee, ) if err != nil { return nil, nil, err diff --git a/loopd/daemon.go b/loopd/daemon.go index a72219e..4989579 100644 --- a/loopd/daemon.go +++ b/loopd/daemon.go @@ -56,10 +56,7 @@ func daemon(config *config, lisCfg *listenerCfg) error { log.Infof("Swap server address: %v", config.SwapServer) // Create an instance of the loop client library. - swapClient, cleanup, err := getClient( - config.Network, config.SwapServer, config.Insecure, - config.TLSPathSwapSrv, &lnd.LndServices, - ) + swapClient, cleanup, err := getClient(config, &lnd.LndServices) if err != nil { return err } diff --git a/loopd/utils.go b/loopd/utils.go index 9b66685..a03c477 100644 --- a/loopd/utils.go +++ b/loopd/utils.go @@ -4,21 +4,24 @@ import ( "os" "path/filepath" + "github.com/btcsuite/btcutil" "github.com/lightninglabs/loop" "github.com/lightninglabs/loop/lndclient" ) // getClient returns an instance of the swap client. -func getClient(network, swapServer string, insecure bool, tlsPathServer string, - lnd *lndclient.LndServices) (*loop.Client, func(), error) { +func getClient(config *config, lnd *lndclient.LndServices) (*loop.Client, + func(), error) { - storeDir, err := getStoreDir(network) + storeDir, err := getStoreDir(config.Network) if err != nil { return nil, nil, err } swapClient, cleanUp, err := loop.NewClient( - storeDir, swapServer, insecure, tlsPathServer, lnd, + storeDir, config.SwapServer, config.Insecure, + config.TLSPathSwapSrv, lnd, btcutil.Amount(config.MaxLSATCost), + btcutil.Amount(config.MaxLSATFee), ) if err != nil { return nil, nil, err diff --git a/loopd/view.go b/loopd/view.go index b9a6b30..433158c 100644 --- a/loopd/view.go +++ b/loopd/view.go @@ -23,10 +23,7 @@ func view(config *config, lisCfg *listenerCfg) error { } defer lnd.Close() - swapClient, cleanup, err := getClient( - config.Network, config.SwapServer, config.Insecure, - config.TLSPathSwapSrv, &lnd.LndServices, - ) + swapClient, cleanup, err := getClient(config, &lnd.LndServices) if err != nil { return err } diff --git a/lsat/interceptor.go b/lsat/interceptor.go index 5c70065..ba7066f 100644 --- a/lsat/interceptor.go +++ b/lsat/interceptor.go @@ -8,6 +8,7 @@ import ( "sync" "time" + "github.com/btcsuite/btcutil" "github.com/lightninglabs/loop/lndclient" "github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnwire" @@ -67,6 +68,8 @@ type Interceptor struct { lnd *lndclient.LndServices store Store callTimeout time.Duration + maxCost btcutil.Amount + maxFee btcutil.Amount lock sync.Mutex } @@ -74,12 +77,15 @@ type Interceptor struct { // lnd connection to automatically acquire and pay for LSAT tokens, unless the // indicated store already contains a usable token. func NewInterceptor(lnd *lndclient.LndServices, store Store, - rpcCallTimeout time.Duration) *Interceptor { + rpcCallTimeout time.Duration, maxCost, + maxFee btcutil.Amount) *Interceptor { return &Interceptor{ lnd: lnd, store: store, callTimeout: rpcCallTimeout, + maxCost: maxCost, + maxFee: maxFee, } } @@ -226,6 +232,14 @@ func (i *Interceptor) payLsatToken(ctx context.Context, md *metadata.MD) ( return nil, fmt.Errorf("unable to decode invoice: %v", err) } + // Check that the charged amount does not exceed our maximum cost. + maxCostMsat := lnwire.NewMSatFromSatoshis(i.maxCost) + if invoice.MilliSat != nil && *invoice.MilliSat > maxCostMsat { + return nil, fmt.Errorf("cannot pay for LSAT automatically, "+ + "cost of %d msat exceeds configured max cost of %d "+ + "msat", *invoice.MilliSat, maxCostMsat) + } + // Create and store the pending token so we can resume the payment in // case the payment is interrupted somehow. token, err := tokenFromChallenge(macBytes, invoice.PaymentHash) @@ -242,7 +256,7 @@ func (i *Interceptor) payLsatToken(ctx context.Context, md *metadata.MD) ( payCtx, cancel := context.WithTimeout(ctx, PaymentTimeout) defer cancel() respChan := i.lnd.Client.PayInvoice( - payCtx, invoiceStr, DefaultMaxRoutingFeeSats, nil, + payCtx, invoiceStr, i.maxFee, nil, ) select { case result := <-respChan: diff --git a/swap_server_client.go b/swap_server_client.go index b8e67f6..95c4786 100644 --- a/swap_server_client.go +++ b/swap_server_client.go @@ -52,13 +52,13 @@ type grpcSwapServerClient struct { var _ swapServerClient = (*grpcSwapServerClient)(nil) func newSwapServerClient(address string, insecure bool, tlsPath string, - lsatStore lsat.Store, lnd *lndclient.LndServices) ( - *grpcSwapServerClient, error) { + lsatStore lsat.Store, lnd *lndclient.LndServices, + maxLSATCost, maxLSATFee btcutil.Amount) (*grpcSwapServerClient, error) { // Create the server connection with the interceptor that will handle // the LSAT protocol for us. clientInterceptor := lsat.NewInterceptor( - lnd, lsatStore, serverRPCTimeout, + lnd, lsatStore, serverRPCTimeout, maxLSATCost, maxLSATFee, ) serverConn, err := getSwapServerConn( address, insecure, tlsPath, clientInterceptor,