mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
Include https://github.com/lightninglabs/lndclient/pull/280 multi: migrate to btcd v2 modules + add WalletKit.SubmitPackage Migrate Loop imports and update Aperture and Taproot Assets to compatible revisions so this commit remains green on its own.
132 lines
3.7 KiB
Go
132 lines
3.7 KiB
Go
package liquidity
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/btcsuite/btcd/btcutil/v2"
|
|
"github.com/lightninglabs/loop"
|
|
"github.com/lightninglabs/loop/labels"
|
|
"github.com/lightninglabs/loop/swap"
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
"github.com/lightningnetwork/lnd/routing/route"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
// Compile-time assertion that loopInBuilder satisfies the swapBuilder
|
|
// interface.
|
|
var _ swapBuilder = (*loopInBuilder)(nil)
|
|
|
|
func newLoopInBuilder(cfg *Config) *loopInBuilder {
|
|
return &loopInBuilder{
|
|
cfg: cfg,
|
|
}
|
|
}
|
|
|
|
type loopInBuilder struct {
|
|
// cfg contains all the external functionality we require to create
|
|
// swaps.
|
|
cfg *Config
|
|
}
|
|
|
|
// swapType returns the swap type that the builder is responsible for creating.
|
|
func (b *loopInBuilder) swapType() swap.Type {
|
|
return swap.TypeIn
|
|
}
|
|
|
|
// maySwap checks whether we can currently execute a swap, examining the
|
|
// current on-chain fee conditions against relevant to our swap type against
|
|
// our fee restrictions.
|
|
//
|
|
// For loop in, we cannot check any upfront costs because we do not know how
|
|
// many inputs will be used for our on-chain htlc before it is made, so we can't
|
|
// make nay estimations.
|
|
func (b *loopInBuilder) maySwap(_ context.Context, _ Parameters) error {
|
|
return nil
|
|
}
|
|
|
|
// inUse examines our current swap traffic to determine whether we should
|
|
// suggest the builder's type of swap for the peer and channels suggested.
|
|
func (b *loopInBuilder) inUse(traffic *swapTraffic, peer route.Vertex,
|
|
channels []lnwire.ShortChannelID) error {
|
|
|
|
for _, chanID := range channels {
|
|
if traffic.ongoingLoopOut[chanID] {
|
|
log.Debugf("Channel: %v not eligible for suggestions, "+
|
|
"ongoing loop out utilizing channel", chanID)
|
|
|
|
return newReasonError(ReasonLoopOut)
|
|
}
|
|
}
|
|
|
|
if traffic.ongoingLoopIn[peer] {
|
|
log.Debugf("Peer: %x not eligible for suggestions ongoing "+
|
|
"loop in utilizing peer", peer)
|
|
|
|
return newReasonError(ReasonLoopIn)
|
|
}
|
|
|
|
lastFail, recentFail := traffic.failedLoopIn[peer]
|
|
if recentFail {
|
|
log.Debugf("Peer: %v not eligible for suggestions, "+
|
|
"was part of a failed swap at: %v", peer,
|
|
lastFail)
|
|
|
|
return newReasonError(ReasonFailureBackoff)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// buildSwap creates a swap for the target peer/channels provided. The autoloop
|
|
// boolean indicates whether this swap will actually be executed.
|
|
//
|
|
// For loop in, we do not add the autoloop label for dry runs.
|
|
func (b *loopInBuilder) buildSwap(ctx context.Context, pubkey route.Vertex,
|
|
_ []lnwire.ShortChannelID, amount btcutil.Amount,
|
|
params Parameters, swapOpts ...buildSwapOption) (swapSuggestion,
|
|
error) {
|
|
|
|
quote, err := b.cfg.LoopInQuote(ctx, &loop.LoopInQuoteRequest{
|
|
Amount: amount,
|
|
LastHop: &pubkey,
|
|
HtlcConfTarget: params.HtlcConfTarget,
|
|
Initiator: getInitiator(params),
|
|
})
|
|
if err != nil {
|
|
// If the server fails our quote, we're not reachable right
|
|
// now, so we want to catch this error and fail with a
|
|
// structured error so that we know why we can't swap.
|
|
status, ok := status.FromError(err)
|
|
if ok && status.Code() == codes.FailedPrecondition {
|
|
return nil, newReasonError(ReasonLoopInUnreachable)
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
if err := params.FeeLimit.loopInLimits(amount, quote); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
request := loop.LoopInRequest{
|
|
Amount: amount,
|
|
MaxSwapFee: quote.SwapFee,
|
|
MaxMinerFee: quote.MinerFee,
|
|
HtlcConfTarget: params.HtlcConfTarget,
|
|
LastHop: &pubkey,
|
|
Initiator: getInitiator(params),
|
|
}
|
|
|
|
if params.Autoloop {
|
|
request.Label = labels.AutoloopLabel(swap.TypeIn)
|
|
|
|
if params.EasyAutoloop {
|
|
request.Label = labels.EasyAutoloopLabel(swap.TypeIn)
|
|
}
|
|
}
|
|
|
|
return &loopInSwapSuggestion{
|
|
LoopInRequest: request,
|
|
}, nil
|
|
}
|