From 693d3a4ca011dbe064957b95694d08569ac8ac50 Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Tue, 29 Apr 2025 17:30:18 +0200 Subject: [PATCH] liquidity: default to slow swaps for autloop --- cmd/loop/liquidity.go | 14 ++++++++++++++ liquidity/autoloop_test.go | 29 +++++++++++++++++++--------- liquidity/loopout_builder.go | 37 +++++++++++++++++++++++++----------- liquidity/parameters.go | 16 +++++++++++++--- 4 files changed, 73 insertions(+), 23 deletions(-) diff --git a/cmd/loop/liquidity.go b/cmd/loop/liquidity.go index 28b64e15..3d58060e 100644 --- a/cmd/loop/liquidity.go +++ b/cmd/loop/liquidity.go @@ -367,6 +367,16 @@ var setParamsCommand = cli.Command{ Usage: "the target size of total local balance in " + "asset units, used by asset easy autoloop.", }, + cli.BoolFlag{ + Name: "fast", + Usage: "if set new swaps are expected to be " + + "published immediately, paying a potentially " + + "higher fee. If not set the swap server " + + "might choose to wait up to 30 minutes " + + "before publishing swap HTLCs on-chain, to " + + "save on chain fees. Not setting this flag " + + "therefore might result in a lower swap fees", + }, }, Action: setParams, } @@ -577,6 +587,10 @@ func setParams(ctx *cli.Context) error { flagSet = true } + if ctx.IsSet("fast") { + params.FastSwapPublication = true + } + if !flagSet { return fmt.Errorf("at least one flag required to set params") } diff --git a/liquidity/autoloop_test.go b/liquidity/autoloop_test.go index 18ff86d1..d0b7ecc0 100644 --- a/liquidity/autoloop_test.go +++ b/liquidity/autoloop_test.go @@ -117,7 +117,8 @@ func TestAutoLoopEnabled(t *testing.T) { chanID1: chanRule, chanID2: chanRule, }, - HtlcConfTarget: defaultHtlcConfTarget, + HtlcConfTarget: defaultHtlcConfTarget, + FastSwapPublication: true, } ) @@ -376,7 +377,8 @@ func TestAutoloopAddress(t *testing.T) { chanID1: chanRule, chanID2: chanRule, }, - HtlcConfTarget: defaultHtlcConfTarget, + HtlcConfTarget: defaultHtlcConfTarget, + FastSwapPublication: true, } ) c := newAutoloopTestCtx(t, params, channels, testRestrictions) @@ -546,7 +548,8 @@ func TestCompositeRules(t *testing.T) { PeerRules: map[route.Vertex]*SwapRule{ peer2: chanRule, }, - HtlcConfTarget: defaultHtlcConfTarget, + HtlcConfTarget: defaultHtlcConfTarget, + FastSwapPublication: true, } ) @@ -923,8 +926,9 @@ func TestAutoloopBothTypes(t *testing.T) { PeerRules: map[route.Vertex]*SwapRule{ peer2: inRule, }, - HtlcConfTarget: htlcConfTarget, - SweepConfTarget: loop.DefaultSweepConfTarget, + HtlcConfTarget: htlcConfTarget, + SweepConfTarget: loop.DefaultSweepConfTarget, + FastSwapPublication: false, } ) c := newAutoloopTestCtx(t, params, channels, testRestrictions) @@ -939,9 +943,11 @@ func TestAutoloopBothTypes(t *testing.T) { } loopOutQuoteReq = &loop.LoopOutQuoteRequest{ - Amount: loopOutAmt, - SweepConfTarget: params.SweepConfTarget, - SwapPublicationDeadline: testTime, + Amount: loopOutAmt, + SweepConfTarget: params.SweepConfTarget, + SwapPublicationDeadline: c.testClock.Now().Add( + defaultSwapPublicationWaitTime, + ), } prepayMaxFee, routeMaxFee, @@ -962,6 +968,9 @@ func TestAutoloopBothTypes(t *testing.T) { }, Label: labels.AutoloopLabel(swap.TypeOut), Initiator: autoloopSwapInitiator, + SwapPublicationDeadline: c.testClock.Now().Add( + defaultSwapPublicationWaitTime, + ), } loopinQuote = &loop.LoopInQuote{ @@ -1069,7 +1078,8 @@ func TestAutoLoopRecurringBudget(t *testing.T) { chanID1: chanRule, chanID2: chanRule, }, - HtlcConfTarget: defaultHtlcConfTarget, + HtlcConfTarget: defaultHtlcConfTarget, + FastSwapPublication: true, } ) @@ -1320,6 +1330,7 @@ func TestEasyAutoloop(t *testing.T) { EasyAutoloop: true, EasyAutoloopTarget: 75000, FeeLimit: defaultFeePortion(), + FastSwapPublication: true, } ) diff --git a/liquidity/loopout_builder.go b/liquidity/loopout_builder.go index 8fbd3760..e0c147ed 100644 --- a/liquidity/loopout_builder.go +++ b/liquidity/loopout_builder.go @@ -3,6 +3,7 @@ package liquidity import ( "context" "encoding/hex" + "time" "github.com/btcsuite/btcd/btcutil" "github.com/lightninglabs/loop" @@ -14,6 +15,12 @@ import ( "github.com/lightningnetwork/lnd/routing/route" ) +const ( + // defaultSwapWaitTime is the default time we set as the deadline by + // which we expect the swap to be published. + defaultSwapPublicationWaitTime = 30 * time.Minute +) + // Compile-time assertion that loopOutBuilder satisfies the swapBuilder // interface. var _ swapBuilder = (*loopOutBuilder)(nil) @@ -151,11 +158,18 @@ func (b *loopOutBuilder) buildSwap(ctx context.Context, pubkey route.Vertex, initiator += "-" + assetSwap.assetID } + var swapPublicationDeadline time.Time + if !params.FastSwapPublication { + swapPublicationDeadline = b.cfg.Clock.Now().Add( + defaultSwapPublicationWaitTime, + ) + } + quote, err := b.cfg.LoopOutQuote( ctx, &loop.LoopOutQuoteRequest{ Amount: amount, SweepConfTarget: params.SweepConfTarget, - SwapPublicationDeadline: b.cfg.Clock.Now(), + SwapPublicationDeadline: swapPublicationDeadline, Initiator: initiator, AssetRFQRequest: assetRfqRequest, }, @@ -193,16 +207,17 @@ func (b *loopOutBuilder) buildSwap(ctx context.Context, pubkey route.Vertex, // swap fee, prepay amount and miner fee from the quote because we have // already validated them. request := loop.OutRequest{ - Amount: amount, - IsExternalAddr: false, - OutgoingChanSet: chanSet, - MaxPrepayRoutingFee: prepayMaxFee, - MaxSwapRoutingFee: routeMaxFee, - MaxMinerFee: minerFee, - MaxSwapFee: quote.SwapFee, - MaxPrepayAmount: quote.PrepayAmount, - SweepConfTarget: params.SweepConfTarget, - Initiator: initiator, + Amount: amount, + IsExternalAddr: false, + OutgoingChanSet: chanSet, + MaxPrepayRoutingFee: prepayMaxFee, + MaxSwapRoutingFee: routeMaxFee, + MaxMinerFee: minerFee, + MaxSwapFee: quote.SwapFee, + MaxPrepayAmount: quote.PrepayAmount, + SweepConfTarget: params.SweepConfTarget, + Initiator: initiator, + SwapPublicationDeadline: swapPublicationDeadline, } if opts.assetSwap != nil { diff --git a/liquidity/parameters.go b/liquidity/parameters.go index cdc9a20c..a7b3824d 100644 --- a/liquidity/parameters.go +++ b/liquidity/parameters.go @@ -31,6 +31,7 @@ var ( SweepConfTarget: defaultConfTarget, HtlcConfTarget: defaultHtlcConfTarget, FeeLimit: defaultFeePortion(), + FastSwapPublication: true, } ) @@ -118,6 +119,11 @@ type Parameters struct { // AssetAutoloopParams maps an asset id hex encoded string to its // easy autoloop parameters. AssetAutoloopParams map[string]AssetParams + + // FastSwapPublication controls publication deadline for new loop out + // swaps. If set to true, the deadline is set to immediate publication. + // If set to false, the deadline is set to 30 minutes. + FastSwapPublication bool } // AssetParams define the asset specific autoloop parameters. @@ -460,10 +466,13 @@ func RpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters, Minimum: btcutil.Amount(req.MinSwapAmount), Maximum: btcutil.Amount(req.MaxSwapAmount), }, - HtlcConfTarget: req.HtlcConfTarget, - EasyAutoloop: req.EasyAutoloop, - EasyAutoloopTarget: btcutil.Amount(req.EasyAutoloopLocalTargetSat), + HtlcConfTarget: req.HtlcConfTarget, + EasyAutoloop: req.EasyAutoloop, + EasyAutoloopTarget: btcutil.Amount( + req.EasyAutoloopLocalTargetSat, + ), AssetAutoloopParams: easyAssetParams, + FastSwapPublication: req.FastSwapPublication, } if req.AutoloopBudgetRefreshPeriodSec != 0 { @@ -592,6 +601,7 @@ func ParametersToRpc(cfg Parameters) (*clientrpc.LiquidityParameters, Account: cfg.Account, AccountAddrType: addrType, EasyAssetParams: easyAssetMap, + FastSwapPublication: cfg.FastSwapPublication, } switch f := cfg.FeeLimit.(type) {