diff --git a/README.md b/README.md index 49d2b45..d990f69 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ Flags: --backoffCoefficient float Coefficient to apply to the backoff (default 0.95) --backoffLimit float Limit coefficient of the backoff (default 0.1) -h, --help help for liquidator - --limitFees float Limit fees for swaps e.g. 0.01 = 1% (default 0.007) + --limitFeesL2 float Limit fee ratio for swaps max routing fee e.g. 0.01 = 1% (default 0.002) + --limitQuoteFees float Limit fee ratio for swaps quotes (e.g. onchain+service fee estimation) e.g. 0.01 = 1% (default 0.005) --lndconnecturis string CSV of lndconnect strings to connect to lnd(s) --logFormat string Log format from: {text, json} (default "text") --logLevel string Log level from values: {trace, debug, info, warn, error, fatal, panic} (default "info") @@ -55,7 +56,8 @@ Available recipes: All the flags can be set as environment variables, with the following format, except stated, they are all mandatory: - LNDCONNECTURIS : CSV of lndconnect strings to connect to lnd(s)\ -- LIMITFEES (optional) : Limit to total Swap Fees (default 0.007 -> 0.7% Swap size) +- LIMITQUOTEFEES (optional) : Limit to total Max Quote Fees (L1+service fee) (default 0.007 -> 0.7% of the Swap size) +- LIMITFEESL2 (optional) : Limit to total Max Routing Fees (L2) (default 0.002 -> 0.2% of the Swap size) - LOOPDCONNECTURIS : CSV of loopdconnect strings to connect to loopd(s) - POLLINGINTERVAL (optional) : Interval to poll data(default 15s) - LOGLEVEL (optional) : Log level (default info) from: {trace, debug, info, warn, error, fatal, panic} diff --git a/flags.go b/flags.go index db6565e..980d1af 100644 --- a/flags.go +++ b/flags.go @@ -113,9 +113,13 @@ func init() { rootCmd.Flags().Float64("backoffLimit", 0.1, "Limit coefficient of the backoff") viper.BindPFlag("backoffLimit", rootCmd.Flags().Lookup("backoffLimit")) - // Limit fees for swaps - rootCmd.Flags().Float64("limitFees", 0.007, "Limit fees for swaps e.g. 0.01 = 1%") - viper.BindPFlag("limitFees", rootCmd.Flags().Lookup("limitFees")) + // Limit fees for swaps quotes + rootCmd.Flags().Float64("limitQuoteFees", 0.005, "Limit fee ratio for swaps quotes (e.g. onchain+service fee estimation) e.g. 0.01 = 1%") + viper.BindPFlag("limitQuoteFees", rootCmd.Flags().Lookup("limitQuoteFees")) + + // Limit fees for swaps L2 + rootCmd.Flags().Float64("limitFeesL2", 0.002, "Limit fee ratio for swaps max routing fee e.g. 0.01 = 1%") + viper.BindPFlag("limitFeesL2", rootCmd.Flags().Lookup("limitFeesL2")) //Sweep conf rootCmd.Flags().String("sweepConfTarget", "400", "Target number of confirmations for swaps, this uses bitcoin core broken estimator, procced with caution") @@ -131,7 +135,6 @@ func init() { retries = viper.GetInt("retriesBeforeBackoff") backoffCoefficient = viper.GetFloat64("backoffCoefficient") backoffLimit = viper.GetFloat64("backoffLimit") - limitFees = viper.GetFloat64("limitFees") //Set log level and format diff --git a/liquidator.go b/liquidator.go index fd00c90..fee0c08 100644 --- a/liquidator.go +++ b/liquidator.go @@ -36,7 +36,6 @@ var ( retries int backoffCoefficient float64 backoffLimit float64 - limitFees float64 ) // Entrypoint of liquidator main logic diff --git a/provider/loop_provider.go b/provider/loop_provider.go index 175c25a..6f97054 100644 --- a/provider/loop_provider.go +++ b/provider/loop_provider.go @@ -61,7 +61,7 @@ func (l *LoopProvider) RequestSubmarineSwap(ctx context.Context, request Submari return SubmarineSwapResponse{}, err } - limitFeesStr := viper.GetString("LIMITFEES") + limitFeesStr := viper.GetString("limitQuoteFees") limitFees, err := strconv.ParseFloat(limitFeesStr, 64) if err != nil { return SubmarineSwapResponse{}, err @@ -228,8 +228,8 @@ func (l *LoopProvider) RequestReverseSubmarineSwap(ctx context.Context, request //Do a quote for loop out quote, err := client.LoopOutQuote(ctx, &looprpc.QuoteRequest{ - Amt: request.SatsAmount, - //ConfTarget: 1, //TODO Make this configurable + Amt: request.SatsAmount, + ConfTarget: viper.GetInt32("sweepConfTarget"), ExternalHtlc: true, Private: false, }) @@ -239,21 +239,24 @@ func (l *LoopProvider) RequestReverseSubmarineSwap(ctx context.Context, request return ReverseSubmarineSwapResponse{}, err } - limitFeesStr := viper.GetString("LIMITFEES") - limitFees, err := strconv.ParseFloat(limitFeesStr, 64) - if err != nil { - return ReverseSubmarineSwapResponse{}, err - } + limitQuoteFees := viper.GetFloat64("limitQuoteFees") + //This fees are onchain + service fees, NOT L2 fees as they are not in the quote sumFees := quote.SwapFeeSat + quote.HtlcSweepFeeSat + quote.PrepayAmtSat - maximumFeesAllowed := int64(float64(request.SatsAmount) * limitFees) + maximumFeesAllowed := int64(float64(request.SatsAmount) * limitQuoteFees) if sumFees > maximumFeesAllowed { - err := fmt.Errorf("swap fees are greater than max limit fees, quote fees: %d, maximum fees allowed: %d", sumFees, maximumFeesAllowed) + err := fmt.Errorf("swap quote fees (L1+Service estimation fees) are greater than max limit fees, quote fees: %d, maximum fees allowed: %d", sumFees, maximumFeesAllowed) log.Error(err) return ReverseSubmarineSwapResponse{}, err } + //Max swap routing fee (L2 fees) is a percentage of the swap amount + l2MaxRoutingFeeRatio := viper.GetFloat64("limitFeesL2") + maxSwapRoutingFee := int64(float64(request.SatsAmount) * l2MaxRoutingFeeRatio) + + log.Infof("max L2 routing fees for the swap: %d", maxSwapRoutingFee) + //Get limits //Amt using btcutil amt := btcutil.Amount(request.SatsAmount) @@ -270,13 +273,13 @@ func (l *LoopProvider) RequestReverseSubmarineSwap(ctx context.Context, request MaxPrepayAmt: int64(limits.maxPrepayAmt), MaxSwapFee: int64(limits.maxSwapFee), MaxPrepayRoutingFee: int64(limits.maxPrepayRoutingFee), - MaxSwapRoutingFee: int64(limits.maxSwapRoutingFee), + MaxSwapRoutingFee: maxSwapRoutingFee, OutgoingChanSet: request.ChannelSet, SweepConfTarget: viper.GetInt32("sweepConfTarget"), HtlcConfirmations: 3, //The publication deadline is maximum the offset of the swap deadline conf plus the current time SwapPublicationDeadline: uint64(time.Now().Add(viper.GetDuration("swapPublicationOffset") * time.Minute).Unix()), - Label: fmt.Sprintf("Reverse submarine swap %d sats on date %s", request.SatsAmount, time.Now().Format(time.RFC3339)), + Label: fmt.Sprintf("Reverse submarine swap %d sats on date %s for channels: %v", request.SatsAmount, time.Now().Format(time.RFC3339), request.ChannelSet), Initiator: "Liquidator", }) diff --git a/provider/loop_provider_test.go b/provider/loop_provider_test.go index 8d996c9..4937e28 100644 --- a/provider/loop_provider_test.go +++ b/provider/loop_provider_test.go @@ -12,13 +12,23 @@ import ( gomock "go.uber.org/mock/gomock" ) +func TestMain(m *testing.M) { + + setLimitFees() + + m.Run() +} + +func setLimitFees() { + viper.Set("limitQuoteFees", "0.005") + viper.Set("limitFeesL2", "0.002") +} + func TestLoopProvider_RequestSubmarineSwap(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() - viper.Set("LIMITFEES", "0.007") - //Mock lightning swapClient GetLoopInQuote and LoopIn methods to return fake data swapClient := NewMockSwapClientClient(ctrl)