Compare commits

..

136 commits

Author SHA1 Message Date
Slyghtning
6d1dbcb599
Merge pull request #1194 from hieblmi/instantout-fixes
Some checks failed
CI / Commit Message (push) Has been cancelled
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
instantout: improve reservation and swap handling
2026-08-12 10:55:24 +02:00
Slyghtning
f826260266
docs: document instant out reliability improvements
Record the Instant Out and reservation validation, recovery,
fee-limit, lifecycle, and custom macaroon updates in the next release
notes.
2026-08-11 21:27:36 +02:00
Slyghtning
e772f8ccfa
instantout: enforce the accepted swap fee
Carry the accepted quote into each request, persist it, and reject
invoices above that limit. Preserve compatibility for requests that
omit the cap while distinguishing an explicit zero.
2026-08-11 21:27:35 +02:00
Slyghtning
b596eabab3
instantout: recheck reservation timing during recovery
Refresh the chain height when a swap resumes, verify both the
reservation and HTLC windows, and select the HTLC path when either
remaining window is too short.
2026-08-11 21:27:35 +02:00
Slyghtning
b689e361c1
instantout: close unfinished MuSig2 sessions
Clean up abandoned signing sessions on error paths while leaving
completed sessions to lnd.
2026-08-11 21:27:35 +02:00
Slyghtning
6853e69a05
instantout: verify finalized MuSig2 witnesses
Run script validation for every combined signature before accepting a
finalized transaction, surfacing invalid witnesses immediately.
2026-08-11 21:27:35 +02:00
Slyghtning
b3776e92f4
instantout: validate MuSig2 response dimensions
Check nonce, signature, session, and transaction input counts before
indexing signing vectors, returning clear errors for incomplete data.
2026-08-11 21:27:34 +02:00
Slyghtning
51eb8f410a
reservation: validate confirmed output amounts
Compare each confirmed transaction output with the expected reservation
amount before advancing the state machine.
2026-08-11 21:27:34 +02:00
Slyghtning
c75d7e3e81
reservation: bound and prune active state machines
Limit newly accepted reservation state machines, resume all persisted
reservations, remove terminal entries from memory, and make cleanup
resilient to observer-driven eviction.
2026-08-11 21:27:34 +02:00
Slyghtning
41b884f610
reservation: reject duplicate reservation entries
Check active and persisted reservations before creating a new state
machine, preserving the existing reservation when a duplicate arrives.
2026-08-11 21:21:53 +02:00
Slyghtning
2989ceee42
reservation: isolate asynchronous initialization errors
Use a goroutine-local result for event dispatch so observer errors
remain independent and initialization outcomes stay deterministic.
2026-08-11 21:21:53 +02:00
Slyghtning
806c1f9356
reservation: keep processing after notification errors
Log individual reservation initialization failures and continue
consuming later notifications instead of stopping the manager.
2026-08-11 21:21:53 +02:00
Slyghtning
7cab89d45b
looprpc: align instant out permissions with loop out
Apply the loop:out permission to Instant Out and reservation RPCs so
their authorization requirements match the rest of the Loop Out API.
2026-08-11 21:21:52 +02:00
Boris Nagaev
aa79fa5262
Merge pull request #1193 from starius/loop-out-validation-reserves
loopd: account for channel reserves in loop out validation
2026-08-11 10:07:26 -05:00
Boris Nagaev
95e184a40f
loopd: account for channel reserves in loop out validation
Use each channel's local balance minus its reserve when simulating Loop
Out payment bandwidth, clamping the result at zero. This prevents swaps
from starting when the gross balance covers the amount and routing fee
but the spendable balance does not.

Add one-sat boundary tests and a bug-fix release note. Leave a TODO for
server-fee and prepay capacity because enforcing their maximum fee caps
could reject viable swaps whose actual routing fees are lower.
2026-08-10 18:48:56 -05:00
Slyghtning
1b81a06b42
Merge pull request #1192 from hieblmi/no-change-label
Some checks failed
CI / Commit Message (push) Has been cancelled
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
github: allow no-changelog to skip release notes
2026-08-06 11:06:38 +02:00
Slyghtning
57fb007f95
docs: document no-changelog release note opt-out 2026-08-04 11:02:33 +02:00
Slyghtning
6f0d817db4
github: allow no-changelog to skip release notes 2026-08-04 11:02:22 +02:00
Slyghtning
f5f76a61cc
Merge pull request #1191 from hieblmi/docs-gate
Some checks failed
CI / Release Notes (push) Has been cancelled
CI / Commit Message (push) Has been cancelled
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
github: require release notes for pull requests
2026-08-03 11:48:15 +02:00
Slyghtning
4016f4a8f2
docs: instruct agents to add release notes 2026-08-03 11:18:14 +02:00
Slyghtning
414760c607
github: require release notes for pull requests 2026-08-03 11:17:54 +02:00
Slyghtning
a8e3e9c853
Merge pull request #1189 from hieblmi/tapd-client-fixes
assets: harden tapd client lifecycle and RFQ handling
2026-08-03 11:10:36 +02:00
Slyghtning
b686d97445
docs: note tapd client hardening
Document the RFQ validation, cache responsiveness, and tapd connection
lifecycle fixes in the rolling release notes.
2026-08-03 10:05:06 +02:00
Slyghtning
9e97992e18
assets: validate accepted RFQ asset rates
Validate the bid rate before returning an accepted asset sell quote.
This prevents malformed rates from reaching downstream quote arithmetic,
where nil or non-positive values can panic. Cover valid and malformed
responses with table-driven tests.
2026-08-03 10:05:05 +02:00
Slyghtning
cfbade1239
assets: reject malformed RFQ asset rates
Validate the rate pointer and decimal coefficient before converting
asset units. Return errors for nil, malformed, non-positive, and
oversized-scale rates instead of allowing nil dereferences or
division-by-zero panics. Add regression tests for each case.
2026-08-03 10:05:05 +02:00
Slyghtning
dc39d63d8d
assets: avoid locking cache during RPC
Restrict the asset-name cache mutex to map access so a slow
QueryAssetStats call cannot block cached readers. Use an RWMutex for
independent cache reads and add a concurrent regression test.
2026-08-03 10:05:05 +02:00
Slyghtning
c7d5e466cd
assets: validate RFQ timeout conversion
Convert the configured duration once during client creation. Round
positive fractional durations up to the whole seconds accepted by tapd.
Reject zero, negative, and overflowing values, and cover the conversion
boundaries with unit tests.
2026-08-03 10:05:05 +02:00
Slyghtning
514c3f06ad
loopd: close tapd client connections
Close the TapdClient when daemon initialization fails, during normal
shutdown, and after the view command completes. This prevents gRPC
transport resources from leaking across embedded daemon lifecycles and
error paths.
2026-08-03 10:05:04 +02:00
Slyghtning
8f831e85ae
Merge pull request #1188 from lightninglabs/gateway-v0.6.0
Some checks failed
CI / Commit Message (push) Has been cancelled
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
github: pin gateway v0.6.0 (Opus 5, /gateway check)
2026-07-28 09:07:41 +02:00
saubyk
2dda482660
github: pin gateway v0.6.0 (Opus 5, /gateway check)
Bumps both pins together: the gateway-action SHA and the runtime_ref it
resolves. runtime_ref is pinned explicitly rather than left to the
action's default, so bumping only the action would leave the job on the
v0.5.0 runtime.

v0.6.0 adds no trigger and no input, so the rest of the shim is
unchanged.

Also corrects a copy-paste artifact in the adjacent comment, which said
runtime upgrades go through an lnd PR.
2026-07-27 20:46:33 -07:00
Slyghtning
dede47e727
Merge pull request #1187 from hieblmi/review-gateway
github: add gateway code-review workflow
2026-07-27 21:53:55 +02:00
Slyghtning
f51148a3a0
github: add gateway code-review workflow 2026-07-27 13:25:29 +02:00
Slyghtning
4acabf72ee
Merge pull request #1181 from hieblmi/release-notes
docs: backdated and new release notes
2026-07-27 12:55:37 +02:00
Slyghtning
6b942941fb
docs: complete historical release notes
Document every published Loop release and preserve authoritative notes.

Add the next-release workflow and rebuild chronological navigation.

Rename the reproducible-build guide for clarity.
2026-07-27 11:54:05 +02:00
Slyghtning
edad26b876
Merge pull request #1165 from GustavoStingelin/feat/monitor-static-address
Some checks failed
CI / Commit Message (push) Has been cancelled
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
multi: add static address loop in monitor
2026-07-24 15:19:11 +02:00
Slyghtning
4732ec71e9
Merge pull request #1185 from lightninglabs/dependabot/go_modules/swapserverrpc/google.golang.org/grpc-1.82.1
build(deps): bump google.golang.org/grpc from 1.79.3 to 1.82.1 in /swapserverrpc
2026-07-24 10:57:12 +02:00
Slyghtning
4ca7a9c5ec
Merge pull request #1180 from hieblmi/multi-address-proto
Some checks are pending
CI / Commit Message (push) Waiting to run
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
swapserverrpc: add multi-address proofs
2026-07-23 21:14:50 +02:00
Slyghtning
cb97b2a37f
swapserverrpc: add multi-address proofs
Carry each deposit client derivation key and an optional generated
change descriptor in static-address loop-in and withdrawal requests. The
server can use these fields to validate scripts it does not store
directly.
2026-07-23 20:59:45 +02:00
Boris Nagaev
4161f5d128
multi: bump google.golang.org/grpc to v1.82.1 2026-07-23 13:13:57 -05:00
Alex Bosworth
d80733a710
Merge pull request #1184 from lightninglabs/alexbosworth-patch-19
version: bump version to v0.34.0-beta
2026-07-23 10:10:51 -07:00
Slyghtning
dbf1205b57
Merge pull request #1183 from hieblmi/gate-commit-messages
Some checks are pending
CI / Commit Message (push) Waiting to run
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
build: add commit message tooling
2026-07-22 21:16:13 +02:00
Alex Bosworth
a463c734ea
version: bump version to v0.34.0-beta 2026-07-22 08:53:15 -07:00
Slyghtning
eb63b0b4fe
build: add commit message tooling
Add a repository-local tool to lint, format, and safely reword commit
messages. Preserve markdown lists, quotes, code blocks, and trailers
while enforcing subject and body width limits.

Expose linting, formatting, and rewording through Make targets and
document the supported workflows. Run the linter in CI for pull request
and push commit ranges so malformed messages are caught before merging.
2026-07-22 14:27:25 +02:00
Slyghtning
41bc5f85df
Merge pull request #1182 from hieblmi/release-notes-34-beta
docs: add `v0.34.0-beta` release notes
2026-07-22 10:09:20 +02:00
Slyghtning
2cc2b9cbb6
docs: add v0.34.0-beta release notes 2026-07-22 09:47:03 +02:00
Gustavo Stingelin
d5fb8b8da8
cmd/loop: clarify traditional swap command scope 2026-07-21 11:33:48 -03:00
Gustavo Stingelin
4a2bcb3374
cmd/loop: display static loop-in monitor stages 2026-07-21 11:33:48 -03:00
Gustavo Stingelin
e3e6205a4b
staticaddr/loopin: publish status updates after persistence 2026-07-21 11:33:47 -03:00
Gustavo Stingelin
f5cc85f7f3
loopd: include static loop-ins in monitor snapshots 2026-07-21 11:33:47 -03:00
Gustavo Stingelin
7200a7ce09
loopd: synchronize cached swap lookups 2026-07-21 11:33:47 -03:00
Gustavo Stingelin
34cf98e8e8
loopd: map static address loop-ins to swap status 2026-07-21 11:33:47 -03:00
Gustavo Stingelin
df7dfba12a
staticaddr/loopin: preserve loop-in last update time 2026-07-21 11:33:46 -03:00
Gustavo Stingelin
4c03e46928
looprpc: expose static loop-in monitor state 2026-07-21 11:33:46 -03:00
Slyghtning
4bb7d5ee29
Merge pull request #1179 from GustavoStingelin/feat/static-address-fsm-diagrams
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
fsm: generate and verify static address diagrams
2026-07-21 14:59:35 +02:00
Boris Nagaev
9bccb649f4
Merge pull request #1175 from starius/bump-for-dependabot
build: fix dependency security alerts
2026-07-21 02:40:48 -05:00
Boris Nagaev
359997ca7b
Merge pull request #1177 from chandachewe10/master
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
fix dead error variable and silent invoice cancel in setStateAbandoned
2026-07-21 01:12:14 -05:00
Gustavo Stingelin
2e80b92cf9 build: rename reservation FSM diagram 2026-07-20 12:08:22 -03:00
Gustavo Stingelin
9f2d724c3e build: verify generated FSM diagrams 2026-07-20 12:08:02 -03:00
Gustavo Stingelin
0176e96e3c staticaddr: generate FSM diagrams 2026-07-20 12:07:26 -03:00
Gustavo Stingelin
e77a1ab634 fsm: harden diagram generation 2026-07-20 12:07:26 -03:00
Gustavo Stingelin
1d5b1c564a fsm: make diagram generation deterministic 2026-07-18 16:27:11 -03:00
Boris Nagaev
378825414b
assets: make tapd macaroon path network-aware
Build the default tapd admin macaroon path from the configured Bitcoin
network while preserving explicit path overrides. Add regression tests for
tapd credential loading and network-specific path selection.
2026-07-18 00:43:17 -05:00
Boris Nagaev
8716a51722
loopin: classify already-settled invoice RPC errors
lnd returns ErrInvoiceAlreadySettled from its RPC handler as an
uncoded gRPC error. On the client it is reconstructed as an Unknown
status, so comparing it directly with the Go sentinel never matches.

This made the abandon path log a warning for an expected condition.
The older timeout path had the same comparison and could return the
RPC error instead of finishing normal timeout processing.

Add a shared classifier that accepts the local sentinel and the exact
gRPC status representation, and use it in both cancellation paths.
Add coverage for the classifier and timeout handling.
2026-07-17 15:47:21 -05:00
Chanda Chewe
89f2dcff8b
loopin: fix dead error variable and silent invoice cancel in setStateAbandoned
The err variable is always nil when the final fmt.Errorf is reached
(a non-nil err exits earlier), producing a trailing ', <nil>' in the
error string visible to callers and in logs.

Additionally, CancelInvoice errors were silently swallowed with a
bare '_' assignment. The timeout path in the same file correctly
checks for ErrInvoiceAlreadySettled; this commit makes the abandon
path consistent: ignore already-settled invoices and log any other
unexpected error so operators can diagnose issues without failing
the abandon itself.

Co-authored-by: Chanda Chewe <chandachewe10@users.noreply.github.com>
2026-07-17 11:57:28 +00:00
Boris Nagaev
74cbb651bc
cmd/loop: normalize static channel memo help 2026-07-16 13:08:01 -05:00
Boris Nagaev
338a6ef9f1
build: fix dependency security alerts 2026-07-16 13:08:01 -05:00
Slyghtning
39c97e60d2
Merge pull request #1141 from lightninglabs/dyn-conf-tracker-staging
Some checks failed
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
staticaddr: dyn-conf-tracker
2026-07-16 15:25:58 +02:00
Slyghtning
43b16ff3e1
cmd/loop: warn for low-confirmation static deposits
Warn before dispatching a static loop-in that selects deposits below
the conservative six-confirmation threshold. Mirror automatic coin
selection before prompting so the warning reflects both manual and
auto-selected deposits.

Cover manual and auto-selected warning paths in CLI tests.
2026-07-15 16:52:39 +02:00
Slyghtning
c718e9a9fb
staticaddr/loopin: retry failed deposit state transitions
Keep the loop-in monitor in its recoverable state when a required deposit transition or unlock fails. Only advance after every selected deposit reaches the expected state, and retry only deposits that remain pending after a partial transition.

Preserve shutdown semantics when observer cancellation races with a completed deposit update, and add regression coverage for transition, partial-transition, and unlock failures.
2026-07-15 16:52:39 +02:00
Slyghtning
6927c67b96
staticaddr/loopin: use risk decision watcher 2026-07-12 09:14:34 +02:00
Slyghtning
332aab79ed
staticaddr/loopin: add risk decision watcher 2026-07-12 09:14:34 +02:00
Slyghtning
6593afc8bc
staticaddr/loopin: recover risk-decision deadlines
Record replayed server risk decisions through the loop-in store,
recover accepted payment-deadline timers using the persisted decision
time, and handle persisted rejections on restart. This lets recovered
static loop-ins keep pending confirmation-risk state instead of
restarting payment timing from scratch.
2026-07-12 09:14:34 +02:00
Slyghtning
f01a1f02d9
staticaddr/loopin: clean up deposits after unpaid htlc timeout
Track whether the invoice was canceled for non-payment while monitoring
the HTLC. If the HTLC never confirms before timeout, unlock the
deposits; if it did confirm, transition them to the HTLC-timeout sweep
state without issuing duplicate transitions.
2026-07-12 09:14:34 +02:00
Slyghtning
3e2b9452fe
loopd: wire static risk decision persistence
Create the static loop-in SQL store before the notification manager and
pass a persistence callback so server confirmation-risk decisions are
durably recorded before fanout.
2026-07-12 09:14:34 +02:00
Slyghtning
e53bb67e73
notifications: persist static loop-in risk decisions
Persist static loop-in confirmation-risk decisions before fanout when a
persistence callback is configured. Keep unpersisted decisions cached
for replay so notification delivery is not lost if the swap row is not
available yet.
2026-07-12 09:14:33 +02:00
Slyghtning
491fddbc34
loopdb: persist static loop-in risk decisions
Add schema, sqlc queries, store fields, and SqlStore support for
recording server confirmation-risk decisions with static loop-in swaps.
Store the decision timestamp so payment-deadline recovery can
reconstruct elapsed time after restart.
2026-07-12 09:14:33 +02:00
Slyghtning
b0f43bbe1e
staticaddr/loopin: wait for risk decisions
Subscribe to static loop-in confirmation-risk notifications before
starting the payment deadline. Start that deadline only after server
acceptance or the legacy confirmation fallback, and cancel the swap
invoice when the server rejects the risk wait. Refresh selected
deposits before the legacy fallback so recovered monitors use current
confirmation heights.
2026-07-12 09:14:33 +02:00
Slyghtning
da96842264
notifications: fan out static loop-in risk decisions
Add cached per-swap notification fanout for static loop-in
confirmation-risk acceptance and rejection notifications so loop-in
FSMs can subscribe by swap hash and receive decisions that arrived
before subscription.
2026-07-12 09:14:33 +02:00
Slyghtning
ef78c85e88
staticaddr/loopin: cancel signing for unavailable deposits
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.
2026-07-12 09:14:33 +02:00
Slyghtning
1d935c657f
loopd: filter static deposit views through active set
Use the deposit manager's visible-deposit view for normal list and
summary RPCs so historical Deposited rows whose outpoints vanished from
lnd's wallet view are not exposed as available funds.
2026-07-12 09:14:32 +02:00
Slyghtning
dc7da41b28
staticaddr: refresh deposits before spend selection
Refresh the active static-address deposit set against lnd's wallet view
before quote, loop-in, withdrawal, channel-open, and autoloop selection
paths. This prevents stale persisted Deposited records from being
selected after replacement, reorg, or an external spend.
2026-07-12 09:14:32 +02:00
Slyghtning
1c89ff83f1
staticaddr/loopin: account for autoloop deposit expiry
Use the shared deposit-expiry helper when building autoloop DP
candidates so unconfirmed deposits do not look like the
earliest-expiring options.

This keeps the no-change selector's expiry tie-break aligned with the
generic loop-in deposit selection rules.
2026-07-12 09:14:32 +02:00
Slyghtning
0223caa370
staticaddr/loopin: treat unconfirmed deposits as swappable
Static address deposits with no confirmation height have not started
their CSV timeout yet, so keep them eligible for loop-in selection
instead of treating them as already near expiry. Prefer confirmed
deposits before unconfirmed ones during automatic selection, and share
the remaining-lifetime calculation used by the selector.
2026-07-12 09:14:32 +02:00
Slyghtning
557ba99513
staticaddr: require confirmed deposits for withdraws and channel opens
Deposited can now include mempool outputs for static loop-ins, but
withdrawals and static channel opens still require confirmed funding
inputs. Filter automatic channel-open selection to confirmed deposits
and reject explicit unconfirmed selections, including withdraw-all
requests that would otherwise silently include mempool deposits.
2026-07-12 09:14:32 +02:00
Slyghtning
e8dd3aa009
staticaddr: expose tracked deposit availability
Build list and summary responses from tracked deposit records instead
of raw wallet UTXOs so RPC clients see the manager availability state.
Split unconfirmed value from confirmed deposited value in summaries,
and reject manual loop-in quotes for selected deposits that are not
currently Deposited.
2026-07-12 09:14:32 +02:00
Slyghtning
e4bcc94a36
staticaddr/deposit: reconcile active deposits with wallet
Treat lnd's wallet view as the source of spendable static-address
outpoints while keeping historical deposit records in the DB. Reconcile
active FSMs against the current wallet view, reactivate known deposits
that reappear, and hide stale Deposited records from the visible
deposit set.
2026-07-12 09:14:32 +02:00
Slyghtning
ac12d251f5
staticaddr/deposit: replay startup block after recovery
The first block epoch is consumed before recovered deposit FSMs exist.
Replay that startup height after recovery so already-expired deposits
can run expiry handling immediately after restart.
2026-07-12 09:14:31 +02:00
Slyghtning
1abe617991
staticaddr/deposit: track unconfirmed deposits
Retain static-address deposits as soon as lnd reports the UTXO, even
when the output is still unconfirmed. Store the first confirmation
height once the output confirms.

Derive confirmation heights from the current wallet view because lnd
reports confirmation counts instead of first-confirmation heights.
2026-07-12 09:14:31 +02:00
Slyghtning
12ebeabd3d
Merge pull request #1161 from hieblmi/dyn-conf-prep
Some checks failed
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
staticaddr: harden deposit and loop-in lifecycle handling
2026-07-08 11:04:11 +02:00
Slyghtning
aed7df97a0
build: replace disappeared Go vanity modules 2026-07-08 10:42:19 +02:00
Slyghtning
c87273d32e
build: increase lint timeout 2026-07-08 09:02:12 +02:00
Slyghtning
814f046d8b
staticaddr/openchannel: fix nolint directive 2026-07-08 09:02:12 +02:00
Slyghtning
6582aa0807
staticaddr/loopin: check deposits before htlc signing
Before we send HTLC signatures to the server, the server cannot publish
the HTLC transaction. After those signatures are handed over, the server
can publish an HTLC that spends the selected deposits even if it never
pays the swap invoice.

Defend against stale local deposit state by checking the wallet's current
txout view immediately before signing. A deposit can have been spent by a
known withdrawal, channel open, timeout sweep, replacement, or another
wallet transaction while the loop-in FSM is recovering or while earlier
state still marked it as selected.

Failing before signing leaves the server without spend authority over an
unavailable input. Include mempool spends in the check so wallet-known
unconfirmed spends are treated as unavailable too.
2026-07-08 09:02:06 +02:00
Slyghtning
bd3882d5b0
staticaddr/loopin: use payment timeout duration helper 2026-07-08 09:01:18 +02:00
Slyghtning
3fdd9e2250
staticaddr/loopin: recover deposits by current outpoint
Recovered loop-ins carry two outpoint views. DepositOutpoints is the
immutable swap input snapshot sent to the server and used to validate
sweep requests. Deposits comes from the store's swap_hash/deposit-id
join and reflects the current deposit rows.

The active-deposit lookup takes a detour through the reconstructed
deposit rows before asking the deposit manager for active deposits.
That keeps recovery from depending on the historical input snapshot.

A future replacement path can RBF a deposit from its original funding
outpoint to a replacement outpoint while the swap still needs to retain
the original input list. Looking up active deposits by DepositOutpoints
would then fail recovery even though the store still maps the correct
deposit IDs to the swap hash.

Keep list responses on the store reconstruction too, so they do not
re-resolve deposits through historical outpoints.
2026-07-08 09:01:17 +02:00
Slyghtning
67252a84de
staticaddr/deposit: canonicalize multi-deposit locks 2026-07-08 09:01:17 +02:00
Slyghtning
814af6aadf
staticaddr/loopin: keep htlc monitor resumable
After the client gives the server HTLC signatures, shutdown must not drive the monitor state through the generic error path. That path cancels the invoice and attempts to unlock deposits even though the server can still publish the HTLC.

Return NoOp for monitor-state cancellation races and cover shutdown with a regression test that asserts no invoice cancellation or deposit unlock occurs.
2026-07-08 09:01:13 +02:00
Slyghtning
0c0cee377b
staticaddr/loopin: keep htlc timeout sweep resumable
A shutdown while publishing or monitoring the HTLC timeout sweep should not
transition the loop-in to Failed.

Return NoOp on context cancellation in those actions so the persisted
state remains a recovery point. Add focused tests for shutdown during
publication retry and confirmation monitoring.
2026-07-08 09:01:02 +02:00
Slyghtning
58fbe2230e
staticaddr/deposit: guard confirmation height access
Document deposit lock ownership for mutable confirmation state and
route production reads through deposit accessors.

Keep store persistence on no-lock helpers while callers hold the
deposit lock, preserving the existing transition behavior without
leaving direct field reads in user-facing paths.
2026-07-08 09:01:01 +02:00
Slyghtning
f468f24e6f
staticaddr/deposit: ignore queued expiry in final states
A block notification can queue OnExpiry before a deposit reaches a final
state. If the final transition wins that race first, the stale expiry event
must not overwrite the terminal outcome.

Keep LoopedIn and Withdrawn as self-loops on OnExpiry, matching the other
final states. Add a focused FSM test that sends OnExpiry directly to each
final state and verifies the state is preserved.
2026-07-08 09:01:01 +02:00
Slyghtning
d8b24d31c0
staticaddr/loopin: default payment timeout duration
Add a duration helper that falls back to the default payment timeout.

Recovered legacy swaps can have a zero persisted timeout, so later
deadline logic can use this without treating zero as immediate expiry.
2026-07-08 09:01:01 +02:00
Slyghtning
7f57f6fc6b
staticaddr/deposit: reject invalid transitions
Reject nil deposits and final-state deposits before sending FSM
events.

This keeps callers from transitioning stale or completed deposits and
uses the no-lock state helper while deposits are already locked.
2026-07-08 09:01:01 +02:00
Slyghtning
77d9335da2
staticaddr/deposit: serialize deposit reconciliation
Guard reconcileDeposits with a dedicated mutex.

Polling and block-driven reconciliation can overlap, so serialize the
path before it updates confirmation data and active FSM state.
2026-07-08 09:01:01 +02:00
Slyghtning
38dce3685f
staticaddr/deposit: factor active deposit notifications
Move active-deposit block notification fan-out into a helper.

This keeps the event loop small and gives later startup replay logic
a single path for notifying recovered deposit FSMs.
2026-07-08 09:01:01 +02:00
Slyghtning
6ce13ba8a4
staticaddr/deposit: document lock ordering
Document the lock-order invariant between Manager.mu and individual
deposit locks.

Later changes need both locks in the same path, so make the rule
explicit before the locking surface grows.
2026-07-08 09:01:00 +02:00
Slyghtning
f8e9d11d04
staticaddr/loopin: add lnd txout checker
Add a TxOutChecker interface for checking whether a selected deposit
outpoint is still available before signing the HTLC transaction.

Back the implementation with lnd wallet transaction data so known
confirmed and mempool spends mark the outpoint unavailable.
2026-07-08 09:00:56 +02:00
Slyghtning
508bf90a1c
staticaddr/loopin: preserve selected deposit outpoints
Store an independent snapshot of the outpoints selected for a
static loop-in.

Recovered swaps remain tied to the original funding outputs even if
deposit records later change confirmation or replacement metadata.

Avoid decoding an empty database outpoint string as a synthetic
outpoint.
2026-07-08 09:00:34 +02:00
Slyghtning
07d87c23a6
staticaddr/deposit: stop removed fsms
Add an explicit Stop method for deposit FSM block-notification
loops.

Call it when the manager removes a finalized active deposit so stale
FSM goroutines stop consuming block updates.
2026-07-08 09:00:26 +02:00
Slyghtning
8456314155
staticaddr/loopin: handle closed invoice updates
Treat closed invoice update channels as terminal for the monitor loop.

This avoids spinning when lnd closes the subscription after invoice cancellation or shutdown.
2026-07-08 09:00:26 +02:00
Slyghtning
a6d061c568
staticaddr/loopin: factor invoice update handling
Extract the monitor invoice update semantics into a helper and cover the existing state mapping with a dedicated test.
2026-07-08 09:00:26 +02:00
Slyghtning
ee5d84b323
staticaddr/deposit: reject duplicate outpoints
Reject duplicate static-address deposit outpoints before creating
withdrawal, loop-in, or channel-open requests.

Use the shared outpoint duplicate helper so each flow reports the
same input validation failure.
2026-07-08 09:00:26 +02:00
Slyghtning
0611832030
staticaddr/deposit: ignore expiry blocks in final states
Return early when block notifications reach deposits that already
moved into a terminal state.

This prevents final deposits from retrying expiry handling after
recovery or while their FSM is still draining block updates.
2026-07-08 09:00:26 +02:00
Slyghtning
ba1c37c0da
staticaddr/deposit: handle loop-in htlc timeout
Keep deposits locked when the server publishes the loop-in HTLC
without paying the invoice.

This lets the client sweep through the HTLC timeout path instead
of making the same outputs available for another action.
2026-07-08 09:00:25 +02:00
Boris Nagaev
eea3f96ada
Merge pull request #1162 from starius/fix-cli-tests
Some checks failed
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
cmd/loop: normalize numeric replay time zones
2026-07-02 09:41:43 -05:00
Boris Nagaev
baecbbfe4c
cmd/loop: normalize numeric replay time zones
Recorded session replay already normalizes timestamps before
comparing CLI output, but the time.String timestamp regex only
matched alphabetic zone names like UTC and EST. Some systems
render the same offset with a numeric zone name, for example
-0300 -03, which left the publication deadline unnormalized
and caused fixture comparisons to fail.

Match numeric zone names as well, and parse the timestamp using
the explicit numeric offset instead of the display zone name. Add a
regression test covering RFC3339, alphabetic time.String zones, and
numeric time.String zones.
2026-07-02 02:50:13 -05:00
Slyghtning
a134cb1f22
Merge pull request #1158 from hieblmi/log-htlc-tx-fee
Some checks failed
CI / RPC compilation check (push) Has been cancelled
CI / SQL compilation check (push) Has been cancelled
CI / go mod check (push) Has been cancelled
CI / build and lint code (push) Has been cancelled
CI / verify that auto-generated documentation is up-to-date (push) Has been cancelled
CI / run unit-test sqlite3 race (push) Has been cancelled
CI / run unit-test postgres race (push) Has been cancelled
CI / run LiT itests (push) Has been cancelled
CI / run LiT unit tests (push) Has been cancelled
staticaddr/loopin: log HTLC fee guard inputs
2026-06-24 14:39:36 +02:00
Slyghtning
22cec7486c
staticaddr/loopin: log HTLC fee guard inputs
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.
2026-06-24 14:22:15 +02:00
Boris Nagaev
375c02e0f6
Merge pull request #1156 from starius/lnd-21-improvements
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
Use new features of LND 0.21
2026-06-23 09:56:53 -05:00
Boris Nagaev
682d45405c
cmd/loop: expose both taproot channel types
LND v0.21 added the production TAPROOT commitment type while
SIMPLE_TAPROOT remains available as the legacy enum.

The static open-channel CLI previously used "taproot" for
SIMPLE_TAPROOT. Keep both choices available by renaming that legacy
spelling to "simple-taproot" and mapping "taproot" to TAPROOT. This
makes the CLI spelling match the channel type it requests while still
leaving an explicit path for users that need SIMPLE_TAPROOT.
2026-06-22 15:06:25 -05:00
Boris Nagaev
5d8a5019cf
lint: enable deprecation checks
Enable staticcheck's SA1019 check in golangci-lint so deprecated
identifiers are caught in CI.

Replace deprecated standard library and bbolt APIs with their current
equivalents. Keep intentional compatibility reads and writes of
deprecated Loop RPC fields behind narrow nolint annotations, because
older clients and persisted liquidity parameters still depend on those
fields.
2026-06-22 12:46:12 -05:00
Boris Nagaev
d324b4bfd8
loop: omit payment hops in cost migration
The cost cleanup migration pages through LND payments only to build
a payment-hash to fee map. It does not inspect HTLC attempts,
routes, or per-hop data; pagination still uses the top-level index
offsets returned by ListPayments.

Setting OmitHops is safe for this migration because LND only strips
hop-level route data from HTLC attempts, while preserving the top-level
payment fields the migration reads: hash, fee, and response offsets.
This reduces response size and query cost for nodes with many or large
MPP payments without changing the calculated swap costs.

The migration test records the mocked ListPayments requests and asserts
that OmitHops is set.
2026-06-22 12:46:12 -05:00
Boris Nagaev
09c92527ea
staticaddr: accept production taproot channels
LND v0.21 exposes CommitmentType_TAPROOT as the production taproot
channel commitment type, while SIMPLE_TAPROOT remains a legacy taproot
enum. Static address channel opens previously rejected TAPROOT and only
classified SIMPLE_TAPROOT as a taproot output for fee and weight
estimates.

Accept TAPROOT in the static address open-channel validator and keep
accepting SIMPLE_TAPROOT for compatibility. Treat both taproot
commitment enums as P2TR outputs for deposit-selection and withdrawal
fee estimates. Callers using the production enum then get the same
weight accounting as the legacy taproot enum.

This does not change the CLI mapping for user-facing
channel_type=taproot. It only makes the static address path compatible
with callers that already send LND production taproot commitment type.
2026-06-22 12:46:12 -05:00
Boris Nagaev
a92f6bc875
build: bump lndclient to v0.21.0-2
Use the tagged lndclient release that exposes the ListPayments
request fields needed by Loop optimizations.
2026-06-22 12:41:03 -05:00
Slyghtning
129d9c1d26
Merge pull request #1154 from hieblmi/pre-dyn-conf-fixes
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
confrisk: preparatory changes
2026-06-22 11:35:02 +02:00
Slyghtning
0bb06b0ba3
notifications: queue blocking fanout
Required notification fanout should not block the manager lock, but subscribers still need ordered delivery once brief backpressure clears. Sending must-deliver notifications directly can couple manager progress to subscriber receive timing, while queueing optional reservation notifications would contradict their best-effort delivery semantics.

Add bounded per-subscriber queues for must-deliver notifications, let those queues own channel shutdown instead of relying on recover for closed-channel sends, keep reservation fanout best-effort, and cover queued delivery, queue cleanup, and capacity drops in manager tests.
2026-06-22 10:58:37 +02:00
Slyghtning
d0c613e5c9 notifications: drop best-effort messages for slow subscribers
A slow optional notification subscriber must not stall the manager lock, while recovery and sweep work requests still need reliable local delivery to keep daemon progress deterministic. Treating all subscribers as blocking makes best-effort fanout a backpressure source for unrelated required work.

Make reservation fanout nonblocking for slow subscribers, keep recovery and sweep notifications on a required cancellation-aware delivery path, and cover both slow best-effort subscribers and required subscribers in manager tests.
2026-06-22 10:18:07 +02:00
Slyghtning
f982ceb753 staticaddr/loopin: include failed swaps in state queries
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.
2026-06-22 10:18:07 +02:00
Slyghtning
bbeb813bfa staticaddr/deposit: finalize deposits asynchronously
Final deposit states should not stall while deposit locks are held, because a blocked manager receive loop can otherwise hold up the deposit FSM; if shutdown happens before notification delivery, startup recovery can still resume from the final state.

Send finalization notifications from a goroutine so final states are recorded without waiting on the manager receive loop, and add tests for blocked manager delivery and shutdown races.
2026-06-22 10:18:07 +02:00
Slyghtning
44a6c7a144 staticaddr/loopin: cancel orphan invoice on init failure
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.
2026-06-22 10:18:07 +02:00
Alex Bosworth
b44f8484f2
Merge pull request #1155 from lightninglabs/alexbosworth-patch-18
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
version: bump version to v0.33.3-beta
2026-06-21 12:50:10 -07:00
Alex Bosworth
a7fb06e205
version: bump version to v0.33.3-beta 2026-06-20 13:39:49 -07:00
Boris Nagaev
8087c7aa13
Merge pull request #1153 from starius/bump-lnd-21
Some checks are pending
CI / RPC compilation check (push) Waiting to run
CI / SQL compilation check (push) Waiting to run
CI / go mod check (push) Waiting to run
CI / build and lint code (push) Waiting to run
CI / verify that auto-generated documentation is up-to-date (push) Waiting to run
CI / run unit-test sqlite3 race (push) Waiting to run
CI / run unit-test postgres race (push) Waiting to run
CI / run LiT itests (push) Waiting to run
CI / run LiT unit tests (push) Waiting to run
build: bump lnd to v0.21
2026-06-20 13:55:04 -05:00
Boris Nagaev
914a3eeced
loopd: raise minimum lnd version to v0.18.4-beta
LoopMinRequiredLndVersion was 0.17.0, a value that only ever tracked the
go.mod lnd dependency rounded down and was never updated as the client
started depending on newer lnd RPC APIs. The client today uses RPC
fields that do not exist in 0.17.0:

  - routerrpc.SendPaymentRequest.first_hop_custom_records and
    lnrpc.Route.custom_channel_data, used by asset loop outs in
    loopout.go: both added in lnd v0.18.4-beta.
  - walletrpc.EstimateFeeResponse.min_relay_fee_sat_per_kw, read by the
    sweep batcher fee floor via lndclient WalletKit.MinRelayFee
    (sweepbatcher/, loopd/sweep_htlc.go): added in lnd v0.18.3-beta. On
    older lnd it silently decodes to 0, disabling the min-relay floor.

Raise the floor to the highest of these (v0.18.4-beta) so loopd fails
fast at startup rather than misbehaving at runtime, and document in
AGENTS.md the rule to keep this value pinned to the lnd APIs the client
actually uses instead of tracking go.mod.
2026-06-16 01:12:03 -05:00
Boris Nagaev
950b5f1772
test: refresh route hint preservation comments
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.
2026-06-11 18:08:05 -05:00
Boris Nagaev
2d446b3b9e
test: remove unused PayInvoice mock path
Loop no longer pays invoices through LightningClient.PayInvoice.
Production payment paths use the router client wrappers. lndclient now
also implements PayInvoice on top of router payment APIs, so the old
SendPaymentChannel mock path is no longer exercised.

Remove the dead PayInvoice mock, its SendPaymentChannel plumbing, and
the loop-in resume assertion that watched that channel.
2026-06-11 18:08:02 -05:00
Boris Nagaev
cfe9e401c4
build: bump lnd to v0.21
Update lnd to v0.21.0-beta and lndclient to v0.21.0-1.

Regenerate the LND-derived swagger and CLI manpage outputs after the
dependency bump.
2026-06-11 16:24:30 -05:00
251 changed files with 20141 additions and 2831 deletions

View file

@ -1,2 +1,3 @@
#### Pull Request Checklist
- [ ] Update `release_notes.md` if your PR contains major features, breaking changes or bugfixes
- [ ] Add an entry to `docs/release-notes/release-notes-next.md`, or apply the
`no-changelog` label (required by CI)

66
.github/workflows/gateway.yml vendored Normal file
View file

@ -0,0 +1,66 @@
name: gateway
# Opt-in code-review bot. Triggered by a `/gateway <command>` comment on a PR
# (e.g. `/gateway review`); review/approve commands are gated to maintainers.
# Comment-commands only — no pull_request triggers — so fork PRs (which receive
# no secrets) never spawn failing runs. v0.5.0 added the
# pull_request_review_comment trigger: /gateway dismiss, promote, and explain
# now also work as replies on a finding's inline thread (finding id inferred
# from the thread when omitted). Also a comment event — same fork-PR safety
# profile as issue_comment.
#
# Thin shim: the public lightninglabs/gateway-action mints an App token and
# checks out the private gateway runtime at execution time. The runtime stays
# private; only this entry point is public.
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
permissions:
# The action mints an App installation token internally; the GITHUB_TOKEN
# handed to this shim is unused, so we minimise it.
contents: read
jobs:
review:
# issue_comment fires for all issues and every PR comment. Filter to PR
# comments that look like a /gateway command so unrelated comments don't
# spin up a no-op runner. `contains` (not `startsWith`) because the runtime
# accepts the command at column 0 of any line, including multi-line bodies.
if: >-
${{
(github.event_name == 'issue_comment'
&& github.event.issue.pull_request != null
&& contains(github.event.comment.body, '/gateway')) ||
(github.event_name == 'pull_request_review_comment'
&& contains(github.event.comment.body, '/gateway'))
}}
runs-on: ubuntu-latest
timeout-minutes: 15
env:
GATEWAY_REVIEW_MODE: multi
steps:
- uses: lightninglabs/gateway-action@334a8455ee316e40668ae3ac85249150c62704ec # v0.6.0
with:
# Pin the private runtime to an immutable commit (matches the action
# SHA-pin above) so runtime upgrades go through a loop PR, not a moved
# tag. Without this, runtime_ref defaults to the v0.6.0 tag.
runtime_ref: 75f6e67deac362bdcfc10d10629ddcf69c0e2615 # gateway v0.6.0
event_name: ${{ github.event_name }}
event_action: ${{ github.event.action }}
repo: ${{ github.repository }}
pr_number: ${{ github.event.issue.number || github.event.pull_request.number }}
actor: ${{ github.event.sender.login }}
comment_body: ${{ github.event.comment.body }}
comment_id: ${{ github.event.comment.id }}
comment_in_reply_to: ${{ github.event.comment.in_reply_to_id }}
# installation_id intentionally omitted: as of gateway v0.4.4 the
# runtime resolves the App installation covering this repo from
# app_id/private_key, so a hardcoded (and easily wrong-org) id is no
# longer needed.
app_id: ${{ secrets.GATEWAY_APP_ID }}
private_key: ${{ secrets.GATEWAY_PRIVATE_KEY }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

View file

@ -24,6 +24,37 @@ env:
LITD_ITEST_BRANCH: master
jobs:
########################
# commit message lint
########################
commit-message:
name: Commit Message
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Lint commit messages
env:
EVENT_NAME: ${{ github.event_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
BEFORE_SHA: ${{ github.event.before }}
GITHUB_SHA: ${{ github.sha }}
run: |
if [ "$EVENT_NAME" = "pull_request" ]; then
range="$BASE_SHA..$HEAD_SHA"
elif [ "$EVENT_NAME" = "push" ] &&
[ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then
range="$BEFORE_SHA..$GITHUB_SHA"
else
range="$(git rev-parse HEAD^ 2>/dev/null)..HEAD"
fi
make commitmsg-lint range="$range"
########################
# RPC compile and check
########################
@ -124,6 +155,9 @@ jobs:
- name: check
run: make docs-check
- name: check generated FSM diagrams
run: make fsm-check
########################
# run unit-test sqlite3 race
########################

58
.github/workflows/release-notes.yml vendored Normal file
View file

@ -0,0 +1,58 @@
name: Release Notes
on:
pull_request:
branches:
- "*"
types:
- opened
- reopened
- synchronize
- labeled
- unlabeled
permissions:
contents: read
defaults:
run:
shell: bash
jobs:
release-notes:
name: Release Notes
runs-on: ubuntu-latest
steps:
- name: Skip release notes check
if: contains(github.event.pull_request.labels.*.name, 'no-changelog')
run: echo "Release notes check skipped by the no-changelog label."
- name: git checkout
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-changelog') }}
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for a release note
if: ${{ !contains(github.event.pull_request.labels.*.name, 'no-changelog') }}
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
RELEASE_NOTES_FILE: docs/release-notes/release-notes-next.md
run: |
if git diff --unified=0 "$BASE_SHA...$HEAD_SHA" -- \
"$RELEASE_NOTES_FILE" |
awk '
/^@@/ { in_hunk = 1; next }
in_hunk && /^\+/ {
line = substr($0, 2)
if (line ~ /[^[:space:]]/) found = 1
}
END { exit found ? 0 : 1 }
'
then
exit 0
fi
echo "::error file=$RELEASE_NOTES_FILE::Add a release note or apply the no-changelog label."
exit 1

View file

@ -3,7 +3,7 @@ run:
go: "1.26"
# timeout for analysis
timeout: 4m
timeout: 6m
linters:
default: all
@ -55,14 +55,16 @@ linters:
- wsl_v5
- noinlineerr
settings:
staticcheck:
checks:
- all
- -QF*
- -ST*
gosec:
excludes:
- G402
- G306
- G115
staticcheck:
checks:
- -SA1019
tagliatelle:
case:
rules:

View file

@ -51,3 +51,33 @@ The project is a client daemon (`loopd`) that connects to a user's `lnd` node an
* **Cryptography:** Extensively uses Taproot and MuSig2 for efficiency, privacy, and complex spending conditions, especially in the `instantout` and `staticaddr` features.
* **Labeling (`labels/`):** A utility to create and validate labels for swaps, which helps distinguish between user-initiated and automated swaps (e.g., `[reserved]: autoloop-out`).
* **Assets (`assets/`):** Contains logic for interacting with `tapd` (Taproot Assets Protocol Daemon), allowing Loop to facilitate swaps involving assets other than Bitcoin.
**5. Minimum `lnd` Version (`loopd/run.go`):**
`loopd` enforces a minimum `lnd` version at startup through
`LoopMinRequiredLndVersion` in `loopd/run.go` (handed to `lndclient` as
`CheckVersion`). This is a hard gate: loopd refuses to start against an older
`lnd` node.
**Maintenance rule:** whenever you start using an `lnd` gRPC method or message
field that does not exist in older `lnd`, bump `LoopMinRequiredLndVersion` to the
`lnd` release that introduced that API, and record which API drove the bump in the
comment above the variable. Pin it to the *real* floor of the APIs the client uses
— do **not** just track the `go.mod` dependency. Historically this value only
tracked `go.mod` and drifted out of sync with the APIs actually called (it sat at
0.17.0 while the client already depended on 0.18.4 APIs). To find the introducing
release, grep the field/method across `lnd` version tags, e.g.
`git grep <field> <tag> -- <proto-file>`. As of the current floor (**v0.18.4-beta**)
the binding dependencies are the asset loop-out fields
`routerrpc.SendPaymentRequest.first_hop_custom_records` and
`lnrpc.Route.custom_channel_data` (lnd v0.18.4-beta), plus the sweep-batcher fee
floor `walletrpc.EstimateFeeResponse.min_relay_fee_sat_per_kw` (lnd v0.18.3-beta).
**6. Pull Request Release Notes:**
Every pull request must either add at least one non-empty line to
`docs/release-notes/release-notes-next.md` or carry the `no-changelog` label.
Before finishing any change intended for a pull request, add a concise entry
under the appropriate section (`New Features`, `Breaking Changes`, `Bug Fixes`,
or `Maintenance`). For a change that does not warrant a release note, ensure the
pull request uses the `no-changelog` label instead. This is enforced by CI.

View file

@ -174,6 +174,43 @@ endif
cd tools/ && GOPROXY=direct $(GOMOD) tidy
if test -n "$$(git status --porcelain)"; then echo "Running go mod tidy changes go.mod/go.sum"; git status; git diff; exit 1; fi
commitmsg-lint:
@$(call print, "Linting commit message(s).")
@if [ -n "$(range)" ]; then \
./scripts/commit_message.py lint --range "$(range)"; \
elif [ -n "$(commit)" ]; then \
./scripts/commit_message.py lint --commit "$(commit)"; \
elif [ -n "$(file)" ]; then \
./scripts/commit_message.py lint --file "$(file)"; \
else \
./scripts/commit_message.py lint --commit HEAD; \
fi
commitmsg-fmt:
@$(call print, "Formatting commit message.")
@if [ -n "$(file)" ]; then \
if [ "$(inplace)" = "1" ]; then \
./scripts/commit_message.py fmt --file "$(file)" --in-place \
$(if $(filter 1,$(decode)),--decode-escaped-newlines,); \
else \
./scripts/commit_message.py fmt --file "$(file)" \
$(if $(filter 1,$(decode)),--decode-escaped-newlines,); \
fi; \
elif [ -n "$(commit)" ]; then \
./scripts/commit_message.py fmt --commit "$(commit)" \
$(if $(filter 1,$(decode)),--decode-escaped-newlines,); \
else \
echo "Error: provide file=<path> or commit=<rev>"; \
exit 1; \
fi
commitmsg-reword:
@$(call print, "Rewording commit with formatted message.")
@./scripts/commit_message.py reword \
--commit "$(if $(commit),$(commit),HEAD)" \
$(if $(filter 1,$(decode)),--decode-escaped-newlines,) \
$(if $(filter 1,$(dryrun)),--dry-run,)
sqlc:
@$(call print, "Generating sql models and queries in Go")
./scripts/gen_sqlc_docker.sh
@ -194,4 +231,20 @@ docs-check: docs
fsm:
@$(call print, "Generating state machine docs")
./scripts/fsm-generate.sh;
.PHONY: fsm
FSM_FILES := \
fsm/example_fsm.md \
instantout/fsm.md \
instantout/reservation/fsm.md \
staticaddr/deposit/fsm.md \
staticaddr/loopin/fsm.md
fsm-check: fsm
@$(call print, "Verifying generated state machine docs")
if test -n "$$(git status --porcelain -- $(FSM_FILES))"; then \
echo "Generated FSM diagrams are not up-to-date!"; \
git status --porcelain -- $(FSM_FILES); \
git diff -- $(FSM_FILES); \
exit 1; \
fi
.PHONY: fsm fsm-check

View file

@ -133,4 +133,4 @@ go install ./...
## Reproducible builds
If you want to build release files yourself, follow
[the guide](./docs/release.md).
[the guide](./docs/reproducible_release.md).

View file

@ -4,14 +4,15 @@ import (
"context"
"encoding/hex"
"fmt"
"math"
"math/big"
"os"
"path/filepath"
"sync"
"time"
"github.com/btcsuite/btcd/btcutil"
"github.com/lightninglabs/taproot-assets/rfqmath"
"github.com/lightninglabs/taproot-assets/rpcutils"
"github.com/lightninglabs/taproot-assets/tapcfg"
"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightninglabs/taproot-assets/taprpc/priceoraclerpc"
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
@ -49,13 +50,24 @@ type TapdConfig struct {
// DefaultTapdConfig returns a default configuration to connect to a taproot
// assets daemon.
func DefaultTapdConfig() *TapdConfig {
defaultConf := tapcfg.DefaultConfig()
return DefaultTapdConfigForNetwork(
btcutil.AppDataDir("tapd", false), "mainnet",
)
}
// DefaultTapdConfigForNetwork returns the default tapd configuration rooted in
// defaultTapdDir for the given Bitcoin network. Passing the directory
// explicitly keeps path construction testable without accessing the user's
// real tapd data.
func DefaultTapdConfigForNetwork(defaultTapdDir, network string) *TapdConfig {
return &TapdConfig{
Activate: false,
Host: "localhost:10029",
MacaroonPath: defaultConf.RpcConf.MacaroonPath,
TLSPath: defaultConf.RpcConf.TLSCertPath,
RFQtimeout: defaultRfqTimeout,
Activate: false,
Host: "localhost:10029",
MacaroonPath: filepath.Join(
defaultTapdDir, "data", network, "admin.macaroon",
),
TLSPath: filepath.Join(defaultTapdDir, "tls.cert"),
RFQtimeout: defaultRfqTimeout,
}
}
@ -67,14 +79,19 @@ type TapdClient struct {
rfqrpc.RfqClient
universerpc.UniverseClient
cfg *TapdConfig
assetNameCache map[string]string
assetNameMutex sync.Mutex
cc *grpc.ClientConn
rfqTimeoutSeconds uint32
assetNameCache map[string]string
assetNameMutex sync.RWMutex
cc *grpc.ClientConn
}
// NewTapdClient returns a new taproot assets client.
func NewTapdClient(config *TapdConfig) (*TapdClient, error) {
rfqTimeoutSeconds, err := getRfqTimeoutSeconds(config.RFQtimeout)
if err != nil {
return nil, err
}
// Create the client connection to the server.
conn, err := getClientConn(config)
if err != nil {
@ -85,7 +102,7 @@ func NewTapdClient(config *TapdConfig) (*TapdClient, error) {
client := &TapdClient{
assetNameCache: make(map[string]string),
cc: conn,
cfg: config,
rfqTimeoutSeconds: rfqTimeoutSeconds,
TaprootAssetsClient: taprpc.NewTaprootAssetsClient(conn),
TaprootAssetChannelsClient: tapchannelrpc.NewTaprootAssetChannelsClient(conn),
PriceOracleClient: priceoraclerpc.NewPriceOracleClient(conn),
@ -128,7 +145,7 @@ func (c *TapdClient) GetRfqForAsset(ctx context.Context,
PeerPubKey: peerPubkey,
PaymentMaxAmt: uint64(paymentMaxAmt),
Expiry: uint64(expiry),
TimeoutSeconds: uint32(c.cfg.RFQtimeout.Seconds()),
TimeoutSeconds: c.rfqTimeoutSeconds,
})
if err != nil {
return nil, err
@ -141,21 +158,26 @@ func (c *TapdClient) GetRfqForAsset(ctx context.Context,
rfq.GetRejectedQuote())
}
if rfq.GetAcceptedQuote() != nil {
return rfq.GetAcceptedQuote(), nil
acceptedQuote := rfq.GetAcceptedQuote()
if acceptedQuote == nil {
return nil, fmt.Errorf("no accepted quote")
}
return nil, fmt.Errorf("no accepted quote")
_, err = unmarshalAssetRate(acceptedQuote.BidAssetRate)
if err != nil {
return nil, fmt.Errorf("invalid accepted quote asset rate: %w",
err)
}
return acceptedQuote, nil
}
// GetAssetName returns the human-readable name of the asset.
func (c *TapdClient) GetAssetName(ctx context.Context,
assetId []byte) (string, error) {
c.assetNameMutex.Lock()
defer c.assetNameMutex.Unlock()
assetIdStr := hex.EncodeToString(assetId)
if name, ok := c.assetNameCache[assetIdStr]; ok {
if name, ok := c.getCachedAssetName(assetIdStr); ok {
return name, nil
}
@ -181,11 +203,28 @@ func (c *TapdClient) GetAssetName(ctx context.Context,
assetName = assetStats.AssetStats[0].Asset.AssetName
}
c.assetNameCache[assetIdStr] = assetName
c.cacheAssetName(assetIdStr, assetName)
return assetName, nil
}
// getCachedAssetName returns an asset name from the cache.
func (c *TapdClient) getCachedAssetName(assetID string) (string, bool) {
c.assetNameMutex.RLock()
defer c.assetNameMutex.RUnlock()
name, ok := c.assetNameCache[assetID]
return name, ok
}
// cacheAssetName adds an asset name to the cache.
func (c *TapdClient) cacheAssetName(assetID, name string) {
c.assetNameMutex.Lock()
defer c.assetNameMutex.Unlock()
c.assetNameCache[assetID] = name
}
// GetAssetPrice returns the price of an asset in satoshis. NOTE: this currently
// uses the rfq process for the asset price. A future implementation should
// use a price oracle to not spam a peer.
@ -209,7 +248,7 @@ func (c *TapdClient) GetAssetPrice(ctx context.Context, assetID string,
},
PaymentMaxAmt: uint64(msatAmt),
Expiry: uint64(rfqExpiry),
TimeoutSeconds: uint32(c.cfg.RFQtimeout.Seconds()),
TimeoutSeconds: c.rfqTimeoutSeconds,
PeerPubKey: peerPubkey,
})
if err != nil {
@ -243,7 +282,7 @@ func (c *TapdClient) GetAssetPrice(ctx context.Context, assetID string,
func getSatsFromAssetAmt(assetAmt uint64, assetRate *rfqrpc.FixedPoint) (
btcutil.Amount, error) {
rateFP, err := rpcutils.UnmarshalRfqFixedPoint(assetRate)
rateFP, err := unmarshalAssetRate(assetRate)
if err != nil {
return 0, fmt.Errorf("cannot unmarshal asset rate: %w", err)
}
@ -255,6 +294,33 @@ func getSatsFromAssetAmt(assetAmt uint64, assetRate *rfqrpc.FixedPoint) (
return msatAmt.ToSatoshis(), nil
}
// unmarshalAssetRate validates and converts an RPC asset rate to the fixed
// point representation used for RFQ arithmetic.
func unmarshalAssetRate(assetRate *rfqrpc.FixedPoint) (
*rfqmath.BigIntFixedPoint, error) {
if assetRate == nil {
return nil, fmt.Errorf("asset rate cannot be nil")
}
if assetRate.Scale > math.MaxUint8 {
return nil, fmt.Errorf("scale value overflow: %v", assetRate.Scale)
}
coefficient, ok := new(big.Int).SetString(assetRate.Coefficient, 10)
if !ok {
return nil, fmt.Errorf("invalid asset rate coefficient: %q",
assetRate.Coefficient)
}
if coefficient.Sign() <= 0 {
return nil, fmt.Errorf("asset rate coefficient must be positive")
}
return &rfqmath.BigIntFixedPoint{
Coefficient: rfqmath.NewBigInt(coefficient),
Scale: uint8(assetRate.Scale),
}, nil
}
// getPaymentMaxAmount returns the milisat amount we are willing to pay for the
// payment.
func getPaymentMaxAmount(satAmount btcutil.Amount, feeLimitMultiplier float64) (
@ -277,6 +343,26 @@ func getPaymentMaxAmount(satAmount btcutil.Amount, feeLimitMultiplier float64) (
)
}
// getRfqTimeoutSeconds converts the configured RFQ timeout to the whole
// seconds accepted by tapd. Fractional seconds are rounded up so tapd's
// timeout is never shorter than the configured duration.
func getRfqTimeoutSeconds(timeout time.Duration) (uint32, error) {
if timeout <= 0 {
return 0, fmt.Errorf("RFQ timeout must be greater than zero")
}
seconds := timeout / time.Second
if timeout%time.Second != 0 {
seconds++
}
if seconds > time.Duration(math.MaxUint32) {
return 0, fmt.Errorf("RFQ timeout exceeds maximum of %v seconds",
uint64(math.MaxUint32))
}
return uint32(seconds), nil
}
func getClientConn(config *TapdConfig) (*grpc.ClientConn, error) {
// Load the specified TLS certificate and build transport credentials.
creds, err := credentials.NewClientTLSFromFile(config.TLSPath, "")

View file

@ -1,14 +1,269 @@
package assets
import (
"context"
"encoding/hex"
"encoding/pem"
"math"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"time"
"github.com/btcsuite/btcd/btcutil"
"github.com/lightninglabs/taproot-assets/taprpc/rfqrpc"
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"gopkg.in/macaroon.v2"
)
type blockingUniverseClient struct {
universerpc.UniverseClient
queryStarted chan struct{}
releaseQuery chan struct{}
}
func (b *blockingUniverseClient) QueryAssetStats(context.Context,
*universerpc.AssetStatsQuery, ...grpc.CallOption) (
*universerpc.UniverseAssetStats, error) {
close(b.queryStarted)
<-b.releaseQuery
return &universerpc.UniverseAssetStats{
AssetStats: []*universerpc.AssetStatsSnapshot{
{
Asset: &universerpc.AssetStatsAsset{
AssetName: "queried asset",
},
},
},
}, nil
}
type staticRfqClient struct {
rfqrpc.RfqClient
response *rfqrpc.AddAssetSellOrderResponse
}
func (s *staticRfqClient) AddAssetSellOrder(context.Context,
*rfqrpc.AddAssetSellOrderRequest, ...grpc.CallOption) (
*rfqrpc.AddAssetSellOrderResponse, error) {
return s.response, nil
}
// TestDefaultTapdConfig tests that the default tapd connection paths match
// tapd's mainnet defaults.
func TestDefaultTapdConfig(t *testing.T) {
defaultTapdDir := btcutil.AppDataDir("tapd", false)
config := DefaultTapdConfig()
require.Equal(t, filepath.Join(
defaultTapdDir, "data", "mainnet", "admin.macaroon",
), config.MacaroonPath)
require.Equal(
t, filepath.Join(defaultTapdDir, "tls.cert"), config.TLSPath,
)
}
// TestTapdConfigClientConn tests that the default tapd file layout can be used
// to construct a client connection.
func TestTapdConfigClientConn(t *testing.T) {
// Use an isolated tapd root so the test never reads from or writes to a
// user's real tapd data directory.
defaultTapdDir := t.TempDir()
network := "regtest"
macaroonPath := filepath.Join(
defaultTapdDir, "data", network, "admin.macaroon",
)
require.NoError(t, os.MkdirAll(filepath.Dir(macaroonPath), 0o700))
// NewTapdClient parses the configured TLS certificate before creating
// its gRPC client. An httptest server provides a valid certificate
// without requiring a running tapd instance.
tlsServer := httptest.NewTLSServer(http.NotFoundHandler())
t.Cleanup(tlsServer.Close)
cert := tlsServer.Certificate()
certBytes := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE", Bytes: cert.Raw,
})
require.NoError(t, os.WriteFile(
filepath.Join(defaultTapdDir, "tls.cert"), certBytes, 0o600,
))
// Store a valid serialized macaroon at tapd's production path. This
// ensures connection setup tests the path itself rather than failing on
// malformed credentials.
mac, err := macaroon.New(
[]byte("root-key"), []byte("id"), "tapd",
macaroon.LatestVersion,
)
require.NoError(t, err)
macBytes, err := mac.MarshalBinary()
require.NoError(t, err)
require.NoError(t, os.WriteFile(macaroonPath, macBytes, 0o600))
// grpc.NewClient connects lazily, so constructing the tapd client verifies
// that both credentials can be loaded and parsed without needing a live
// tapd server.
config := DefaultTapdConfigForNetwork(defaultTapdDir, network)
client, err := NewTapdClient(config)
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, client.cc.Close())
})
require.Equal(t, macaroonPath, config.MacaroonPath)
require.Equal(
t, filepath.Join(defaultTapdDir, "tls.cert"), config.TLSPath,
)
}
// TestGetAssetNameCachedLookupNotBlocked verifies that a slow universe query
// for one asset does not prevent another caller from reading a cached name.
func TestGetAssetNameCachedLookupNotBlocked(t *testing.T) {
const cachedName = "cached asset"
cachedAssetID := []byte{1}
queryStarted := make(chan struct{})
releaseQuery := make(chan struct{})
client := &TapdClient{
UniverseClient: &blockingUniverseClient{
queryStarted: queryStarted,
releaseQuery: releaseQuery,
},
assetNameCache: map[string]string{
hex.EncodeToString(cachedAssetID): cachedName,
},
}
queryResult := make(chan error, 1)
go func() {
_, err := client.GetAssetName(context.Background(), []byte{2})
queryResult <- err
}()
select {
case <-queryStarted:
case <-time.After(time.Second):
t.Fatal("universe query did not start")
}
type nameResult struct {
name string
err error
}
cachedResult := make(chan nameResult, 1)
go func() {
name, err := client.GetAssetName(
context.Background(), cachedAssetID,
)
cachedResult <- nameResult{name: name, err: err}
}()
select {
case result := <-cachedResult:
require.NoError(t, result.err)
require.Equal(t, cachedName, result.name)
case <-time.After(time.Second):
close(releaseQuery)
t.Fatal("cached lookup blocked behind universe query")
}
close(releaseQuery)
require.NoError(t, <-queryResult)
}
// TestGetRfqForAssetValidatesRate verifies that malformed accepted quote rates
// are rejected before they reach downstream RFQ arithmetic.
func TestGetRfqForAssetValidatesRate(t *testing.T) {
tests := []struct {
name string
assetRate *rfqrpc.FixedPoint
expectError bool
}{
{
name: "valid",
assetRate: &rfqrpc.FixedPoint{
Coefficient: "100000", Scale: 0,
},
},
{
name: "nil",
assetRate: nil,
expectError: true,
},
{
name: "malformed coefficient",
assetRate: &rfqrpc.FixedPoint{
Coefficient: "not-a-number", Scale: 0,
},
expectError: true,
},
{
name: "zero coefficient",
assetRate: &rfqrpc.FixedPoint{
Coefficient: "0", Scale: 0,
},
expectError: true,
},
{
name: "negative coefficient",
assetRate: &rfqrpc.FixedPoint{
Coefficient: "-1", Scale: 0,
},
expectError: true,
},
{
name: "scale overflow",
assetRate: &rfqrpc.FixedPoint{
Coefficient: "1", Scale: 256,
},
expectError: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
acceptedQuote := &rfqrpc.PeerAcceptedSellQuote{
BidAssetRate: test.assetRate,
}
acceptedResponse :=
&rfqrpc.AddAssetSellOrderResponse_AcceptedQuote{
AcceptedQuote: acceptedQuote,
}
client := &TapdClient{
RfqClient: &staticRfqClient{
response: &rfqrpc.AddAssetSellOrderResponse{
Response: acceptedResponse,
},
},
rfqTimeoutSeconds: 60,
}
quote, err := client.GetRfqForAsset(
context.Background(), 1000, []byte{1}, []byte{2},
time.Now().Add(time.Minute).Unix(), 1,
)
if test.expectError {
require.Error(t, err)
require.Nil(t, quote)
return
}
require.NoError(t, err)
require.Same(t, acceptedQuote, quote)
})
}
}
func TestGetPaymentMaxAmount(t *testing.T) {
tests := []struct {
satAmount btcutil.Amount
@ -68,6 +323,62 @@ func TestGetPaymentMaxAmount(t *testing.T) {
}
}
// TestGetRfqTimeoutSeconds verifies that configured durations are safely
// converted to tapd's whole-second timeout field.
func TestGetRfqTimeoutSeconds(t *testing.T) {
tests := []struct {
name string
timeout time.Duration
expectedSeconds uint32
expectError bool
}{
{
name: "whole seconds",
timeout: 60 * time.Second,
expectedSeconds: 60,
},
{
name: "sub-second rounded up",
timeout: time.Millisecond,
expectedSeconds: 1,
},
{
name: "fractional second rounded up",
timeout: time.Second + time.Nanosecond,
expectedSeconds: 2,
},
{
name: "zero",
timeout: 0,
expectError: true,
},
{
name: "negative",
timeout: -time.Second,
expectError: true,
},
{
name: "overflow",
timeout: time.Duration(math.MaxUint32)*time.Second +
time.Nanosecond,
expectError: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
seconds, err := getRfqTimeoutSeconds(test.timeout)
if test.expectError {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, test.expectedSeconds, seconds)
})
}
}
func TestGetSatsFromAssetAmt(t *testing.T) {
tests := []struct {
assetAmt uint64
@ -93,6 +404,39 @@ func TestGetSatsFromAssetAmt(t *testing.T) {
expected: btcutil.Amount(0),
expectError: false,
},
{
assetAmt: 1000,
assetRate: nil,
expectError: true,
},
{
assetAmt: 1000,
assetRate: &rfqrpc.FixedPoint{
Coefficient: "not-a-number", Scale: 0,
},
expectError: true,
},
{
assetAmt: 1000,
assetRate: &rfqrpc.FixedPoint{
Coefficient: "0", Scale: 0,
},
expectError: true,
},
{
assetAmt: 1000,
assetRate: &rfqrpc.FixedPoint{
Coefficient: "-1", Scale: 0,
},
expectError: true,
},
{
assetAmt: 1000,
assetRate: &rfqrpc.FixedPoint{
Coefficient: "1", Scale: 256,
},
expectError: true,
},
}
for _, test := range tests {

View file

@ -183,6 +183,8 @@ func instantOut(ctx context.Context, cmd *cli.Command) error {
fmt.Println("Starting instant swap out")
maxSwapFee := quote.ServiceFeeSat
// Now we can request the instant out swap.
instantOutRes, err := client.InstantOut(
ctx,
@ -190,6 +192,9 @@ func instantOut(ctx context.Context, cmd *cli.Command) error {
ReservationIds: selectedReservations,
OutgoingChanSet: outgoingChanSet,
DestAddr: cmd.String("addr"),
MaxSwapFee: &looprpc.InstantOutRequest_MaxSwapFeeSat{
MaxSwapFeeSat: maxSwapFee,
},
},
)
if err != nil {

View file

@ -207,7 +207,7 @@ func loopIn(ctx context.Context, cmd *cli.Command) error {
}
fmt.Printf("Swap initiated\n")
fmt.Printf("ID: %v\n", resp.Id)
fmt.Printf("ID: %x\n", resp.IdBytes)
if resp.HtlcAddressP2Tr != "" {
fmt.Printf("HTLC address (P2TR): %v\n", resp.HtlcAddressP2Tr)

View file

@ -6,7 +6,6 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"os/signal"
"path/filepath"
@ -561,10 +560,7 @@ func parseAmt(text string) (btcutil.Amount, error) {
func logSwap(swap *looprpc.SwapStatus) {
// If our swap failed, we add our failure reason to the state.
swapState := fmt.Sprintf("%v", swap.State)
if swap.State == looprpc.SwapState_FAILED {
swapState = fmt.Sprintf("%v (%v)", swapState, swap.FailureReason)
}
swapState := monitorSwapState(swap)
if swap.Type == looprpc.SwapType_LOOP_OUT {
fmt.Printf("%v %v %v %v - %v",
@ -586,10 +582,32 @@ func logSwap(swap *looprpc.SwapStatus) {
}
}
if swap.State != looprpc.SwapState_INITIATED &&
swap.State != looprpc.SwapState_HTLC_PUBLISHED &&
swap.State != looprpc.SwapState_PREIMAGE_REVEALED {
showCost := shouldShowSwapCost(swap.GetState())
if swap.Type == looprpc.SwapType_STATIC_LOOP_IN {
staticState := swap.GetStaticLoopInState()
// Static loop-ins key cost visibility off the dedicated FSM state, not
// the generic SwapState lifecycle used by traditional swaps.
switch staticState {
case looprpc.StaticAddressLoopInSwapState_INIT_HTLC,
looprpc.StaticAddressLoopInSwapState_SIGN_HTLC_TX,
looprpc.StaticAddressLoopInSwapState_MONITOR_INVOICE_HTLC_TX,
looprpc.StaticAddressLoopInSwapState_SWEEP_STATIC_ADDRESS_HTLC_TIMEOUT,
looprpc.StaticAddressLoopInSwapState_MONITOR_HTLC_TIMEOUT_SWEEP,
looprpc.StaticAddressLoopInSwapState_UNLOCK_DEPOSITS:
showCost = false
case looprpc.StaticAddressLoopInSwapState_PAYMENT_RECEIVED,
looprpc.StaticAddressLoopInSwapState_HTLC_STATIC_ADDRESS_TIMEOUT_SWEPT,
looprpc.StaticAddressLoopInSwapState_SUCCEEDED,
looprpc.StaticAddressLoopInSwapState_SUCCEEDED_TRANSITIONING_FAILED,
looprpc.StaticAddressLoopInSwapState_FAILED_STATIC_ADDRESS_SWAP:
showCost = true
}
}
if showCost {
fmt.Printf(" (cost: server %v, onchain %v, offchain %v)",
swap.CostServer, swap.CostOnchain, swap.CostOffchain,
)
@ -598,6 +616,38 @@ func logSwap(swap *looprpc.SwapStatus) {
fmt.Println()
}
// monitorSwapState returns the static loop-in FSM label for static swaps and
// the shared swap-state label for all others.
func monitorSwapState(swap *looprpc.SwapStatus) string {
if swap.Type == looprpc.SwapType_STATIC_LOOP_IN {
return swap.GetStaticLoopInState().String()
}
return genericMonitorSwapState(swap)
}
// shouldShowSwapCost reports whether a swap's generic state is terminal enough
// to include the persisted cost summary in monitor output.
func shouldShowSwapCost(loopState looprpc.SwapState) bool {
return loopState != looprpc.SwapState_INITIATED &&
loopState != looprpc.SwapState_HTLC_PUBLISHED &&
loopState != looprpc.SwapState_PREIMAGE_REVEALED
}
// genericMonitorSwapState formats the shared swap-state label and failure
// reason used by non-static swaps.
func genericMonitorSwapState(swap *looprpc.SwapStatus) string {
loopState := swap.GetState()
swapState := fmt.Sprintf("%v", loopState)
if loopState == looprpc.SwapState_FAILED {
swapState = fmt.Sprintf(
"%v (%v)", swapState, swap.FailureReason,
)
}
return swapState
}
// getClientConn dials the loopd gRPC server with TLS and macaroon auth.
func getClientConn(address, tlsCertPath, macaroonPath string) (daemonConn,
func(), error) {
@ -646,7 +696,7 @@ func getClientConn(address, tlsCertPath, macaroonPath string) (daemonConn,
// gRPC dial options from it.
func readMacaroon(macPath string) (grpc.DialOption, error) {
// Load the specified macaroon file.
macBytes, err := ioutil.ReadFile(macPath)
macBytes, err := os.ReadFile(macPath)
if err != nil {
return nil, fmt.Errorf("unable to read macaroon path : %v", err)
}

275
cmd/loop/monitor_test.go Normal file
View file

@ -0,0 +1,275 @@
package main
import (
"bytes"
"io"
"os"
"strings"
"testing"
"time"
"github.com/lightninglabs/loop/looprpc"
"github.com/stretchr/testify/require"
)
// TestMonitorSwapStateKeepsRegularLoopInFailureReason preserves the generic
// failure suffix for regular loop-in swaps so terminal errors stay visible.
func TestMonitorSwapStateKeepsRegularLoopInFailureReason(t *testing.T) {
swap := &looprpc.SwapStatus{
Type: looprpc.SwapType_LOOP_IN,
State: looprpc.SwapState_FAILED,
FailureReason: looprpc.
FailureReason_FAILURE_REASON_TIMEOUT,
}
got := monitorSwapState(swap)
require.Equal(t, "FAILED (FAILURE_REASON_TIMEOUT)", got)
}
// TestMonitorSwapStateLabelsStaticLoopInStages locks the precise static loop-in
// stage names so monitor output stays stable as the FSM evolves.
func TestMonitorSwapStateLabelsStaticLoopInStages(t *testing.T) {
tests := []struct {
name string
staticState looprpc.StaticAddressLoopInSwapState
want string
}{
{
name: "init htlc",
staticState: looprpc.StaticAddressLoopInSwapState_INIT_HTLC,
want: "INIT_HTLC",
},
{
name: "sign htlc",
staticState: looprpc.
StaticAddressLoopInSwapState_SIGN_HTLC_TX,
want: "SIGN_HTLC_TX",
},
{
name: "monitor invoice and htlc",
staticState: looprpc.
StaticAddressLoopInSwapState_MONITOR_INVOICE_HTLC_TX,
want: "MONITOR_INVOICE_HTLC_TX",
},
{
name: "unlock deposits",
staticState: looprpc.
StaticAddressLoopInSwapState_UNLOCK_DEPOSITS,
want: "UNLOCK_DEPOSITS",
},
{
name: "payment received",
staticState: looprpc.StaticAddressLoopInSwapState_PAYMENT_RECEIVED,
want: "PAYMENT_RECEIVED",
},
{
name: "timeout sweep",
staticState: looprpc.
StaticAddressLoopInSwapState_SWEEP_STATIC_ADDRESS_HTLC_TIMEOUT,
want: "SWEEP_STATIC_ADDRESS_HTLC_TIMEOUT",
},
{
name: "monitor timeout sweep",
staticState: looprpc.
StaticAddressLoopInSwapState_MONITOR_HTLC_TIMEOUT_SWEEP,
want: "MONITOR_HTLC_TIMEOUT_SWEEP",
},
{
name: "timeout swept",
staticState: looprpc.
StaticAddressLoopInSwapState_HTLC_STATIC_ADDRESS_TIMEOUT_SWEPT,
want: "HTLC_STATIC_ADDRESS_TIMEOUT_SWEPT",
},
{
name: "success",
staticState: looprpc.StaticAddressLoopInSwapState_SUCCEEDED,
want: "SUCCEEDED",
},
{
name: "succeeded transitioning failed",
staticState: looprpc.
StaticAddressLoopInSwapState_SUCCEEDED_TRANSITIONING_FAILED,
want: "SUCCEEDED_TRANSITIONING_FAILED",
},
{
name: "failed",
staticState: looprpc.
StaticAddressLoopInSwapState_FAILED_STATIC_ADDRESS_SWAP,
want: "FAILED_STATIC_ADDRESS_SWAP",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
swap := &looprpc.SwapStatus{
Type: looprpc.SwapType_STATIC_LOOP_IN,
StaticLoopInStateOptional: &looprpc.SwapStatus_StaticLoopInState{
StaticLoopInState: test.staticState,
},
}
got := monitorSwapState(swap)
require.Equal(t, test.want, got)
})
}
initSwap := &looprpc.SwapStatus{
Type: looprpc.SwapType_STATIC_LOOP_IN,
StaticLoopInStateOptional: &looprpc.SwapStatus_StaticLoopInState{
StaticLoopInState: looprpc.
StaticAddressLoopInSwapState_INIT_HTLC,
},
}
signSwap := &looprpc.SwapStatus{
Type: looprpc.SwapType_STATIC_LOOP_IN,
StaticLoopInStateOptional: &looprpc.SwapStatus_StaticLoopInState{
StaticLoopInState: looprpc.
StaticAddressLoopInSwapState_SIGN_HTLC_TX,
},
}
require.NotEqual(t, monitorSwapState(initSwap), monitorSwapState(signSwap))
}
// TestMonitorSwapStateLabelsUnknownStaticLoopIn ensures the absent static
// oneof maps to the UNKNOWN static loop-in label.
func TestMonitorSwapStateLabelsUnknownStaticLoopIn(t *testing.T) {
swap := &looprpc.SwapStatus{
Type: looprpc.SwapType_STATIC_LOOP_IN,
}
got := monitorSwapState(swap)
require.Equal(t, "UNKNOWN_STATIC_ADDRESS_SWAP_STATE", got)
}
// TestLogSwapHidesStaticLoopInCostForInFlightState proves in-flight static FSM
// state suppresses cost even with generic SUCCESS set deliberately.
func TestLogSwapHidesStaticLoopInCostForInFlightState(t *testing.T) {
swap := &looprpc.SwapStatus{
LastUpdateTime: time.Unix(1, 0).UnixNano(),
Type: looprpc.SwapType_STATIC_LOOP_IN,
State: looprpc.SwapState_SUCCESS,
StaticLoopInStateOptional: &looprpc.SwapStatus_StaticLoopInState{
StaticLoopInState: looprpc.
StaticAddressLoopInSwapState_INIT_HTLC,
},
Amt: 50_000,
CostServer: 11,
CostOnchain: 22,
CostOffchain: 33,
HtlcAddressP2Wsh: "bc1qstaticinflighttestaddress",
}
output := captureStdout(t, func() {
logSwap(swap)
})
require.Contains(t, output, "STATIC_LOOP_IN INIT_HTLC 0.00050000 BTC")
require.NotContains(t, output, "(cost:")
}
// TestLogSwapHidesCostForUnknownStaticLoopInState ensures unknown static
// states print the UNKNOWN label without a cost summary.
func TestLogSwapHidesCostForUnknownStaticLoopInState(t *testing.T) {
swap := &looprpc.SwapStatus{
LastUpdateTime: time.Unix(3, 0).UnixNano(),
Type: looprpc.SwapType_STATIC_LOOP_IN,
StaticLoopInStateOptional: &looprpc.SwapStatus_StaticLoopInState{
StaticLoopInState: looprpc.
StaticAddressLoopInSwapState_UNKNOWN_STATIC_ADDRESS_SWAP_STATE,
},
Amt: 50_000,
CostServer: 11,
CostOnchain: 22,
CostOffchain: 33,
HtlcAddressP2Wsh: "bc1qunknownstaticterminaltestaddress",
}
output := captureStdout(t, func() {
logSwap(swap)
})
require.Contains(
t, output, "STATIC_LOOP_IN UNKNOWN_STATIC_ADDRESS_SWAP_STATE 0.00050000 BTC",
)
require.NotContains(t, output, "(cost:")
}
// TestLogSwapShowsStaticLoopInCostForTerminalState preserves terminal cost
// output, including the P2WSH address, once the static loop-in is done.
func TestLogSwapShowsStaticLoopInCostForTerminalState(t *testing.T) {
swap := &looprpc.SwapStatus{
LastUpdateTime: time.Unix(2, 0).UnixNano(),
Type: looprpc.SwapType_STATIC_LOOP_IN,
State: looprpc.SwapState_INITIATED,
StaticLoopInStateOptional: &looprpc.SwapStatus_StaticLoopInState{
StaticLoopInState: looprpc.
StaticAddressLoopInSwapState_SUCCEEDED,
},
Amt: 50_000,
CostServer: 11,
CostOnchain: 22,
CostOffchain: 33,
HtlcAddressP2Wsh: "bc1qstaticterminaltestaddress",
}
output := captureStdout(t, func() {
logSwap(swap)
})
require.Contains(
t, output,
"STATIC_LOOP_IN SUCCEEDED 0.00050000 BTC - P2WSH: bc1qstaticterminaltestaddress",
)
require.Contains(
t, output,
"(cost: server 11, onchain 22, offchain 33)",
)
}
// TestLogSwapDisplaysStaticLoopInTypeAndStage ensures the monitor output names
// the static loop-in type and active FSM stage instead of collapsing them.
func TestLogSwapDisplaysStaticLoopInTypeAndStage(t *testing.T) {
swap := &looprpc.SwapStatus{
LastUpdateTime: time.Unix(1, 0).UnixNano(),
Type: looprpc.SwapType_STATIC_LOOP_IN,
StaticLoopInStateOptional: &looprpc.SwapStatus_StaticLoopInState{
StaticLoopInState: looprpc.
StaticAddressLoopInSwapState_SIGN_HTLC_TX,
},
Amt: 50_000,
HtlcAddressP2Wsh: "tb1q5cyxnuxmeuwuvkwfem96llyxf8duyshm56t8k8",
}
output := captureStdout(t, func() {
logSwap(swap)
})
require.Contains(
t, output, "STATIC_LOOP_IN SIGN_HTLC_TX 0.00050000 BTC",
)
require.Contains(
t, output, "P2WSH: tb1q5cyxnuxmeuwuvkwfem96llyxf8duyshm56t8k8",
)
require.NotContains(t, output, "STATIC_LOOP_IN INIT_HTLC")
}
func captureStdout(t *testing.T, fn func()) string {
t.Helper()
originalStdout := os.Stdout
reader, writer, err := os.Pipe()
require.NoError(t, err)
os.Stdout = writer
fn()
require.NoError(t, writer.Close())
os.Stdout = originalStdout
var buf bytes.Buffer
_, err = io.Copy(&buf, reader)
require.NoError(t, err)
require.NoError(t, reader.Close())
return strings.TrimSpace(buf.String())
}

View file

@ -7,19 +7,17 @@ import (
"strconv"
"github.com/lightninglabs/loop/looprpc"
lndcommands "github.com/lightningnetwork/lnd/cmd/commands"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/urfave/cli/v3"
)
const (
defaultUtxoMinConf = 1
)
var (
defaultUtxoMinConf = 1
channelTypeTweakless = "tweakless"
channelTypeAnchors = "anchors"
channelTypeSimpleTaproot = "taproot"
channelTypeSimpleTaproot = "simple-taproot"
channelTypeTaproot = "taproot"
)
var openChannelCommand = &cli.Command{
@ -137,9 +135,9 @@ var openChannelCommand = &cli.Command{
&cli.StringFlag{
Name: "channel_type",
Usage: fmt.Sprintf("(optional) the type of channel to "+
"propose to the remote peer (%q, %q, %q)",
"propose to the remote peer (%q, %q, %q, %q)",
channelTypeTweakless, channelTypeAnchors,
channelTypeSimpleTaproot),
channelTypeSimpleTaproot, channelTypeTaproot),
},
&cli.BoolFlag{
Name: "zero_conf",
@ -160,11 +158,11 @@ var openChannelCommand = &cli.Command{
},
&cli.StringFlag{
Name: "memo",
Usage: `(optional) a note-to-self containing some useful
information about the channel. This is stored
locally only, and is purely for reference. It
has no bearing on the channel's operation. Max
allowed length is 500 characters`,
Usage: "(optional) a note-to-self containing some useful " +
"information about the channel. This is stored " +
"locally only, and is purely for reference. It " +
"has no bearing on the channel's operation. Max " +
"allowed length is 500 characters",
},
&cli.BoolFlag{
Name: "fundmax",
@ -271,7 +269,7 @@ func openChannel(ctx context.Context, cmd *cli.Command) error {
if cmd.IsSet("utxo") {
utxos := cmd.StringSlice("utxo")
outpoints, err := lndcommands.UtxosToOutpoints(utxos)
outpoints, err := lnd.UtxosToOutpoints(utxos)
if err != nil {
return fmt.Errorf("unable to decode utxos: %w", err)
}
@ -322,6 +320,7 @@ func openChannel(ctx context.Context, cmd *cli.Command) error {
switch channelType {
case "":
break
case channelTypeTweakless:
req.CommitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY
@ -330,6 +329,10 @@ func openChannel(ctx context.Context, cmd *cli.Command) error {
case channelTypeSimpleTaproot:
req.CommitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
case channelTypeTaproot:
req.CommitmentType = lnrpc.CommitmentType_TAPROOT
default:
return fmt.Errorf("unsupported channel type %v", channelType)
}

View file

@ -1193,7 +1193,7 @@ var rfc3339TimestampRegex = regexp.MustCompile(
// timeStringTimestampRegex matches time.String-style timestamps embedded in
// CLI output.
var timeStringTimestampRegex = regexp.MustCompile(
`\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [+-]\d{4} [A-Z]{2,5}`,
`\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [+-]\d{4} (?:[A-Z]{2,5}|[+-]\d{2}(?:\d{2})?)`,
)
// normalizeTimestamps rewrites embedded timestamps to UTC to avoid
@ -1214,7 +1214,14 @@ func normalizeTimestamps(text string) string {
// Normalize time.String timestamps next.
timeReplacer := func(ts string) string {
parsed, err := time.Parse("2006-01-02 15:04:05 -0700 MST", ts)
zoneNameIndex := strings.LastIndex(ts, " ")
if zoneNameIndex <= 0 {
return ts
}
parsed, err := time.Parse(
"2006-01-02 15:04:05 -0700", ts[:zoneNameIndex],
)
if err != nil {
return ts
}
@ -1229,6 +1236,41 @@ func normalizeTimestamps(text string) string {
return text
}
// TestNormalizeTimestamps verifies that timestamp normalization handles the
// timestamp formats emitted by CLI commands in different local time zones.
func TestNormalizeTimestamps(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
text string
want string
}{
{
name: "rfc3339",
text: "updated: 2026-01-26T01:28:06-05:00\n",
want: "updated: 2026-01-26T06:28:06Z\n",
},
{
name: "alphabetic time string zone",
text: "deadline: 2026-01-26 01:28:06 -0500 EST\n",
want: "deadline: 2026-01-26 06:28:06 +0000 UTC\n",
},
{
name: "numeric time string zone",
text: "deadline: 2026-01-26 03:28:06 -0300 -03\n",
want: "deadline: 2026-01-26 06:28:06 +0000 UTC\n",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
got := normalizeTimestamps(testCase.text)
require.Equal(t, testCase.want, got)
})
}
}
// TestCloneCommandForReplayResetsFlagState verifies cloned commands reset flag
// state.
func TestCloneCommandForReplayResetsFlagState(t *testing.T) {

View file

@ -4,14 +4,17 @@ import (
"context"
"errors"
"fmt"
"sort"
"strings"
"github.com/lightninglabs/loop/labels"
"github.com/lightninglabs/loop/looprpc"
"github.com/lightninglabs/loop/staticaddr/deposit"
"github.com/lightninglabs/loop/staticaddr/loopin"
"github.com/lightninglabs/loop/swapserverrpc"
lndcommands "github.com/lightningnetwork/lnd/cmd/commands"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/urfave/cli/v3"
)
@ -192,7 +195,7 @@ func withdraw(ctx context.Context, cmd *cli.Command) error {
case isAllSelected:
case isUtxoSelected:
utxos := cmd.StringSlice("utxo")
outpoints, err = lndcommands.UtxosToOutpoints(utxos)
outpoints, err = lnd.UtxosToOutpoints(utxos)
if err != nil {
return err
}
@ -553,11 +556,7 @@ func staticAddressLoopIn(ctx context.Context, cmd *cli.Command) error {
allDeposits := depositList.FilteredDeposits
if len(allDeposits) == 0 {
errString := fmt.Sprintf("no confirmed deposits available, "+
"deposits need at least %v confirmations",
deposit.MinConfs)
return errors.New(errString)
return errors.New("no deposited outputs available")
}
var depositOutpoints []string
@ -614,6 +613,28 @@ func staticAddressLoopIn(ctx context.Context, cmd *cli.Command) error {
return err
}
// Warn the user if any selected deposits have fewer than 6
// confirmations, as the swap payment won't be received immediately
// for those.
summary, err := client.GetStaticAddressSummary(
ctx, &looprpc.StaticAddressSummaryRequest{},
)
if err != nil {
return err
}
depositsToCheck := warningDepositOutpoints(
allDeposits, depositOutpoints, autoSelectDepositsForQuote,
quoteReq.Amt,
)
warning := lowConfDepositWarning(
allDeposits, depositsToCheck,
int64(summary.RelativeExpiryBlocks),
)
if warning != "" {
fmt.Println(warning)
}
if !(cmd.Bool("force") || cmd.Bool("f")) {
err = displayInDetails(quoteReq, quote, cmd.Bool("verbose"))
if err != nil {
@ -669,6 +690,162 @@ func depositsToOutpoints(deposits []*looprpc.Deposit) []string {
return outpoints
}
var warningSelectionDustLimit = int64(lnwallet.DustLimitForSize(input.P2TRSize))
// warningDepositOutpoints returns the deposit outpoints to check for
// low-confirmation warnings.
func warningDepositOutpoints(allDeposits []*looprpc.Deposit,
selectedOutpoints []string, autoSelect bool, targetAmount int64) []string {
if !autoSelect {
return selectedOutpoints
}
return autoSelectedWarningOutpoints(allDeposits, targetAmount)
}
// autoSelectedWarningOutpoints returns the outpoints selected by the same
// ordering used for automatic static loop-in deposit selection.
func autoSelectedWarningOutpoints(allDeposits []*looprpc.Deposit,
targetAmount int64) []string {
if targetAmount <= 0 {
return nil
}
// KEEP IN SYNC with staticaddr/loopin.SelectDeposits.
deposits := filterSwappableWarningDeposits(allDeposits)
sort.Slice(deposits, func(i, j int) bool {
iConfirmed := deposits[i].ConfirmationHeight > 0
jConfirmed := deposits[j].ConfirmationHeight > 0
if iConfirmed != jConfirmed {
return iConfirmed
}
if deposits[i].Value == deposits[j].Value {
return deposits[i].BlocksUntilExpiry <
deposits[j].BlocksUntilExpiry
}
return deposits[i].Value > deposits[j].Value
})
selectedOutpoints := make([]string, 0, len(deposits))
var selectedAmount int64
for _, deposit := range deposits {
selectedOutpoints = append(selectedOutpoints, deposit.Outpoint)
selectedAmount += deposit.Value
if selectedAmount == targetAmount {
return selectedOutpoints
}
if selectedAmount > targetAmount &&
selectedAmount-targetAmount >= warningSelectionDustLimit {
return selectedOutpoints
}
}
return nil
}
// filterSwappableWarningDeposits filters deposits for CLI warning selection.
func filterSwappableWarningDeposits(
allDeposits []*looprpc.Deposit) []*looprpc.Deposit {
swappable := make([]*looprpc.Deposit, 0, len(allDeposits))
minBlocksUntilExpiry := int64(
loopin.DefaultLoopInOnChainCltvDelta + loopin.DepositHtlcDelta,
)
for _, deposit := range allDeposits {
// Unconfirmed deposits remain swappable because their CSV timeout has
// not started yet. This mirrors loopin.IsSwappable.
if deposit.ConfirmationHeight > 0 &&
deposit.BlocksUntilExpiry < minBlocksUntilExpiry {
continue
}
swappable = append(swappable, deposit)
}
return swappable
}
// conservativeWarningConfs is the highest default confirmation tier used by
// the server's dynamic confirmation-risk policy.
//
// The CLI does not currently know the server's exact policy, so we use this
// conservative threshold for warnings without promising immediate execution.
const conservativeWarningConfs = 6
// lowConfDepositWarning checks the selected deposits against a conservative
// confirmation threshold and returns a warning string if any are found.
func lowConfDepositWarning(allDeposits []*looprpc.Deposit,
selectedOutpoints []string, csvExpiry int64) string {
depositMap := make(map[string]*looprpc.Deposit, len(allDeposits))
for _, d := range allDeposits {
depositMap[d.Outpoint] = d
}
var lowConfEntries []string
for _, op := range selectedOutpoints {
d, ok := depositMap[op]
if !ok {
continue
}
var confs int64
switch {
case d.ConfirmationHeight <= 0:
confs = 0
case csvExpiry > 0:
// For confirmed deposits we can compute
// confirmations as CSVExpiry - BlocksUntilExpiry + 1.
confs = csvExpiry - d.BlocksUntilExpiry + 1
default:
// Can't determine confirmations without the CSV expiry.
continue
}
if confs >= conservativeWarningConfs {
continue
}
if confs == 0 {
lowConfEntries = append(
lowConfEntries,
fmt.Sprintf(" - %s (unconfirmed)", op),
)
} else {
lowConfEntries = append(
lowConfEntries,
fmt.Sprintf(
" - %s (%d confirmations)", op,
confs,
),
)
}
}
if len(lowConfEntries) == 0 {
return ""
}
return fmt.Sprintf(
"\nWARNING: The following deposits are below the "+
"conservative %d-confirmation threshold:\n%s\n"+
"The swap payment for these deposits may wait for "+
"more confirmations depending on the server's "+
"confirmation-risk policy.\n",
conservativeWarningConfs,
strings.Join(lowConfEntries, "\n"),
)
}
func displayNewAddressWarning() error {
fmt.Printf("\nWARNING: Be aware that loosing your l402.token file in " +
".loop under your home directory will take your ability to " +

220
cmd/loop/staticaddr_test.go Normal file
View file

@ -0,0 +1,220 @@
package main
import (
"strings"
"testing"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/loop/looprpc"
"github.com/lightninglabs/loop/staticaddr/deposit"
"github.com/lightninglabs/loop/staticaddr/loopin"
"github.com/stretchr/testify/require"
)
// TestLowConfDepositWarningConfirmedOnly verifies confirmed deposits below the
// conservative warning threshold are included in the warning text.
func TestLowConfDepositWarningConfirmedOnly(t *testing.T) {
t.Parallel()
deposits := []*looprpc.Deposit{
{
Outpoint: "confirmed-low",
ConfirmationHeight: 100,
BlocksUntilExpiry: 140,
},
{
Outpoint: "confirmed-high",
ConfirmationHeight: 95,
BlocksUntilExpiry: 139,
},
}
warning := lowConfDepositWarning(
deposits, []string{"confirmed-low", "confirmed-high"}, 144,
)
require.Contains(t, warning, "confirmed-low (5 confirmations)")
require.NotContains(t, warning, "confirmed-high")
}
// TestLowConfDepositWarningUnconfirmed verifies unconfirmed deposits get a
// warning that the swap may wait for confirmation-risk acceptance.
func TestLowConfDepositWarningUnconfirmed(t *testing.T) {
t.Parallel()
deposits := []*looprpc.Deposit{
{
Outpoint: "mempool",
ConfirmationHeight: 0,
BlocksUntilExpiry: 144,
},
}
warning := lowConfDepositWarning(deposits, []string{"mempool"}, 144)
require.Contains(t, warning, "mempool (unconfirmed)")
require.True(
t,
strings.Contains(
warning,
"conservative 6-confirmation threshold",
),
)
require.NotContains(t, warning, "executed immediately")
}
// TestWarningDepositOutpointsAutoSelectPrefersConfirmed verifies automatic
// warning selection keeps the loop-in preference for confirmed outputs.
func TestWarningDepositOutpointsAutoSelectPrefersConfirmed(t *testing.T) {
t.Parallel()
const csvExpiry = 1100
deposits := []*looprpc.Deposit{
{
Outpoint: "mempool-large",
Value: 2_000_000,
ConfirmationHeight: 0,
BlocksUntilExpiry: csvExpiry,
},
{
Outpoint: "confirmed",
Value: 1_500_000,
ConfirmationHeight: 100,
BlocksUntilExpiry: csvExpiry - 5,
},
}
selected := warningDepositOutpoints(deposits, nil, true, 1_000_000)
require.Equal(t, []string{"confirmed"}, selected)
require.Empty(t, lowConfDepositWarning(deposits, selected, csvExpiry))
}
// TestWarningDepositOutpointsAutoSelectIncludesNeededUnconfirmed verifies the
// warning path includes mempool deposits when they are needed for the target.
func TestWarningDepositOutpointsAutoSelectIncludesNeededUnconfirmed(t *testing.T) {
t.Parallel()
const csvExpiry = 1100
deposits := []*looprpc.Deposit{
{
Outpoint: "confirmed-small",
Value: 500_000,
ConfirmationHeight: 100,
BlocksUntilExpiry: csvExpiry - 5,
},
{
Outpoint: "mempool-large",
Value: 2_000_000,
ConfirmationHeight: 0,
BlocksUntilExpiry: csvExpiry,
},
}
selected := warningDepositOutpoints(deposits, nil, true, 1_000_000)
require.Equal(
t, []string{"confirmed-small", "mempool-large"}, selected,
)
warning := lowConfDepositWarning(deposits, selected, csvExpiry)
require.Contains(t, warning, "mempool-large (unconfirmed)")
require.NotContains(t, warning, "confirmed-small")
}
// TestWarningDepositSelectionMatchesLoopInSelection verifies CLI warning
// selection matches the loop-in selector.
func TestWarningDepositSelectionMatchesLoopInSelection(t *testing.T) {
t.Parallel()
const (
blockHeight = uint32(10_000)
csvExpiry = uint32(1_200)
targetAmount = int64(2_500_000)
)
type fixture struct {
name string
value int64
confirmationHeight int64
}
fixtures := []fixture{
{
name: "mempool-huge",
value: 3_000_000,
confirmationHeight: 0,
},
{
name: "confirmed-later-expiry",
value: 2_000_000,
confirmationHeight: 9_900,
},
{
name: "confirmed-earlier-expiry",
value: 2_000_000,
confirmationHeight: 9_890,
},
{
name: "confirmed-small",
value: 600_000,
confirmationHeight: 9_900,
},
{
name: "confirmed-too-close-to-expiry",
value: 5_000_000,
confirmationHeight: 9_849,
},
}
rpcDeposits := make([]*looprpc.Deposit, 0, len(fixtures))
loopInDeposits := make([]*deposit.Deposit, 0, len(fixtures))
for idx, fixture := range fixtures {
hash := chainhash.Hash{byte(idx + 1)}
outpoint := wire.OutPoint{
Hash: hash,
Index: uint32(idx),
}
blocksUntilExpiry := int64(0)
if fixture.confirmationHeight > 0 {
blocksUntilExpiry = fixture.confirmationHeight +
int64(csvExpiry) - int64(blockHeight)
}
rpcDeposits = append(rpcDeposits, &looprpc.Deposit{
Outpoint: outpoint.String(),
Value: fixture.value,
ConfirmationHeight: fixture.confirmationHeight,
BlocksUntilExpiry: blocksUntilExpiry,
})
loopInDeposits = append(loopInDeposits, &deposit.Deposit{
OutPoint: outpoint,
Value: btcutil.Amount(fixture.value),
ConfirmationHeight: fixture.confirmationHeight,
})
}
cliSelected := autoSelectedWarningOutpoints(
rpcDeposits, targetAmount,
)
loopInSelected, err := loopin.SelectDeposits(
btcutil.Amount(targetAmount), loopInDeposits, csvExpiry,
blockHeight,
)
require.NoError(t, err)
loopInSelectedOutpoints := make([]string, 0, len(loopInSelected))
for _, selected := range loopInSelected {
loopInSelectedOutpoints = append(
loopInSelectedOutpoints, selected.OutPoint.String(),
)
}
require.Equal(t, loopInSelectedOutpoints, cliSelected)
}

View file

@ -15,9 +15,10 @@ import (
var listSwapsCommand = &cli.Command{
Name: "listswaps",
Usage: "list all swaps in the local database",
Description: "Allows the user to get a list of all swaps that are " +
"currently stored in the database",
Usage: "list traditional Loop In and Loop Out swaps",
Description: "Lists traditional Loop In and Loop Out swaps that are " +
"currently stored in the database. Static address loop-ins are not " +
"included; use `loop static listswaps` to view them.",
Action: listSwaps,
Flags: []cli.Flag{
&cli.BoolFlag{
@ -128,10 +129,12 @@ func listSwaps(ctx context.Context, cmd *cli.Command) error {
var swapInfoCommand = &cli.Command{
Name: "swapinfo",
Usage: "show the status of a swap",
Usage: "show the status of a traditional swap",
ArgsUsage: "id",
Description: "Allows the user to get the status of a single swap " +
"currently stored in the database",
Description: "Shows the status of a traditional Loop In or Loop Out " +
"swap currently stored in the database. Static address loop-ins " +
"must be viewed with `loop static listswaps`; there is no generic " +
"per-swap static lookup command.",
Flags: []cli.Flag{
&cli.Uint64Flag{
Name: "id",

View file

@ -71,7 +71,7 @@ Base URL: `http://127.0.0.1:12345`
| `quote/` | `loop quote out` (success + verbose), `loop quote in` (help + verbose), `loop quote out` (help), `loop quote in` (deposit_outpoint success), `loop quote in` (positional + last_hop) |
| `static/` | `loop static withdraw` (no selection error), `loop static withdraw` (invalid utxo), `loop static withdraw` (all success), `loop static withdraw` (utxo + dest_addr success), `loop static listwithdrawals`, `loop static listswaps` |
| `static-autoloop/` | `loop setparams --loopinsource static-address` (success + no-experimental error), `loop getparams` (static-address loop-in source), `loop suggestswaps` (static loop-in suggestion) |
| `static-loop-in/` | `loop static new`, `loop static` (help), `loop static listunspent` (incl alias), `loop static listdeposits`, `loop static summary`, `loop static in` (multiple args/flags cases), `loop static in` (duplicate outpoints), `loop static in` (positional low amount error), `loop static in` (positional + last_hop + payment_timeout), `loop static in` (all cancel) |
| `static-loop-in/` | `loop static new`, `loop static` (help), `loop static listunspent` (incl alias), `loop static listdeposits`, `loop static summary`, `loop static in` (multiple args/flags cases), `loop static in` (duplicate outpoints), `loop static in` (positional low amount error), `loop static in` (positional + last_hop + payment_timeout), `loop static in` (all cancel), `loop static in` (explicit and automatically selected low-confirmation warnings) |
| `static-filters/` | `loop static listdeposits --filter ...` for each state (deposited/withdrawing/withdrawn/looping_in/looped_in/publish_expired_deposit/sweep_htlc_timeout/htlc_timeout_swept/wait_for_expiry_sweep/expired/failed) |
| `swaps/` | `loop listswaps` (success + conflicting filters + loop_out_only filters + loop_in_only), `loop swapinfo` (success + invalid id + id flag errors), `loop abandonswap` (help + invalid id + success) |

View file

@ -0,0 +1,267 @@
{
"metadata": {
"args": [
"loop",
"monitor",
"--network",
"regtest"
],
"env": {},
"version": "0.33.3-beta commit= commit_hash=",
"run_error": "recv: rpc error: code = Canceled desc = context canceled",
"duration": 25407490958,
"clock_start_unix": 1784150305
},
"events": [
{
"time_ms": 13,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/Monitor",
"event": "send",
"message_type": "looprpc.MonitorRequest",
"payload": {}
}
},
{
"time_ms": 13,
"kind": "stdout",
"data": {
"lines": [
"Note: offchain cost may report as 0 after loopd restart during swap\n"
]
}
},
{
"time_ms": 16479,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/Monitor",
"event": "recv",
"message_type": "looprpc.SwapStatus",
"payload": {
"amt": "500000",
"id": "bec3777d45337f652d96136e5714ed90a5d4f7cda87b5842110ecc38c9a65826",
"id_bytes": "vsN3fUUzf2UtlhNuVxTtkKXU982oe1hCEQ7MOMmmWCY=",
"type": "STATIC_LOOP_IN",
"state": "INITIATED",
"static_loop_in_state": "INIT_HTLC",
"failure_reason": "FAILURE_REASON_NONE",
"initiation_time": "1784150320647961000",
"last_update_time": "1784150321494895000",
"htlc_address": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2wsh": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2tr": "",
"cost_server": "0",
"cost_onchain": "0",
"cost_offchain": "0",
"last_hop": "",
"outgoing_chan_set": [],
"label": "",
"asset_info": null
}
}
},
{
"time_ms": 16479,
"kind": "stdout",
"data": {
"lines": [
"2026-07-15T18:18:41-03:00 STATIC_LOOP_IN INIT_HTLC 0.00500000 BTC - P2WSH: bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv\n"
]
}
},
{
"time_ms": 16482,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/Monitor",
"event": "recv",
"message_type": "looprpc.SwapStatus",
"payload": {
"amt": "500000",
"id": "bec3777d45337f652d96136e5714ed90a5d4f7cda87b5842110ecc38c9a65826",
"id_bytes": "vsN3fUUzf2UtlhNuVxTtkKXU982oe1hCEQ7MOMmmWCY=",
"type": "STATIC_LOOP_IN",
"state": "INITIATED",
"static_loop_in_state": "SIGN_HTLC_TX",
"failure_reason": "FAILURE_REASON_NONE",
"initiation_time": "1784150320647961000",
"last_update_time": "1784150321499639000",
"htlc_address": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2wsh": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2tr": "",
"cost_server": "0",
"cost_onchain": "0",
"cost_offchain": "0",
"last_hop": "",
"outgoing_chan_set": [],
"label": "",
"asset_info": null
}
}
},
{
"time_ms": 16482,
"kind": "stdout",
"data": {
"lines": [
"2026-07-15T18:18:41-03:00 STATIC_LOOP_IN SIGN_HTLC_TX 0.00500000 BTC - P2WSH: bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv\n"
]
}
},
{
"time_ms": 16530,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/Monitor",
"event": "recv",
"message_type": "looprpc.SwapStatus",
"payload": {
"amt": "500000",
"id": "bec3777d45337f652d96136e5714ed90a5d4f7cda87b5842110ecc38c9a65826",
"id_bytes": "vsN3fUUzf2UtlhNuVxTtkKXU982oe1hCEQ7MOMmmWCY=",
"type": "STATIC_LOOP_IN",
"state": "INITIATED",
"static_loop_in_state": "MONITOR_INVOICE_HTLC_TX",
"failure_reason": "FAILURE_REASON_NONE",
"initiation_time": "1784150320647961000",
"last_update_time": "1784150321548450000",
"htlc_address": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2wsh": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2tr": "",
"cost_server": "0",
"cost_onchain": "0",
"cost_offchain": "0",
"last_hop": "",
"outgoing_chan_set": [],
"label": "",
"asset_info": null
}
}
},
{
"time_ms": 16530,
"kind": "stdout",
"data": {
"lines": [
"2026-07-15T18:18:41-03:00 STATIC_LOOP_IN MONITOR_INVOICE_HTLC_TX 0.00500000 BTC - P2WSH: bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv\n"
]
}
},
{
"time_ms": 17027,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/Monitor",
"event": "recv",
"message_type": "looprpc.SwapStatus",
"payload": {
"amt": "500000",
"id": "bec3777d45337f652d96136e5714ed90a5d4f7cda87b5842110ecc38c9a65826",
"id_bytes": "vsN3fUUzf2UtlhNuVxTtkKXU982oe1hCEQ7MOMmmWCY=",
"type": "STATIC_LOOP_IN",
"state": "INITIATED",
"static_loop_in_state": "PAYMENT_RECEIVED",
"failure_reason": "FAILURE_REASON_NONE",
"initiation_time": "1784150320647961000",
"last_update_time": "1784150322044521000",
"htlc_address": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2wsh": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2tr": "",
"cost_server": "1828",
"cost_onchain": "0",
"cost_offchain": "0",
"last_hop": "",
"outgoing_chan_set": [],
"label": "",
"asset_info": null
}
}
},
{
"time_ms": 17027,
"kind": "stdout",
"data": {
"lines": [
"2026-07-15T18:18:42-03:00 STATIC_LOOP_IN PAYMENT_RECEIVED 0.00500000 BTC - P2WSH: bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv (cost: server 1828, onchain 0, offchain 0)\n"
]
}
},
{
"time_ms": 17036,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/Monitor",
"event": "recv",
"message_type": "looprpc.SwapStatus",
"payload": {
"amt": "500000",
"id": "bec3777d45337f652d96136e5714ed90a5d4f7cda87b5842110ecc38c9a65826",
"id_bytes": "vsN3fUUzf2UtlhNuVxTtkKXU982oe1hCEQ7MOMmmWCY=",
"type": "STATIC_LOOP_IN",
"state": "INITIATED",
"static_loop_in_state": "SUCCEEDED",
"failure_reason": "FAILURE_REASON_NONE",
"initiation_time": "1784150320647961000",
"last_update_time": "1784150322052572000",
"htlc_address": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2wsh": "bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv",
"htlc_address_p2tr": "",
"cost_server": "1828",
"cost_onchain": "0",
"cost_offchain": "0",
"last_hop": "",
"outgoing_chan_set": [],
"label": "",
"asset_info": null
}
}
},
{
"time_ms": 17036,
"kind": "stdout",
"data": {
"lines": [
"2026-07-15T18:18:42-03:00 STATIC_LOOP_IN SUCCEEDED 0.00500000 BTC - P2WSH: bcrt1qjsl6tmv2vf3p5wwv28jh6xwettds934k02c3l5w6zyjsyrsd3lfskgdjmv (cost: server 1828, onchain 0, offchain 0)\n"
]
}
},
{
"time_ms": 25406,
"kind": "signal",
"data": {
"signal": "interrupt"
}
},
{
"time_ms": 25407,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/Monitor",
"event": "error",
"error": "rpc error: code = Canceled desc = context canceled",
"status": {
"code": 1,
"message": "context canceled"
}
}
},
{
"time_ms": 25407,
"kind": "stderr",
"data": {
"lines": [
"[loop] recv: rpc error: code = Canceled desc = context canceled\n"
]
}
},
{
"time_ms": 25407,
"kind": "exit",
"data": {
"run_error": "recv: rpc error: code = Canceled desc = context canceled"
}
}
]
}

View file

@ -139,7 +139,8 @@
"Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI="
],
"outgoing_chan_set": [],
"dest_addr": ""
"dest_addr": "",
"max_swap_fee_sat": "4800"
}
}
},

View file

@ -148,7 +148,8 @@
"outgoing_chan_set": [
"125344325763072"
],
"dest_addr": ""
"dest_addr": "",
"max_swap_fee_sat": "3200"
}
}
},

View file

@ -162,7 +162,8 @@
"cSfKVONNmsK9+p4Uc5nc3ZtE+37uOODHeq1vprhh/x4="
],
"outgoing_chan_set": [],
"dest_addr": ""
"dest_addr": "",
"max_swap_fee_sat": "1600"
}
}
},

View file

@ -91,6 +91,37 @@
}
}
},
{
"time_ms": 65,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "request",
"message_type": "looprpc.StaticAddressSummaryRequest",
"payload": {}
}
},
{
"time_ms": 65,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "response",
"message_type": "looprpc.StaticAddressSummaryResponse",
"payload": {
"static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw",
"relative_expiry_blocks": "14400",
"total_num_deposits": 1,
"value_unconfirmed_satoshis": "0",
"value_deposited_satoshis": "2500000",
"value_expired_satoshis": "0",
"value_withdrawn_satoshis": "0",
"value_looped_in_satoshis": "0",
"value_htlc_timeout_sweeps_satoshis": "0",
"value_channels_opened": "0"
}
}
},
{
"time_ms": 65,
"kind": "stdout",

View file

@ -94,6 +94,37 @@
}
}
},
{
"time_ms": 500,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "request",
"message_type": "looprpc.StaticAddressSummaryRequest",
"payload": {}
}
},
{
"time_ms": 500,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "response",
"message_type": "looprpc.StaticAddressSummaryResponse",
"payload": {
"static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw",
"relative_expiry_blocks": "14400",
"total_num_deposits": 1,
"value_unconfirmed_satoshis": "0",
"value_deposited_satoshis": "500000",
"value_expired_satoshis": "0",
"value_withdrawn_satoshis": "0",
"value_looped_in_satoshis": "0",
"value_htlc_timeout_sweeps_satoshis": "0",
"value_channels_opened": "0"
}
}
},
{
"time_ms": 500,
"kind": "grpc",

View file

@ -99,6 +99,37 @@
}
}
},
{
"time_ms": 446,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "request",
"message_type": "looprpc.StaticAddressSummaryRequest",
"payload": {}
}
},
{
"time_ms": 446,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "response",
"message_type": "looprpc.StaticAddressSummaryResponse",
"payload": {
"static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw",
"relative_expiry_blocks": "14400",
"total_num_deposits": 1,
"value_unconfirmed_satoshis": "0",
"value_deposited_satoshis": "500000",
"value_expired_satoshis": "0",
"value_withdrawn_satoshis": "0",
"value_looped_in_satoshis": "0",
"value_htlc_timeout_sweeps_satoshis": "0",
"value_channels_opened": "0"
}
}
},
{
"time_ms": 446,
"kind": "stdout",

View file

@ -127,6 +127,37 @@
}
}
},
{
"time_ms": 50,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "request",
"message_type": "looprpc.StaticAddressSummaryRequest",
"payload": {}
}
},
{
"time_ms": 50,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "response",
"message_type": "looprpc.StaticAddressSummaryResponse",
"payload": {
"static_address": "bcrt1p604kzzh28764kkw45yps48weergwljggamhhe7tqfglzjzang6cs43f2m2",
"relative_expiry_blocks": "14400",
"total_num_deposits": 4,
"value_unconfirmed_satoshis": "0",
"value_deposited_satoshis": "2546150",
"value_expired_satoshis": "0",
"value_withdrawn_satoshis": "0",
"value_looped_in_satoshis": "0",
"value_htlc_timeout_sweeps_satoshis": "0",
"value_channels_opened": "0"
}
}
},
{
"time_ms": 50,
"kind": "grpc",

View file

@ -118,6 +118,37 @@
}
}
},
{
"time_ms": 45,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "request",
"message_type": "looprpc.StaticAddressSummaryRequest",
"payload": {}
}
},
{
"time_ms": 45,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "response",
"message_type": "looprpc.StaticAddressSummaryResponse",
"payload": {
"static_address": "bcrt1p604kzzh28764kkw45yps48weergwljggamhhe7tqfglzjzang6cs43f2m2",
"relative_expiry_blocks": "14400",
"total_num_deposits": 3,
"value_unconfirmed_satoshis": "0",
"value_deposited_satoshis": "2046150",
"value_expired_satoshis": "0",
"value_withdrawn_satoshis": "0",
"value_looped_in_satoshis": "0",
"value_htlc_timeout_sweeps_satoshis": "0",
"value_channels_opened": "0"
}
}
},
{
"time_ms": 45,
"kind": "grpc",

View file

@ -0,0 +1,242 @@
{
"metadata": {
"args": [
"loop",
"static",
"in",
"--amt",
"500000",
"--utxo",
"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0",
"--network",
"regtest"
],
"env": {},
"version": "0.31.7-beta commit=vbump-lndclient-70-g352a68cd43f1976a937faaf76041bc078fdd16f6 commit_hash=352a68cd43f1976a937faaf76041bc078fdd16f6",
"duration": 2826015164,
"clock_start_unix": 1769407086
},
"events": [
{
"time_ms": 3,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/ListStaticAddressDeposits",
"event": "request",
"message_type": "looprpc.ListStaticAddressDepositsRequest",
"payload": {
"state_filter": "DEPOSITED",
"outpoints": []
}
}
},
{
"time_ms": 22,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/ListStaticAddressDeposits",
"event": "response",
"message_type": "looprpc.ListStaticAddressDepositsResponse",
"payload": {
"filtered_deposits": [
{
"id": "6mq78FccC6ghF66fIIZhTqzqiykT3AVEtwwA3ng1PnE=",
"state": "DEPOSITED",
"outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0",
"value": "2500000",
"confirmation_height": "131",
"blocks_until_expiry": "14396",
"swap_hash": ""
}
]
}
}
},
{
"time_ms": 22,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetLoopInQuote",
"event": "request",
"message_type": "looprpc.QuoteRequest",
"payload": {
"amt": "500000",
"conf_target": 0,
"external_htlc": false,
"swap_publication_deadline": "0",
"loop_in_last_hop": "",
"loop_in_route_hints": [],
"private": false,
"deposit_outpoints": [
"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0"
],
"asset_info": null,
"auto_select_deposits": false,
"fast": false
}
}
},
{
"time_ms": 65,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetLoopInQuote",
"event": "response",
"message_type": "looprpc.InQuoteResponse",
"payload": {
"swap_fee_sat": "1824",
"htlc_publish_fee_sat": "0",
"cltv_delta": 0,
"conf_target": 0,
"quoted_amt": "500000"
}
}
},
{
"time_ms": 65,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "request",
"message_type": "looprpc.StaticAddressSummaryRequest",
"payload": {}
}
},
{
"time_ms": 65,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "response",
"message_type": "looprpc.StaticAddressSummaryResponse",
"payload": {
"static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw",
"relative_expiry_blocks": "14400",
"total_num_deposits": 1,
"value_unconfirmed_satoshis": "0",
"value_deposited_satoshis": "2500000",
"value_expired_satoshis": "0",
"value_withdrawn_satoshis": "0",
"value_looped_in_satoshis": "0",
"value_htlc_timeout_sweeps_satoshis": "0",
"value_channels_opened": "0"
}
}
},
{
"time_ms": 65,
"kind": "stdout",
"data": {
"lines": [
"\n",
"WARNING: The following deposits are below the conservative 6-confirmation threshold:\n",
" - 188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0 (5 confirmations)\n",
"The swap payment for these deposits may wait for more confirmations depending on the server's confirmation-risk policy.\n",
"\n",
"Previously deposited on-chain: 500000 sat\n",
"Receive off-chain: 498176 sat\n",
"Estimated total fee: 1824 sat\n",
"\n",
"CONTINUE SWAP? (y/n): {\n",
" \"amount\": \"2500000\",\n",
" \"change\": \"2000000\",\n",
" \"fast\": false,\n",
" \"htlc_cltv\": 1136,\n",
" \"initiation_height\": 136,\n",
" \"initiator\": \"loop-cli\",\n",
" \"label\": \"\",\n",
" \"max_swap_fee_satoshis\": \"1824\",\n",
" \"payment_timeout_seconds\": 60,\n",
" \"protocol_version\": \"V0\",\n",
" \"quoted_swap_fee_satoshis\": \"1824\",\n",
" \"state\": \"SignHtlcTx\",\n",
" \"swap_amount\": \"500000\",\n",
" \"swap_hash\": \"9f19fb5042a5de6da2f1ce183c5e224fd7802db408e9afdd598ee8174b2bce3f\",\n",
" \"used_deposits\": [\n",
" {\n",
" \"blocks_until_expiry\": \"14396\",\n",
" \"confirmation_height\": \"131\",\n",
" \"id\": \"ea6abbf0571c0ba82117ae9f2086614eacea8b2913dc0544b70c00de78353e71\",\n",
" \"outpoint\": \"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0\",\n",
" \"state\": \"LOOPING_IN\",\n",
" \"swap_hash\": \"\",\n",
" \"value\": \"2500000\"\n",
" }\n",
" ]\n",
"}\n"
]
}
},
{
"time_ms": 2358,
"kind": "stdin",
"data": {
"text": "y\n"
}
},
{
"time_ms": 2358,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticAddressLoopIn",
"event": "request",
"message_type": "looprpc.StaticAddressLoopInRequest",
"payload": {
"outpoints": [
"188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0"
],
"max_swap_fee_satoshis": "1824",
"last_hop": "",
"label": "",
"initiator": "loop-cli",
"route_hints": [],
"private": false,
"payment_timeout_seconds": 60,
"amount": "500000",
"fast": false
}
}
},
{
"time_ms": 2824,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticAddressLoopIn",
"event": "response",
"message_type": "looprpc.StaticAddressLoopInResponse",
"payload": {
"swap_hash": "nxn7UEKl3m2i8c4YPF4iT9eALbQI6a/dWY7oF0srzj8=",
"state": "SignHtlcTx",
"amount": "2500000",
"htlc_cltv": 1136,
"quoted_swap_fee_satoshis": "1824",
"max_swap_fee_satoshis": "1824",
"initiation_height": 136,
"protocol_version": "V0",
"label": "",
"initiator": "loop-cli",
"payment_timeout_seconds": 60,
"used_deposits": [
{
"id": "6mq78FccC6ghF66fIIZhTqzqiykT3AVEtwwA3ng1PnE=",
"state": "LOOPING_IN",
"outpoint": "188f55042e49cfa9942cc1f8e216c5e8679a7036e9ee6449d0fcc6c6b81561be:0",
"value": "2500000",
"confirmation_height": "131",
"blocks_until_expiry": "14396",
"swap_hash": ""
}
],
"swap_amount": "500000",
"change": "2000000",
"fast": false
}
}
},
{
"time_ms": 2826,
"kind": "exit",
"data": {}
}
]
}

View file

@ -0,0 +1,231 @@
{
"metadata": {
"args": [
"/home/user/bin/loop",
"static",
"in",
"--network",
"regtest",
"500000",
"--payment_timeout",
"30s",
"--last_hop",
"0271d6e29301159d9e1cc5d3983479a51f3b3c0c682eda7f16aa1f47dfe09b22f7",
"--force"
],
"env": {
"HOME": "/home/user"
},
"version": "0.31.7-beta commit=v0.31.7-beta-28-g6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845 commit_hash=6d8ddfc59ddc2dcfd1a9b4e4b3c53a9cf15dd845",
"duration": 1078774451,
"clock_start_unix": 1769407086
},
"events": [
{
"time_ms": 4,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/ListStaticAddressDeposits",
"event": "request",
"message_type": "looprpc.ListStaticAddressDepositsRequest",
"payload": {
"state_filter": "DEPOSITED",
"outpoints": []
}
}
},
{
"time_ms": 179,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/ListStaticAddressDeposits",
"event": "response",
"message_type": "looprpc.ListStaticAddressDepositsResponse",
"payload": {
"filtered_deposits": [
{
"id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=",
"state": "DEPOSITED",
"outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0",
"value": "500000",
"confirmation_height": "0",
"blocks_until_expiry": "14400",
"swap_hash": ""
}
]
}
}
},
{
"time_ms": 180,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetLoopInQuote",
"event": "request",
"message_type": "looprpc.QuoteRequest",
"payload": {
"amt": "500000",
"conf_target": 0,
"external_htlc": false,
"swap_publication_deadline": "0",
"loop_in_last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3",
"loop_in_route_hints": [],
"private": false,
"deposit_outpoints": [],
"asset_info": null,
"auto_select_deposits": true,
"fast": false
}
}
},
{
"time_ms": 500,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetLoopInQuote",
"event": "response",
"message_type": "looprpc.InQuoteResponse",
"payload": {
"swap_fee_sat": "1824",
"htlc_publish_fee_sat": "0",
"cltv_delta": 0,
"conf_target": 0,
"quoted_amt": "500000"
}
}
},
{
"time_ms": 500,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "request",
"message_type": "looprpc.StaticAddressSummaryRequest",
"payload": {}
}
},
{
"time_ms": 500,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/GetStaticAddressSummary",
"event": "response",
"message_type": "looprpc.StaticAddressSummaryResponse",
"payload": {
"static_address": "bcrt1pfu9g59aqtxd39653f76y4c8z7r3t9tmcvrvhl57a3dgj3epdwxdqcd9fpw",
"relative_expiry_blocks": "14400",
"total_num_deposits": 1,
"value_unconfirmed_satoshis": "500000",
"value_deposited_satoshis": "0",
"value_expired_satoshis": "0",
"value_withdrawn_satoshis": "0",
"value_looped_in_satoshis": "0",
"value_htlc_timeout_sweeps_satoshis": "0",
"value_channels_opened": "0"
}
}
},
{
"time_ms": 500,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticAddressLoopIn",
"event": "request",
"message_type": "looprpc.StaticAddressLoopInRequest",
"payload": {
"outpoints": [],
"max_swap_fee_satoshis": "1824",
"last_hop": "AnHW4pMBFZ2eHMXTmDR5pR87PAxoLtp/FqofR9/gmyL3",
"label": "",
"initiator": "loop-cli",
"route_hints": [],
"private": false,
"payment_timeout_seconds": 30,
"amount": "500000",
"fast": false
}
}
},
{
"time_ms": 1078,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticAddressLoopIn",
"event": "response",
"message_type": "looprpc.StaticAddressLoopInResponse",
"payload": {
"swap_hash": "hDAjN0JANkGTlqt5ZN14uFsaSBqfHbc9tc3e5XwkQ+c=",
"state": "SignHtlcTx",
"amount": "500000",
"htlc_cltv": 1165,
"quoted_swap_fee_satoshis": "1824",
"max_swap_fee_satoshis": "1824",
"initiation_height": 165,
"protocol_version": "V0",
"label": "",
"initiator": "loop-cli",
"payment_timeout_seconds": 30,
"used_deposits": [
{
"id": "j71tovlF3ikFqn+pOGB0TZOH00ZEhDYOluRnpR3jvJ0=",
"state": "LOOPING_IN",
"outpoint": "9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0",
"value": "500000",
"confirmation_height": "0",
"blocks_until_expiry": "14400",
"swap_hash": ""
}
],
"swap_amount": "500000",
"change": "0",
"fast": false
}
}
},
{
"time_ms": 1078,
"kind": "stdout",
"data": {
"lines": [
"\n",
"WARNING: The following deposits are below the conservative 6-confirmation threshold:\n",
" - 9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0 (unconfirmed)\n",
"The swap payment for these deposits may wait for more confirmations depending on the server's confirmation-risk policy.\n",
"\n",
"{\n",
" \"amount\": \"500000\",\n",
" \"change\": \"0\",\n",
" \"fast\": false,\n",
" \"htlc_cltv\": 1165,\n",
" \"initiation_height\": 165,\n",
" \"initiator\": \"loop-cli\",\n",
" \"label\": \"\",\n",
" \"max_swap_fee_satoshis\": \"1824\",\n",
" \"payment_timeout_seconds\": 30,\n",
" \"protocol_version\": \"V0\",\n",
" \"quoted_swap_fee_satoshis\": \"1824\",\n",
" \"state\": \"SignHtlcTx\",\n",
" \"swap_amount\": \"500000\",\n",
" \"swap_hash\": \"84302337424036419396ab7964dd78b85b1a481a9f1db73db5cddee57c2443e7\",\n",
" \"used_deposits\": [\n",
" {\n",
" \"blocks_until_expiry\": \"14400\",\n",
" \"confirmation_height\": \"0\",\n",
" \"id\": \"8fbd6da2f945de2905aa7fa93860744d9387d3464484360e96e467a51de3bc9d\",\n",
" \"outpoint\": \"9fa0d5dd5348794aa0541dd2729497f0907890606d044e1c4757bdc848f38df8:0\",\n",
" \"state\": \"LOOPING_IN\",\n",
" \"swap_hash\": \"\",\n",
" \"value\": \"500000\"\n",
" }\n",
" ]\n",
"}\n"
]
}
},
{
"time_ms": 1078,
"kind": "exit",
"data": {}
}
]
}

View file

@ -67,15 +67,11 @@
" --max_local_csv uint (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close. (default: 0)\n",
" --close_address string (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will *not* be able to cooperatively close to a different address.\n",
" --remote_max_value_in_flight_msat uint (optional) the maximum value in msat that can be pending within the channel at any given time (default: 0)\n",
" --channel_type string (optional) the type of channel to propose to the remote peer (\"tweakless\", \"anchors\", \"taproot\")\n",
" --channel_type string (optional) the type of channel to propose to the remote peer (\"tweakless\", \"anchors\", \"simple-taproot\", \"taproot\")\n",
" --zero_conf (optional) whether a zero-conf channel open should be attempted. (default: false)\n",
" --scid_alias (optional) whether a scid-alias channel type should be negotiated. (default: false)\n",
" --remote_reserve_sats uint (optional) the minimum number of satoshis we require the remote node to keep as a direct payment. If not specified, a default of 1% of the channel capacity will be used. (default: 0)\n",
" --memo string (optional) a note-to-self containing some useful\n",
" information about the channel. This is stored\n",
" locally only, and is purely for reference. It\n",
" has no bearing on the channel's operation. Max\n",
" allowed length is 500 characters\n",
" --memo string (optional) a note-to-self containing some useful information about the channel. This is stored locally only, and is purely for reference. It has no bearing on the channel's operation. Max allowed length is 500 characters\n",
" --fundmax if set, the wallet will attempt to commit the maximum possible local amount to the channel. This must not be set at the same time as local_amt (default: false)\n",
" --utxo string [ --utxo string ] a utxo specified as outpoint(tx:idx) which will be used to fund a channel. This flag can be repeatedly used to fund a channel with a selection of utxos. The selected funds can either be entirely spent by specifying the fundmax flag or partially by selecting a fraction of the sum of the outpoints in local_amt\n",
" --help, -h show help\n",

View file

@ -0,0 +1,104 @@
{
"metadata": {
"args": [
"/home/user/bin/loop",
"--rpcserver=localhost:11010",
"--loopdir=/redacted/loop",
"--tlscertpath=/redacted/loop/regtest/tls.cert",
"--macaroonpath=/redacted/loop/regtest/loop.macaroon",
"static",
"openchannel",
"--node_key",
"03465f68fd39358667678f8353a31e0d99475e3fd2fb4e58daf7dbfabe04c011f4",
"--fundmax",
"--utxo",
"89f6fd2ee96445c6e48278e7eaaca7de8e342904f20609ce72c0d27afb443e2d:1",
"--channel_type",
"taproot",
"--private",
"--network",
"regtest"
],
"env": {},
"version": "0.33.2-beta commit=v0.33.2-beta-bump-lnd-21-a-7-g21019e684ed06e2267382f473dfeaafb81a33310 commit_hash=21019e684ed06e2267382f473dfeaafb81a33310",
"duration": 295879956,
"clock_start_unix": 1782002722
},
"events": [
{
"time_ms": 2,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticOpenChannel",
"event": "request",
"message_type": "looprpc.StaticOpenChannelRequest",
"payload": {
"open_channel_request": {
"sat_per_vbyte": "0",
"node_pubkey": "A0ZfaP05NYZnZ4+DU6MeDZlHXj/S+05Y2vfb+r4EwBH0",
"node_pubkey_string": "",
"local_funding_amount": "0",
"push_sat": "0",
"target_conf": 0,
"sat_per_byte": "0",
"private": true,
"min_htlc_msat": "0",
"remote_csv_delay": 0,
"min_confs": 1,
"spend_unconfirmed": false,
"close_address": "",
"funding_shim": null,
"remote_max_value_in_flight_msat": "0",
"remote_max_htlcs": 0,
"max_local_csv": 0,
"commitment_type": "TAPROOT",
"zero_conf": false,
"scid_alias": false,
"base_fee": "0",
"fee_rate": "0",
"use_base_fee": false,
"use_fee_rate": false,
"remote_chan_reserve_sat": "0",
"fund_max": true,
"memo": "",
"outpoints": [
{
"txid_bytes": "",
"txid_str": "89f6fd2ee96445c6e48278e7eaaca7de8e342904f20609ce72c0d27afb443e2d",
"output_index": 1
}
]
}
}
}
},
{
"time_ms": 295,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticOpenChannel",
"event": "response",
"message_type": "looprpc.StaticOpenChannelResponse",
"payload": {
"channel_open_outpoint": "302a41b53946494306e415bdf4724e88b2cf2b37ad2f36dc075db00cc6499e9f:0"
}
}
},
{
"time_ms": 295,
"kind": "stdout",
"data": {
"lines": [
"{\n",
" \"channel_open_outpoint\": \"302a41b53946494306e415bdf4724e88b2cf2b37ad2f36dc075db00cc6499e9f:0\"\n",
"}\n"
]
}
},
{
"time_ms": 295,
"kind": "exit",
"data": {}
}
]
}

View file

@ -0,0 +1,106 @@
{
"metadata": {
"args": [
"/home/user/bin/loop",
"--rpcserver=localhost:11010",
"--loopdir=/redacted/loop",
"--tlscertpath=/redacted/loop/regtest/tls.cert",
"--macaroonpath=/redacted/loop/regtest/loop.macaroon",
"static",
"openchannel",
"--node_key",
"026eca9330cc3e589505c4a240ea1f7f551e5765b1aae9040c6667141da657eae6",
"--fundmax",
"--utxo",
"dc942b3252ded50abc30ef4e8614d392ab0f091acab75fdd09e18a07f6ac36e6:0",
"--channel_type",
"taproot",
"--private",
"--network",
"regtest"
],
"env": {},
"version": "0.33.3-beta commit= commit_hash=",
"run_error": "rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7",
"duration": 39639744,
"clock_start_unix": 1782158339
},
"events": [
{
"time_ms": 7,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticOpenChannel",
"event": "request",
"message_type": "looprpc.StaticOpenChannelRequest",
"payload": {
"open_channel_request": {
"sat_per_vbyte": "0",
"node_pubkey": "Am7KkzDMPliVBcSiQOoff1UeV2WxqukEDGZnFB2mV+rm",
"node_pubkey_string": "",
"local_funding_amount": "0",
"push_sat": "0",
"target_conf": 0,
"sat_per_byte": "0",
"private": true,
"min_htlc_msat": "0",
"remote_csv_delay": 0,
"min_confs": 1,
"spend_unconfirmed": false,
"close_address": "",
"funding_shim": null,
"remote_max_value_in_flight_msat": "0",
"remote_max_htlcs": 0,
"max_local_csv": 0,
"commitment_type": "TAPROOT",
"zero_conf": false,
"scid_alias": false,
"base_fee": "0",
"fee_rate": "0",
"use_base_fee": false,
"use_fee_rate": false,
"remote_chan_reserve_sat": "0",
"fund_max": true,
"memo": "",
"outpoints": [
{
"txid_bytes": "",
"txid_str": "dc942b3252ded50abc30ef4e8614d392ab0f091acab75fdd09e18a07f6ac36e6",
"output_index": 0
}
]
}
}
}
},
{
"time_ms": 39,
"kind": "grpc",
"data": {
"method": "/looprpc.SwapClient/StaticOpenChannel",
"event": "error",
"error": "rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7",
"status": {
"code": 2,
"message": "channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7"
}
}
},
{
"time_ms": 39,
"kind": "stderr",
"data": {
"lines": [
"[loop] rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7\n"
]
}
},
{
"time_ms": 39,
"kind": "exit",
"data": {
"run_error": "rpc error: code = Unknown desc = channel_type=taproot is not supported by the connected lnd; update LND to v0.21.0-beta or later to use this channel type: got error from server: rpc error: code = Unknown desc = unhandled request channel type 7"
}
}
]
}

View file

@ -142,6 +142,7 @@ func MigrateLoopOutCosts(ctx context.Context, lnd lndclient.LndServices,
ctx, lndclient.ListPaymentsRequest{
Offset: offset,
MaxPayments: uint64(paymentBatchSize),
OmitHops: true,
},
)
if err != nil {

View file

@ -163,6 +163,11 @@ func TestCostMigration(t *testing.T) {
// Now we can run the migration.
err = MigrateLoopOutCosts(context.Background(), lnd.LndServices, 1, store)
require.NoError(t, err)
listPaymentsRequests := lnd.ListPaymentsRequestsSnapshot()
require.NotEmpty(t, listPaymentsRequests)
for _, req := range listPaymentsRequests {
require.True(t, req.OmitHops)
}
// Finally check that the swap cost has been updated correctly.
swap, err := store.FetchLoopOutSwap(

30
docs/commit-tooling.md Normal file
View file

@ -0,0 +1,30 @@
# Commit Message Tooling
Use `scripts/commit_message.py` to lint, format, and safely reword commit
messages. The script enforces subject/body wrapping (`69`/`72`), keeps real
newlines, and preserves markdown-like body structure (lists, quotes, fenced
blocks, trailers).
## Common Workflows
```bash
# Lint the current commit message
make commitmsg-lint commit=HEAD
# Lint a commit range
make commitmsg-lint range=upstream/master..HEAD
# Format a message file in place
make commitmsg-fmt file=/tmp/msg inplace=1
# Reword a commit from formatted output
make commitmsg-reword commit=<sha>
# Preview a reword without rewriting history
make commitmsg-reword commit=<sha> dryrun=1
```
## Literal Newlines
If a message was created with literal `\n` sequences, use `decode=1` with
`commitmsg-fmt` or `commitmsg-reword` to convert them to real line breaks.

View file

@ -2,18 +2,13 @@
.TH loop 1
.SH NAME
.PP
loop - control plane for your loopd
loop \- control plane for your loopd
.SH SYNOPSIS
.PP
loop
.PP
.RS
.nf
.EX
[--help|-h]
[--loopdir]=[value]
[--macaroonpath]=[value]
@ -21,25 +16,17 @@ loop
[--rpcserver]=[value]
[--tlscertpath]=[value]
[--version|-v]
.fi
.RE
.EE
.PP
\fBUsage\fP:
.PP
.RS
.nf
.EX
loop [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
.fi
.RE
.EE
.SH GLOBAL OPTIONS
.PP
\fB--help, -h\fP: show help
.PP
@ -63,7 +50,6 @@ loop [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
.SH COMMANDS
.SH out
.PP
perform an off-chain to on-chain swap (looping out)
.PP
@ -115,7 +101,6 @@ perform an off-chain to on-chain swap (looping out)
\fB--verbose, -v\fP: show expanded details
.SH in
.PP
perform an on-chain to off-chain swap (loop in)
.PP
@ -149,28 +134,24 @@ perform an on-chain to off-chain swap (loop in)
\fB--verbose, -v\fP: show expanded details
.SH terms
.PP
Display the current swap terms imposed by the server.
.PP
\fB--help, -h\fP: show help
.SH monitor
.PP
monitor progress of any active swaps
.PP
\fB--help, -h\fP: show help
.SH quote
.PP
get a quote for the cost of a swap
.PP
\fB--help, -h\fP: show help
.SS in
.PP
get a quote for the cost of a loop in swap
.PP
@ -195,7 +176,6 @@ get a quote for the cost of a loop in swap
\fB--verbose, -v\fP: show expanded details
.SS out
.PP
get a quote for the cost of a loop out swap
.PP
@ -211,22 +191,19 @@ get a quote for the cost of a loop out swap
\fB--verbose, -v\fP: show expanded details
.SH listauth
.PP
list all L402 tokens
.PP
\fB--help, -h\fP: show help
.SH fetchl402
.PP
fetches a new L402 authentication token from the server
.PP
\fB--help, -h\fP: show help
.SH listswaps
.PP
list all swaps in the local database
list traditional Loop In and Loop Out swaps
.PP
\fB--channel\fP="": the comma-separated list of short channel IDs of the channels to loop out
@ -256,8 +233,7 @@ list all swaps in the local database
\fB--start_time_ns\fP="": Unix timestamp in nanoseconds to select swaps initiated after this time (default: 0)
.SH swapinfo
.PP
show the status of a swap
show the status of a traditional swap
.PP
\fB--help, -h\fP: show help
@ -266,14 +242,12 @@ show the status of a swap
\fB--id\fP="": the ID of the swap (default: 0)
.SH getparams
.PP
show liquidity manager parameters
.PP
\fB--help, -h\fP: show help
.SH setrule
.PP
set liquidity manager rule for a channel/peer
.PP
@ -292,14 +266,12 @@ set liquidity manager rule for a channel/peer
\fB--type\fP="": the type of swap to perform, set to 'out' for acquiring inbound liquidity or 'in' for acquiring outbound liquidity. (default: out)
.SH suggestswaps
.PP
show a list of suggested swaps
.PP
\fB--help, -h\fP: show help
.SH setparams
.PP
update the parameters set for the liquidity manager
.PP
@ -390,14 +362,12 @@ update the parameters set for the liquidity manager
\fB--sweeplimit\fP="": the limit placed on our estimated sweep fee in sat/vByte. (default: 0)
.SH getinfo
.PP
show general information about the loop daemon
.PP
\fB--help, -h\fP: show help
.SH abandonswap
.PP
abandon a swap with a given swap hash
.PP
@ -407,21 +377,18 @@ abandon a swap with a given swap hash
\fB--i_know_what_i_am_doing\fP: Specify this flag if you made sure that you read and understood the following consequence of applying this command.
.SH reservations, r
.PP
manage reservations
.PP
\fB--help, -h\fP: show help
.SS list, l
.PP
list all reservations
.PP
\fB--help, -h\fP: show help
.SH instantout
.PP
perform an instant off-chain to on-chain swap (looping out)
.PP
@ -434,14 +401,12 @@ perform an instant off-chain to on-chain swap (looping out)
\fB--help, -h\fP: show help
.SH listinstantouts
.PP
list all instant out swaps
.PP
\fB--help, -h\fP: show help
.SH stop
.PP
stop the loop daemon
.PP
@ -451,21 +416,18 @@ stop the loop daemon
\fB--wait\fP: wait until loopd fully shuts down
.SH static, s
.PP
perform on-chain to off-chain swaps using static addresses.
.PP
\fB--help, -h\fP: show help
.SS new, n
.PP
Create a new static loop in address.
.PP
\fB--help, -h\fP: show help
.SS listunspent, l
.PP
List unspent static address outputs.
.PP
@ -478,7 +440,6 @@ List unspent static address outputs.
\fB--min_confs\fP="": The minimum amount of confirmations an output should have to be listed. (default: 0)
.SS listdeposits
.PP
Displays static address deposits. A filter can be applied to only show deposits in a specific state.
.PP
@ -497,27 +458,24 @@ htlc_timeout_swept
wait_for_expiry_sweep
expired
failed
.
\&.
.PP
\fB--help, -h\fP: show help
.SS listwithdrawals
.PP
Display a summary of past withdrawals.
.PP
\fB--help, -h\fP: show help
.SS listswaps
.PP
Shows a list of static address swaps.
.PP
\fB--help, -h\fP: show help
.SS withdraw, w
.PP
Withdraw from static address deposits.
.PP
@ -539,14 +497,12 @@ Withdraw from static address deposits.
\fB--utxo\fP="": specify utxos as outpoints(tx:idx) which willbe withdrawn. (default: [])
.SS summary, s
.PP
Display a summary of static address related information.
.PP
\fB--help, -h\fP: show help
.SS in
.PP
Loop in funds from static address deposits.
.PP
@ -592,14 +548,13 @@ Loop in funds from static address deposits.
\fB--verbose, -v\fP: show expanded details
.SS openchannel
.PP
Open a channel to an existing peer.
.PP
\fB--base_fee_msat\fP="": the base fee in milli-satoshis that will be charged for each forwarded HTLC, regardless of payment size (default: 0)
.PP
\fB--channel_type\fP="": (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "taproot")
\fB--channel_type\fP="": (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "simple-taproot", "taproot")
.PP
\fB--close_address\fP="": (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will \fInot\fP be able to cooperatively close to a different address.
@ -620,11 +575,7 @@ Open a channel to an existing peer.
\fB--max_local_csv\fP="": (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close. (default: 0)
.PP
\fB--memo\fP="": (optional) a note-to-self containing some useful
information about the channel. This is stored
locally only, and is purely for reference. It
has no bearing on the channel's operation. Max
allowed length is 500 characters
\fB--memo\fP="": (optional) a note-to-self containing some useful information about the channel. This is stored locally only, and is purely for reference. It has no bearing on the channel's operation. Max allowed length is 500 characters
.PP
\fB--min_htlc_msat\fP="": (optional) the minimum value we will require for incoming HTLCs on the channel (default: 0)

View file

@ -235,9 +235,9 @@ The following flags are supported:
### `listswaps` command
list all swaps in the local database.
list traditional Loop In and Loop Out swaps.
Allows the user to get a list of all swaps that are currently stored in the database.
Lists traditional Loop In and Loop Out swaps that are currently stored in the database. Static address loop-ins are not included; use `loop static listswaps` to view them.
Usage:
@ -261,9 +261,9 @@ The following flags are supported:
### `swapinfo` command
show the status of a swap.
show the status of a traditional swap.
Allows the user to get the status of a single swap currently stored in the database.
Shows the status of a traditional Loop In or Loop Out swap currently stored in the database. Static address loop-ins must be viewed with `loop static listswaps`; there is no generic per-swap static lookup command.
Usage:
@ -715,11 +715,11 @@ The following flags are supported:
| `--max_local_csv="…"` | (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close | uint | `0` |
| `--close_address="…"` | (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will *not* be able to cooperatively close to a different address | string |
| `--remote_max_value_in_flight_msat="…"` | (optional) the maximum value in msat that can be pending within the channel at any given time | uint | `0` |
| `--channel_type="…"` | (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "taproot") | string |
| `--channel_type="…"` | (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "simple-taproot", "taproot") | string |
| `--zero_conf` | (optional) whether a zero-conf channel open should be attempted | bool | `false` |
| `--scid_alias` | (optional) whether a scid-alias channel type should be negotiated | bool | `false` |
| `--remote_reserve_sats="…"` | (optional) the minimum number of satoshis we require the remote node to keep as a direct payment. If not specified, a default of 1% of the channel capacity will be used | uint | `0` |
| `--memo="…"` | (optional) a note-to-self containing some useful information about the channel. This is stored locally only, and is purely for reference. It has no bearing on the channel's operation. Max allowed length is 500 characters | string |
| `--memo="…"` | (optional) a note-to-self containing some useful information about the channel. This is stored locally only, and is purely for reference. It has no bearing on the channel's operation. Max allowed length is 500 characters | string |
| `--fundmax` | if set, the wallet will attempt to commit the maximum possible local amount to the channel. This must not be set at the same time as local_amt | bool | `false` |
| `--utxo="…"` | a utxo specified as outpoint(tx:idx) which will be used to fund a channel. This flag can be repeatedly used to fund a channel with a selection of utxos. The selected funds can either be entirely spent by specifying the fundmax flag or partially by selecting a fraction of the sum of the outpoints in local_amt | string | `[]` |
| `--help` (`-h`) | show help | bool | `false` |

View file

@ -0,0 +1,113 @@
# Loop Client Release Notes
Release notes are listed in chronological order and include every published
GitHub release. Previous and next links connect adjacent files in this index.
Contributor lists are derived from non-merge commit authors and co-authors
between consecutive official release tags.
Add user-facing changes to [release-notes-next.md](release-notes-next.md).
When preparing a release, use
[release-notes-template.md](release-notes-template.md) to turn those notes into
a versioned file, then reset the next-release sections.
| Release notes | Date | Highlights |
| --- | --- | --- |
| [v0.1-alpha](release-notes-0.1.md) | 2019-03-21 | Initial Loop Out release |
| [v0.1.1-alpha](release-notes-0.1.1.md) | 2019-04-17 | Added testnet Loop In |
| [v0.1.2-alpha](release-notes-0.1.2.md) | 2019-05-03 | Fixed macaroon, testnet, and routing fee handling |
| [v0.1.3-beta](release-notes-0.1.3-beta.md) | 2019-05-31 | Published the v0.1.3 beta tag with Docker and accounting updates |
| [v0.1.3-alpha](release-notes-0.1.3.md) | 2019-05-31 | Added Docker support and accounting improvements |
| [v0.2-alpha](release-notes-0.2.md) | 2019-06-26 | Introduced Loop In |
| [v0.2.0-alpha](release-notes-0.2.0.md) | 2019-06-26 | Aliased v0.2-alpha without source changes |
| [v0.2.1-alpha](release-notes-0.2.1.md) | 2019-07-25 | Added configurable Loop Out sweep confirmation targets |
| [v0.2.2-alpha](release-notes-0.2.2.md) | 2019-07-31 | Improved external Loop Out validation |
| [v0.2.3-alpha](release-notes-0.2.3.md) | 2019-10-03 | Fixed REST parity, fee estimation, and confirmation targets |
| [v0.2.4-alpha](release-notes-0.2.4.md) | 2019-10-11 | Prepared flexible swap fees and timing |
| [v0.3.0-alpha](release-notes-0.3.0.md) | 2019-11-21 | Added delayed, batchable Loop Out execution |
| [v0.3.1-alpha](release-notes-0.3.1.md) | 2020-01-15 | Added fee controls for Loop Out and fast quotes |
| [v0.4.0-rc1.beta](release-notes-0.4.0-rc1.md) | 2020-01-24 | Previewed authenticated requests and fixed Loop In timeouts |
| [v0.4.0-beta](release-notes-0.4.0.md) | 2020-02-04 | Added authenticated requests and REST monitoring |
| [v0.4.1-beta](release-notes-0.4.1.md) | 2020-02-11 | Added REST CORS controls and fixed delayed quote errors |
| [v0.5.0-beta](release-notes-0.5.0.md) | 2020-03-05 | Added Loop In last-hop selection |
| [v0.5.1-beta](release-notes-0.5.1.md) | 2020-03-15 | Improved Loop In quotes and fee sanity checks |
| [v0.6.0-beta](release-notes-0.6.0.md) | 2020-04-30 | Added LND v0.10 support and Loop In confirmation targets |
| [v0.6.1-beta](release-notes-0.6.1.md) | 2020-05-12 | Added native SegWit Loop In HTLCs and fixed multipart limits |
| [v0.6.2-beta](release-notes-0.6.2.md) | 2020-05-12 | Published native SegWit Loop In and multipart-limit fixes |
| [v0.6.3-beta](release-notes-0.6.3.md) | 2020-06-04 | Restored multi-channel Loop Out with LND v0.10.1 |
| [v0.6.4-beta](release-notes-0.6.4.md) | 2020-06-12 | Improved Loop Out restart behavior and liquidity speed |
| [v0.6.5-beta](release-notes-0.6.5.md) | 2020-07-02 | Added human-readable server messages |
| [v0.7.0-beta](release-notes-0.7.0.md) | 2020-07-21 | Added longer confirmation targets and server status subscriptions |
| [v0.8.0-beta](release-notes-0.8.0.md) | 2020-08-11 | Improved swap failure reporting and confirmation controls |
| [v0.8.1-beta](release-notes-0.8.1.md) | 2020-08-28 | Reduced Loop Out routing and sweep fees |
| [v0.9.0-beta](release-notes-0.9.0.md) | 2020-09-10 | Introduced liquidity management and TLS |
| [v0.10.0-beta](release-notes-0.10.0.md) | 2020-10-13 | Added multipath Loop In and fee-aware swap suggestions |
| [v0.11.0-beta](release-notes-0.11.0.md) | 2020-10-27 | Introduced Autoloop and transaction labels |
| [v0.11.1-beta](release-notes-0.11.1.md) | 2020-11-12 | Added swap initiator metadata |
| [v0.11.2-beta](release-notes-0.11.2.md) | 2020-12-08 | Added configurable Autoloop swap size limits |
| [v0.11.3-beta](release-notes-0.11.3.md) | 2021-02-09 | Added locked-LND startup waiting and single macaroon support |
| [v0.11.4-beta](release-notes-0.11.4.md) | 2021-02-11 | Defaulted to LND's admin macaroon path |
| [v0.12.0-beta](release-notes-0.12.0.md) | 2021-03-06 | Added per-peer Autoloop rules |
| [v0.12.1-beta](release-notes-0.12.1.md) | 2021-03-26 | Added verbose quote and swap output |
| [v0.12.2-beta](release-notes-0.12.2.md) | 2021-04-29 | Retried failed LSAT payments |
| [v0.13.0-beta](release-notes-0.13.0.md) | 2021-05-19 | Raised the minimum LND version to v0.11.1-beta |
| [v0.14.0-beta](release-notes-0.14.0.md) | 2021-06-01 | Reported Loop Out routing failures to the server |
| [v0.14.1-beta](release-notes-0.14.1.md) | 2021-06-09 | Removed protobuf startup warnings |
| [v0.14.2-beta](release-notes-0.14.2.md) | 2021-07-20 | Fixed Python gRPC client connectivity |
| [v0.15.0-beta](release-notes-0.15.0.md) | 2021-08-03 | Added Loop In quote probing |
| [v0.15.1-beta](release-notes-0.15.1.md) | 2021-11-18 | Updated to LND v0.14 and added WASM RPC stubs |
| [v0.16.0-beta](release-notes-0.16.0.md) | 2021-12-14 | Added private Loop In route hints |
| [v0.17.0-beta](release-notes-0.17.0.md) | 2022-02-07 | Added Loop In support to Autoloop |
| [v0.18.0-beta](release-notes-0.18.0.md) | 2022-03-30 | Added optional routing plugins |
| [v0.19.1-beta](release-notes-0.19.1.md) | 2022-06-09 | Persisted liquidity parameters |
| [v0.20.0-beta](release-notes-0.20.0.md) | 2022-07-20 | Added experimental P2TR HTLCs and MuSig2 sweeps |
| [v0.20.1-beta](release-notes-0.20.1.md) | 2022-08-01 | Improved sweep transaction logging |
| [v0.20.2-beta](release-notes-0.20.2.md) | 2022-10-26 | Raised the minimum LND version for Taproot support |
| [v0.21.0-beta](release-notes-0.21.0.md) | 2022-12-16 | Added Autoloop destination addresses |
| [v0.22.0-beta](release-notes-0.22.0.md) | 2023-03-29 | Added recurring Autoloop budgets |
| [v0.22.1-beta](release-notes-0.22.1.md) | 2023-04-24 | Corrected the HTLC script version for legacy swaps |
| [v0.23.0-beta](release-notes-0.23.0.md) | 2023-04-25 | Made MuSig2 the default swap protocol |
| [v0.24.0-beta](release-notes-0.24.0.md) | 2023-05-24 | Added Easy Autoloop |
| [v0.24.1-beta](release-notes-0.24.1.md) | 2023-05-26 | Added REST bindings for GetInfo |
| [v0.25.0-beta](release-notes-0.25.0.md) | 2023-07-03 | Added SQL stores and Easy Autoloop fee fixes |
| [v0.25.1-beta](release-notes-0.25.1.md) | 2023-07-04 | Removed Windows 386 release builds |
| [v0.25.2-beta](release-notes-0.25.2.md) | 2023-07-04 | Removed unsupported release platforms |
| [v0.26.0-beta](release-notes-0.26.0.md) | 2023-07-28 | Added xpub-backed Loop Out destinations |
| [v0.26.1-beta](release-notes-0.26.1.md) | 2023-08-08 | Recorded swap initiators and repaired faulty timestamps |
| [v0.26.2-beta](release-notes-0.26.2.md) | 2023-08-09 | Migrated faulty Loop Out timestamps |
| [v0.26.3-beta](release-notes-0.26.3.md) | 2023-09-18 | Added the FSM foundation and hardened Loop In settlement |
| [v0.26.4-beta](release-notes-0.26.4.md) | 2023-10-04 | Added Easy Autoloop destinations and Apple Silicon builds |
| [v0.26.5-beta](release-notes-0.26.5.md) | 2023-10-31 | Fixed leap-year parsing and refactored database startup |
| [v0.26.6-beta](release-notes-0.26.6.md) | 2023-11-28 | Added Loop In abandonment and specific balance failures |
| [v0.27.0-beta](release-notes-0.27.0.md) | 2024-01-30 | Added batched Loop Out sweeps |
| [v0.27.1-beta](release-notes-0.27.1.md) | 2024-02-14 | Automatically recovered incorrectly funded external Loop Ins |
| [v0.28.0-beta](release-notes-0.28.0.md) | 2024-03-05 | Expanded Instant Out listing, destinations, and fee accounting |
| [v0.28.1-beta](release-notes-0.28.1.md) | 2024-04-16 | Routed Loop Out prepayments over selected channels |
| [v0.28.2-beta](release-notes-0.28.2.md) | 2024-05-25 | Renamed LSAT options and APIs to L402 |
| [v0.28.3-beta](release-notes-0.28.3.md) | 2024-06-03 | Corrected stored Loop Out costs and batch restoration |
| [v0.28.4-beta](release-notes-0.28.4.md) | 2024-06-04 | Fixed pending-swap cost migration and added RPC timeouts |
| [v0.28.5-beta](release-notes-0.28.5.md) | 2024-06-06 | Paginated cost-migration payment lookups |
| [v0.28.6-beta](release-notes-0.28.6.md) | 2024-07-11 | Expanded sweep-batcher signing and fee controls |
| [v0.28.7-beta](release-notes-0.28.7.md) | 2024-08-08 | Improved sweep selection and stored swap metadata |
| [v0.28.8-beta](release-notes-0.28.8.md) | 2024-10-21 | Introduced the notification manager and mixed sweep batches |
| [v0.28.9-beta](release-notes-0.28.9.md) | 2024-10-30 | Added L402 retrieval and FSM context propagation |
| [v0.29.0-beta](release-notes-0.29.0.md) | 2024-12-18 | Persisted static address Loop In mode |
| [v0.29.1-beta](release-notes-0.29.1.md) | 2025-03-18 | Added Taproot Asset Loop Outs and partial static withdrawals |
| [v0.30.0-beta](release-notes-0.30.0.md) | 2025-03-27 | Added Taproot Asset Easy Autoloop and hardened recovery |
| [v0.31.0-beta](release-notes-0.31.0.md) | 2025-04-25 | Added filtering and pagination to loop listswaps |
| [v0.31.1-beta](release-notes-0.31.1.md) | 2025-05-05 | Changed Autoloop to use a slow publication deadline |
| [v0.31.2-beta](release-notes-0.31.2.md) | 2025-06-18 | Corrected commit hash and version reporting |
| [v0.31.3-beta](release-notes-0.31.3.md) | 2025-09-25 | Added partial static Loop Ins and hardened static address recovery |
| [v0.31.4-beta](release-notes-0.31.4.md) | 2025-10-16 | Added fast static Loop Ins and reproducible releases |
| [v0.31.5-beta](release-notes-0.31.5.md) | 2025-10-31 | Added swap resumption and notification versioning |
| [v0.31.5-beta-lnd0.20](release-notes-0.31.5-lnd0.20.md) | 2025-10-31 | Updated LND 0.20 compatibility and module version metadata |
| [v0.31.6-beta](release-notes-0.31.6.md) | 2025-11-26 | Added Easy Autoloop peer exclusions and loop stop |
| [v0.31.7-beta](release-notes-0.31.7.md) | 2025-11-26 | Bumped the release version after v0.31.6 |
| [v0.31.8-beta](release-notes-0.31.8.md) | 2026-02-03 | Added manual HTLC sweeps and PSBT static withdrawals |
| [v0.32.0-beta](release-notes-0.32.0.md) | 2026-03-02 | Opened channels directly from static address deposits |
| [v0.32.1-beta](release-notes-0.32.1.md) | 2026-03-02 | Updated reproducible releases to Go 1.26 |
| [v0.33.0-beta](release-notes-0.33.0.md) | 2026-04-08 | Added static Loop In fee caps and lifecycle hardening |
| [v0.33.1-beta](release-notes-0.33.1.md) | 2026-05-26 | Added Static Address Autoloop and CLI session tests |
| [v0.33.2-beta](release-notes-0.33.2.md) | 2026-06-08 | Exposed static swap details and hardened MuSig2 inputs |
| [v0.33.3-beta](release-notes-0.33.3.md) | 2026-06-21 | Raised the LND floor and updated the LND dependency |
| [v0.34.0-beta](release-notes-0.34.0.md) | 2026-07-23 | Tracked low-confirmation deposits and production Taproot channels |
| [Next release](release-notes-next.md) | Unreleased | No changes yet |

View file

@ -0,0 +1,148 @@
# Loop Client Release Notes
- **Release date:** 2019-04-17
- **Release page:**
[v0.1.1-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.1.1-alpha)
- **Previous release:** [v0.1-alpha](release-notes-0.1.md)
- **Next release:** [v0.1.2-alpha](release-notes-0.1.2.md)
#### New Features
This is a minor release of the Lightning Loop Go client.
Includes changes to:
- Add testnet support for Loop In (on-chain to off-chain swaps)
- Add amt as a keyword argument
The Loop In implementation can be kicked off using the `loop in ` command:
```
⛰ loop in -h
NAME:
loop in - perform an on-chain to off-chain swap (loop in)
USAGE:
loop in [command options] amt
DESCRIPTION:
Send the amount in satoshis specified by the amt argument off-chain.
OPTIONS:
--amt value the amount in satoshis to loop in (default: 0)
--external expect htlc to be published externally
```
The `--external` flag is of note as it allows the HTLC to be paid by a wallet
other then `lnd`. This allows for users to do things like top-off channel from
_another wallet_, or _withdrawal_ funds from an exchange directly into one's
channel. It can also be used to obtain an address to give to someone else, which
once paid and Looped In, is credited to your channel!
#### Breaking Changes
#### Bug Fixes
- Fix monitoring exception
#### Maintenance
- Documentation updates
**Verifying the Release**
In order to verify the release, you'll need to have `gpg` or `gpg2` installed on
your system. Once you've obtained a copy (and hopefully verified that as well),
you'll first need to import the keys that have signed this release if you
haven't done so already:
```
curl https://keybase.io/roasbeef/pgp_keys.asc | gpg --import
```
Once you have his PGP key you can verify the release (assuming
`manifest-v0.1.1-alpha.txt` and `manifest-v0.1.1-alpha.txt.sig` are in the
current directory) with:
```
gpg --verify manifest-v0.1.1-alpha.txt
```
You should see the following if the verification was successful:
```
gpg: assuming signed data in 'manifest-v0.1.1-alpha.txt'
gpg: Signature made Wed Apr 17 15:20:49 2019 PDT
gpg: using RSA key F8037E70C12C7A263C032508CE58F7F8E20FD9A2
gpg: Good signature from "Olaoluwa Osuntokun <laolu32@gmail.com>" [ultimate]
```
That will verify the signature on the main manifest page which ensures integrity
and authenticity of the binaries you've downloaded locally. Next, depending on
your operating system you should then re-calculate the `sha256` sum of the
binary, and compare that with the following hashes (which are included in the
manifest file):
```
d3c3db1bed3ff0fb125514d9072d621492ff2b86f4a90200e93686052f18f5bd loop-darwin-386-v0.1.1-alpha.tar.gz
ebf461a604b681d8a5c82bae14a0620a38a9f65604ca4f532aedb44ddc7c4ea0 loop-darwin-amd64-v0.1.1-alpha.tar.gz
bc83eb2eefb91054858c2a9164fdf245848f2f861d01526261e65dbd2d8237e0 loop-dragonfly-amd64-v0.1.1-alpha.tar.gz
ece2bb8e4c477627a4485f809e7f0d1c88893e01ca7e33363784c392875f00b6 loop-freebsd-386-v0.1.1-alpha.tar.gz
496941befd46331a4551ff9ff60fe4dc1a49434c1593960f3ed53a255aca0783 loop-freebsd-amd64-v0.1.1-alpha.tar.gz
6e21b065178d9616e78a63bacdca4401f8ed36a82dbdfb0d915099af29ae29da loop-freebsd-arm-v0.1.1-alpha.tar.gz
3264e23ffe8994bd374c961f4973eaa6288e4dce0531967de85b23b342518824 loop-linux-386-v0.1.1-alpha.tar.gz
476f26083febb42fab15fa263048cf8bddcc86671aeaa98e1b74f5c422ebaee4 loop-linux-amd64-v0.1.1-alpha.tar.gz
9f13fb6cc9df51501e4c9560da96d96a9d0f385e600eb77fdbfdb97fb731a4a6 loop-linux-arm64-v0.1.1-alpha.tar.gz
53faaf225412c4f9dc16d437252f666243dba13f9135f07886ec019e5b109ebb loop-linux-armv6-v0.1.1-alpha.tar.gz
4e8c04d1585476a8efb02805181dde80be0a1b45816d24f004924b6756298dd5 loop-linux-armv7-v0.1.1-alpha.tar.gz
a21b05379615a6d7d4de68c3edb2f5a341f23dd0f4895b646b5272e6b99e98d2 loop-linux-mips64-v0.1.1-alpha.tar.gz
047c2a9e62b477db7eb8c4f88a5bda68bcdd10bb396d4ba66ff34328a7b9e6d8 loop-linux-mips64le-v0.1.1-alpha.tar.gz
bd25a16e27fb3140be8ae62a8df1076a80ceac443420738d6261f0c375e60bb5 loop-linux-ppc64-v0.1.1-alpha.tar.gz
ef1a37d85c8ae1eb7fba34a66613344042f26867ab838017b3995ef4d7d8cd95 loop-netbsd-386-v0.1.1-alpha.tar.gz
1962c2b174bc401c5362ca1f7282e8129b6958dae08a1fd0248de6505d4b6c4c loop-netbsd-amd64-v0.1.1-alpha.tar.gz
be27b8c84fac5c0e492aa7b395e3b344f8e0c7170525610e2df51238f8fea7de loop-openbsd-386-v0.1.1-alpha.tar.gz
31ce199daf1af10f328af3b5d8b9cfcefc980eabffd6b91481ddf8a5d2b1e235 loop-openbsd-amd64-v0.1.1-alpha.tar.gz
406d5989ec935faf85dbdaccb88a659ba88ff35ca111b71bf769871f20139ccd loop-source-v0.1.1-alpha.tar.gz
61395e480f7e1cecb9b945a7cad4a0b81186767474da5520dee48b6e89191f9b loop-windows-386-v0.1.1-alpha.zip
01848825834fb4fc1c13841ffdfdc1b59b4f352d350d5b7ffbb3252885f0330d loop-windows-amd64-v0.1.1-alpha.zip
2f0fcaca1479d04b49e85e0a3b7f70dd430cf675daaaa4b77104a83747bba3e0 vendor.tar.gz
```
One can use the `shasum -a 256 <file name here>` tool in order to re-compute the
`sha256` hash of the target binary for your operating system. The produced hash
should be compared with the hashes listed above and they should match *exactly*.
Finally, you can also verify the _tag_ itself with the following command:
```
git verify-tag v0.1.1-alpha
```
**Building the Contained Release**
With this new version of `loop`, we've modified our release process to ensure
the bundled release is now _fully self contained_. As a result, with only the
attached payload with this release, users will be able to rebuild the target
release themselves without having to fetch any of the dependancies. Note that at
this stage, binaries aren't yet fully reproducible (even with `go modules` ).
This is due to the fact that by default,
[Go will include the full directory path where the binary was built in the binary itself](https://github.com/golang/go/issues/16860).
As a result, unless your file system exactly mirrors the machine used to build
the binary, you'll get a different binary, as it includes artifacts from your
local file system. This will be fixed in `go1.13`, and before then we may modify
our release system to do this automatically.
In order to re-build from scratch, assuming that `vendor.tar.gz` and
`loop-source-v0.1.1-alpha.tar.gz` are in the current directory:
```
tar -xvzf vendor.tar.gz
tar -xvzf loop-source-v0.1.1-alpha.tar.gz
GO111MODULE=on go install -v -mod=vendor -ldflags "-X github.com/lightninglabs/loop.Commit=v0.1.1-alpha" ./cmd/loop
GO111MODULE=on go install -v -mod=vendor -ldflags "-X github.com/lightninglabs/loop.Commit=v0.1.1-alpha" ./cmd/loopd
```
The `-mod=vendor` flag tells the `go build` command that it doesn't need to
fetch the dependencies, and instead, they're all enclosed in the local vendor
directory.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- conscott
- Francisco Calderón
- Joost Jager
- Olaoluwa Osuntokun

View file

@ -0,0 +1,27 @@
# Loop Client Release Notes
- **Release date:** 2019-05-03
- **Release page:**
[v0.1.2-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.1.2-alpha)
- **Previous release:** [v0.1.1-alpha](release-notes-0.1.1.md)
- **Next release:** [v0.1.3-beta](release-notes-0.1.3-beta.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
Patch release for Loop client with fixes:
- No more need to regenerate macaroons
- Fixes issue that required specifying testnet remote service URL directly
- Reduce max routing fee
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Joost Jager
- Olaoluwa Osuntokun

View file

@ -0,0 +1,31 @@
# Loop Client Release Notes
- **Release date:** 2019-05-31
- **Release page:**
[v0.1.3-beta](https://github.com/lightninglabs/loop/releases/tag/v0.1.3-beta)
- **Previous release:** [v0.1.2-alpha](release-notes-0.1.2.md)
- **Next release:** [v0.1.3-alpha](release-notes-0.1.3.md)
#### New Features
* Add Docker integration.
[PR #46](https://github.com/lightninglabs/loop/pull/46)
* Persist completed swap costs and expose them through the RPC interface.
[PR #55](https://github.com/lightninglabs/loop/pull/55)
#### Breaking Changes
#### Bug Fixes
#### Maintenance
* Increase the maximum Lightning gRPC receive size to accommodate larger
responses.
[PR #56](https://github.com/lightninglabs/loop/pull/56)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Geoff Taylor
- Joost Jager
- Valentine Wallace

View file

@ -0,0 +1,26 @@
# Loop Client Release Notes
- **Release date:** 2019-05-31
- **Release page:**
[v0.1.3-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.1.3-alpha)
- **Previous release:** [v0.1.3-beta](release-notes-0.1.3-beta.md)
- **Next release:** [v0.2-alpha](release-notes-0.2.md)
#### New Features
Minor changes:
- Add Docker support
- Improve after-the-fact accounting
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Joost Jager
- Olaoluwa Osuntokun
- Valentine Wallace

View file

@ -0,0 +1,170 @@
# Loop Client Release Notes
- **Release date:** 2019-03-21
- **Release page:**
[v0.1-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.1-alpha)
- **Previous release:** None
- **Next release:** [v0.1.1-alpha](release-notes-0.1.1.md)
#### New Features
This is the first major release of Lightning Loop! This release is the first of
many planned, and includes the initial base functionality for the system.
[Check out our blog post for a high level overview on how the Loop service works](https://blog.lightning.engineering/posts/2019/03/20/loop.html).
With this new release, users can use Loop Out to free up inbound receiving
bandwidth in their channels and also send coins on chain from their existing
channel.
The Lightning Loop client software is similar to `lnd`. There's the primary
daemon `loopd`, and its command-line interface `loop`.
[Check out the instructions in the `README` to get started](https://github.com/lightninglabs/loop/blob/master/README.md).
The `loop` command is very simple and at initial release has the following
commands:
```
⛰ loop -h
NAME:
loop - control plane for your loopd
USAGE:
loop [global options] command [command options] [arguments...]
VERSION:
0.1.0-alpha commit=v0.1-alpha
COMMANDS:
out perform an off-chain to on-chain swap (looping out)
terms Display the current swap terms imposed by the server.
monitor monitor progress of any active swaps
quote get a quote for the cost of a swap
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--loopd value loopd daemon address host:port (default: "localhost:11010")
--help, -h show help
--version, -v print the version
```
You'll most frequently be using `loop out`. A sample run looks something like:
```
loop out 500000 --addr=bc1qnrhawnjr7fn3gd09s8gltzzjdfsxsrm2k64ze7
```
By specifying the optional `addr` flag, I tell `loopd` that I'd like to have the
funds sent to that target address. This lets one do cool things like send
directly from your channel into cold storage, or even deposit directly into an
exchange or another wallet under one's control.
Once the loop has been initiated, you can use `loop monitor` to check on its
status.
The other primary way to
[interact with Lightning Loop is via the gRPC API](https://lightning.engineering/loop).
This lets existing lapps, services, and businesses drive Loop programmatically
in a similar fashion to how they interact with `lnd` today. We'll have more
example uses cases, documentation, and explainers in the near future.
Loop there it is!! ⚡️🔁
#### Breaking Changes
#### Bug Fixes
#### Maintenance
**Verifying the Release**
In order to verify the release, you'll need to have `gpg` or `gpg2` installed on
your system. Once you've obtained a copy (and hopefully verified that as well),
you'll first need to import the keys that have signed this release if you
haven't done so already:
```
curl https://keybase.io/roasbeef/pgp_keys.asc | gpg --import
```
Once you have his PGP key you can verify the release (assuming
`manifest-v0.1-alpha.txt` and `manifest-v0.1-alpha.txt.sig` are in the current
directory) with:
```
gpg --verify manifest-v0.1-alpha.txt
```
You should see the following if the verification was successful:
```
gpg: assuming signed data in 'manifest-v0.1-alpha.txt'
gpg: Signature made Wed Mar 20 20:22:49 2019 PDT
gpg: using RSA key F8037E70C12C7A263C032508CE58F7F8E20FD9A2
gpg: Good signature from "Olaoluwa Osuntokun <laolu32@gmail.com>" [ultimate]
```
That will verify the signature on the main manifest page which ensures integrity
and authenticity of the binaries you've downloaded locally. Next, depending on
your operating system you should then re-calculate the `sha256` sum of the
binary, and compare that with the following hashes (which are included in the
manifest file):
```
5c63d870d007d4dd9d0480a0ebc1fee83f1099acac12a4bdd121d3882b772bfb loop-darwin-386-v0.1-alpha.tar.gz
98fc299e107c89df4875af0f2fe46957b228321036c60661507ecdbb9ba1a56a loop-darwin-amd64-v0.1-alpha.tar.gz
761c5af296e62b2eaa9421e9d36a258e9f435a2bc53df33b950b41d3a9eef89d loop-dragonfly-amd64-v0.1-alpha.tar.gz
269997eba3daebeeac7edb82739b3406df3e52b3345c61124c60b145b9080c0f loop-freebsd-386-v0.1-alpha.tar.gz
38fb7a32c9c36f80cac9a47e448338dedde53554f569454202236d278654eadf loop-freebsd-amd64-v0.1-alpha.tar.gz
7226a8c5171c6e10adf754d1c3acd81dee84497d170877981ea441108368fee7 loop-freebsd-arm-v0.1-alpha.tar.gz
e07552fd11967743262a678060369f5fbe17bcde3c4ee6cc21196618248afb9c loop-linux-386-v0.1-alpha.tar.gz
816a7050c91652a8e5b881e939c1bc70e06fe23e8309ac80ef5d38fda06969b7 loop-linux-amd64-v0.1-alpha.tar.gz
75a9ce3f605359735d39d9a0fb5037676c6ac29a70d7db5bc75fc1e5e3fcc465 loop-linux-arm64-v0.1-alpha.tar.gz
b7c7668c90f1d67689a9e557346e32bf10c169ace220cd507ae4ee63f64b12d1 loop-linux-armv6-v0.1-alpha.tar.gz
8aad519ff927643c35968bc9eb4e91a5a1f063ebf60e50b12c05f745d3602540 loop-linux-armv7-v0.1-alpha.tar.gz
5b3be8f2ab4acff7e854a794ecde59abd7feed3002bb13177f89c1cd1c9419e7 loop-linux-mips64-v0.1-alpha.tar.gz
aa3da5049eb2d411912aba8386dcc241f9db2b41dd4571ddbea80cf07f3fbc20 loop-linux-mips64le-v0.1-alpha.tar.gz
1a6a8e8e93df6c02eac1e61d4e9f3a518bc2c2a096deb0b77f0e5a6c0afb553d loop-linux-ppc64-v0.1-alpha.tar.gz
85e4f4e32783aad5e7e53125ca4c2efecaf997b24e81e54db0cc380cdf876cf9 loop-netbsd-386-v0.1-alpha.tar.gz
8896df3499e9287177b5eacb2fc6b964e6dec698807f49582cbccbd3b7088878 loop-netbsd-amd64-v0.1-alpha.tar.gz
133b069ad151adeac9c62596ba507f9ed425cfe6670a03e2e5dea6316e522f18 loop-openbsd-386-v0.1-alpha.tar.gz
a9d1f80d34f698450d413844ff1a4536a4377faa6debd7c16bcfde94964cd628 loop-openbsd-amd64-v0.1-alpha.tar.gz
94c35abdcafeebb17f19850b5e88031926116cce8bd22cdf56d905716a0063d8 loop-source-v0.1-alpha.tar.gz
5cd5171f469e639ece6b37a2ff35bae3dac6d1b0a9490ed9e3f90e4f1fcadb97 loop-windows-386-v0.1-alpha.zip
b139416e426868b060ea6fd28ba840398a6e45ad492eac50297462d4391bc0ce loop-windows-amd64-v0.1-alpha.zip
e2ab0d8f7ec07468ea46e551f17521799147a01f48a3f2c5b1c2d62efd9512a5 vendor.tar.gz
```
One can use the `shasum -a 256 <file name here>` tool in order to re-compute the
`sha256` hash of the target binary for your operating system. The produced hash
should be compared with the hashes listed above and they should match *exactly*.
Finally, you can also verify the _tag_ itself with the following command:
```
git verify-tag v0.1-alpha
```
**Building the Contained Release**
With this new version of `loop`, we've modified our release process to ensure
the bundled release is now _fully self contained_. As a result, with only the
attached payload with this release, users will be able to rebuild the target
release themselves without having to fetch any of the dependancies. Note that at
this stage, binaries aren't yet fully reproducible (even with `go modules` ).
This is due to the fact that by default,
[Go will include the full directory path where the binary was built in the binary itself](https://github.com/golang/go/issues/16860).
As a result, unless your file system exactly mirrors the machine used to build
the binary, you'll get a different binary, as it includes artifacts from your
local file system. This will be fixed in `go1.13`, and before then we may modify
our release system to do this automatically.
In order to re-build from scratch, assuming that `vendor.tar.gz` and
`loop-source-v0.1-alpha.tar.gz` are in the current directory:
```
tar -xvzf vendor.tar.gz
tar -xvzf loop-source-v0.1-alpha.tar.gz
GO111MODULE=on go install -v -mod=vendor -ldflags "-X github.com/lightninglabs/loop.Commit=v0.1-alpha" ./cmd/loop
GO111MODULE=on go install -v -mod=vendor -ldflags "-X github.com/lightninglabs/loop.Commit=v0.1-alpha" ./cmd/loopd
```
The `-mod=vendor` flag tells the `go build` command that it doesn't need to
fetch the dependencies, and instead, they're all enclosed in the local vendor
directory.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Joost Jager
- Olaoluwa Osuntokun
- Wilmer Paulino

View file

@ -0,0 +1,56 @@
# Loop Client Release Notes
- **Release date:** 2020-10-13
- **Release page:**
[v0.10.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.10.0-beta)
- **Previous release:** [v0.9.0-beta](release-notes-0.9.0.md)
- **Next release:** [v0.11.0-beta](release-notes-0.11.0.md)
#### New Features
* Multi-path payment has been enabled for Loop In. This means that it is now
possible to replenish multiple channels via a single Loop In request and a
single on-chain htlc. This has to potential to greatly reduce chain fee costs.
Note that it is not yet possible to select specific peers to loop in through.
* The daemon now sends a user agent string with each swap. This allows
developers to identify their fork or custom implementation of the loop client.
**Updated Swap Suggestions**
* The swap suggestions endpoint has been updated to be fee-aware. Swaps that
exceed the fee limits set by the liquidity manager will no longer be suggested
(see `getparams` for the current limits, and use `setparams` to update these
values).
* Swap suggestions are now aware of ongoing and previously failed swaps. They
will not suggest swaps for channels that are currently being utilized for
swaps, and will not suggest any swaps if a swap that is not limited to a
specific peer or channel is ongoing. If a channel was part of a failed swap
within the last 24H, it will be excluded from our swap suggestions (this value
is configurable).
* The `debug` logging level is recommended if using this feature.
#### Breaking Changes
* Macaroon authentication has been enabled for the `loopd` gRPC and REST
connections. This makes it possible for the loop API to be exposed safely over
the internet as unauthorized access is now prevented.
The daemon will write a default `loop.macaroon` in its main directory. For
mainnet this file will be picked up automatically by the `loop` CLI tool. For
testnet you need to specify the `--network=testnet` flag.
[More information about TLS and macaroons.](../../README.md#authentication-and-transport-security)
* The `setparm` loopcli endpoint is renamed to `setrule` because this endpoint
is only used for setting liqudity rules (parameters can be set using the new
`setparams` endpoint).
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- Joost Jager
- Oliver Gugger

View file

@ -0,0 +1,37 @@
# Loop Client Release Notes
- **Release date:** 2020-10-27
- **Release page:**
[v0.11.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.11.0-beta)
- **Previous release:** [v0.10.0-beta](release-notes-0.10.0.md)
- **Next release:** [v0.11.1-beta](release-notes-0.11.1.md)
#### New Features
* The loop client now labels all its on-chain transactions to make them easily
identifiable in `lnd` 's `listchaintxns` output.
**Introducing Autoloop**
* This release includes support for opt-in automatic dispatch of loop out swaps,
based on the output of the `Suggestions` endpoint.
* To enable the autolooper, the following command can be used:
`loop setparams --autoout=true --autobudget={budget in sats} --budgetstart={start time for budget}`
* Automatically dispatched swaps are identified in the output of the `ListSwaps`
with the label `[reserved]: autoloop-out`.
* If autoloop is not enabled, the client will log the actions that the
autolooper would have taken if it was enabled, and the `Suggestions` endpoint
can be used to view the exact set of swaps that the autolooper would make if
enabled.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- Oliver Gugger

View file

@ -0,0 +1,28 @@
# Loop Client Release Notes
- **Release date:** 2020-11-12
- **Release page:**
[v0.11.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.11.1-beta)
- **Previous release:** [v0.11.0-beta](release-notes-0.11.0.md)
- **Next release:** [v0.11.2-beta](release-notes-0.11.2.md)
#### New Features
* When requesting a swap, a new `initiator` field can be set on the gRPC/REST
interface that is appended to the user agent string that is sent to the server
to give information about Loop usage. The initiator field is meant for user
interfaces to add their name to give the full picture of the binary used
(`loopd`, LiT) and the method/interface used for triggering the swap (`loop`
CLI, autolooper, LiT UI, other 3rd party UI).
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- Oliver Gugger

View file

@ -0,0 +1,35 @@
# Loop Client Release Notes
- **Release date:** 2020-12-08
- **Release page:**
[v0.11.2-beta](https://github.com/lightninglabs/loop/releases/tag/v0.11.2-beta)
- **Previous release:** [v0.11.1-beta](release-notes-0.11.1.md)
- **Next release:** [v0.11.3-beta](release-notes-0.11.3.md)
#### New Features
**Autoloop Swap Size**
* Autoloop can now be configured with custom swap size limits. Previously,
autoloop would use the minimum/maximum swap amount set by the server (exposed
by the `loop terms` command) to decide on swap size.
* Setting a custom minimum swap amount is particularly useful for clients that
would like to perform fewer, larger swaps to save on fees. The trade-off when
setting a large minimum amount is that autoloop will wait until your channel
is at least the minimum amount below its incoming threshold amount before
executing a swap, which may result in channels staying under the threshold for
longer.
* These values can be set using the following command:
`loop setparams --minamt={minimum in sats} --maxamt={maximum in sats}`.
* The values set must fall within the limits set by the loop server.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen

View file

@ -0,0 +1,50 @@
# Loop Client Release Notes
- **Release date:** 2021-02-09
- **Release page:**
[v0.11.3-beta](https://github.com/lightninglabs/loop/releases/tag/v0.11.3-beta)
- **Previous release:** [v0.11.2-beta](release-notes-0.11.2.md)
- **Next release:** [v0.11.4-beta](release-notes-0.11.4.md)
#### New Features
* If lnd is locked when the loop client starts up, it will wait for lnd to be
unlocked. Previous versions would exit with an error.
* Loop will no longer need all `lnd` subserver macaroons to be present in the
`--lnd.macaroondir`. Instead the new `--lnd.macaroonpath` option can be
pointed to a single macaroon, for example the `admin.macaroon` or a custom
baked one with the exact permissions needed for Loop. If the now deprecated
flag/option `--lnd.macaroondir` is used, it will fall back to use only the
`admin.macaroon` from that directory.
* The rules used for autoloop have been relaxed to allow autoloop to dispatch
swaps even if there are manually initiated swaps that are not limited to a
single channel in progress. This change was made to allow autoloop to coexist
with manual swaps.
* The `SuggestSwaps` endpoint has been updated to include reasons that indicate
why the Autolooper is not currently dispatching swaps for the set of rules
that the client is configured with. See the
[autoloop documentation](../autoloop.md) for a detailed explanations of
these reasons.
#### Breaking Changes
* The `AutoOut`, `AutoOutBudgetSat` and `AutoOutBudgetStartSec` fields in the
`LiquidityParameters` message used in the experimental autoloop API have been
renamed to `Autoloop`, `AutoloopBudgetSat` and `AutoloopBudgetStartSec`.
* The `autoout` flag for enabling automatic dispatch of loop out swaps has been
renamed to `autoloop` so that it can cover loop out and loop in.
* The `SuggestSwaps` rpc call will now fail with a `FailedPrecondition` grpc
error code if no rules are configured for the autolooper. Previously the rpc
would return an empty response.
#### Bug Fixes
- Fixed compile time compatibility with `lnd v0.12.0-beta`.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- Oliver Gugger

View file

@ -0,0 +1,23 @@
# Loop Client Release Notes
- **Release date:** 2021-02-11
- **Release page:**
[v0.11.4-beta](https://github.com/lightninglabs/loop/releases/tag/v0.11.4-beta)
- **Previous release:** [v0.11.3-beta](release-notes-0.11.3.md)
- **Next release:** [v0.12.0-beta](release-notes-0.12.0.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Default for `--lnd.macaroonpath` is set to the default path for the LND
`admin.macaroon` (https://github.com/lightninglabs/loop/issues/336)
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath

View file

@ -0,0 +1,40 @@
# Loop Client Release Notes
- **Release date:** 2021-03-06
- **Release page:**
[v0.12.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.12.0-beta)
- **Previous release:** [v0.11.4-beta](release-notes-0.11.4.md)
- **Next release:** [v0.12.1-beta](release-notes-0.12.1.md)
#### New Features
* Autoloop can now be configured on a per-peer basis, rather than only on an
individual channel level. This change allows desired liquidity thresholds to
be set for an individual peer, rather than a specific channel, and leverages
multi-loop-out to more efficiently manage liquidity. To configure peer-level
rules, provide the 'setrule' command with the peer's pubkey.
* Autoloop's fee API has been simplified to allow setting a single percentage
which will be used to limit total swap fees to a percentage of the amount
being swapped, the default budget has been updated to reflect this. Use
`loop setparams --feepercent={percentage}` to update this value. This fee
setting has been updated to the default for autoloop.
* The default confirmation target for automated loop out swap sweeps has been
increased to 100 blocks. This change will not affect the time it takes to
acquire inbound liquidity, but will decrease the cost of swaps.
#### Breaking Changes
#### Bug Fixes
* The loop dockerfile has been updated to use the `make` command so that the
latest commit hash of the code being run will be included in `loopd`.
* A bug where loop in on-chain fees were not recorded properly has been
addressed.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- rockstardev

View file

@ -0,0 +1,40 @@
# Loop Client Release Notes
- **Release date:** 2021-03-26
- **Release page:**
[v0.12.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.12.1-beta)
- **Previous release:** [v0.12.0-beta](release-notes-0.12.0.md)
- **Next release:** [v0.12.2-beta](release-notes-0.12.2.md)
#### New Features
* A new flag, `--verbose`, or `-v`, is added to `loop in`, `loop out` and
`loop quote`. Responses from these commands are also updated to provide more
verbose info, giving users a more intuitive view about money paid on/off-chain
and fees incurred. Use `loop in -v`, `loop out -v`, `loop quote in -v` or
`loop quote out -v` to view the details.
* A stripped down version of the Loop server is now provided as a
[Docker image](https://hub.docker.com/r/lightninglabs/loopserver). A quick
start script and example `docker-compose` environment as well as
[documentation on how to use the `regtest` Loop server](https://github.com/lightninglabs/loop/blob/master/regtest/README.md)
was added too.
#### Breaking Changes
#### Bug Fixes
* A bug that would not list autoloop rules set on a per-peer basis when they
were excluded due to insufficient budget, or the number of swaps in flight has
been corrected. These rules will now be included in the output of
`suggestswaps` with other autoloop peer rules.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- Elle Mouton
- Justin O'Brien
- Oliver Gugger
- Yong Yu

View file

@ -0,0 +1,29 @@
# Loop Client Release Notes
- **Release date:** 2021-04-29
- **Release page:**
[v0.12.2-beta](https://github.com/lightninglabs/loop/releases/tag/v0.12.2-beta)
- **Previous release:** [v0.12.1-beta](release-notes-0.12.1.md)
- **Next release:** [v0.13.0-beta](release-notes-0.13.0.md)
#### New Features
- If the payment for an LSAT fails, it is now automatically re-tried.
#### Breaking Changes
#### Bug Fixes
- Instead of just blocking for forever without any apparent reason if another
Loop daemon process is already running, we now exit with an error after 5
seconds if acquiring the unique lock on the Loop `bbolt` DB fails.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Elle Mouton
- Oliver Gugger
- Yong Yu

View file

@ -0,0 +1,25 @@
# Loop Client Release Notes
- **Release date:** 2021-05-19
- **Release page:**
[v0.13.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.13.0-beta)
- **Previous release:** [v0.12.2-beta](release-notes-0.12.2.md)
- **Next release:** [v0.14.0-beta](release-notes-0.14.0.md)
#### New Features
#### Breaking Changes
A breaking change is required due to poold changes.
- Bumped the minimum required version of `lnd` to `v0.11.1-beta`.
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Carla Kirk-Cohen
- Oliver Gugger
- Yong Yu

View file

@ -0,0 +1,30 @@
# Loop Client Release Notes
- **Release date:** 2021-06-01
- **Release page:**
[v0.14.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.14.0-beta)
- **Previous release:** [v0.13.0-beta](release-notes-0.13.0.md)
- **Next release:** [v0.14.1-beta](release-notes-0.14.1.md)
#### New Features
- The loopd client reports off-chain routing failures for loop out swaps if it
cannot find a route to the server for the swap's prepay or invoice payment.
This allows the server to release accepted invoices, if there are any,
earlier, reducing the amount of time that funds are held off-chain. If the
swap failed on one of the loop server's channels, it will report failure
location of its off-chain failure. If the failure occurred outside of the loop
server's infrastructure, a generic failure will be used so that no information
about the client's position in the network is leaked.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- Maurice Poirrier

View file

@ -0,0 +1,23 @@
# Loop Client Release Notes
- **Release date:** 2021-06-09
- **Release page:**
[v0.14.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.14.1-beta)
- **Previous release:** [v0.14.0-beta](release-notes-0.14.0.md)
- **Next release:** [v0.14.2-beta](release-notes-0.14.2.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* A protobuf warning that was being logged on `loopd` startup and `loop` cli
calls has been addressed.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen

View file

@ -0,0 +1,27 @@
# Loop Client Release Notes
- **Release date:** 2021-07-20
- **Release page:**
[v0.14.2-beta](https://github.com/lightninglabs/loop/releases/tag/v0.14.2-beta)
- **Previous release:** [v0.14.1-beta](release-notes-0.14.1.md)
- **Next release:** [v0.15.0-beta](release-notes-0.15.0.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
- Certain versions of the Python gRPC library
[weren't able to connect](https://github.com/grpc/grpc/issues/23172) to
`loopd` 's gRPC interface, getting the `missing selected ALPN property` error.
A server side fix was introduced to get rid of that error message.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Carla Kirk-Cohen
- Olaoluwa Osuntokun
- Oliver Gugger

View file

@ -0,0 +1,34 @@
# Loop Client Release Notes
- **Release date:** 2021-08-03
- **Release page:**
[v0.15.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.15.0-beta)
- **Previous release:** [v0.14.2-beta](release-notes-0.14.2.md)
- **Next release:** [v0.15.1-beta](release-notes-0.15.1.md)
#### New Features
* Loop-in quote now asks the server to optionally probe the client to test
inbound liquidity. The server may use this information to give more accurate
quotes.
#### Breaking Changes
#### Bug Fixes
* Grpc error codes returned by the swap server when swap initiation fails are
now surfaced to the client. Previously these error codes would be returned as
a string.
#### Maintenance
* Updated compile time dependencies of `lnd`, `grpc-gateway`, `protobuf` and
`grpc`.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Carla Kirk-Cohen
- Oliver Gugger
- Yong Yu

View file

@ -0,0 +1,41 @@
# Loop Client Release Notes
- **Release date:** 2021-11-18
- **Release page:**
[v0.15.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.15.1-beta)
- **Previous release:** [v0.15.0-beta](release-notes-0.15.0.md)
- **Next release:** [v0.16.0-beta](release-notes-0.16.0.md)
#### New Features
* Add JSON client stubs for using the Loop RPC interface from WebAssembly.
[PR #411](https://github.com/lightninglabs/loop/pull/411)
* Export `NewListenerConfig` so callers can construct custom listeners.
[PR #432](https://github.com/lightninglabs/loop/pull/432)
#### Breaking Changes
#### Bug Fixes
* Improve errors for explicitly configured files.
[PR #413](https://github.com/lightninglabs/loop/pull/413)
* Create the default macaroon only when required by the active configuration.
[PR #428](https://github.com/lightninglabs/loop/pull/428)
#### Maintenance
* Refactor Autoloop swap construction behind a swap-builder interface.
[PR #418](https://github.com/lightninglabs/loop/pull/418)
* Update `lndclient` and the compile-time LND dependency for LND v0.14.
[PR #425](https://github.com/lightninglabs/loop/pull/425)
[PR #426](https://github.com/lightninglabs/loop/pull/426)
[PR #438](https://github.com/lightninglabs/loop/pull/438)
#### Contributors (Alphabetical Order)
- Carla Kirk-Cohen
- Harsha Goli
- Martin Habovštiak
- Oliver Gugger
- Turtle
- Yong Yu

View file

@ -0,0 +1,41 @@
# Loop Client Release Notes
- **Release date:** 2021-12-14
- **Release page:**
[v0.16.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.16.0-beta)
- **Previous release:** [v0.15.1-beta](release-notes-0.15.1.md)
- **Next release:** [v0.17.0-beta](release-notes-0.17.0.md)
#### New Features
* `--private` flag is now available on the `loop in` command, meaning users can
now loop in to private nodes! This was implemented in
[#415](https://github.com/lightninglabs/loop/pull/415) and has an
implementation of LND's hop hints creation feature for the time being. The
flag is also available in `loop quote in` as an extension.
* `--route_hints` has also been added on the `loop in` and `loop quote in` cli
commands, and was also include in
[#415](https://github.com/lightninglabs/loop/pull/415). While the `--private`
flag autogenerates routehints to assist the payer (Lightning Labs),
`--route_hints` allows the user to feed their own crafted versions if they so
please.
#### Breaking Changes
#### Bug Fixes
* Fixed issue where loop assumes the mainnet location for lnd.macaroonpath
regardless of passed network parameters.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Carla Kirk-Cohen
- Harsha Goli
- Martin Habovštiak
- Oliver Gugger
- Turtle
- Yong Yu

View file

@ -0,0 +1,32 @@
# Loop Client Release Notes
- **Release date:** 2022-02-07
- **Release page:**
[v0.17.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.17.0-beta)
- **Previous release:** [v0.16.0-beta](release-notes-0.16.0.md)
- **Next release:** [v0.18.0-beta](release-notes-0.18.0.md)
#### New Features
* Loop in functionality has been added to AutoLoop. This feature can be enabled
to acquire outgoing capacity on your node automatically, using
`loop setrule --type=in`. At present, autoloop can only be set to loop out
*or* loop in, and cannot manage liquidity in both directions.
* Use LND's hop hint selector when doing private loop-ins.
#### Breaking Changes
#### Bug Fixes
* Close local databases when loopd daemon is stopped programmatically.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Carla Kirk-Cohen
- Elle Mouton
- Suhail Saqan

View file

@ -0,0 +1,33 @@
# Loop Client Release Notes
- **Release date:** 2022-03-30
- **Release page:**
[v0.18.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.18.0-beta)
- **Previous release:** [v0.17.0-beta](release-notes-0.17.0.md)
- **Next release:** [v0.19.1-beta](release-notes-0.19.1.md)
#### New Features
* Loop client now supports optional routing plugins to improve off-chain payment
reliability. One such plugin that the client implements will gradually prefer
increasingly more expensive routes in case payments using cheap routes time
out. Note that with this addition the minimum required LND version is LND
0.14.2-beta.
#### Breaking Changes
#### Bug Fixes
* Loop now supports being hooked up to a remote signing pair of `lnd` nodes, as
long as `lnd` is `v0.14.3-beta` or later.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Harsha Goli
- Marnix
- Oliver Gugger
- Yong Yu

View file

@ -0,0 +1,32 @@
# Loop Client Release Notes
- **Release date:** 2022-06-09
- **Release page:**
[v0.19.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.19.1-beta)
- **Previous release:** [v0.18.0-beta](release-notes-0.18.0.md)
- **Next release:** [v0.20.0-beta](release-notes-0.20.0.md)
#### New Features
* User-specified liquidity parameters are persisted on disk to enable the
liquidity manager's config to survive after a restart.
#### Breaking Changes
#### Bug Fixes
* The `SuggestSwaps` rpc now returns the correct peer pubkeys in the
disqualified list.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Alex Miller
- Andras Banki-Horvath
- Carsten Otto
- Harsha Goli
- Oliver Gugger
- sputn1ck
- Yong Yu

View file

@ -0,0 +1,23 @@
# Loop Client Release Notes
- **Release date:** 2019-06-26
- **Release page:**
[v0.2.0-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.2.0-alpha)
- **Previous release:** [v0.2-alpha](release-notes-0.2.md)
- **Next release:** [v0.2.1-alpha](release-notes-0.2.1.md)
#### New Features
The `v0.2.0-alpha` and `v0.2-alpha` tags point to the same source commit. This
tag does not introduce additional source changes.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
No additional contributors; this tag points to the same commit as
`v0.2-alpha`.

View file

@ -0,0 +1,38 @@
# Loop Client Release Notes
- **Release date:** 2019-07-25
- **Release page:**
[v0.2.1-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.2.1-alpha)
- **Previous release:** [v0.2.0-alpha](release-notes-0.2.0.md)
- **Next release:** [v0.2.2-alpha](release-notes-0.2.2.md)
#### New Features
This release includes a new option to specify the sweep confirmation target for
Loop Out.
```
--conf_target=block_count
```
This will delay the finality of the swap in favor of a potential reduction in
chain fee expenditure.
If you are using this feature, please note that it does become increasingly
important that you do not allow `loopd` to terminate before the swap is final,
otherwise the timeout pathway may activate in the HTLC.
Because of the finality problem, the target will only be used at the start of
the swap preimage reveal time period and is not a guaranteed final sweep fee
rate.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Wilmer Paulino

View file

@ -0,0 +1,26 @@
# Loop Client Release Notes
- **Release date:** 2019-07-31
- **Release page:**
[v0.2.2-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.2.2-alpha)
- **Previous release:** [v0.2.1-alpha](release-notes-0.2.1.md)
- **Next release:** [v0.2.3-alpha](release-notes-0.2.3.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
This release includes some important fixes for Loop Out.
- Improved support for selecting an external Loop Out address
- Better validation for executing a Loop Out swap
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Bjorn Olav Jalborg
- Joost Jager

View file

@ -0,0 +1,37 @@
# Loop Client Release Notes
- **Release date:** 2019-10-03
- **Release page:**
[v0.2.3-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.2.3-alpha)
- **Previous release:** [v0.2.2-alpha](release-notes-0.2.2.md)
- **Next release:** [v0.2.4-alpha](release-notes-0.2.4.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
This patch release fixes the following issues:
- Max confirmations now respects a longer confirmation target more reliably
- REST API now matches the gRPC API more closely
- Fix issue encountered when using external address with Loop In
For more details, see:
- https://github.com/lightninglabs/loop/pull/74 - REST API Update
- https://github.com/lightninglabs/loop/pull/86 - Loop In Fee Estimation Failure
- https://github.com/lightninglabs/loop/pull/89 - Max Confirmation Target Issue
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Nigel Christian
- Olaoluwa Osuntokun
- Oliver Gugger
- saguywalker
- William O'Beirne
- Wilmer Paulino

View file

@ -0,0 +1,32 @@
# Loop Client Release Notes
- **Release date:** 2019-10-11
- **Release page:**
[v0.2.4-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.2.4-alpha)
- **Previous release:** [v0.2.3-alpha](release-notes-0.2.3.md)
- **Next release:** [v0.3.0-alpha](release-notes-0.3.0.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
#### Maintenance
This patch release includes:
- Preparatory changes for upcoming server changes related to swap fees and
timing.
In the future, the Loop service will allow more flexibility around extensions to
the swap timing in order to get a lower swap fee.
In preparation, the API will be adjusted to provide for multiple fee rates at
different preferred swap wait times.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Johan T. Halseth
- Oliver Gugger

View file

@ -0,0 +1,153 @@
# Loop Client Release Notes
- **Release date:** 2019-06-26
- **Release page:**
[v0.2-alpha](https://github.com/lightninglabs/loop/releases/tag/v0.2-alpha)
- **Previous release:** [v0.1.3-alpha](release-notes-0.1.3.md)
- **Next release:** [v0.2.0-alpha](release-notes-0.2.0.md)
#### New Features
This is the first second release of Lightning Loop! This new release enables
**Loop In** on mainnet, and also exposes some additional code used to build the
`loop` daemon as an external package that others can use.
[Check out our latest blog post for more details on Loop In, and the future of Lightning Loop](https://blog.lightning.engineering/announcement/2019/06/25/loop-in.html).
**Loop In**
At a high-level a Loop In swap can be used to:
* Refilling depleted channels with funds from cold-wallets or exchange
withdrawals
* Servicing off-chain Lightning withdrawals using on-chain payments, with no
funds in channels required
#### Breaking Changes
#### Bug Fixes
* As a failsafe payment method that can be used when channel liquidity along a
route is insufficient
A new command has been added to the `loop` cli command to allow users to drive
Loop In swaps:
```
NAME:
loop in - perform an on-chain to off-chain swap (loop in)
USAGE:
loop in [command options] amt
DESCRIPTION:
Send the amount in satoshis specified by the amt argument off-chain.
OPTIONS:
--amt value the amount in satoshis to loop in (default: 0)
--external expect htlc to be published externally
```
The `--external` argument allows the on-chain HTLC transacting to be published
externally. This allows for a number of use cases like using this address to
withdraw from an exchange into your Lightning channel!
[Additionally, the gRPC API (and REST!) docs have also been updated](https://lightning.engineering/loop).
Loop there it is!! ⚡️🔁
#### Maintenance
**Verifying the Release**
In order to verify the release, you'll need to have `gpg` or `gpg2` installed on
your system. Once you've obtained a copy (and hopefully verified that as well),
you'll first need to import the keys that have signed this release if you
haven't done so already:
```
curl https://keybase.io/roasbeef/pgp_keys.asc | gpg --import
```
Once you have his PGP key you can verify the release (assuming
`manifest-v0.2-alpha.txt` and `manifest-v0.2-alpha.txt.sig` are in the current
directory) with:
```
gpg --verify manifest-v0.2-alpha.txt
```
You should see the following if the verification was successful:
```
gpg: assuming signed data in 'manifest-v0.2-alpha.txt'
gpg: Signature made Wed Jun 26 09:56:58 2019 PDT
gpg: using RSA key F8037E70C12C7A263C032508CE58F7F8E20FD9A2
gpg: Good signature from "Olaoluwa Osuntokun <laolu32@gmail.com>" [ultimate]
```
That will verify the signature on the main manifest page which ensures integrity
and authenticity of the binaries you've downloaded locally. Next, depending on
your operating system you should then re-calculate the `sha256` sum of the
binary, and compare that with the following hashes (which are included in the
manifest file):
```
de97a2e33fcce9650911f8976ed9089d061a1d5fb374bdfd3be0d6101871585d loop-darwin-386-v0.2-alpha.tar.gz
666a5910757cb15dd2a62ac009b31359a97f4f1c83803d4028d10d23db6ee587 loop-darwin-amd64-v0.2-alpha.tar.gz
4a06d43e48e7537975a92d25ac187b78a74426976ffd36bb1efaeb83bae7aa4f loop-dragonfly-amd64-v0.2-alpha.tar.gz
f6cf356db4060d8c90b91dc1d8547472b255ceb8aae2197f531a177a285f60fc loop-freebsd-386-v0.2-alpha.tar.gz
74fdb8d3a8e0a91cfeabe5e06f2be386a68e4524fa42d9c042b9a2030499a76d loop-freebsd-amd64-v0.2-alpha.tar.gz
d500f36eefc1e1ee63b8259d4eefcd64f34b295781956559bd52389b5a37a98b loop-freebsd-arm-v0.2-alpha.tar.gz
d2d01f9a8d1483173c5f1618477ff1929e8aa5e322849091d7b86694fedbf0bb loop-linux-386-v0.2-alpha.tar.gz
da92445ec5e754da3f379e85310d697f3609a17e6639d1251a479a09fc0c16e1 loop-linux-amd64-v0.2-alpha.tar.gz
04edae2cbdb6943b70b13cbc678901d26f4f06767f60f591f7c7d791c8b5925f loop-linux-arm64-v0.2-alpha.tar.gz
5fae0185f8849364af9b998609d002f5e226d3e937dabfd56d1474415f6555db loop-linux-armv6-v0.2-alpha.tar.gz
931a43c8a936db0a3a6a3d099b67d953b69344259bfa7d37faac985341ff27e9 loop-linux-armv7-v0.2-alpha.tar.gz
757ae30b349f8fc209f7df20e1b6010814d0dd279a3717b8c7ba5cb7a092103b loop-linux-mips64-v0.2-alpha.tar.gz
900c8ce735ac94f1d35c179e4387cc9292f261be685eb57b865d772bd668d8ec loop-linux-mips64le-v0.2-alpha.tar.gz
aeb3d2f882405308827974515ea5d652d5e6d72188165ab315dbbb4c7402bc3f loop-linux-ppc64-v0.2-alpha.tar.gz
0d072fd9ed648de679f46ee959a3aef1ae9e025d756140e432df2a51bfe57221 loop-netbsd-386-v0.2-alpha.tar.gz
f26cedf2e8a38b175b47a6b6101edab99033e4776c6de21306cdc793e6dc0b0b loop-netbsd-amd64-v0.2-alpha.tar.gz
3ea2bb1482c78d2bb45358c3de7961670b5ed64a231ec9a2dc2b6ba13a3e76a6 loop-openbsd-386-v0.2-alpha.tar.gz
7a67ae9805beb8e43bd257e8355f8c471bbc740b1b2f1bbf8f834d50312299fe loop-openbsd-amd64-v0.2-alpha.tar.gz
8f15d5c5f56bd19952361ee27b1821306d634bbe8799e52ab36a09f8c151ff6d loop-source-v0.2-alpha.tar.gz
99de0a0e0464a5d7910e6ec4c5cdc881db278bf1bbb6095d5aec7c7a033aca0f loop-windows-386-v0.2-alpha.zip
fb1e4dca3728a2608dce560385bf6e07cb319d27f4d7cfeb0a4aaf00b1cc2a4c loop-windows-amd64-v0.2-alpha.zip
47b208033931c22fd6b1b23b723d49e18359709cb6b29a3f2623e6f80179bfbf vendor.tar.gz
```
One can use the `shasum -a 256 <file name here>` tool in order to re-compute the
`sha256` hash of the target binary for your operating system. The produced hash
should be compared with the hashes listed above and they should match *exactly*.
Finally, you can also verify the _tag_ itself with the following command:
```
git verify-tag v0.2-alpha
```
**Building the Contained Release**
With this new version of `loop`, we've modified our release process to ensure
the bundled release is now _fully self contained_. As a result, with only the
attached payload with this release, users will be able to rebuild the target
release themselves without having to fetch any of the dependancies. Note that at
this stage, binaries aren't yet fully reproducible (even with `go modules` ).
This is due to the fact that by default,
[Go will include the full directory path where the binary was built in the binary itself](https://github.com/golang/go/issues/16860).
As a result, unless your file system exactly mirrors the machine used to build
the binary, you'll get a different binary, as it includes artifacts from your
local file system. This will be fixed in `go1.13`, and before then we may modify
our release system to do this automatically.
In order to re-build from scratch, assuming that `vendor.tar.gz` and
`loop-source-v0.2-alpha.tar.gz` are in the current directory:
```
tar -xvzf vendor.tar.gz
tar -xvzf loop-source-v0.2-alpha.tar.gz
GO111MODULE=on go install -v -mod=vendor -ldflags "-X github.com/lightninglabs/loop.Commit=v0.2-alpha" ./cmd/loop
GO111MODULE=on go install -v -mod=vendor -ldflags "-X github.com/lightninglabs/loop.Commit=v0.2-alpha" ./cmd/loopd
```
The `-mod=vendor` flag tells the `go build` command that it doesn't need to
fetch the dependencies, and instead, they're all enclosed in the local vendor
directory.
#### Contributors (Alphabetical Order)
No additional contributors; this tag points to the same commit as
`v0.1.3-alpha`.

View file

@ -0,0 +1,28 @@
# Loop Client Release Notes
- **Release date:** 2022-07-20
- **Release page:**
[v0.20.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.20.0-beta)
- **Previous release:** [v0.19.1-beta](release-notes-0.19.1.md)
- **Next release:** [v0.20.1-beta](release-notes-0.20.1.md)
#### New Features
* P2TR HTLCs and privacy preserving and cheaper MuSig2 loopout sweeps are now
supported as an experimental feature when running `loopd` with
the`--experimental` flag.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Carla Kirk-Cohen
- Elle Mouton
- Oliver Gugger
- sputn1ck

View file

@ -0,0 +1,22 @@
# Loop Client Release Notes
- **Release date:** 2022-08-01
- **Release page:**
[v0.20.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.20.1-beta)
- **Previous release:** [v0.20.0-beta](release-notes-0.20.0.md)
- **Next release:** [v0.20.2-beta](release-notes-0.20.2.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
#### Maintenance
- Improve logging for sweep transactions
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath

View file

@ -0,0 +1,26 @@
# Loop Client Release Notes
- **Release date:** 2022-10-26
- **Release page:**
[v0.20.2-beta](https://github.com/lightninglabs/loop/releases/tag/v0.20.2-beta)
- **Previous release:** [v0.20.1-beta](release-notes-0.20.1.md)
- **Next release:** [v0.21.0-beta](release-notes-0.21.0.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Bump minimum LND version to v0.15.1-beta to avoid failed swaps due to the
chain backend not properly supporting taproot (fixed in:
https://github.com/lightningnetwork/lnd/pull/6798).
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Evan Kaloudis
- sputn1ck

View file

@ -0,0 +1,30 @@
# Loop Client Release Notes
- **Release date:** 2022-12-16
- **Release page:**
[v0.21.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.21.0-beta)
- **Previous release:** [v0.20.2-beta](release-notes-0.20.2.md)
- **Next release:** [v0.22.0-beta](release-notes-0.22.0.md)
#### New Features
* Autoloop now has a new parameter named `destaddr` which if set to a valid
bitcoin address will direct all funds from automatically dispatched loop outs
towards that address.
#### Breaking Changes
* Listing loop-in swaps will not display old, nested segwit swap htlc addresses
correctly anymore since support for these htlc types is removed from the code
base.
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- George Tsagkarelis
- sputn1ck

View file

@ -0,0 +1,26 @@
# Loop Client Release Notes
- **Release date:** 2023-03-29
- **Release page:**
[v0.22.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.22.0-beta)
- **Previous release:** [v0.21.0-beta](release-notes-0.21.0.md)
- **Next release:** [v0.22.1-beta](release-notes-0.22.1.md)
#### New Features
* Autoloop now uses a recurring budget. Users can now specify `autobudget` and
`autobudgetrefreshperiod` to specify the amount of the budget and the period
over which it will refresh.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- George Tsagkarelis
- sputn1ck

View file

@ -0,0 +1,27 @@
# Loop Client Release Notes
- **Release date:** 2023-04-24
- **Release page:**
[v0.22.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.22.1-beta)
- **Previous release:** [v0.22.0-beta](release-notes-0.22.0.md)
- **Next release:** [v0.23.0-beta](release-notes-0.23.0.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Correct the HTLC script version used when resuming very old swaps.
[PR #571](https://github.com/lightninglabs/loop/pull/571)
#### Maintenance
* Update the Go Docker image and remove the local `swapserverrpc` module
replacement.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Oliver Gugger

View file

@ -0,0 +1,23 @@
# Loop Client Release Notes
- **Release date:** 2023-04-25
- **Release page:**
[v0.23.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.23.0-beta)
- **Previous release:** [v0.22.1-beta](release-notes-0.22.1.md)
- **Next release:** [v0.24.0-beta](release-notes-0.24.0.md)
#### New Features
* Set musig2 to be the default swap protocol.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- George Tsagkarelis
- sputn1ck

View file

@ -0,0 +1,26 @@
# Loop Client Release Notes
- **Release date:** 2023-05-24
- **Release page:**
[v0.24.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.24.0-beta)
- **Previous release:** [v0.23.0-beta](release-notes-0.23.0.md)
- **Next release:** [v0.24.1-beta](release-notes-0.24.1.md)
#### New Features
- Easy Autoloop: a new mode for autoloop which requires the user to only set a
single target balance. Autoloop will start dispatching loop outs
whenever the total channel balance of the node exceeds that target.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- George Tsagkarelis
- Slyghtning
- sputn1ck

View file

@ -0,0 +1,23 @@
# Loop Client Release Notes
- **Release date:** 2023-05-26
- **Release page:**
[v0.24.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.24.1-beta)
- **Previous release:** [v0.24.0-beta](release-notes-0.24.0.md)
- **Next release:** [v0.25.0-beta](release-notes-0.25.0.md)
#### New Features
* Add REST bindings for the `GetInfo` RPC.
[PR #588](https://github.com/lightninglabs/loop/pull/588)
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Slyghtning

View file

@ -0,0 +1,42 @@
# Loop Client Release Notes
- **Release date:** 2023-07-03
- **Release page:**
[v0.25.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.25.0-beta)
- **Previous release:** [v0.24.1-beta](release-notes-0.24.1.md)
- **Next release:** [v0.25.1-beta](release-notes-0.25.1.md)
#### New Features
* Add SQLite and PostgreSQL stores, including migration from an existing bbolt
database.
[PR #585](https://github.com/lightninglabs/loop/pull/585)
* Expose the L402 token identifier through the gRPC interface.
[PR #601](https://github.com/lightninglabs/loop/pull/601)
* Distinguish swaps initiated by Easy Autoloop in their labels.
[PR #591](https://github.com/lightninglabs/loop/pull/591)
#### Breaking Changes
#### Bug Fixes
* Respect the configured fee-PPM limit in Easy Autoloop.
[PR #595](https://github.com/lightninglabs/loop/pull/595)
* Read the Autoloop enabled flag directly from the active liquidity
parameters.
[PR #590](https://github.com/lightninglabs/loop/pull/590)
#### Maintenance
* Correct Autoloop documentation and harden its tests.
[PR #593](https://github.com/lightninglabs/loop/pull/593)
[PR #594](https://github.com/lightninglabs/loop/pull/594)
[PR #596](https://github.com/lightninglabs/loop/pull/596)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- George Tsagkarelis
- Slyghtning
- sputn1ck

View file

@ -0,0 +1,25 @@
# Loop Client Release Notes
- **Release date:** 2023-07-04
- **Release page:**
[v0.25.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.25.1-beta)
- **Previous release:** [v0.25.0-beta](release-notes-0.25.0.md)
- **Next release:** [v0.25.2-beta](release-notes-0.25.2.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
#### Maintenance
* Stop publishing Windows 386 release artifacts.
[PR #606](https://github.com/lightninglabs/loop/pull/606)
* Bump the release version to v0.25.1-beta.
[PR #607](https://github.com/lightninglabs/loop/pull/607)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath

View file

@ -0,0 +1,25 @@
# Loop Client Release Notes
- **Release date:** 2023-07-04
- **Release page:**
[v0.25.2-beta](https://github.com/lightninglabs/loop/releases/tag/v0.25.2-beta)
- **Previous release:** [v0.25.1-beta](release-notes-0.25.1.md)
- **Next release:** [v0.26.0-beta](release-notes-0.26.0.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
#### Maintenance
* Remove unsupported release platforms, including Windows 386.
[PR #608](https://github.com/lightninglabs/loop/pull/608)
* Bump the release version to v0.25.2-beta.
[PR #609](https://github.com/lightninglabs/loop/pull/609)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath

View file

@ -0,0 +1,34 @@
# Loop Client Release Notes
- **Release date:** 2023-07-28
- **Release page:**
[v0.26.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.26.0-beta)
- **Previous release:** [v0.25.2-beta](release-notes-0.25.2.md)
- **Next release:** [v0.26.1-beta](release-notes-0.26.1.md)
#### New Features
This new feature enables loop out and autoloop out operations to sweep htlcs to
addresses generated from an extened public key. A precondition for using the
loop client in this fashion is onboarding a xpub account in the backing lnd
instance, e.g.
`lncli wallet accounts import xpub... my_loop_account --address_type p2tr --master_key_fingerprint 0df50`.
Loop outs can then be instructed to sweep to a new derived address from the
specified account, e.g:
`loop out --amt 10000000 --account my_loop_account --address_type p2tr`. To use
this functionality with autoloop out one has to set the backing lnd account and
address type via liquidity parameters for autoloop, e.g.
`loop --network regtest setparams --autoloop=true --account=my_loop_account --account_addr_type=p2tr...`
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- George Tsagkarelis
- Guillermo Caracuel
- Slyghtning

View file

@ -0,0 +1,30 @@
# Loop Client Release Notes
- **Release date:** 2023-08-08
- **Release page:**
[v0.26.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.26.1-beta)
- **Previous release:** [v0.26.0-beta](release-notes-0.26.0.md)
- **Next release:** [v0.26.2-beta](release-notes-0.26.2.md)
#### New Features
* Record the initiator associated with each swap.
[PR #600](https://github.com/lightninglabs/loop/pull/600)
#### Breaking Changes
#### Bug Fixes
* Repair faulty Loop Out timestamps on startup.
[PR #617](https://github.com/lightninglabs/loop/pull/617)
#### Maintenance
* Bump the release version to v0.26.1-beta.
[PR #618](https://github.com/lightninglabs/loop/pull/618)
#### Contributors (Alphabetical Order)
- Andras Banki-Horvath
- George Tsagkarelis
- sputn1ck

View file

@ -0,0 +1,27 @@
# Loop Client Release Notes
- **Release date:** 2023-08-09
- **Release page:**
[v0.26.2-beta](https://github.com/lightninglabs/loop/releases/tag/v0.26.2-beta)
- **Previous release:** [v0.26.1-beta](release-notes-0.26.1.md)
- **Next release:** [v0.26.3-beta](release-notes-0.26.3.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Add a SQL migration for faulty timestamps that may have appeared for users
who were looping out through LiT v0.10.4-alpha.
[PR #619](https://github.com/lightninglabs/loop/pull/619)
#### Maintenance
* Bump the release version to v0.26.2-beta.
[PR #620](https://github.com/lightninglabs/loop/pull/620)
#### Contributors (Alphabetical Order)
- Andras Banki-Horvath
- sputn1ck

View file

@ -0,0 +1,33 @@
# Loop Client Release Notes
- **Release date:** 2023-09-18
- **Release page:**
[v0.26.3-beta](https://github.com/lightninglabs/loop/releases/tag/v0.26.3-beta)
- **Previous release:** [v0.26.2-beta](release-notes-0.26.2.md)
- **Next release:** [v0.26.4-beta](release-notes-0.26.4.md)
#### New Features
* Add the reusable finite state machine module.
[PR #631](https://github.com/lightninglabs/loop/pull/631)
#### Breaking Changes
#### Bug Fixes
* Treat an already-settled Loop In invoice as a successful settlement.
[PR #636](https://github.com/lightninglabs/loop/pull/636)
* Correct SQL time parsing and the faulty-year migration, and skip bbolt
migration when the SQLite database already exists.
[PR #627](https://github.com/lightninglabs/loop/pull/627)
[PR #630](https://github.com/lightninglabs/loop/pull/630)
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Liongrass
- Slyghtning
- sputn1ck

View file

@ -0,0 +1,32 @@
# Loop Client Release Notes
- **Release date:** 2023-10-04
- **Release page:**
[v0.26.4-beta](https://github.com/lightninglabs/loop/releases/tag/v0.26.4-beta)
- **Previous release:** [v0.26.3-beta](release-notes-0.26.3.md)
- **Next release:** [v0.26.5-beta](release-notes-0.26.5.md)
#### New Features
* Add destination-address support to Easy Autoloop.
[PR #644](https://github.com/lightninglabs/loop/pull/644)
* Add Apple Silicon as a release target and provide a sample `loopd`
configuration.
[PR #643](https://github.com/lightninglabs/loop/pull/643)
#### Breaking Changes
#### Bug Fixes
#### Maintenance
* Update the compile-time LND dependency to v0.17.0-beta.
[PR #641](https://github.com/lightninglabs/loop/pull/641)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- dstadulis
- Oliver Gugger
- Slyghtning

View file

@ -0,0 +1,28 @@
# Loop Client Release Notes
- **Release date:** 2023-10-31
- **Release page:**
[v0.26.5-beta](https://github.com/lightninglabs/loop/releases/tag/v0.26.5-beta)
- **Previous release:** [v0.26.4-beta](release-notes-0.26.4.md)
- **Next release:** [v0.26.6-beta](release-notes-0.26.6.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Correct leap-year handling in database timestamp parsing.
[PR #657](https://github.com/lightninglabs/loop/pull/657)
#### Maintenance
* Refactor database initialization and update security-sensitive dependencies.
[PR #649](https://github.com/lightninglabs/loop/pull/649)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Slyghtning
- sputn1ck

View file

@ -0,0 +1,27 @@
# Loop Client Release Notes
- **Release date:** 2023-11-28
- **Release page:**
[v0.26.6-beta](https://github.com/lightninglabs/loop/releases/tag/v0.26.6-beta)
- **Previous release:** [v0.26.5-beta](release-notes-0.26.5.md)
- **Next release:** [v0.27.0-beta](release-notes-0.27.0.md)
#### New Features
* Add RPC and CLI support for abandoning Loop In swaps.
[PR #661](https://github.com/lightninglabs/loop/pull/661)
#### Breaking Changes
#### Bug Fixes
* Finalize Loop Ins that fail because confirmed wallet funds are insufficient
and expose a specific failure reason.
[PR #665](https://github.com/lightninglabs/loop/pull/665)
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Slyghtning

View file

@ -0,0 +1,34 @@
# Loop Client Release Notes
- **Release date:** 2024-01-30
- **Release page:**
[v0.27.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.27.0-beta)
- **Previous release:** [v0.26.6-beta](release-notes-0.26.6.md)
- **Next release:** [v0.27.1-beta](release-notes-0.27.1.md)
#### New Features
* Sweep Batcher: A new sub-system was added that handles all the loopout sweeps.
Successful loopout HTLCs will no longer be swept back to the wallet via
individual transactions but will instead form a single transaction that holds
multiple inputs and pays to a single output. This will significantly reduce
chain fee costs as it's using less block space by directly consolidating all
the htlcs to a single address. Loopouts that pay to non-wallet addresses will
still use individual transactions as their output cannot be mutated.
#### Breaking Changes
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- bitcoin-lightning
- elbandi
- George Tsagkarelis
- GoodDaisy
- Mohamed Awnallah
- shuoer86
- sputn1ck

View file

@ -0,0 +1,28 @@
# Loop Client Release Notes
- **Release date:** 2024-02-14
- **Release page:**
[v0.27.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.27.1-beta)
- **Previous release:** [v0.27.0-beta](release-notes-0.27.0.md)
- **Next release:** [v0.28.0-beta](release-notes-0.28.0.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
This release adds automatic sweeping of incorrectly deposited amounts to
external loop in addresses. Previously, a mismatch in the contract amount and
the actually deposited amount required external tools to recover the client
funds. With this release the client automatically sweeps the funds back to the
wallet upon contract expiry.
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Slyghtning
- sputn1ck

View file

@ -0,0 +1,35 @@
# Loop Client Release Notes
- **Release date:** 2024-03-05
- **Release page:**
[v0.28.0-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.0-beta)
- **Previous release:** [v0.27.1-beta](release-notes-0.27.1.md)
- **Next release:** [v0.28.1-beta](release-notes-0.28.1.md)
#### New Features
* Add RPC and CLI support for listing Instant Out swaps.
[PR #708](https://github.com/lightninglabs/loop/pull/708)
* Allow Instant Out funds to be sent to a custom destination and improve the
command-line flow.
[PR #709](https://github.com/lightninglabs/loop/pull/709)
[PR #710](https://github.com/lightninglabs/loop/pull/710)
#### Breaking Changes
#### Bug Fixes
* Correct per-sweep on-chain fee accounting and improve displayed server costs.
[PR #694](https://github.com/lightninglabs/loop/pull/694)
#### Maintenance
* Increase SQLite durability.
[PR #712](https://github.com/lightninglabs/loop/pull/712)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Slyghtning
- sputn1ck

View file

@ -0,0 +1,28 @@
# Loop Client Release Notes
- **Release date:** 2024-04-16
- **Release page:**
[v0.28.1-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.1-beta)
- **Previous release:** [v0.28.0-beta](release-notes-0.28.0.md)
- **Next release:** [v0.28.2-beta](release-notes-0.28.2.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Route the Loop Out prepayment over the selected outgoing channel set and
populate the correct HTLC in swap updates.
[PR #727](https://github.com/lightninglabs/loop/pull/727)
#### Maintenance
* Update SQLite, SQLC, PostgreSQL, and Docker dependencies and cache Docker
builds.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Slyghtning

View file

@ -0,0 +1,36 @@
# Loop Client Release Notes
- **Release date:** 2024-05-25
- **Release page:**
[v0.28.2-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.2-beta)
- **Previous release:** [v0.28.1-beta](release-notes-0.28.1.md)
- **Next release:** [v0.28.3-beta](release-notes-0.28.3.md)
#### New Features
#### Breaking Changes
In loopd.conf file `maxlsatcost` and `maxlsatfee` were renamed to `maxl402cost`
and `maxl402fee` accordingly. Old versions of the options are still recognized
for backward compatibility, but a deprecation warning is printed. Users are
encouraged to change the options to new names if they have been changed locally.
The path in looprpc "/v1/lsat/tokens" was renamed to "/v1/l402/tokens" and the
corresponding method was renamed from `GetLsatTokens` to `GetL402Tokens`. New
`loop` binary won't work with old `loopd`, because `loop listauth` is now
calling `GetL402Tokens` method, which does not exist in previous `loopd` binary.
Old `loop` binary works with new `loopd`, since `loopd` provides a wrapper for
`GetLsatTokens` which calls `GetL402Tokens`; the wrapper logs a warning and it
will be removed in a couple of releases. HTTP endpoint "/v1/l402/tokens" is now
an additional binding for API "/v1/lsat/tokens", so it still works.
#### Bug Fixes
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Boris Nagaev
- Slyghtning

View file

@ -0,0 +1,31 @@
# Loop Client Release Notes
- **Release date:** 2024-06-03
- **Release page:**
[v0.28.3-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.3-beta)
- **Previous release:** [v0.28.2-beta](release-notes-0.28.2.md)
- **Next release:** [v0.28.4-beta](release-notes-0.28.4.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Migrate incorrectly stored negative Loop Out costs and account for the
prepayment amount correctly.
[PR #764](https://github.com/lightninglabs/loop/pull/764)
* Restore sweep-batcher swaps from the Loop database and preserve their
confirmation targets.
[PR #761](https://github.com/lightninglabs/loop/pull/761)
#### Maintenance
* Update the compile-time LND dependency to v0.18.0-beta.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Boris Nagaev
- Slyghtning

View file

@ -0,0 +1,33 @@
# Loop Client Release Notes
- **Release date:** 2024-06-04
- **Release page:**
[v0.28.4-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.4-beta)
- **Previous release:** [v0.28.3-beta](release-notes-0.28.3.md)
- **Next release:** [v0.28.5-beta](release-notes-0.28.5.md)
#### New Features
* Make the LND RPC timeout configurable.
[PR #771](https://github.com/lightninglabs/loop/pull/771)
#### Breaking Changes
#### Bug Fixes
* Correct the cost migration for pending swaps.
[PR #771](https://github.com/lightninglabs/loop/pull/771)
#### Maintenance
* Factor out a sweep-batcher implementation that does not depend on the Loop
database and update LND to v0.18.0-beta.1.
[PR #766](https://github.com/lightninglabs/loop/pull/766)
[PR #770](https://github.com/lightninglabs/loop/pull/770)
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Boris Nagaev
- sputn1ck

View file

@ -0,0 +1,24 @@
# Loop Client Release Notes
- **Release date:** 2024-06-06
- **Release page:**
[v0.28.5-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.5-beta)
- **Previous release:** [v0.28.4-beta](release-notes-0.28.4.md)
- **Next release:** [v0.28.6-beta](release-notes-0.28.6.md)
#### New Features
#### Breaking Changes
#### Bug Fixes
* Paginate LND payment lookups while migrating stored Loop Out costs.
[PR #773](https://github.com/lightninglabs/loop/pull/773)
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- jinjingroad

View file

@ -0,0 +1,34 @@
# Loop Client Release Notes
- **Release date:** 2024-07-11
- **Release page:**
[v0.28.6-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.6-beta)
- **Previous release:** [v0.28.5-beta](release-notes-0.28.5.md)
- **Next release:** [v0.28.7-beta](release-notes-0.28.7.md)
#### New Features
* Add sweep-batcher options for custom MuSig2 signing and disabling fee
bumping.
[PR #783](https://github.com/lightninglabs/loop/pull/783)
[PR #784](https://github.com/lightninglabs/loop/pull/784)
* Track a minimum fee rate for sweeps and log transaction weight.
[PR #785](https://github.com/lightninglabs/loop/pull/785)
#### Breaking Changes
#### Bug Fixes
* Fix sweep-batcher shutdown and database transaction races.
[PR #779](https://github.com/lightninglabs/loop/pull/779)
[PR #780](https://github.com/lightninglabs/loop/pull/780)
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Boris Nagaev
- chengehe
- Slyghtning

View file

@ -0,0 +1,34 @@
# Loop Client Release Notes
- **Release date:** 2024-08-08
- **Release page:**
[v0.28.7-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.7-beta)
- **Previous release:** [v0.28.6-beta](release-notes-0.28.6.md)
- **Next release:** [v0.28.8-beta](release-notes-0.28.8.md)
#### New Features
* Return the last hop when fetching stored swaps.
[PR #806](https://github.com/lightninglabs/loop/pull/806)
* Add greedy sweep-batch selection.
[PR #787](https://github.com/lightninglabs/loop/pull/787)
#### Breaking Changes
#### Bug Fixes
* Correct command path handling, sweep fee estimates, and Instant Out SQL
network configuration.
[PR #803](https://github.com/lightninglabs/loop/pull/803)
[PR #793](https://github.com/lightninglabs/loop/pull/793)
#### Maintenance
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Boris Nagaev
- crystalstall
- longxiangqiao
- Slyghtning
- yingshanghuangqiao

View file

@ -0,0 +1,41 @@
# Loop Client Release Notes
- **Release date:** 2024-10-21
- **Release page:**
[v0.28.8-beta](https://github.com/lightninglabs/loop/releases/tag/v0.28.8-beta)
- **Previous release:** [v0.28.7-beta](release-notes-0.28.7.md)
- **Next release:** [v0.28.9-beta](release-notes-0.28.9.md)
#### New Features
* Add a persistent notification manager and generalize the server notification
stream.
[PR #826](https://github.com/lightninglabs/loop/pull/826)
* Add mixed sweep batches, configurable publication delays, transaction labels,
and a maximum batch size.
[PR #791](https://github.com/lightninglabs/loop/pull/791)
[PR #801](https://github.com/lightninglabs/loop/pull/801)
[PR #809](https://github.com/lightninglabs/loop/pull/809)
[PR #813](https://github.com/lightninglabs/loop/pull/813)
#### Breaking Changes
#### Bug Fixes
* Prevent sweep-batcher fee rates from decreasing and improve publication error
handling.
[PR #815](https://github.com/lightninglabs/loop/pull/815)
[PR #833](https://github.com/lightninglabs/loop/pull/833)
#### Maintenance
* Publish `looprpc` as a separately versioned Go module.
#### Contributors (Alphabetical Order)
- Alex Bosworth
- Andras Banki-Horvath
- Boris Nagaev
- drawdrop
- Slyghtning
- sputn1ck

Some files were not shown because too many files have changed in this diff Show more