Skip to content

Commit d3a2bad

Browse files
committed
loopd: filter unavailable deposits in ListUnspentDeposits
ListUnspentRaw returns the unspent wallet view of the backing lnd wallet. It might be that deposits show up there that are actually not spendable because they already have been used but not yet spent by the server. We filter out such deposits in ListUnspentDeposits.
1 parent 70cf2d8 commit d3a2bad

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

loopd/swapclient_server.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1546,9 +1546,65 @@ func (s *swapClientServer) ListUnspentDeposits(ctx context.Context,
15461546
return nil, err
15471547
}
15481548

1549-
// Prepare the list response.
1549+
// ListUnspentRaw returns the unspent wallet view of the backing lnd
1550+
// wallet. It might be that deposits show up there that are actually
1551+
// not spendable because they already have been used but not yet spent
1552+
// by the server. We filter out such deposits here.
1553+
var (
1554+
outpoints []string
1555+
isUnspent = make(map[wire.OutPoint]struct{})
1556+
)
1557+
1558+
// Keep track of confirmed outpoints that we need to check against our
1559+
// database.
1560+
confirmedToCheck := make(map[wire.OutPoint]struct{})
1561+
1562+
for _, utxo := range utxos {
1563+
if utxo.Confirmations < deposit.MinConfs {
1564+
// Unconfirmed deposits are always available.
1565+
isUnspent[utxo.OutPoint] = struct{}{}
1566+
} else {
1567+
// Confirmed deposits need to be checked.
1568+
outpoints = append(outpoints, utxo.OutPoint.String())
1569+
confirmedToCheck[utxo.OutPoint] = struct{}{}
1570+
}
1571+
}
1572+
1573+
// Check the spent status of the deposits by looking at their states.
1574+
deposits, err := s.depositManager.DepositsForOutpoints(ctx, outpoints)
1575+
if err != nil {
1576+
return nil, err
1577+
}
1578+
for _, d := range deposits {
1579+
// A nil deposit means we don't have a record for it. We'll
1580+
// handle this case after the loop.
1581+
if d == nil {
1582+
continue
1583+
}
1584+
1585+
// If the deposit is in the "Deposited" state, it's available.
1586+
if d.IsInState(deposit.Deposited) {
1587+
isUnspent[d.OutPoint] = struct{}{}
1588+
}
1589+
1590+
// We have a record for this deposit, so we no longer need to
1591+
// check it.
1592+
delete(confirmedToCheck, d.OutPoint)
1593+
}
1594+
1595+
// Any remaining outpoints in confirmedToCheck are ones that lnd knows
1596+
// about but we don't. These are new, unspent deposits.
1597+
for op := range confirmedToCheck {
1598+
isUnspent[op] = struct{}{}
1599+
}
1600+
1601+
// Prepare the list of unspent deposits for the rpc response.
15501602
var respUtxos []*looprpc.Utxo
15511603
for _, u := range utxos {
1604+
if _, ok := isUnspent[u.OutPoint]; !ok {
1605+
continue
1606+
}
1607+
15521608
utxo := &looprpc.Utxo{
15531609
StaticAddress: staticAddress.String(),
15541610
AmountSat: int64(u.Value),

0 commit comments

Comments
 (0)