Check the originally selected deposit outpoints before signing a static
loop-in HTLC transaction. If any selected outpoint is no longer
available, cancel the swap invoice and fail the signing action instead
of producing signatures for stale inputs.
Wire the lnd-backed checker through loopd and make invoice-monitoring
handle closed subscription channels without spinning.
Add a TxOutChecker interface for testing whether an original deposit
outpoint is still available before a static loop-in signs its HTLC
transaction.
Implement the checker using lnd's wallet transaction view so wallet-known
spends, including mempool spends when requested, cause the outpoint to be
reported unavailable.
Store an independent snapshot of the deposit outpoints selected for a
static loop-in. This keeps recovered swaps tied to the original funding
outputs even if the deposit records later reflect replacement or
confirmation changes.
Avoid recovering an empty database outpoint string as a synthetic
outpoint entry, and cover recovery of the stored snapshot separately
from the current deposit metadata.
Treat lnd wallet view as the source of spendable static-address
outputs while keeping historical deposit records in the DB. Reconcile
active FSMs against the current wallet view and reactivate known
deposits when their outpoints are visible again.
Refresh deposits before selection, withdrawal, loop-in, and channel-open
paths, and filter list and summary responses through the live active set
so stale Deposited records are not exposed as available funds.
Treat unconfirmed static-address deposits as swappable because their CSV
timeout has not started yet. Keep confirmed deposits ahead of
unconfirmed ones during automatic selection, then sort by value and
remaining lifetime within each confirmation group.
Share the expiry calculation with the dynamic-programming selector so
unconfirmed deposits do not look like the earliest-expiring candidates.
Log the static address loop-in HTLC weight, fee rates, computed fees, and configured fee caps before fee validation. This keeps the existing fee guard behavior intact while making validation failures easier to diagnose.
The final-state query previously formatted the state list with braces, which broke the comma-delimited match for both boundary entries: the first state was compared with a leading brace and the last state with a trailing brace. Final-state callers need swaps at both ends of the list, including HtlcTimeoutSwept and Failed, to remain visible once they reach a terminal status.
Return the final-state list as plain comma-separated state names, update the store comment to match the query format, and extend the store test so it inserts and retrieves swaps in the first final state, a middle final state, and the last final state without relying on result order.
A static address loop-in that creates an invoice but then fails before storage cannot be recovered after restart, and persisted error paths that unlock deposits should not leave the swap invoice live either. The payment-deadline path also needs to report the real deposit unlock error instead of checking the FSM event returned by UnlockDepositsAction, because that action returns OnError on both success and failure.
Cancel private swap invoices on pre-storage init failures, monitor timeouts, and stored unlock paths using a detached timeout-limited helper. Factor deposit unlocking into an error-returning helper so deadline handling can log transition failures, and add coverage for early-init cancellation plus generic unlock invoice cleanup and error propagation.
lndclient now forwards route hints through AddInvoice. These tests
assert that Loop preserves explicit hints on generated loop-in invoices.
Remove stale comments that described the old wrapper behavior as
dropping hints.
Server-supplied nonces and partial signatures are consumed by the static address loop-in and withdrawal MuSig2 signing paths. Reject nil signing info, wrong nonce lengths, and wrong partial signature lengths before registering nonces or combining signatures, so malformed responses cannot be silently zero-padded into signing attempts.
Add withdrawal coverage for nil and malformed server signing data.
Replace the recursive full-deposit autoloop selector with a bounded-memory
DP implementation in staticaddr/loopin/autoloop_dp.go. The new selector
keeps the existing no-change semantics, first finds the best reachable
total, then applies the 25 percent band rule so earlier-expiring deposits
can win inside that near-optimal range.
The DP table is capped at 128 MiB and keeps exact satoshi sums alongside
compressed bucket weights, so planning stays memory-bounded without
allowing oversized candidates. The compressed weighting now rounds down
with a minimum of one bucket, which avoids rejecting valid sums after
multiple per-deposit rounding steps while leaving the exact-sum check
as the real safety boundary.
Teach the liquidity manager to include persisted static loop-ins
in budget accounting, in-flight limits, and peer traffic backoff.
This adds the static fee model used for conservative accounting
and passes storage errors through the relevant planner helpers.
The daemon wiring now exposes static loop-ins to liquidity so the
manager can see the same ongoing swaps that the static-address
subsystem persists, while easy autoloop keeps working with the new
fallible traffic lookup path.
Add the static-address helper that prepares full-deposit autoloop loop-ins
without dispatching them. The helper selects no-change deposit sets, records
explicit outpoints, and quotes the exact selected amount before the planner
tries to dispatch anything.
The tests cover the full-deposit selector, the quoted request construction,
and excluded outpoint handling so later liquidity work can rely on a stable
preparation surface.
Move static loop-in label validation to the rpc boundary and
remove the same check from the internal manager path.
This keeps external requests aligned with the existing swap rpc
surface while allowing internal autoloop callers to keep using
reserved labels for automated swaps. The tests cover both sides of
that contract: rpc requests still reject reserved labels, and the
manager path accepts them.
The Parameters struct describes the keys, expiry and pkScript that
define the static address script, so its natural home is the script
package. Moving it there lets staticutil drop its dependency on the
address package and lets callers reuse a single type alongside
script.StaticAddress and script.NewStaticAddress.
No behavior change.
Closes#1056
Reduce MinConfs from 6 to 3 to allow faster swap attempts while the
server enforces risk-based confirmation requirements. Update
SelectDeposits to prioritize more-confirmed deposits first, increasing
the likelihood of server acceptance. Add client-side logging of
insufficient confirmation details from server error responses.
Remove unused errChan fields from the loopin, openchannel, and withdraw
managers. These channels were declared and initialized but never read
from or written to.
Remove the unused activeLoopIns map from the loopin manager. The map
was only written to but never read, making it dead code.
Remove the stale withdraw.Store interface whose method signatures no
longer match the concrete SqlStore API used by the manager.
Remove unused config fields from openchannel.Config (Server,
AddressManager, ChainNotifier, Signer) and deposit.ManagerConfig
(AddressClient, SwapClient, ChainParams) along with their daemon
wiring. Also remove the now-orphaned openchannel.AddressManager
interface.
Remove the unused GetStaticAddress and Close methods from
address.SqlStore and the GetStaticAddress method from the address.Store
interface, as the codebase only uses GetAllStaticAddresses.
recoverLoopIns wrote to the activeLoopIns map from inside a goroutine
without any synchronization. The map is shared state accessed from
the manager's main Run loop, creating a data race.
Move the map write before the goroutine spawn so it happens
synchronously during recovery. Also fix the stale log message that
said "OnStart" instead of "OnRecover".
SweepHtlcTimeoutAction used a select with a default case containing a
blocking time.After. When the context was canceled, it logged the error
but continued the retry loop instead of returning. The default case
also meant that ctx.Done was only checked when it was already signaled,
while an hour-long sleep blocked without listening for cancellation.
Replace the default+time.After pattern with a proper select on both
ctx.Done and time.After so the function exits promptly on shutdown.
createHtlcTx always places the HTLC output at index 0 and the change
output (if any) at index 1. Previously, createHtlcSweepTx attempted to
dynamically find the HTLC index but then unconditionally read
TxOut[0].Value, ignoring the computed index.
Replace the dynamic search with a const htlcInputIndex=0 and a fail-fast
check that errors if the layout invariant is ever violated. Add a test
that verifies the sweep value is derived from the HTLC output, not the
change output.
- reset htlcConfirmed when the HTLC conf subscription errors and we re-register
- add regression test ensuring re-registers after a conf error require a fresh
confirmation instead of sweeping on a stale one
Loop now guards all static-address managers against zero block heights: each
constructor returns an error when invoked with a non-positive current height,
and `loopd` validates the height from `GetInfo` before instantiating them.
Tests and helper code were updated accordingly so we fail fast instead of
registering chain notifications with invalid hints.
In this commit we add a new function SelectDeposits
to the loop-in manager. It coin-selects deposits that
meet an arbitrary swap amount provided by the client.
We have to ensure that the server creates the correct
change outputs for the htlc- and sweepless sweep
transactions.
since deposits have been normalized in the db in the
context of a static address swap this commit now
retrieves the deposit information as part of
GetLoopInByHash and GetStaticAddressLoopInSwapsByStates.