liquidity: add static autoloop planner

Wire static-address-backed loop-ins into the existing autoloop
planner and dispatch path. Loop-in rules can now be converted into
static candidates, prepared after global sorting, filtered with
static fee limits, and dispatched through the static manager.

This also fixes MaxAutoInFlight enforcement across all suggested
swap types and adds planner tests for missing static candidates
and mixed in-flight filtering.
This commit is contained in:
Boris Nagaev 2026-04-11 00:00:25 -05:00
parent e467ac932b
commit 58ebb042ff
No known key found for this signature in database
4 changed files with 617 additions and 21 deletions

View file

@ -2,6 +2,7 @@ package loopd
import (
"context"
"errors"
"fmt"
"slices"
@ -17,6 +18,7 @@ import (
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/sweepbatcher"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/ticker"
)
@ -161,6 +163,58 @@ func getLiquidityManager(client *loop.Client,
return result, nil
}
prepareStaticLoopIn := func(ctx context.Context, peer route.Vertex,
minAmount, amount btcutil.Amount, label, initiator string,
excludedOutpoints []string) (*liquidity.PreparedStaticLoopIn,
error) {
if staticLoopInManager == nil {
return nil, errors.New(
"static loop in manager unavailable",
)
}
request, numDeposits, hasChange, err :=
staticLoopInManager.PrepareAutoloopLoopIn(
ctx, peer, minAmount, amount, label,
initiator, excludedOutpoints,
)
if errors.Is(err, loopin.ErrNoAutoloopCandidate) {
return nil, liquidity.ErrNoStaticLoopInCandidate
}
if err != nil {
return nil, err
}
return &liquidity.PreparedStaticLoopIn{
Request: *request,
NumDeposits: numDeposits,
HasChange: hasChange,
}, nil
}
staticLoopIn := func(ctx context.Context,
request *loop.StaticAddressLoopInRequest) (
*liquidity.StaticLoopInDispatchResult, error) {
if staticLoopInManager == nil {
return nil, errors.New(
"static loop in manager unavailable",
)
}
swapInfo, err := staticLoopInManager.DeliverLoopInRequest(
ctx, request,
)
if err != nil {
return nil, err
}
return &liquidity.StaticLoopInDispatchResult{
SwapHash: swapInfo.SwapHash,
}, nil
}
mngrCfg := &liquidity.Config{
AutoloopTicker: ticker.NewForce(liquidity.DefaultAutoloopTicker),
LoopOut: client.LoopOut,
@ -196,6 +250,8 @@ func getLiquidityManager(client *loop.Client,
GetLoopOut: client.Store.FetchLoopOutSwap,
ListLoopIn: client.Store.FetchLoopInSwaps,
ListStaticLoopIn: listStaticLoopIn,
PrepareStaticLoopIn: prepareStaticLoopIn,
StaticLoopIn: staticLoopIn,
LoopInTerms: client.LoopInTerms,
LoopOutTerms: client.LoopOutTerms,
GetAssetPrice: client.AssetClient.GetAssetPrice,