mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
The selected_amount column of all previous swaps is filled with the total value of deposits that partook in these swaps.
598 lines
17 KiB
Go
598 lines
17 KiB
Go
package loopin
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"strings"
|
|
|
|
"github.com/btcsuite/btcd/btcec/v2"
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/lightninglabs/loop/fsm"
|
|
"github.com/lightninglabs/loop/loopdb"
|
|
"github.com/lightninglabs/loop/loopdb/sqlc"
|
|
"github.com/lightninglabs/loop/staticaddr/deposit"
|
|
"github.com/lightninglabs/loop/staticaddr/version"
|
|
"github.com/lightningnetwork/lnd/clock"
|
|
"github.com/lightningnetwork/lnd/keychain"
|
|
"github.com/lightningnetwork/lnd/lntypes"
|
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
|
)
|
|
|
|
const OutpointSeparator = ";"
|
|
|
|
var (
|
|
// ErrInvalidOutpoint is returned when an outpoint contains the outpoint
|
|
// separator.
|
|
ErrInvalidOutpoint = errors.New("outpoint contains outpoint separator")
|
|
)
|
|
|
|
// Querier is the interface that contains all the queries generated by sqlc for
|
|
// the static_address_swaps table.
|
|
type Querier interface {
|
|
// InsertSwap inserts a new base swap.
|
|
InsertSwap(ctx context.Context, arg sqlc.InsertSwapParams) error
|
|
|
|
// InsertHtlcKeys inserts the htlc keys for a swap.
|
|
InsertHtlcKeys(ctx context.Context, arg sqlc.InsertHtlcKeysParams) error
|
|
|
|
// InsertStaticAddressLoopIn inserts a new static address loop-in swap.
|
|
InsertStaticAddressLoopIn(ctx context.Context,
|
|
arg sqlc.InsertStaticAddressLoopInParams) error
|
|
|
|
// InsertStaticAddressMetaUpdate inserts metadata about loop-in
|
|
// updates.
|
|
InsertStaticAddressMetaUpdate(ctx context.Context,
|
|
arg sqlc.InsertStaticAddressMetaUpdateParams) error
|
|
|
|
// UpdateStaticAddressLoopIn updates a loop-in swap.
|
|
UpdateStaticAddressLoopIn(ctx context.Context,
|
|
arg sqlc.UpdateStaticAddressLoopInParams) error
|
|
|
|
// GetStaticAddressLoopInSwap retrieves a loop-in swap by its swap hash.
|
|
GetStaticAddressLoopInSwap(ctx context.Context,
|
|
swapHash []byte) (sqlc.GetStaticAddressLoopInSwapRow, error)
|
|
|
|
// GetStaticAddressLoopInSwapsByStates retrieves all swaps with the
|
|
// given states. The states string is an input for the IN primitive in
|
|
// sqlite, hence the format needs to be '{State1,State2,...}'.
|
|
GetStaticAddressLoopInSwapsByStates(ctx context.Context,
|
|
states sql.NullString) ([]sqlc.GetStaticAddressLoopInSwapsByStatesRow,
|
|
error)
|
|
|
|
// GetLoopInSwapUpdates retrieves all updates for a loop-in swap.
|
|
GetLoopInSwapUpdates(ctx context.Context,
|
|
swapHash []byte) ([]sqlc.StaticAddressSwapUpdate, error)
|
|
|
|
// IsStored returns true if a swap with the given hash is stored in the
|
|
// database, false otherwise.
|
|
IsStored(ctx context.Context, swapHash []byte) (bool, error)
|
|
|
|
// MapDepositToSwap maps a deposit to a swap in the database.
|
|
MapDepositToSwap(ctx context.Context,
|
|
arg sqlc.MapDepositToSwapParams) error
|
|
|
|
// SwapHashForDepositID retrieves the swap hash for the given deposit
|
|
// ID.
|
|
SwapHashForDepositID(ctx context.Context,
|
|
depositID []byte) ([]byte, error)
|
|
|
|
// DepositIDsForSwapHash retrieves all deposit IDs for a given swap
|
|
// hash.
|
|
DepositIDsForSwapHash(ctx context.Context,
|
|
swapHash []byte) ([][]byte, error)
|
|
|
|
// DepositsForSwapHash retrieves all deposits for a given swap hash.
|
|
DepositsForSwapHash(ctx context.Context,
|
|
swapHash []byte) ([]sqlc.DepositsForSwapHashRow, error)
|
|
|
|
// OverrideSelectedSwapAmount updates the selected swap amount for
|
|
// a given swap hash.
|
|
OverrideSelectedSwapAmount(ctx context.Context,
|
|
params sqlc.OverrideSelectedSwapAmountParams) error
|
|
}
|
|
|
|
// BaseDB is the interface that contains all the queries generated by sqlc for
|
|
// the static_address_swaps table and transaction functionality.
|
|
type BaseDB interface {
|
|
Querier
|
|
|
|
// ExecTx allows for executing a function in the context of a database
|
|
// transaction.
|
|
ExecTx(ctx context.Context, txOptions loopdb.TxOptions,
|
|
txBody func(Querier) error) error
|
|
}
|
|
|
|
// SqlStore is the backing store for static address loop-ins.
|
|
type SqlStore struct {
|
|
baseDB BaseDB
|
|
clock clock.Clock
|
|
network *chaincfg.Params
|
|
}
|
|
|
|
// NewSqlStore constructs a new SQLStore from a BaseDB. The BaseDB is agnostic
|
|
// to the underlying driver which can be postgres or sqlite.
|
|
func NewSqlStore(db BaseDB, clock clock.Clock,
|
|
network *chaincfg.Params) *SqlStore {
|
|
|
|
return &SqlStore{
|
|
baseDB: db,
|
|
clock: clock,
|
|
network: network,
|
|
}
|
|
}
|
|
|
|
// GetLoopInByHash returns the loop-in swap with the given hash.
|
|
func (s *SqlStore) GetLoopInByHash(ctx context.Context,
|
|
swapHash lntypes.Hash) (*StaticAddressLoopIn, error) {
|
|
|
|
var (
|
|
err error
|
|
swap sqlc.GetStaticAddressLoopInSwapRow
|
|
updates []sqlc.StaticAddressSwapUpdate
|
|
)
|
|
swap, err = s.baseDB.GetStaticAddressLoopInSwap(ctx, swapHash[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
deposits, err := s.baseDB.DepositsForSwapHash(ctx, swapHash[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
updates, err = s.baseDB.GetLoopInSwapUpdates(ctx, swapHash[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return toStaticAddressLoopIn(ctx, s.network, swap, deposits, updates)
|
|
}
|
|
|
|
// GetStaticAddressLoopInSwapsByStates returns all static address loop-ins from
|
|
// the db that are in the given states.
|
|
func (s *SqlStore) GetStaticAddressLoopInSwapsByStates(ctx context.Context,
|
|
states []fsm.StateType) ([]*StaticAddressLoopIn, error) {
|
|
|
|
var (
|
|
err error
|
|
rows []sqlc.GetStaticAddressLoopInSwapsByStatesRow
|
|
updates []sqlc.StaticAddressSwapUpdate
|
|
loopIn *StaticAddressLoopIn
|
|
)
|
|
joinedStates := toJointStringStates(states)
|
|
joinedNullStringStates := sql.NullString{
|
|
String: joinedStates,
|
|
Valid: joinedStates != "",
|
|
}
|
|
rows, err = s.baseDB.GetStaticAddressLoopInSwapsByStates(
|
|
ctx, joinedNullStringStates,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loopIns := make([]*StaticAddressLoopIn, 0, len(rows))
|
|
for _, row := range rows {
|
|
deposits, err := s.baseDB.DepositsForSwapHash(ctx, row.SwapHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
updates, err = s.baseDB.GetLoopInSwapUpdates(
|
|
ctx, row.SwapHash,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loopIn, err = toStaticAddressLoopIn(
|
|
ctx, s.network, sqlc.GetStaticAddressLoopInSwapRow(row),
|
|
deposits, updates,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loopIns = append(loopIns, loopIn)
|
|
}
|
|
|
|
return loopIns, nil
|
|
}
|
|
|
|
func toJointStringStates(states []fsm.StateType) string {
|
|
return "{" + strings.Join(toStrings(states), ",") + "}"
|
|
}
|
|
|
|
func toStrings(states []fsm.StateType) []string {
|
|
stringStates := make([]string, len(states))
|
|
for i, state := range states {
|
|
stringStates[i] = string(state)
|
|
}
|
|
|
|
return stringStates
|
|
}
|
|
|
|
// CreateLoopIn inserts a new loop-in swap into the database. Basic loop-in
|
|
// parameters are stored in the swaps table, htlc key information is stored in
|
|
// the htlc_keys table, and loop-in specific information is stored in the
|
|
// static_address_swaps table.
|
|
func (s *SqlStore) CreateLoopIn(ctx context.Context,
|
|
loopIn *StaticAddressLoopIn) error {
|
|
|
|
if loopIn == nil {
|
|
return errors.New("loop-in cannot be nil")
|
|
}
|
|
|
|
if len(loopIn.Deposits) == 0 {
|
|
return errors.New("loop-in must have at least one deposit")
|
|
}
|
|
|
|
amountRequested := int64(loopIn.TotalDepositAmount())
|
|
if loopIn.SelectedAmount > 0 {
|
|
amountRequested = int64(loopIn.SelectedAmount)
|
|
}
|
|
|
|
swapArgs := sqlc.InsertSwapParams{
|
|
SwapHash: loopIn.SwapHash[:],
|
|
Preimage: loopIn.SwapPreimage[:],
|
|
InitiationTime: loopIn.InitiationTime,
|
|
AmountRequested: amountRequested,
|
|
CltvExpiry: loopIn.HtlcCltvExpiry,
|
|
MaxSwapFee: int64(loopIn.MaxSwapFee),
|
|
InitiationHeight: int32(loopIn.InitiationHeight),
|
|
ProtocolVersion: int32(loopIn.ProtocolVersion),
|
|
Label: loopIn.Label,
|
|
}
|
|
|
|
htlcKeyArgs := sqlc.InsertHtlcKeysParams{
|
|
SwapHash: loopIn.SwapHash[:],
|
|
SenderScriptPubkey: loopIn.ClientPubkey.SerializeCompressed(),
|
|
ReceiverScriptPubkey: loopIn.ServerPubkey.SerializeCompressed(),
|
|
ClientKeyFamily: int32(loopIn.HtlcKeyLocator.Family),
|
|
ClientKeyIndex: int32(loopIn.HtlcKeyLocator.Index),
|
|
}
|
|
|
|
// Sanity check, if any of the outpoints contain the outpoint separator.
|
|
// If so, we reject the loop-in to prevent potential issues with
|
|
// parsing.
|
|
for _, outpoint := range loopIn.DepositOutpoints {
|
|
if strings.Contains(outpoint, OutpointSeparator) {
|
|
return ErrInvalidOutpoint
|
|
}
|
|
}
|
|
|
|
joinedOutpoints := strings.Join(
|
|
loopIn.DepositOutpoints, OutpointSeparator,
|
|
)
|
|
staticAddressLoopInParams := sqlc.InsertStaticAddressLoopInParams{
|
|
SwapHash: loopIn.SwapHash[:],
|
|
SwapInvoice: loopIn.SwapInvoice,
|
|
LastHop: loopIn.LastHop,
|
|
QuotedSwapFeeSatoshis: int64(loopIn.QuotedSwapFee),
|
|
HtlcTimeoutSweepAddress: loopIn.HtlcTimeoutSweepAddress.String(),
|
|
HtlcTxFeeRateSatKw: int64(loopIn.HtlcTxFeeRate),
|
|
DepositOutpoints: joinedOutpoints,
|
|
SelectedAmount: int64(loopIn.SelectedAmount),
|
|
PaymentTimeoutSeconds: int32(loopIn.PaymentTimeoutSeconds),
|
|
}
|
|
|
|
updateArgs := sqlc.InsertStaticAddressMetaUpdateParams{
|
|
SwapHash: loopIn.SwapHash[:],
|
|
UpdateTimestamp: s.clock.Now(),
|
|
UpdateState: string(loopIn.GetState()),
|
|
}
|
|
|
|
return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
|
|
func(q Querier) error {
|
|
err := q.InsertSwap(ctx, swapArgs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = q.InsertHtlcKeys(ctx, htlcKeyArgs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = q.InsertStaticAddressLoopIn(
|
|
ctx, staticAddressLoopInParams,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Map each deposit to the swap hash in the
|
|
// deposit_to_swap table. This allows us to track which
|
|
// deposits are used for which swaps.
|
|
for _, d := range loopIn.Deposits {
|
|
err = q.MapDepositToSwap(
|
|
ctx, sqlc.MapDepositToSwapParams{
|
|
DepositID: d.ID[:],
|
|
SwapHash: loopIn.SwapHash[:],
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return q.InsertStaticAddressMetaUpdate(ctx, updateArgs)
|
|
},
|
|
)
|
|
}
|
|
|
|
// UpdateLoopIn updates the loop-in in the database.
|
|
func (s *SqlStore) UpdateLoopIn(ctx context.Context,
|
|
loopIn *StaticAddressLoopIn) error {
|
|
|
|
var htlcTimeoutSweepTxID string
|
|
if loopIn.HtlcTimeoutSweepTxHash != nil {
|
|
htlcTimeoutSweepTxID = loopIn.HtlcTimeoutSweepTxHash.String()
|
|
}
|
|
|
|
updateParams := sqlc.UpdateStaticAddressLoopInParams{
|
|
SwapHash: loopIn.SwapHash[:],
|
|
HtlcTxFeeRateSatKw: int64(loopIn.HtlcTxFeeRate),
|
|
HtlcTimeoutSweepTxID: sql.NullString{
|
|
String: htlcTimeoutSweepTxID,
|
|
Valid: htlcTimeoutSweepTxID != "",
|
|
},
|
|
}
|
|
|
|
updateArgs := sqlc.InsertStaticAddressMetaUpdateParams{
|
|
SwapHash: loopIn.SwapHash[:],
|
|
UpdateState: string(loopIn.GetState()),
|
|
UpdateTimestamp: s.clock.Now(),
|
|
}
|
|
|
|
return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
|
|
func(q Querier) error {
|
|
err := q.UpdateStaticAddressLoopIn(ctx, updateParams)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return q.InsertStaticAddressMetaUpdate(ctx, updateArgs)
|
|
},
|
|
)
|
|
}
|
|
|
|
func (s *SqlStore) BatchUpdateSelectedSwapAmounts(ctx context.Context,
|
|
updateAmounts map[lntypes.Hash]btcutil.Amount) error {
|
|
|
|
return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
|
|
func(q Querier) error {
|
|
for swapHash, amount := range updateAmounts {
|
|
err := q.OverrideSelectedSwapAmount(
|
|
ctx, sqlc.OverrideSelectedSwapAmountParams{
|
|
SwapHash: swapHash[:],
|
|
SelectedAmount: int64(amount),
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// IsStored returns true if a swap with the given hash is stored in the
|
|
// database, false otherwise.
|
|
func (s *SqlStore) IsStored(ctx context.Context, swapHash lntypes.Hash) (bool,
|
|
error) {
|
|
|
|
return s.baseDB.IsStored(ctx, swapHash[:])
|
|
}
|
|
|
|
// BatchMapDepositsToSwapHashes maps multiple deposits to their respective swap
|
|
// hashes in a single transaction.
|
|
func (s *SqlStore) BatchMapDepositsToSwapHashes(ctx context.Context,
|
|
depositsToHashes map[deposit.ID]lntypes.Hash) error {
|
|
|
|
return s.baseDB.ExecTx(ctx, loopdb.NewSqlWriteOpts(),
|
|
func(q Querier) error {
|
|
for deposit, swapHash := range depositsToHashes {
|
|
err := q.MapDepositToSwap(
|
|
ctx, sqlc.MapDepositToSwapParams{
|
|
DepositID: deposit[:],
|
|
SwapHash: swapHash[:],
|
|
},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// SwapHashesForDepositIDs retrieves the swap hashes for the given deposit IDs.
|
|
func (s *SqlStore) SwapHashesForDepositIDs(ctx context.Context,
|
|
depositIDs []deposit.ID) (map[lntypes.Hash][]deposit.ID, error) {
|
|
|
|
swapHashes := make(map[lntypes.Hash][]deposit.ID)
|
|
for _, id := range depositIDs {
|
|
swapHash, err := s.baseDB.SwapHashForDepositID(ctx, id[:])
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) ||
|
|
errors.Is(err, pgx.ErrNoRows) {
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
if swapHash == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
if len(swapHash) != lntypes.HashSize {
|
|
return nil, errors.New("invalid swap hash length")
|
|
}
|
|
|
|
swapHashParsed, err := lntypes.MakeHash(swapHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Place the deposit ID in the map under the
|
|
// corresponding swap hash.
|
|
swapHashes[swapHashParsed] = append(
|
|
swapHashes[swapHashParsed], id,
|
|
)
|
|
}
|
|
|
|
return swapHashes, nil
|
|
}
|
|
|
|
// DepositIDsForSwapHash retrieves all deposit IDs for a given swap hash.
|
|
func (s *SqlStore) DepositIDsForSwapHash(ctx context.Context,
|
|
swapHash lntypes.Hash) ([]deposit.ID, error) {
|
|
|
|
byteIDs, err := s.baseDB.DepositIDsForSwapHash(ctx, swapHash[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
depositIDs := make([]deposit.ID, len(byteIDs))
|
|
for i, id := range byteIDs {
|
|
if len(id) != deposit.IdLength {
|
|
return nil, errors.New("invalid deposit ID length")
|
|
}
|
|
copy(depositIDs[i][:], id)
|
|
}
|
|
|
|
return depositIDs, nil
|
|
}
|
|
|
|
// toStaticAddressLoopIn converts sql rows to an instant out struct.
|
|
func toStaticAddressLoopIn(_ context.Context, network *chaincfg.Params,
|
|
swap sqlc.GetStaticAddressLoopInSwapRow,
|
|
deposits []sqlc.DepositsForSwapHashRow,
|
|
updates []sqlc.StaticAddressSwapUpdate) (*StaticAddressLoopIn, error) {
|
|
|
|
swapHash, err := lntypes.MakeHash(swap.SwapHash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
swapPreImage, err := lntypes.MakePreimage(swap.Preimage)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
clientKey, err := btcec.ParsePubKey(swap.SenderScriptPubkey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
serverKey, err := btcec.ParsePubKey(swap.ReceiverScriptPubkey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var htlcTimeoutSweepTxHash *chainhash.Hash
|
|
if swap.HtlcTimeoutSweepTxID.Valid {
|
|
htlcTimeoutSweepTxHash, err = chainhash.NewHashFromStr(
|
|
swap.HtlcTimeoutSweepTxID.String,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
depositOutpoints := strings.Split(
|
|
swap.DepositOutpoints, OutpointSeparator,
|
|
)
|
|
|
|
timeoutAddressString := swap.HtlcTimeoutSweepAddress
|
|
var timeoutAddress btcutil.Address
|
|
if timeoutAddressString != "" {
|
|
timeoutAddress, err = btcutil.DecodeAddress(
|
|
timeoutAddressString, network,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
depositList := make([]*deposit.Deposit, 0, len(deposits))
|
|
for _, d := range deposits {
|
|
id := deposit.ID{}
|
|
err = id.FromByteSlice(d.DepositID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sqlcDeposit := sqlc.Deposit{
|
|
DepositID: id[:],
|
|
TxHash: d.TxHash,
|
|
Amount: d.Amount,
|
|
OutIndex: d.OutIndex,
|
|
ConfirmationHeight: d.ConfirmationHeight,
|
|
TimeoutSweepPkScript: d.TimeoutSweepPkScript,
|
|
ExpirySweepTxid: d.ExpirySweepTxid,
|
|
FinalizedWithdrawalTx: d.FinalizedWithdrawalTx,
|
|
}
|
|
|
|
sqlcDepositUpdate := sqlc.DepositUpdate{
|
|
DepositID: id[:],
|
|
UpdateState: d.UpdateState.String,
|
|
UpdateTimestamp: d.UpdateTimestamp.Time,
|
|
}
|
|
deposit, err := deposit.ToDeposit(
|
|
sqlcDeposit, sqlcDepositUpdate,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
depositList = append(depositList, deposit)
|
|
}
|
|
|
|
loopIn := &StaticAddressLoopIn{
|
|
SwapHash: swapHash,
|
|
SwapPreimage: swapPreImage,
|
|
HtlcCltvExpiry: swap.CltvExpiry,
|
|
MaxSwapFee: btcutil.Amount(swap.MaxSwapFee),
|
|
InitiationHeight: uint32(swap.InitiationHeight),
|
|
InitiationTime: swap.InitiationTime,
|
|
ProtocolVersion: version.AddressProtocolVersion(
|
|
swap.ProtocolVersion,
|
|
),
|
|
Label: swap.Label,
|
|
ClientPubkey: clientKey,
|
|
ServerPubkey: serverKey,
|
|
HtlcKeyLocator: keychain.KeyLocator{
|
|
Family: keychain.KeyFamily(swap.ClientKeyFamily),
|
|
Index: uint32(swap.ClientKeyIndex),
|
|
},
|
|
SwapInvoice: swap.SwapInvoice,
|
|
PaymentTimeoutSeconds: uint32(swap.PaymentTimeoutSeconds),
|
|
LastHop: swap.LastHop,
|
|
QuotedSwapFee: btcutil.Amount(swap.QuotedSwapFeeSatoshis),
|
|
DepositOutpoints: depositOutpoints,
|
|
SelectedAmount: btcutil.Amount(swap.SelectedAmount),
|
|
HtlcTxFeeRate: chainfee.SatPerKWeight(
|
|
swap.HtlcTxFeeRateSatKw,
|
|
),
|
|
HtlcTimeoutSweepAddress: timeoutAddress,
|
|
HtlcTimeoutSweepTxHash: htlcTimeoutSweepTxHash,
|
|
Deposits: depositList,
|
|
}
|
|
|
|
if len(updates) > 0 {
|
|
lastUpdate := updates[len(updates)-1]
|
|
loopIn.SetState(fsm.StateType(lastUpdate.UpdateState))
|
|
}
|
|
|
|
return loopIn, nil
|
|
}
|