Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6825e35
looprpc: align instant out permissions with loop out
hieblmi Aug 11, 2026
a4973ca
reservation: keep processing after notification errors
hieblmi Aug 11, 2026
055a80c
reservation: isolate asynchronous initialization errors
hieblmi Aug 11, 2026
e11c0bd
reservation: reject duplicate reservation entries
hieblmi Aug 11, 2026
94015a5
reservation: bound and prune active state machines
hieblmi Aug 11, 2026
a491bcc
reservation: validate confirmed output amounts
hieblmi Aug 11, 2026
35a2df0
instantout: validate MuSig2 response dimensions
hieblmi Aug 11, 2026
e0412ac
instantout: verify finalized MuSig2 witnesses
hieblmi Aug 11, 2026
adc181e
instantout: close unfinished MuSig2 sessions
hieblmi Aug 11, 2026
cfbf741
instantout: recheck reservation timing during recovery
hieblmi Aug 11, 2026
63a0bcc
instantout: enforce the accepted swap fee
hieblmi Aug 11, 2026
4f07354
docs: document instant out reliability improvements
hieblmi Aug 11, 2026
96572f3
reservation: add protocol version
sputn1ck Feb 3, 2025
af01741
swapserverrpc: add buying reservations
sputn1ck Jan 31, 2025
23e533e
reservations: add client requested fsm
sputn1ck Feb 3, 2025
4f12128
reservation: add client requested reservations to manager
sputn1ck Feb 3, 2025
327d4b4
loopdb: store reservation prepay invoice
sputn1ck Feb 3, 2025
5ca0ccd
loopd: update reservation cfg
sputn1ck Feb 3, 2025
04a874e
looprpc: add client calls
sputn1ck Feb 3, 2025
b48fd9a
looprpc_server: add reservation calls
sputn1ck Feb 3, 2025
56be61c
cmd: add new reservation clis
sputn1ck Feb 3, 2025
e4c4e11
loopd: nil-guard reservation/instant-out RPC handlers
hieblmi May 11, 2026
508b9df
multi: require Loop Out permission for Instant Out
hieblmi May 11, 2026
eb58fca
instantout/reservation: avoid uint32 underflow in expiry-bounds check
hieblmi May 11, 2026
800dae0
instantout/reservation: honor context when queueing request
hieblmi May 11, 2026
3c495a2
cmd/loop: require explicit 'y' confirmation on reservation new
hieblmi May 11, 2026
402b431
instantout/reservation: persist client reservations as Init
hieblmi May 11, 2026
b988ea8
loopdb: lowercase protocol_version column in migration 14
hieblmi May 11, 2026
17df6e8
instantout/reservation: extend RPC state wait timeout
hieblmi May 11, 2026
10512bf
instantout: unlock reservations on OnRecover from in-flight states
hieblmi May 11, 2026
29c92a1
instantout: detach reservation unlock cleanup context
hieblmi May 11, 2026
10a50ef
instantout/reservation: lock initial currentHeight write in Run
hieblmi May 11, 2026
08a06a1
loopdb: renumber reservation prepay migration
hieblmi Aug 11, 2026
fb6e610
instantout/reservation: adapt hardening tests to protocol FSM
hieblmi Aug 11, 2026
696f798
docs: regenerate reservation CLI reference
hieblmi Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/loop/instantout.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ func instantOut(ctx context.Context, cmd *cli.Command) error {
ReservationIds: selectedReservations,
OutgoingChanSet: outgoingChanSet,
DestAddr: cmd.String("addr"),
MaxSwapFeeSat: quote.ServiceFeeSat,
},
)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions cmd/loop/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ var (

defaultSwapWaitTime = 30 * time.Minute

defaultRpcTimeout = 30 * time.Second

// maxMsgRecvSize is the largest message our client will receive. We
// set this to 200MiB atm.
maxMsgRecvSize = grpc.MaxCallRecvMsgSize(1 * 1024 * 1024 * 200)
Expand Down
85 changes: 84 additions & 1 deletion cmd/loop/reservations.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,27 @@ package main

import (
"context"
"errors"
"fmt"
"strings"

"github.com/lightninglabs/loop/looprpc"
"github.com/urfave/cli/v3"
)

var reservationsCommands = &cli.Command{
var (
reservationAmountFlag = &cli.Uint64Flag{
Name: "amt",
Usage: "the amount in satoshis for the reservation",
}
reservationExpiryFlag = &cli.UintFlag{
Name: "expiry",
Usage: "the relative block height at which the reservation" +
" expires",
}
)

var reservationsCommands = &cli.Command{
Name: "reservations",
Aliases: []string{"r"},
Usage: "manage reservations",
Expand All @@ -20,6 +34,7 @@ var reservationsCommands = &cli.Command{
`,
Commands: []*cli.Command{
listReservationsCommand,
newReservationCommand,
},
}

Expand All @@ -34,8 +49,76 @@ var (
`,
Action: listReservations,
}

newReservationCommand = &cli.Command{
Name: "new",
Aliases: []string{"n"},
Usage: "create a new reservation",
Description: `
Create a new reservation with the given value and expiry.
`,
Action: newReservation,
Flags: []cli.Flag{
reservationAmountFlag,
reservationExpiryFlag,
},
}
)

func newReservation(ctx context.Context, cmd *cli.Command) error {
client, cleanup, err := getClient(cmd)
if err != nil {
return err
}
defer cleanup()

rpcCtx, cancel := context.WithTimeout(ctx, defaultRpcTimeout)
defer cancel()

if !cmd.IsSet(reservationAmountFlag.Name) {
return errors.New("amt flag missing")
}

if !cmd.IsSet(reservationExpiryFlag.Name) {
return errors.New("expiry flag missing")
}

quoteReq, err := client.ReservationQuote(
rpcCtx, &looprpc.ReservationQuoteRequest{
Amt: cmd.Uint64(reservationAmountFlag.Name),
Expiry: uint32(cmd.Uint(reservationExpiryFlag.Name)),
},
)
if err != nil {
return err
}

fmt.Printf(satAmtFmt, "Reservation Cost: ", quoteReq.PrepayAmt)

fmt.Printf("CONTINUE RESERVATION? (y/n): ")

var answer string
if _, err := fmt.Scanln(&answer); err != nil ||
!strings.EqualFold(answer, "y") {

return nil
}

reservationRes, err := client.ReservationRequest(
rpcCtx, &looprpc.ReservationRequestRequest{
Amt: cmd.Uint64(reservationAmountFlag.Name),
Expiry: uint32(cmd.Uint(reservationExpiryFlag.Name)),
MaxPrepayAmt: quoteReq.PrepayAmt,
},
)
if err != nil {
return err
}

printRespJSON(reservationRes)
return nil
}

func listReservations(ctx context.Context, cmd *cli.Command) error {
client, cleanup, err := getClient(cmd)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@
"Mu65fbhayEtRzougKLBnoeRN8f+tEM1+O9QuNvUIfbI="
],
"outgoing_chan_set": [],
"dest_addr": ""
"dest_addr": "",
"max_swap_fee_sat": "4800"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@
"outgoing_chan_set": [
"125344325763072"
],
"dest_addr": ""
"dest_addr": "",
"max_swap_fee_sat": "3200"
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@
"cSfKVONNmsK9+p4Uc5nc3ZtE+37uOODHeq1vprhh/x4="
],
"outgoing_chan_set": [],
"dest_addr": ""
"dest_addr": "",
"max_swap_fee_sat": "1600"
}
}
},
Expand Down
12 changes: 12 additions & 0 deletions docs/loop.1
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,18 @@ list all reservations
.PP
\fB--help, -h\fP: show help

.SS new, n
create a new reservation

.PP
\fB--amt\fP="": the amount in satoshis for the reservation (default: 0)

.PP
\fB--expiry\fP="": the relative block height at which the reservation expires (default: 0)

.PP
\fB--help, -h\fP: show help

.SH instantout
perform an instant off-chain to on-chain swap (looping out)

Expand Down
20 changes: 20 additions & 0 deletions docs/loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,26 @@ The following flags are supported:
|-----------------|-------------|------|:-------------:|
| `--help` (`-h`) | show help | bool | `false` |

### `reservations new` subcommand (aliases: `n`)

create a new reservation.

Create a new reservation with the given value and expiry.

Usage:

```bash
$ loop [GLOBAL FLAGS] reservations new [COMMAND FLAGS] [ARGUMENTS...]
```

The following flags are supported:

| Name | Description | Type | Default value |
|-----------------|------------------------------------------------------------|------|:-------------:|
| `--amt="…"` | the amount in satoshis for the reservation | uint | `0` |
| `--expiry="…"` | the relative block height at which the reservation expires | uint | `0` |
| `--help` (`-h`) | show help | bool | `false` |

### `instantout` command

perform an instant off-chain to on-chain swap (looping out).
Expand Down
4 changes: 4 additions & 0 deletions docs/release-notes/release-notes-next.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

#### Bug Fixes

* Hardened Instant Out and reservation handling against malformed server
responses, invalid signatures and reservation outputs, resource exhaustion,
unsafe recovery, excessive swap fees, and under-scoped macaroon permissions.

* Taproot Asset Loop Out handling now validates RFQ timeouts and asset rates,
keeps cached asset-name lookups responsive during slow `tapd` queries, and
closes `tapd` connections cleanly during shutdown and startup failures.
Expand Down
Loading
Loading