From 52fc54ab729fa27bb0529bbcc90b0dd4c96729c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20A=2EP?= <53834183+Jossec101@users.noreply.github.com> Date: Wed, 8 May 2024 19:56:42 +0200 Subject: [PATCH] Add flags for setting fee limits for swaps (L2 routing) (#79) * Flags limitQuoteFees and limitFeesL2, to set fee limits for swaps. The limitQuoteFees flag sets the fee ratio for swaps quotes, while the limitFeesL2 flag sets the fee ratio for swaps max routing fee. * Docs update * Add logging for max L2 routing fees in RequestReverseSubmarineSwap function --- README.md | 6 ++++-- flags.go | 11 +++++++---- liquidator.go | 1 - provider/loop_provider.go | 27 +++++++++++++++------------ provider/loop_provider_test.go | 14 ++++++++++++-- 5 files changed, 38 insertions(+), 21 deletions(-) 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)