package loopin

import (
	"context"
	"testing"
	"time"

	"github.com/btcsuite/btcd/btcutil"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	"github.com/lightninglabs/loop/loopdb"
	"github.com/lightninglabs/loop/staticaddr/deposit"
	"github.com/lightninglabs/loop/test"
	"github.com/lightningnetwork/lnd/clock"
	"github.com/lightningnetwork/lnd/lntypes"
	"github.com/stretchr/testify/require"
)

// TestGetStaticAddressLoopInSwapsByStates tests that we can retrieve
// StaticAddressLoopIn swaps by their states and that the deposits
// associated with the swaps are correctly populated.
func TestGetStaticAddressLoopInSwapsByStates(t *testing.T) {
	// Set up test context objects.
	ctxb := context.Background()
	testDb := loopdb.NewTestDB(t)
	testClock := clock.NewTestClock(time.Now())
	defer testDb.Close()

	depositStore := deposit.NewSqlStore(testDb.BaseDB)
	swapStore := NewSqlStore(
		loopdb.NewTypedStore[Querier](testDb), testClock,
		&chaincfg.RegressionNetParams,
	)

	newID := func() deposit.ID {
		did, err := deposit.GetRandomDepositID()
		require.NoError(t, err)

		return did
	}

	loopingDepositID := newID()
	timeoutDepositID := newID()
	loopedInDepositID := newID()
	failedDepositID := newID()
	d1, d2, d3, d4 := &deposit.Deposit{
		ID: loopingDepositID,
		OutPoint: wire.OutPoint{
			Hash:  chainhash.Hash{0x1a, 0x2b, 0x3c, 0x4d},
			Index: 0,
		},
		Value: btcutil.Amount(100_000),
		TimeOutSweepPkScript: []byte{
			0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x41,
		},
	},
		&deposit.Deposit{
			ID: timeoutDepositID,
			OutPoint: wire.OutPoint{
				Hash:  chainhash.Hash{0x2a, 0x2b, 0x3c, 0x4e},
				Index: 1,
			},
			Value: btcutil.Amount(200_000),
			TimeOutSweepPkScript: []byte{
				0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x4d,
			},
		},
		&deposit.Deposit{
			ID: loopedInDepositID,
			OutPoint: wire.OutPoint{
				Hash:  chainhash.Hash{0x3a, 0x2b, 0x3c, 0x4e},
				Index: 2,
			},
			Value: btcutil.Amount(300_000),
			TimeOutSweepPkScript: []byte{
				0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x4f,
			},
		},
		&deposit.Deposit{
			ID: failedDepositID,
			OutPoint: wire.OutPoint{
				Hash:  chainhash.Hash{0x4a, 0x2b, 0x3c, 0x4e},
				Index: 3,
			},
			Value: btcutil.Amount(400_000),
			TimeOutSweepPkScript: []byte{
				0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x50,
			},
		}

	err := depositStore.CreateDeposit(ctxb, d1)
	require.NoError(t, err)
	err = depositStore.CreateDeposit(ctxb, d2)
	require.NoError(t, err)
	err = depositStore.CreateDeposit(ctxb, d3)
	require.NoError(t, err)
	err = depositStore.CreateDeposit(ctxb, d4)
	require.NoError(t, err)

	// Add two updates per deposit, expect the last to be retrieved.
	d1.SetState(deposit.Deposited)
	d2.SetState(deposit.Deposited)
	d3.SetState(deposit.Deposited)
	d4.SetState(deposit.Deposited)

	err = depositStore.UpdateDeposit(ctxb, d1)
	require.NoError(t, err)
	err = depositStore.UpdateDeposit(ctxb, d2)
	require.NoError(t, err)
	err = depositStore.UpdateDeposit(ctxb, d3)
	require.NoError(t, err)
	err = depositStore.UpdateDeposit(ctxb, d4)
	require.NoError(t, err)

	d1.SetState(deposit.LoopingIn)
	d2.SetState(deposit.HtlcTimeoutSwept)
	d3.SetState(deposit.LoopedIn)
	d4.SetState(deposit.Deposited)

	err = depositStore.UpdateDeposit(ctxb, d1)
	require.NoError(t, err)
	err = depositStore.UpdateDeposit(ctxb, d2)
	require.NoError(t, err)
	err = depositStore.UpdateDeposit(ctxb, d3)
	require.NoError(t, err)
	err = depositStore.UpdateDeposit(ctxb, d4)
	require.NoError(t, err)

	_, clientPubKey := test.CreateKey(1)
	_, serverPubKey := test.CreateKey(2)
	addr, err := btcutil.DecodeAddress(P2wkhAddr, nil)
	require.NoError(t, err)

	// Create pending swap.
	swapHashPending := lntypes.Hash{0x1, 0x2, 0x3, 0x4}
	swapPending := StaticAddressLoopIn{
		SwapHash:                swapHashPending,
		SwapPreimage:            lntypes.Preimage{0x1, 0x2, 0x3, 0x4},
		DepositOutpoints:        []string{d1.OutPoint.String()},
		Deposits:                []*deposit.Deposit{d1},
		ClientPubkey:            clientPubKey,
		ServerPubkey:            serverPubKey,
		HtlcTimeoutSweepAddress: addr,
	}
	swapPending.SetState(SignHtlcTx)

	err = swapStore.CreateLoopIn(ctxb, &swapPending)
	require.NoError(t, err)

	// Create htlc-timeout-swept swap. HtlcTimeoutSwept is the first final
	// state, so this exercises the state-list query boundary.
	swapHashTimeoutSwept := lntypes.Hash{0x4, 0x2, 0x3, 0x5}
	swapTimeoutSwept := StaticAddressLoopIn{
		SwapHash:                swapHashTimeoutSwept,
		SwapPreimage:            lntypes.Preimage{0x4, 0x2, 0x3, 0x5},
		DepositOutpoints:        []string{d2.OutPoint.String()},
		Deposits:                []*deposit.Deposit{d2},
		ClientPubkey:            clientPubKey,
		ServerPubkey:            serverPubKey,
		HtlcTimeoutSweepAddress: addr,
	}
	swapTimeoutSwept.SetState(HtlcTimeoutSwept)

	err = swapStore.CreateLoopIn(ctxb, &swapTimeoutSwept)
	require.NoError(t, err)

	// Create succeeded swap.
	swapHashSucceeded := lntypes.Hash{0x2, 0x2, 0x3, 0x5}
	swapSucceeded := StaticAddressLoopIn{
		SwapHash:                swapHashSucceeded,
		SwapPreimage:            lntypes.Preimage{0x2, 0x2, 0x3, 0x5},
		DepositOutpoints:        []string{d3.OutPoint.String()},
		Deposits:                []*deposit.Deposit{d3},
		ClientPubkey:            clientPubKey,
		ServerPubkey:            serverPubKey,
		HtlcTimeoutSweepAddress: addr,
	}
	swapSucceeded.SetState(Succeeded)

	err = swapStore.CreateLoopIn(ctxb, &swapSucceeded)
	require.NoError(t, err)

	// Create failed swap. Failed is the last final state, so this
	// exercises the state-list query boundary.
	swapHashFailed := lntypes.Hash{0x3, 0x2, 0x3, 0x5}
	swapFailed := StaticAddressLoopIn{
		SwapHash:                swapHashFailed,
		SwapPreimage:            lntypes.Preimage{0x3, 0x2, 0x3, 0x5},
		DepositOutpoints:        []string{d4.OutPoint.String()},
		Deposits:                []*deposit.Deposit{d4},
		ClientPubkey:            clientPubKey,
		ServerPubkey:            serverPubKey,
		HtlcTimeoutSweepAddress: addr,
	}
	swapFailed.SetState(Failed)

	err = swapStore.CreateLoopIn(ctxb, &swapFailed)
	require.NoError(t, err)

	pendingSwaps, err := swapStore.GetStaticAddressLoopInSwapsByStates(ctxb, PendingStates)
	require.NoError(t, err)

	require.Len(t, pendingSwaps, 1)
	require.Equal(t, swapHashPending, pendingSwaps[0].SwapHash)
	require.Equal(t, []string{d1.OutPoint.String()}, pendingSwaps[0].DepositOutpoints)
	require.Equal(t, SignHtlcTx, pendingSwaps[0].GetState())

	pendingDeposits := pendingSwaps[0].Deposits
	require.Len(t, pendingDeposits, 1)
	require.Equal(t, d1.ID, pendingDeposits[0].ID)
	require.Equal(t, d1.OutPoint, pendingDeposits[0].OutPoint)
	require.Equal(t, d1.Value, pendingDeposits[0].Value)
	require.Equal(t, deposit.LoopingIn, pendingDeposits[0].GetState())

	finalizedSwaps, err := swapStore.GetStaticAddressLoopInSwapsByStates(ctxb, FinalStates)
	require.NoError(t, err)

	require.Len(t, finalizedSwaps, 3)
	finalizedByState := make(map[string]*StaticAddressLoopIn)
	for _, swap := range finalizedSwaps {
		finalizedByState[string(swap.GetState())] = swap
	}

	timeoutSweptSwap := finalizedByState[string(HtlcTimeoutSwept)]
	require.NotNil(t, timeoutSweptSwap)
	require.Equal(t, swapHashTimeoutSwept, timeoutSweptSwap.SwapHash)
	require.Equal(t, HtlcTimeoutSwept, timeoutSweptSwap.GetState())

	succeededSwap := finalizedByState[string(Succeeded)]
	require.NotNil(t, succeededSwap)
	require.Equal(t, swapHashSucceeded, succeededSwap.SwapHash)
	require.Equal(t, []string{d3.OutPoint.String()}, succeededSwap.DepositOutpoints)
	require.Equal(t, Succeeded, succeededSwap.GetState())

	failedSwap := finalizedByState[string(Failed)]
	require.NotNil(t, failedSwap)
	require.Equal(t, swapHashFailed, failedSwap.SwapHash)
	require.Equal(t, Failed, failedSwap.GetState())

	finalizedDeposits := succeededSwap.Deposits
	require.Len(t, finalizedDeposits, 1)
	require.Equal(t, d3.ID, finalizedDeposits[0].ID)
	require.Equal(t, d3.OutPoint, finalizedDeposits[0].OutPoint)
	require.Equal(t, d3.Value, finalizedDeposits[0].Value)
	require.Equal(t, deposit.LoopedIn, finalizedDeposits[0].GetState())
}

// TestCreateLoopIn tests that CreateLoopIn correctly creates a new
// StaticAddressLoopIn swap and associates it with the provided deposits.
func TestCreateLoopIn(t *testing.T) {
	// Set up test context objects.
	ctx := t.Context()
	testDb := loopdb.NewTestDB(t)
	createTime := time.Unix(1_717_171_717, 123_456_789).UTC()
	expectedCreateTime := createTime.Truncate(time.Microsecond)
	testClock := clock.NewTestClock(createTime)
	defer testDb.Close()

	depositStore := deposit.NewSqlStore(testDb.BaseDB)
	swapStore := NewSqlStore(
		loopdb.NewTypedStore[Querier](testDb), testClock,
		&chaincfg.RegressionNetParams,
	)

	newID := func() deposit.ID {
		did, err := deposit.GetRandomDepositID()
		require.NoError(t, err)

		return did
	}

	d1, d2 := &deposit.Deposit{
		ID: newID(),
		OutPoint: wire.OutPoint{
			Hash:  chainhash.Hash{0x1a, 0x2b, 0x3c, 0x4d},
			Index: 0,
		},
		Value: btcutil.Amount(100_000),
		TimeOutSweepPkScript: []byte{
			0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x41,
		},
	},
		&deposit.Deposit{
			ID: newID(),
			OutPoint: wire.OutPoint{
				Hash:  chainhash.Hash{0x2a, 0x2b, 0x3c, 0x4e},
				Index: 1,
			},
			Value: btcutil.Amount(200_000),
			TimeOutSweepPkScript: []byte{
				0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x4d,
			},
		}

	err := depositStore.CreateDeposit(ctx, d1)
	require.NoError(t, err)
	err = depositStore.CreateDeposit(ctx, d2)
	require.NoError(t, err)

	d1.SetState(deposit.LoopingIn)
	d2.SetState(deposit.LoopingIn)

	err = depositStore.UpdateDeposit(ctx, d1)
	require.NoError(t, err)
	err = depositStore.UpdateDeposit(ctx, d2)
	require.NoError(t, err)

	_, clientPubKey := test.CreateKey(1)
	_, serverPubKey := test.CreateKey(2)
	addr, err := btcutil.DecodeAddress(P2wkhAddr, nil)
	require.NoError(t, err)

	// Create pending swap.
	swapHashPending := lntypes.Hash{0x1, 0x2, 0x3, 0x4}
	swapPending := StaticAddressLoopIn{
		SwapHash:     swapHashPending,
		SwapPreimage: lntypes.Preimage{0x1, 0x2, 0x3, 0x4},
		DepositOutpoints: []string{d1.OutPoint.String(),
			d2.OutPoint.String()},
		Deposits:                []*deposit.Deposit{d1, d2},
		ClientPubkey:            clientPubKey,
		ServerPubkey:            serverPubKey,
		HtlcTimeoutSweepAddress: addr,
	}
	swapPending.SetState(SignHtlcTx)

	err = swapStore.CreateLoopIn(ctx, &swapPending)
	require.NoError(t, err)
	require.Equal(t, expectedCreateTime, swapPending.LastUpdateTime)

	depositIDs, err := swapStore.DepositIDsForSwapHash(
		ctx, swapHashPending,
	)
	require.NoError(t, err)
	require.Len(t, depositIDs, 2)
	require.Contains(t, depositIDs, d1.ID)
	require.Contains(t, depositIDs, d2.ID)

	swapHashes, err := swapStore.SwapHashesForDepositIDs(
		ctx, []deposit.ID{depositIDs[0], depositIDs[1]},
	)
	require.NoError(t, err)
	require.Len(t, swapHashes, 1)
	require.Len(t, swapHashes[swapHashPending], 2)
	require.Contains(t, swapHashes[swapHashPending], depositIDs[0])
	require.Contains(t, swapHashes[swapHashPending], depositIDs[1])

	swap, err := swapStore.GetLoopInByHash(ctx, swapHashPending)
	require.NoError(t, err)
	require.Equal(t, swapHashPending, swap.SwapHash)
	require.Equal(t, []string{d1.OutPoint.String(), d2.OutPoint.String()},
		swap.DepositOutpoints)
	require.Equal(t, SignHtlcTx, swap.GetState())
	require.Equal(t, swapPending.LastUpdateTime, swap.LastUpdateTime)
	require.Equal(
		t, ConfirmationRiskDecisionNone,
		swap.ConfirmationRiskDecision,
	)

	decisionTime := time.Unix(123, 0).UTC()
	testClock.SetTime(decisionTime)
	err = swapStore.RecordStaticAddressRiskDecision(
		ctx, swapHashPending, ConfirmationRiskDecisionAccepted,
	)
	require.NoError(t, err)

	swap, err = swapStore.GetLoopInByHash(ctx, swapHashPending)
	require.NoError(t, err)
	require.Equal(
		t, ConfirmationRiskDecisionAccepted,
		swap.ConfirmationRiskDecision,
	)
	require.True(t, swap.ConfirmationRiskDecisionTime.Equal(decisionTime))

	// Replaying the same decision must retain its original deadline anchor.
	laterDecisionTime := decisionTime.Add(time.Hour)
	testClock.SetTime(laterDecisionTime)
	err = swapStore.RecordStaticAddressRiskDecision(
		ctx, swapHashPending, ConfirmationRiskDecisionAccepted,
	)
	require.NoError(t, err)

	swap, err = swapStore.GetLoopInByHash(ctx, swapHashPending)
	require.NoError(t, err)
	require.Equal(
		t, ConfirmationRiskDecisionAccepted,
		swap.ConfirmationRiskDecision,
	)
	require.True(t, swap.ConfirmationRiskDecisionTime.Equal(decisionTime))

	// A different decision is a new event and receives a new timestamp.
	rejectedDecisionTime := laterDecisionTime.Add(time.Hour)
	testClock.SetTime(rejectedDecisionTime)
	err = swapStore.RecordStaticAddressRiskDecision(
		ctx, swapHashPending, ConfirmationRiskDecisionRejected,
	)
	require.NoError(t, err)

	swap, err = swapStore.GetLoopInByHash(ctx, swapHashPending)
	require.NoError(t, err)
	require.Equal(
		t, ConfirmationRiskDecisionRejected,
		swap.ConfirmationRiskDecision,
	)
	require.True(t, swap.ConfirmationRiskDecisionTime.Equal(
		rejectedDecisionTime,
	))

	// Rejected is terminal: a racing synthetic acceptance must not replace
	// the server's rejection or move its deadline anchor.
	testClock.SetTime(rejectedDecisionTime.Add(time.Hour))
	err = swapStore.RecordStaticAddressRiskDecision(
		ctx, swapHashPending, ConfirmationRiskDecisionAccepted,
	)
	require.NoError(t, err)

	swap, err = swapStore.GetLoopInByHash(ctx, swapHashPending)
	require.NoError(t, err)
	require.Equal(
		t, ConfirmationRiskDecisionRejected,
		swap.ConfirmationRiskDecision,
	)
	require.True(t, swap.ConfirmationRiskDecisionTime.Equal(
		rejectedDecisionTime,
	))

	err = swapStore.RecordStaticAddressRiskDecision(
		ctx, lntypes.Hash{0x9, 0x9, 0x9},
		ConfirmationRiskDecisionRejected,
	)
	require.ErrorIs(t, err, ErrLoopInNotFound)

	require.Len(t, swap.Deposits, 2)

	require.Equal(t, d1.ID, swap.Deposits[0].ID)
	require.Equal(t, d1.OutPoint, swap.Deposits[0].OutPoint)
	require.Equal(t, d1.Value, swap.Deposits[0].Value)
	require.Equal(t, deposit.LoopingIn, swap.Deposits[0].GetState())

	require.Equal(t, d2.ID, swap.Deposits[1].ID)
	require.Equal(t, d2.OutPoint, swap.Deposits[1].OutPoint)
	require.Equal(t, d2.Value, swap.Deposits[1].Value)
	require.Equal(t, deposit.LoopingIn, swap.Deposits[1].GetState())

	updateTime := testClock.Now().Add(time.Minute)
	testClock.SetTime(updateTime)
	swapPending.SetState(Succeeded)

	err = swapStore.UpdateLoopIn(ctx, &swapPending)
	require.NoError(t, err)
	require.Equal(
		t, updateTime.Truncate(time.Microsecond),
		swapPending.LastUpdateTime,
	)

	swap, err = swapStore.GetLoopInByHash(ctx, swapHashPending)
	require.NoError(t, err)
	require.Equal(t, Succeeded, swap.GetState())
	require.Equal(t, swapPending.LastUpdateTime, swap.LastUpdateTime)
}

// TestGetLoopInByHashOrdersDepositsBySnapshot ensures recovered deposits are
// ordered by the stored swap input snapshot, which is the signing order shared
// with the server.
func TestGetLoopInByHashOrdersDepositsBySnapshot(t *testing.T) {
	ctx := context.Background()
	testDb := loopdb.NewTestDB(t)
	testClock := clock.NewTestClock(time.Now())
	defer testDb.Close()

	depositStore := deposit.NewSqlStore(testDb.BaseDB)
	swapStore := NewSqlStore(
		loopdb.NewTypedStore[Querier](testDb), testClock,
		&chaincfg.RegressionNetParams,
	)

	newID := func() deposit.ID {
		did, err := deposit.GetRandomDepositID()
		require.NoError(t, err)

		return did
	}

	d1 := &deposit.Deposit{
		ID: newID(),
		OutPoint: wire.OutPoint{
			Hash:  chainhash.Hash{0x11},
			Index: 0,
		},
		Value: 100_000,
		TimeOutSweepPkScript: []byte{
			0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x41,
		},
	}
	d2 := &deposit.Deposit{
		ID: newID(),
		OutPoint: wire.OutPoint{
			Hash:  chainhash.Hash{0x22},
			Index: 1,
		},
		Value: 200_000,
		TimeOutSweepPkScript: []byte{
			0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x4d,
		},
	}

	require.NoError(t, depositStore.CreateDeposit(ctx, d1))
	require.NoError(t, depositStore.CreateDeposit(ctx, d2))

	d1.SetState(deposit.LoopingIn)
	d2.SetState(deposit.LoopingIn)
	require.NoError(t, depositStore.UpdateDeposit(ctx, d1))
	require.NoError(t, depositStore.UpdateDeposit(ctx, d2))

	_, clientPubKey := test.CreateKey(1)
	_, serverPubKey := test.CreateKey(2)
	addr, err := btcutil.DecodeAddress(P2wkhAddr, nil)
	require.NoError(t, err)

	swapHash := lntypes.Hash{0x1, 0x2, 0x3, 0x4}
	swap := StaticAddressLoopIn{
		SwapHash:     swapHash,
		SwapPreimage: lntypes.Preimage{0x1, 0x2, 0x3, 0x4},
		DepositOutpoints: []string{
			d2.OutPoint.String(), d1.OutPoint.String(),
		},
		Deposits:                []*deposit.Deposit{d2, d1},
		ClientPubkey:            clientPubKey,
		ServerPubkey:            serverPubKey,
		HtlcTimeoutSweepAddress: addr,
	}
	swap.SetState(SignHtlcTx)

	require.NoError(t, swapStore.CreateLoopIn(ctx, &swap))

	storedSwap, err := swapStore.GetLoopInByHash(ctx, swapHash)
	require.NoError(t, err)
	require.Equal(t, []string{
		d2.OutPoint.String(), d1.OutPoint.String(),
	}, storedSwap.DepositOutpoints)
	require.Len(t, storedSwap.Deposits, 2)
	require.Equal(t, d2.ID, storedSwap.Deposits[0].ID)
	require.Equal(t, d1.ID, storedSwap.Deposits[1].ID)
}

// TestGetLoopInByHashPreservesStoredDepositOutpoints ensures recovered loop-ins
// keep the original outpoint snapshot stored when the swap was created.
func TestGetLoopInByHashPreservesStoredDepositOutpoints(t *testing.T) {
	ctxb := context.Background()
	testDb := loopdb.NewTestDB(t)
	testClock := clock.NewTestClock(time.Now())
	defer testDb.Close()

	depositStore := deposit.NewSqlStore(testDb.BaseDB)
	swapStore := NewSqlStore(
		loopdb.NewTypedStore[Querier](testDb), testClock,
		&chaincfg.RegressionNetParams,
	)

	depositID, err := deposit.GetRandomDepositID()
	require.NoError(t, err)

	oldOutpoint := wire.OutPoint{
		Hash:  chainhash.Hash{0x1a, 0x2b, 0x3c, 0x4d},
		Index: 0,
	}
	currentOutpoint := wire.OutPoint{
		Hash:  chainhash.Hash{0x5a, 0x6b, 0x7c, 0x8d},
		Index: 1,
	}

	d := &deposit.Deposit{
		ID:       depositID,
		OutPoint: oldOutpoint,
		Value:    btcutil.Amount(100_000),
		TimeOutSweepPkScript: []byte{
			0x00, 0x14, 0x1a, 0x2b, 0x3c, 0x41,
		},
	}
	require.NoError(t, depositStore.CreateDeposit(ctxb, d))

	d.SetState(deposit.LoopingIn)
	require.NoError(t, depositStore.UpdateDeposit(ctxb, d))

	_, clientPubKey := test.CreateKey(1)
	_, serverPubKey := test.CreateKey(2)
	addr, err := btcutil.DecodeAddress(P2wkhAddr, nil)
	require.NoError(t, err)

	swapHash := lntypes.Hash{0x1, 0x2, 0x3, 0x4}
	swap := StaticAddressLoopIn{
		SwapHash:                swapHash,
		SwapPreimage:            lntypes.Preimage{0x1, 0x2, 0x3, 0x4},
		DepositOutpoints:        []string{oldOutpoint.String()},
		Deposits:                []*deposit.Deposit{d},
		ClientPubkey:            clientPubKey,
		ServerPubkey:            serverPubKey,
		HtlcTimeoutSweepAddress: addr,
	}
	swap.SetState(SignHtlcTx)

	require.NoError(t, swapStore.CreateLoopIn(ctxb, &swap))

	d.OutPoint = currentOutpoint
	d.ConfirmationHeight = 42
	require.NoError(t, depositStore.UpdateDeposit(ctxb, d))

	storedSwap, err := swapStore.GetLoopInByHash(ctxb, swapHash)
	require.NoError(t, err)
	require.Equal(
		t, []string{oldOutpoint.String()},
		storedSwap.DepositOutpoints,
	)
	require.Len(t, storedSwap.Deposits, 1)
	require.Equal(t, currentOutpoint, storedSwap.Deposits[0].OutPoint)
	require.Equal(t, int64(42), storedSwap.Deposits[0].ConfirmationHeight)
}
