liquidity+loopd: move last budget refresh to parameters

pull/556/head
George Tsagkarelis 1 year ago
parent 74f6cc8d4b
commit aca6428b0e
No known key found for this signature in database
GPG Key ID: E08DEA9B12B66AF6

@ -28,6 +28,7 @@ func TestAutoLoopDisabled(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
} }
@ -98,6 +99,7 @@ func TestAutoLoopEnabled(t *testing.T) {
Autoloop: true, Autoloop: true,
AutoFeeBudget: 40066, AutoFeeBudget: 40066,
AutoFeeRefreshPeriod: testBudgetRefresh, AutoFeeRefreshPeriod: testBudgetRefresh,
AutoloopBudgetLastRefresh: testBudgetStart,
MaxAutoInFlight: 2, MaxAutoInFlight: 2,
FailureBackOff: time.Hour, FailureBackOff: time.Hour,
SweepConfTarget: 10, SweepConfTarget: 10,
@ -357,6 +359,7 @@ func TestAutoloopAddress(t *testing.T) {
AutoFeeBudget: 40066, AutoFeeBudget: 40066,
DestAddr: addr, DestAddr: addr,
AutoFeeRefreshPeriod: testBudgetRefresh, AutoFeeRefreshPeriod: testBudgetRefresh,
AutoloopBudgetLastRefresh: testBudgetStart,
MaxAutoInFlight: 2, MaxAutoInFlight: 2,
FailureBackOff: time.Hour, FailureBackOff: time.Hour,
SweepConfTarget: 10, SweepConfTarget: 10,
@ -526,6 +529,7 @@ func TestCompositeRules(t *testing.T) {
Autoloop: true, Autoloop: true,
AutoFeeBudget: 100000, AutoFeeBudget: 100000,
AutoFeeRefreshPeriod: testBudgetRefresh, AutoFeeRefreshPeriod: testBudgetRefresh,
AutoloopBudgetLastRefresh: testBudgetStart,
MaxAutoInFlight: 2, MaxAutoInFlight: 2,
FailureBackOff: time.Hour, FailureBackOff: time.Hour,
SweepConfTarget: 10, SweepConfTarget: 10,
@ -718,6 +722,7 @@ func TestAutoLoopInEnabled(t *testing.T) {
Autoloop: true, Autoloop: true,
AutoFeeBudget: peer1MaxFee + peer2MaxFee + 1, AutoFeeBudget: peer1MaxFee + peer2MaxFee + 1,
AutoFeeRefreshPeriod: testBudgetRefresh, AutoFeeRefreshPeriod: testBudgetRefresh,
AutoloopBudgetLastRefresh: testBudgetStart,
MaxAutoInFlight: 2, MaxAutoInFlight: 2,
FailureBackOff: time.Hour, FailureBackOff: time.Hour,
FeeLimit: NewFeePortion(swapFeePPM), FeeLimit: NewFeePortion(swapFeePPM),
@ -901,6 +906,7 @@ func TestAutoloopBothTypes(t *testing.T) {
Autoloop: true, Autoloop: true,
AutoFeeBudget: loopOutMaxFee + loopInMaxFee + 1, AutoFeeBudget: loopOutMaxFee + loopInMaxFee + 1,
AutoFeeRefreshPeriod: testBudgetRefresh, AutoFeeRefreshPeriod: testBudgetRefresh,
AutoloopBudgetLastRefresh: testBudgetStart,
MaxAutoInFlight: 2, MaxAutoInFlight: 2,
FailureBackOff: time.Hour, FailureBackOff: time.Hour,
FeeLimit: NewFeePortion(swapFeePPM), FeeLimit: NewFeePortion(swapFeePPM),
@ -1044,6 +1050,7 @@ func TestAutoLoopRecurringBudget(t *testing.T) {
Autoloop: true, Autoloop: true,
AutoFeeBudget: 36000, AutoFeeBudget: 36000,
AutoFeeRefreshPeriod: time.Hour * 3, AutoFeeRefreshPeriod: time.Hour * 3,
AutoloopBudgetLastRefresh: testBudgetStart,
MaxAutoInFlight: 2, MaxAutoInFlight: 2,
FailureBackOff: time.Hour, FailureBackOff: time.Hour,
SweepConfTarget: 10, SweepConfTarget: 10,

@ -130,7 +130,6 @@ func newAutoloopTestCtx(t *testing.T, parameters Parameters,
cfg := &Config{ cfg := &Config{
AutoloopTicker: ticker.NewForce(DefaultAutoloopTicker), AutoloopTicker: ticker.NewForce(DefaultAutoloopTicker),
AutoloopBudgetLastRefresh: testBudgetStart,
Restrictions: func(_ context.Context, swapType swap.Type) (*Restrictions, Restrictions: func(_ context.Context, swapType swap.Type) (*Restrictions,
error) { error) {

@ -166,10 +166,6 @@ type Config struct {
// trigger autoloop in itests. // trigger autoloop in itests.
AutoloopTicker *ticker.Force AutoloopTicker *ticker.Force
// AutoloopBudgetLastRefresh is the last time at which we refreshed
// our budget.
AutoloopBudgetLastRefresh time.Time
// Restrictions returns the restrictions that the server applies to // Restrictions returns the restrictions that the server applies to
// swaps. // swaps.
Restrictions func(ctx context.Context, swapType swap.Type) ( Restrictions func(ctx context.Context, swapType swap.Type) (
@ -301,7 +297,7 @@ func (m *Manager) GetParameters() Parameters {
func (m *Manager) SetParameters(ctx context.Context, func (m *Manager) SetParameters(ctx context.Context,
req *clientrpc.LiquidityParameters) error { req *clientrpc.LiquidityParameters) error {
params, err := rpcToParameters(req) params, err := RpcToParameters(req)
if err != nil { if err != nil {
return err return err
} }
@ -743,7 +739,7 @@ func (m *Manager) SuggestSwaps(ctx context.Context, autoloop bool) (
} }
} else { } else {
refreshTime := m.params.AutoFeeRefreshPeriod - refreshTime := m.params.AutoFeeRefreshPeriod -
time.Since(m.cfg.AutoloopBudgetLastRefresh) time.Since(m.params.AutoloopBudgetLastRefresh)
log.Infof("Swap fee exceeds budget, remaining budget: "+ log.Infof("Swap fee exceeds budget, remaining budget: "+
"%v, swap fee %v, next budget refresh: %v", "%v, swap fee %v, next budget refresh: %v",
@ -929,7 +925,7 @@ func (m *Manager) checkExistingAutoLoops(ctx context.Context,
mSatToSatoshis(prepay.Value), mSatToSatoshis(prepay.Value),
) )
} else if out.LastUpdateTime().After( } else if out.LastUpdateTime().After(
m.cfg.AutoloopBudgetLastRefresh, m.params.AutoloopBudgetLastRefresh,
) { ) {
summary.spentFees += out.State().Cost.Total() summary.spentFees += out.State().Cost.Total()
@ -943,7 +939,7 @@ func (m *Manager) checkExistingAutoLoops(ctx context.Context,
pending := in.State().State.Type() == loopdb.StateTypePending pending := in.State().State.Type() == loopdb.StateTypePending
inBudget := !in.LastUpdateTime(). inBudget := !in.LastUpdateTime().
Before(m.cfg.AutoloopBudgetLastRefresh) Before(m.params.AutoloopBudgetLastRefresh)
// If an autoloop is in a pending state, we always count it in // If an autoloop is in a pending state, we always count it in
// our current budget, and record the worst-case fees for it, // our current budget, and record the worst-case fees for it,
@ -1054,11 +1050,23 @@ func (m *Manager) currentSwapTraffic(loopOut []*loopdb.LoopOut,
// budget refresh is greater than our configured refresh period. If so, the last // budget refresh is greater than our configured refresh period. If so, the last
// refresh timestamp. // refresh timestamp.
func (m *Manager) refreshAutoloopBudget(ctx context.Context) { func (m *Manager) refreshAutoloopBudget(ctx context.Context) {
if time.Since(m.cfg.AutoloopBudgetLastRefresh) > if time.Since(m.params.AutoloopBudgetLastRefresh) >
m.params.AutoFeeRefreshPeriod { m.params.AutoFeeRefreshPeriod {
log.Debug("Refreshing autoloop budget") log.Debug("Refreshing autoloop budget")
m.cfg.AutoloopBudgetLastRefresh = m.cfg.Clock.Now() m.params.AutoloopBudgetLastRefresh = m.cfg.Clock.Now()
paramsRpc, err := ParametersToRpc(m.params)
if err != nil {
log.Errorf("Error converting parameters to rpc: %v",
err)
return
}
err = m.saveParams(paramsRpc)
if err != nil {
log.Errorf("Error saving parameters: %v", err)
}
} }
} }

@ -150,7 +150,6 @@ func newTestConfig() (*Config, *test.LndMockServices) {
}, },
Lnd: &lnd.LndServices, Lnd: &lnd.LndServices,
Clock: clock.NewTestClock(testTime), Clock: clock.NewTestClock(testTime),
AutoloopBudgetLastRefresh: testBudgetStart,
ListLoopOut: func() ([]*loopdb.LoopOut, error) { ListLoopOut: func() ([]*loopdb.LoopOut, error) {
return nil, nil return nil, nil
}, },
@ -572,6 +571,7 @@ func TestRestrictedSuggestions(t *testing.T) {
lnd.Channels = testCase.channels lnd.Channels = testCase.channels
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
if testCase.chanRules != nil { if testCase.chanRules != nil {
params.ChannelRules = testCase.chanRules params.ChannelRules = testCase.chanRules
} }
@ -652,6 +652,7 @@ func TestSweepFeeLimit(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
params.FeeLimit = defaultFeeCategoryLimit() params.FeeLimit = defaultFeeCategoryLimit()
// Set our budget to cover a single swap with these // Set our budget to cover a single swap with these
@ -794,6 +795,7 @@ func TestSuggestSwaps(t *testing.T) {
lnd.Channels = testCase.channels lnd.Channels = testCase.channels
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
if testCase.rules != nil { if testCase.rules != nil {
params.ChannelRules = testCase.rules params.ChannelRules = testCase.rules
} }
@ -901,6 +903,7 @@ func TestFeeLimits(t *testing.T) {
// Set our params to use individual fee limits. // Set our params to use individual fee limits.
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
params.FeeLimit = defaultFeeCategoryLimit() params.FeeLimit = defaultFeeCategoryLimit()
// Set our budget to cover a single swap with these // Set our budget to cover a single swap with these
@ -1108,6 +1111,7 @@ func TestFeeBudget(t *testing.T) {
} }
params.AutoFeeBudget = testCase.budget params.AutoFeeBudget = testCase.budget
params.AutoFeeRefreshPeriod = testBudgetRefresh params.AutoFeeRefreshPeriod = testBudgetRefresh
params.AutoloopBudgetLastRefresh = testBudgetStart
params.MaxAutoInFlight = 2 params.MaxAutoInFlight = 2
params.FeeLimit = NewFeeCategoryLimit( params.FeeLimit = NewFeeCategoryLimit(
defaultSwapFeePPM, defaultRoutingFeePPM, defaultSwapFeePPM, defaultRoutingFeePPM,
@ -1272,6 +1276,7 @@ func TestInFlightLimit(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
if testCase.peerRules != nil { if testCase.peerRules != nil {
params.PeerRules = testCase.peerRules params.PeerRules = testCase.peerRules
@ -1431,6 +1436,7 @@ func TestSizeRestrictions(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
params.ClientRestrictions = testCase.clientRestrictions params.ClientRestrictions = testCase.clientRestrictions
params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
@ -1593,6 +1599,7 @@ func TestFeePercentage(t *testing.T) {
} }
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
params.FeeLimit = NewFeePortion(testCase.feePPM) params.FeeLimit = NewFeePortion(testCase.feePPM)
params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
@ -1765,6 +1772,7 @@ func TestBudgetWithLoopin(t *testing.T) {
params := defaultParameters params := defaultParameters
params.AutoFeeBudget = budget params.AutoFeeBudget = budget
params.AutoFeeRefreshPeriod = testBudgetRefresh params.AutoFeeRefreshPeriod = testBudgetRefresh
params.AutoloopBudgetLastRefresh = testBudgetStart
params.FeeLimit = NewFeePortion(testPPM) params.FeeLimit = NewFeePortion(testPPM)
params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
@ -1821,6 +1829,7 @@ func testSuggestSwaps(t *testing.T, setup *testSuggestSwapsSetup,
} }
params := defaultParameters params := defaultParameters
params.AutoloopBudgetLastRefresh = testBudgetStart
params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{ params.ChannelRules = map[lnwire.ShortChannelID]*SwapRule{
chanID1: chanRule, chanID1: chanRule,
chanID2: chanRule, chanID2: chanRule,

@ -22,6 +22,7 @@ var (
defaultParameters = Parameters{ defaultParameters = Parameters{
AutoFeeBudget: defaultBudget, AutoFeeBudget: defaultBudget,
AutoFeeRefreshPeriod: defaultBudgetRefreshPeriod, AutoFeeRefreshPeriod: defaultBudgetRefreshPeriod,
AutoloopBudgetLastRefresh: time.Now(),
DestAddr: nil, DestAddr: nil,
MaxAutoInFlight: defaultMaxInFlight, MaxAutoInFlight: defaultMaxInFlight,
ChannelRules: make(map[lnwire.ShortChannelID]*SwapRule), ChannelRules: make(map[lnwire.ShortChannelID]*SwapRule),
@ -52,6 +53,10 @@ type Parameters struct {
// auto fee budget is refreshed. // auto fee budget is refreshed.
AutoFeeRefreshPeriod time.Duration AutoFeeRefreshPeriod time.Duration
// AutoloopBudgetLastRefresh is the last time at which we refreshed
// our budget.
AutoloopBudgetLastRefresh time.Time
// MaxAutoInFlight is the maximum number of in-flight automatically // MaxAutoInFlight is the maximum number of in-flight automatically
// dispatched swaps we allow. // dispatched swaps we allow.
MaxAutoInFlight int MaxAutoInFlight int
@ -348,7 +353,7 @@ func rpcToRule(rule *clientrpc.LiquidityRule) (*SwapRule, error) {
// rpcToParameters takes a `LiquidityParameters` and creates a `Parameters` // rpcToParameters takes a `LiquidityParameters` and creates a `Parameters`
// from it. // from it.
func rpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters, func RpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters,
error) { error) {
feeLimit, err := rpcToFee(req) feeLimit, err := rpcToFee(req)
@ -374,6 +379,9 @@ func rpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters,
FailureBackOff: time.Duration(req.FailureBackoffSec) * FailureBackOff: time.Duration(req.FailureBackoffSec) *
time.Second, time.Second,
Autoloop: req.Autoloop, Autoloop: req.Autoloop,
AutoloopBudgetLastRefresh: time.Unix(
int64(req.AutoloopBudgetLastRefresh), 0,
),
DestAddr: destaddr, DestAddr: destaddr,
AutoFeeBudget: btcutil.Amount(req.AutoloopBudgetSat), AutoFeeBudget: btcutil.Amount(req.AutoloopBudgetSat),
MaxAutoInFlight: int(req.AutoMaxInFlight), MaxAutoInFlight: int(req.AutoMaxInFlight),
@ -442,3 +450,90 @@ func rpcToParameters(req *clientrpc.LiquidityParameters) (*Parameters,
return params, nil return params, nil
} }
// ParametersToRpc takes a `Parameters` and creates a `LiquidityParameters`
// from it.
func ParametersToRpc(cfg Parameters) (*clientrpc.LiquidityParameters,
error) {
totalRules := len(cfg.ChannelRules) + len(cfg.PeerRules)
var destaddr string
if cfg.DestAddr != nil {
destaddr = cfg.DestAddr.String()
}
rpcCfg := &clientrpc.LiquidityParameters{
SweepConfTarget: cfg.SweepConfTarget,
FailureBackoffSec: uint64(cfg.FailureBackOff.Seconds()),
Autoloop: cfg.Autoloop,
AutoloopBudgetSat: uint64(cfg.AutoFeeBudget),
AutoloopBudgetRefreshPeriodSec: uint64(
cfg.AutoFeeRefreshPeriod.Seconds(),
),
AutoloopBudgetLastRefresh: uint64(
cfg.AutoloopBudgetLastRefresh.Unix(),
),
AutoMaxInFlight: uint64(cfg.MaxAutoInFlight),
AutoloopDestAddress: destaddr,
Rules: make(
[]*clientrpc.LiquidityRule, 0, totalRules,
),
MinSwapAmount: uint64(cfg.ClientRestrictions.Minimum),
MaxSwapAmount: uint64(cfg.ClientRestrictions.Maximum),
HtlcConfTarget: cfg.HtlcConfTarget,
}
switch f := cfg.FeeLimit.(type) {
case *FeeCategoryLimit:
satPerByte := f.SweepFeeRateLimit.FeePerKVByte() / 1000
rpcCfg.SweepFeeRateSatPerVbyte = uint64(satPerByte)
rpcCfg.MaxMinerFeeSat = uint64(f.MaximumMinerFee)
rpcCfg.MaxSwapFeePpm = f.MaximumSwapFeePPM
rpcCfg.MaxRoutingFeePpm = f.MaximumRoutingFeePPM
rpcCfg.MaxPrepayRoutingFeePpm = f.MaximumPrepayRoutingFeePPM
rpcCfg.MaxPrepaySat = uint64(f.MaximumPrepay)
case *FeePortion:
rpcCfg.FeePpm = f.PartsPerMillion
default:
return nil, fmt.Errorf("unknown fee limit: %T", cfg.FeeLimit)
}
for channel, rule := range cfg.ChannelRules {
rpcRule := newRPCRule(channel.ToUint64(), nil, rule)
rpcCfg.Rules = append(rpcCfg.Rules, rpcRule)
}
for peer, rule := range cfg.PeerRules {
peer := peer
rpcRule := newRPCRule(0, peer[:], rule)
rpcCfg.Rules = append(rpcCfg.Rules, rpcRule)
}
return rpcCfg, nil
}
// newRPCRule is a helper function that creates a `LiquidityRule` based on the
// provided `SwapRule` for the given channelID or peer.
func newRPCRule(channelID uint64, peer []byte,
rule *SwapRule) *clientrpc.LiquidityRule {
rpcRule := &clientrpc.LiquidityRule{
ChannelId: channelID,
Pubkey: peer,
Type: clientrpc.LiquidityRuleType_THRESHOLD,
IncomingThreshold: uint32(rule.MinimumIncoming),
OutgoingThreshold: uint32(rule.MinimumOutgoing),
SwapType: clientrpc.SwapType_LOOP_OUT,
}
if rule.Type == swap.TypeIn {
rpcRule.SwapType = clientrpc.SwapType_LOOP_IN
}
return rpcRule
}

@ -745,83 +745,14 @@ func (s *swapClientServer) GetLiquidityParams(_ context.Context,
cfg := s.liquidityMgr.GetParameters() cfg := s.liquidityMgr.GetParameters()
totalRules := len(cfg.ChannelRules) + len(cfg.PeerRules) rpcCfg, err := liquidity.ParametersToRpc(cfg)
if err != nil {
var destaddr string return nil, err
if cfg.DestAddr != nil {
destaddr = cfg.DestAddr.String()
}
rpcCfg := &clientrpc.LiquidityParameters{
SweepConfTarget: cfg.SweepConfTarget,
FailureBackoffSec: uint64(cfg.FailureBackOff.Seconds()),
Autoloop: cfg.Autoloop,
AutoloopBudgetSat: uint64(cfg.AutoFeeBudget),
AutoloopBudgetRefreshPeriodSec: uint64(
cfg.AutoFeeRefreshPeriod.Seconds(),
),
AutoMaxInFlight: uint64(cfg.MaxAutoInFlight),
AutoloopDestAddress: destaddr,
Rules: make(
[]*clientrpc.LiquidityRule, 0, totalRules,
),
MinSwapAmount: uint64(cfg.ClientRestrictions.Minimum),
MaxSwapAmount: uint64(cfg.ClientRestrictions.Maximum),
HtlcConfTarget: cfg.HtlcConfTarget,
}
switch f := cfg.FeeLimit.(type) {
case *liquidity.FeeCategoryLimit:
satPerByte := f.SweepFeeRateLimit.FeePerKVByte() / 1000
rpcCfg.SweepFeeRateSatPerVbyte = uint64(satPerByte)
rpcCfg.MaxMinerFeeSat = uint64(f.MaximumMinerFee)
rpcCfg.MaxSwapFeePpm = f.MaximumSwapFeePPM
rpcCfg.MaxRoutingFeePpm = f.MaximumRoutingFeePPM
rpcCfg.MaxPrepayRoutingFeePpm = f.MaximumPrepayRoutingFeePPM
rpcCfg.MaxPrepaySat = uint64(f.MaximumPrepay)
case *liquidity.FeePortion:
rpcCfg.FeePpm = f.PartsPerMillion
default:
return nil, fmt.Errorf("unknown fee limit: %T", cfg.FeeLimit)
}
for channel, rule := range cfg.ChannelRules {
rpcRule := newRPCRule(channel.ToUint64(), nil, rule)
rpcCfg.Rules = append(rpcCfg.Rules, rpcRule)
}
for peer, rule := range cfg.PeerRules {
peer := peer
rpcRule := newRPCRule(0, peer[:], rule)
rpcCfg.Rules = append(rpcCfg.Rules, rpcRule)
} }
return rpcCfg, nil return rpcCfg, nil
} }
func newRPCRule(channelID uint64, peer []byte,
rule *liquidity.SwapRule) *clientrpc.LiquidityRule {
rpcRule := &clientrpc.LiquidityRule{
ChannelId: channelID,
Pubkey: peer,
Type: clientrpc.LiquidityRuleType_THRESHOLD,
IncomingThreshold: uint32(rule.MinimumIncoming),
OutgoingThreshold: uint32(rule.MinimumOutgoing),
SwapType: clientrpc.SwapType_LOOP_OUT,
}
if rule.Type == swap.TypeIn {
rpcRule.SwapType = clientrpc.SwapType_LOOP_IN
}
return rpcRule
}
// SetLiquidityParams attempts to set our current liquidity manager's // SetLiquidityParams attempts to set our current liquidity manager's
// parameters. // parameters.
func (s *swapClientServer) SetLiquidityParams(ctx context.Context, func (s *swapClientServer) SetLiquidityParams(ctx context.Context,

@ -2,7 +2,6 @@ package loopd
import ( import (
"context" "context"
"time"
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/lightninglabs/lndclient" "github.com/lightninglabs/lndclient"
@ -41,7 +40,6 @@ func getClient(config *Config, lnd *lndclient.LndServices) (*loop.Client,
func getLiquidityManager(client *loop.Client) *liquidity.Manager { func getLiquidityManager(client *loop.Client) *liquidity.Manager {
mngrCfg := &liquidity.Config{ mngrCfg := &liquidity.Config{
AutoloopTicker: ticker.NewForce(liquidity.DefaultAutoloopTicker), AutoloopTicker: ticker.NewForce(liquidity.DefaultAutoloopTicker),
AutoloopBudgetLastRefresh: time.Now(),
LoopOut: client.LoopOut, LoopOut: client.LoopOut,
LoopIn: client.LoopIn, LoopIn: client.LoopIn,
Restrictions: func(ctx context.Context, Restrictions: func(ctx context.Context,

Loading…
Cancel
Save