loop/interface.go
Boris Nagaev d554b42ef6
multi: migrate to btcd v2 modules
Update LND, Aperture, and Taproot Assets to revisions using the
btcd v2 modules, and update lndclient to v0.21.0-3. Migrate Loop
chain, transaction, and address types to their corresponding v2
packages.

The lndclient release includes the migration from:
https://github.com/lightninglabs/lndclient/pull/280

Taproot Assets is temporarily replaced with its btcd v2 revision
because the v0.8 release branch has not adopted the new modules.

This raises the minimum Go version to 1.26 and changes exported
address types.
2026-08-12 23:39:26 +00:00

555 lines
19 KiB
Go

package loop
import (
"time"
btcaddr "github.com/btcsuite/btcd/address/v2"
"github.com/btcsuite/btcd/btcutil/v2"
"github.com/lightninglabs/loop/fsm"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/taproot-assets/rfqmath"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/zpay32"
)
// OutRequest contains the required parameters for a loop out swap.
type OutRequest struct {
// Amount specifies the requested swap amount in sat. This does not
// include the swap and miner fee.
Amount btcutil.Amount
// DestAddr is the destination address for the swap.
DestAddr btcaddr.Address
// IsExternalAddr indicates whether the provided destination address
// does not belong to the underlying wallet. This helps indicate
// whether the sweep of this swap can be batched or not.
IsExternalAddr bool
// MaxSwapRoutingFee is the maximum off-chain fee in msat that may be
// paid for payment to the server. This limit is applied during path
// finding. Typically this value is taken from the response of the
// LoopOutQuote call.
MaxSwapRoutingFee btcutil.Amount
// MaxPrepayRoutingFee is the maximum off-chain fee in msat that may be
// paid for payment to the server. This limit is applied during path
// finding. Typically this value is taken from the response of the
// LoopOutQuote call.
MaxPrepayRoutingFee btcutil.Amount
// MaxSwapFee is the maximum we are willing to pay the server for the
// swap. This value is not disclosed in the swap initiation call, but
// if the server asks for a higher fee, we abort the swap. Typically
// this value is taken from the response of the LoopOutQuote call. It
// includes the prepay amount.
MaxSwapFee btcutil.Amount
// MaxPrepayAmount is the maximum amount of the swap fee that may be
// charged as a prepayment.
MaxPrepayAmount btcutil.Amount
// MaxMinerFee is the maximum in on-chain fees that we are willing to
// spent. If we want to sweep the on-chain htlc and the fee estimate
// turns out higher than this value, we cancel the swap. If the fee
// estimate is lower, we publish the sweep tx.
//
// If the sweep tx isn't confirmed, we are forced to ratchet up fees
// until it is swept. Possibly even exceeding MaxMinerFee if we get
// close to the htlc timeout. Because the initial publication revealed
// the preimage, we have no other choice. The server may already have
// pulled the off-chain htlc. Only when the fee becomes higher than the
// swap amount, we can only wait for fees to come down and hope - if we
// are past the timeout - that the server isn't publishing the
// revocation.
//
// MaxMinerFee is typically taken from the response of the
// LoopOutQuote call.
MaxMinerFee btcutil.Amount
// SweepConfTarget specifies the targeted confirmation target for the
// client sweep tx.
SweepConfTarget int32
// HtlcConfirmations specifies the number of confirmations we require
// for on chain loop out htlcs.
HtlcConfirmations int32
// OutgoingChanSet optionally specifies the short channel ids of the
// channels that may be used to loop out.
OutgoingChanSet loopdb.ChannelSet
// SwapPublicationDeadline can be set by the client to allow the server
// delaying publication of the swap HTLC to save on chain fees.
SwapPublicationDeadline time.Time
// Expiry is the absolute expiry height of the on-chain htlc.
Expiry int32
// Label contains an optional label for the swap.
Label string
// Initiator is an optional string that identifies what software
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
// appended to the user agent string.
Initiator string
// PaymentTimeout specifies the payment timeout for the individual
// off-chain payments. As the swap payment may be retried (depending on
// the configured maximum payment timeout) the total time spent may be
// a multiple of this value.
PaymentTimeout time.Duration
// AssetId is an optional asset id that can be used to specify the asset
// that will be used to pay for the swap. If this is set, a connection
// to a tapd server is required to pay for the asset.
AssetId []byte
// AssetPrepayRfqId is the rfq id that is used to pay the prepay
// invoice.
AssetPrepayRfqId []byte
// AssetSwapRfqId is the rfq id that is used to pay the swap invoice.
AssetSwapRfqId []byte
}
// Out contains the full details of a loop out request. This includes things
// like the payment hash, the total value, and the final CTLV delay of the
// swap. We'll use this to track an active swap throughout those various swap
// stages.
type Out struct {
// SwapInfoKit contains shared data amongst all swap types.
SwapInfoKit
// LoopOutContract describes the details of this loop.Out. Using these
// details, the full swap can be executed.
loopdb.LoopOutContract
// State is the current state of the target swap.
State loopdb.SwapState
}
// LoopOutQuoteRequest specifies the swap parameters for which a quote is
// requested.
type LoopOutQuoteRequest struct {
// Amount specifies the requested swap amount in sat. This does not
// include the swap and miner fee.
Amount btcutil.Amount
// SweepConfTarget specifies the targeted confirmation target for the
// client sweep tx.
SweepConfTarget int32
// SwapPublicationDeadline can be set by the client to allow the server
// delaying publication of the swap HTLC to save on chain fees.
SwapPublicationDeadline time.Time
// TODO: Add argument to specify confirmation target for server
// publishing htlc. This may influence the swap fee quote, because the
// server needs to pay more for faster confirmations.
//
// TODO: Add arguments to specify maximum total time locks for the
// off-chain swap payment and prepayment. This may influence the
// available routes and off-chain fee estimates. To apply these maximum
// values properly, the server needs to be queried for its required
// final cltv delta values for the off-chain payments.
// Initiator is an optional string that identifies what software
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
// appended to the user agent string.
Initiator string
// AssetRFQRequest is the optional RFQ request that can be used to quote
// for asset rfqs using the asset client
AssetRFQRequest *AssetRFQRequest
}
type AssetRFQRequest struct {
// AssetId is the asset that we'll quote for.
AssetId []byte
// AssetEdgeNode is the pubkey of the peer that we'll quote for.
AssetEdgeNode []byte
// Expiry is the unix timestamp when the rfq will expire.
Expiry int64
// MaxLimitMultiplier is the multiplier that we'll use to calculate the
// max limit we'll quote for.
MaxLimitMultiplier float64
}
// LoopOutTerms are the server terms on which it executes swaps.
type LoopOutTerms struct {
// MinSwapAmount is the minimum amount that the server requires for a
// swap.
MinSwapAmount btcutil.Amount
// MaxSwapAmount is the maximum amount that the server accepts for a
// swap.
MaxSwapAmount btcutil.Amount
// MinCltvDelta is the minimum expiry delta for loop out swaps.
MinCltvDelta int32
// MaxCltvDelta is the maximum expiry delta for loop out swaps.
MaxCltvDelta int32
}
// LoopOutQuote contains estimates for the fees making up the total swap cost
// for the client.
type LoopOutQuote struct {
// SwapFee is the fee that the swap server is charging for the swap.
SwapFee btcutil.Amount
// PrepayAmount is the part of the swap fee that is requested as a
// prepayment.
PrepayAmount btcutil.Amount
// MinerFee is an estimate of the on-chain fee that needs to be paid to
// sweep the htlc.
MinerFee btcutil.Amount
// SwapPaymentDest is the node pubkey where to swap payment needs to be
// sent to.
SwapPaymentDest [33]byte
// LoopOutRfq is the RFQ that can be used in the actual loop out to
// commit to an asset exchange rate.
LoopOutRfq *LoopOutRfq
}
// LoopOutRfq contains the details of an asset request for quote for a loop out
// swap.
type LoopOutRfq struct {
// PrepayRfqId is the ID of the prepay RFQ.
PrepayRfqId []byte
// MaxPrepayAssetAmt is the maximum amount of the asset that will be
// used to pay for the prepay invoice.
MaxPrepayAssetAmt uint64
// PrepayAssetRate is the rate at which the asset is exchanged for
// bitcoin.
PrepayAssetRate *rfqmath.BigIntFixedPoint
// SwapRfqId is the ID of the swap RFQ.
SwapRfqId []byte
// MaxSwapAssetAmt is the maximum amount of the asset that will be used
// to pay for the swap invoice.
MaxSwapAssetAmt uint64
// SwapAssetRate is the rate at which the asset is exchanged for bitcoin.
SwapAssetRate *rfqmath.BigIntFixedPoint
// AssetName is the human readable name of the asset.
AssetName string
}
// LoopInRequest contains the required parameters for the swap.
type LoopInRequest struct {
// Amount specifies the requested swap amount in sat. This does not
// include the swap and miner fee.
Amount btcutil.Amount
// MaxSwapFee is the maximum we are willing to pay the server for the
// swap. This value is not disclosed in the swap initiation call, but if
// the server asks for a higher fee, we abort the swap. Typically this
// value is taken from the response of the LoopInQuote call. It
// includes the prepay amount.
MaxSwapFee btcutil.Amount
// MaxMinerFee is the maximum in on-chain fees that we are willing to
// spent. If we publish the on-chain htlc and the fee estimate turns out
// higher than this value, we cancel the swap.
//
// MaxMinerFee is typically taken from the response of the LoopInQuote
// call.
MaxMinerFee btcutil.Amount
// HtlcConfTarget specifies the targeted confirmation target for the
// client htlc tx.
HtlcConfTarget int32
// LastHop optionally specifies the last hop to use for the loop in
// payment.
LastHop *route.Vertex
// ExternalHtlc specifies whether the htlc is published by an external
// source.
ExternalHtlc bool
// Label contains an optional label for the swap.
Label string
// Initiator is an optional string that identifies what software
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
// appended to the user agent string.
Initiator string
// Private indicates whether the destination node should be considered
// private. In which case, loop will generate hophints to assist with
// probing and payment.
Private bool
// RouteHints are optional route hints to reach the destination through
// private channels.
RouteHints [][]zpay32.HopHint
}
// StaticAddressLoopInRequest contains the required parameters for the swap.
type StaticAddressLoopInRequest struct {
// DepositOutpoints contain the outpoints in format txid:idx of the
// static address deposits that are being looped in. The sum of output
// values constitute the swap amount.
DepositOutpoints []string
// MaxSwapFee is the maximum we are willing to pay the server for the
// swap. This value is not disclosed in the swap initiation call, but if
// the server asks for a higher fee, we abort the swap. Typically, this
// value is taken from the response of the LoopInQuote call. It
// includes the pre-pay amount.
MaxSwapFee btcutil.Amount
// LastHop optionally specifies the last hop to use for the loop in
// payment.
LastHop *route.Vertex
// Label contains an optional text label for the swap.
Label string
// Initiator is an optional string that identifies what software
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
// appended to the user agent string.
Initiator string
// Private indicates whether the destination node should be considered
// private. In which case, loop will generate hophints to assist with
// probing and payment.
Private bool
// RouteHints are optional route hints to reach the destination through
// private channels.
RouteHints [][]zpay32.HopHint
// PaymentTimeoutSeconds allows the user to specify an upper limit for
// the amount of time the server is allowed to fulfill the off-chain
// swap payment. If the timeout is reached the swap will be aborted and
// the client can retry the swap if desired with different parameters.
PaymentTimeoutSeconds uint32
// SelectedAmount is the amount that the user selected for the swap. If
// the user did not select an amount, the amount of the selected
// deposits is used.
SelectedAmount btcutil.Amount
// Fast indicates whether the user requested a fast static loop-in. If
// set, the flag is passed to the server which may alter its behavior
// (for example, publish sooner) and is stored in the database.
Fast bool
}
// LoopInTerms are the server terms on which it executes loop in swaps.
type LoopInTerms struct {
// MinSwapAmount is the minimum amount that the server requires for a
// swap.
MinSwapAmount btcutil.Amount
// MaxSwapAmount is the maximum amount that the server accepts for a
// swap.
MaxSwapAmount btcutil.Amount
}
// In contains status information for a loop in swap.
type In struct {
loopdb.LoopInContract
SwapInfoKit
// State where the swap is in.
State loopdb.SwapState
}
// LoopInQuoteRequest specifies the swap parameters for which a quote is
// requested.
type LoopInQuoteRequest struct {
// Amount specifies the requested swap amount in sat. This does not
// include the swap and miner fee.
Amount btcutil.Amount
// HtlcConfTarget specifies the targeted confirmation target for the
// client sweep tx.
HtlcConfTarget int32
// ExternalHtlc specifies whether the htlc is published by an external
// source.
ExternalHtlc bool
// LastHop is an optional last hop to use. This last hop is used when
// the client has already requested a server probe for more accurate
// routing fee estimation.
LastHop *route.Vertex
// RouteHints are optional route hints to reach the destination through
// private channels.
RouteHints [][]zpay32.HopHint
// Private indicates whether the destination node should be considered
// private. In which case, loop will generate hophints to assist with
// probing and payment.
Private bool
// Initiator is an optional string that identifies what software
// initiated the swap (loop CLI, autolooper, LiT UI and so on) and is
// appended to the user agent string.
Initiator string
// The number of static address deposits the client wants to quote for.
// If the number of deposits exceeds one the server will apply a
// per-input service fee. This is to cover for the increased on-chain
// fee the server has to pay when the sweeping transaction is broadcast.
NumDeposits uint32
// Fast indicates whether the user requested a fast static loop-in
// publication on-chain. This is helpful if swap change needs to get
// confirmed fast. This comes at a higher swap cost since the server has
// to pay more on-chain fees.
Fast bool
}
// LoopInQuote contains estimates for the fees making up the total swap cost
// for the client.
type LoopInQuote struct {
// SwapFee is the fee that the swap server is charging for the swap.
SwapFee btcutil.Amount
// MinerFee is an estimate of the on-chain fee that needs to be paid to
// sweep the htlc.
MinerFee btcutil.Amount
// CltvDelta is the time lock delta relative to current block height
// that the swap server will accept on the swap initiation call.
CltvDelta int32
}
// LoopInSwapInfo contains essential information of a loop-in swap after the
// swap is initiated.
type LoopInSwapInfo struct { // nolint
// SwapHash contains the sha256 hash of the swap preimage.
SwapHash lntypes.Hash
// HtlcAddressP2WSH contains the native segwit swap htlc address,
// where the loop-in funds may be paid.
HtlcAddressP2WSH btcaddr.Address
// HtlcAddressP2TR contains the v3 (pay to taproot) htlc address.
HtlcAddressP2TR btcaddr.Address
// ServerMessage is the human-readable message received from the loop
// server.
ServerMessage string
}
// LoopOutSwapInfo contains essential information of a loop-out swap after the
// swap is initiated.
type LoopOutSwapInfo struct { // nolint:revive
// SwapHash contains the sha256 hash of the swap preimage.
SwapHash lntypes.Hash
// HtlcAddress contains the swap htlc address that the server will
// publish to.
HtlcAddress btcaddr.Address
// ServerMessage is the human-readable message received from the loop
// server.
ServerMessage string
}
// SwapInfoKit contains common swap info fields.
type SwapInfoKit struct {
// Hash is the sha256 hash of the preimage that unlocks the htlcs. It
// is used to uniquely identify this swap.
Hash lntypes.Hash
// LastUpdateTime is the time of the last update of this swap.
LastUpdateTime time.Time
}
// SwapInfo exposes common info fields for traditional swaps and static address
// loop-ins.
type SwapInfo struct {
// SwapStateData.State is authoritative for swap.TypeIn and swap.TypeOut.
// For swap.TypeStaticAddressLoopIn, StaticAddressLoopInState is
// authoritative and State remains its zero value, loopdb.StateInitiated.
loopdb.SwapStateData
loopdb.SwapContract
// LastUpdate is the time of the last state change.
LastUpdate time.Time
// SwapHash stores the swap preimage hash.
SwapHash lntypes.Hash
// SwapType describes the kind of swap.
SwapType swap.Type
// StaticAddressLoopInState stores the precise static address loop-in FSM
// state when SwapType is swap.TypeStaticAddressLoopIn. For traditional
// swaps, it remains the fsm.StateType zero value, fsm.EmptyState.
StaticAddressLoopInState fsm.StateType
// HtlcAddressP2WSH stores the address of the P2WSH (native segwit)
// swap htlc. This is used for both loop-in and loop-out.
HtlcAddressP2WSH btcaddr.Address
// HtlcAddressP2TR stores the address of the P2TR (taproot) swap htlc.
// This is used for both internal and external loop-in and loop out.
HtlcAddressP2TR btcaddr.Address
// ExternalHtlc is set to true for external loop-in swaps.
ExternalHtlc bool
// LastHop optionally specifies the last hop to use for the loop in
// payment. On a loop out this field is nil.
LastHop *route.Vertex
// OutgoingChanSet optionally specifies the short channel ids of the
// channels that may be used to loop out. On a loop in this field
// is nil.
OutgoingChanSet loopdb.ChannelSet
// AssetSwapInfo contains the asset information for the swap.
AssetSwapInfo *loopdb.LoopOutAssetSwap
}
// LastUpdate returns the last update time of the swap.
func (s *In) LastUpdate() time.Time {
return s.LastUpdateTime
}
// SwapHash returns the swap hash.
func (s *In) SwapHash() lntypes.Hash {
return s.Hash
}
// ProbeRequest specifies probe parameters for the server probe.
type ProbeRequest struct {
// Amount is the amount that will be probed.
Amount btcutil.Amount
// LastHop is the last hop along the route.
LastHop *route.Vertex
// RouteHints are optional hop hints.
RouteHints [][]zpay32.HopHint
}
// AbandonSwapRequest specifies the swap to abandon. It is identified by its
// swap hash.
type AbandonSwapRequest struct {
SwapHash lntypes.Hash
}