Skip to content

Commit bc06754

Browse files
committed
loop: add manual static deposit recovery
Add recoverdeposit CLI/RPC support for verifying one static-address output on-chain, matching it to a derived static address, restoring the address/import, and directly creating or reactivating the deposit row.
1 parent 40fd9bd commit bc06754

26 files changed

Lines changed: 2115 additions & 296 deletions

cmd/loop/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ var (
8989
listSwapsCommand, swapInfoCommand, getLiquidityParamsCommand,
9090
setLiquidityRuleCommand, suggestSwapCommand, setParamsCommand,
9191
getInfoCommand, abandonSwapCommand, recoverCommand,
92+
recoverDepositCommand,
9293
reservationsCommands,
9394
instantOutCommand, listInstantOutsCommand, stopCommand,
9495
printManCommand, printMarkdownCommand,

cmd/loop/recover.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,37 @@ var recoverCommand = &cli.Command{
2525
Action: runRecover,
2626
}
2727

28+
var recoverDepositCommand = &cli.Command{
29+
Name: "recoverdeposit",
30+
Usage: "recover one static address deposit from on-chain data",
31+
Description: "Verifies the provided transaction output on-chain, " +
32+
"restores the matching static address, stores the deposit, and " +
33+
"starts normal deposit tracking.",
34+
Flags: []cli.Flag{
35+
&cli.StringFlag{
36+
Name: "txid",
37+
Usage: "transaction ID containing the deposit output",
38+
Required: true,
39+
},
40+
&cli.UintFlag{
41+
Name: "vout",
42+
Usage: "deposit output index",
43+
Required: true,
44+
},
45+
&cli.IntFlag{
46+
Name: "height_hint",
47+
Usage: "block height hint for the deposit transaction",
48+
Required: true,
49+
},
50+
&cli.StringFlag{
51+
Name: "pkscript_hex",
52+
Usage: "expected static address P2TR pkScript in hex",
53+
Required: true,
54+
},
55+
},
56+
Action: runRecoverDeposit,
57+
}
58+
2859
func runRecover(ctx context.Context, cmd *cli.Command) error {
2960
if cmd.NArg() > 0 {
3061
return showCommandHelp(ctx, cmd)
@@ -48,3 +79,32 @@ func runRecover(ctx context.Context, cmd *cli.Command) error {
4879
printRespJSON(resp)
4980
return nil
5081
}
82+
83+
// runRecoverDeposit calls the daemon to manually recover one static-address
84+
// deposit from caller-supplied on-chain coordinates.
85+
func runRecoverDeposit(ctx context.Context, cmd *cli.Command) error {
86+
if cmd.NArg() > 0 {
87+
return showCommandHelp(ctx, cmd)
88+
}
89+
90+
client, cleanup, err := getClient(cmd)
91+
if err != nil {
92+
return err
93+
}
94+
defer cleanup()
95+
96+
resp, err := client.RecoverDeposit(
97+
ctx, &looprpc.RecoverDepositRequest{
98+
Txid: cmd.String("txid"),
99+
Vout: uint32(cmd.Uint("vout")),
100+
HeightHint: int32(cmd.Int("height_hint")),
101+
PkscriptHex: cmd.String("pkscript_hex"),
102+
},
103+
)
104+
if err != nil {
105+
return err
106+
}
107+
108+
printRespJSON(resp)
109+
return nil
110+
}

docs/loop.1

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,25 @@ restore static address and L402 state from a local backup file
413413
.PP
414414
\fB--help, -h\fP: show help
415415

416+
.SH recoverdeposit
417+
.PP
418+
recover one static address deposit from on-chain data
419+
420+
.PP
421+
\fB--height_hint\fP="": block height hint for the deposit transaction (default: 0)
422+
423+
.PP
424+
\fB--help, -h\fP: show help
425+
426+
.PP
427+
\fB--pkscript_hex\fP="": expected static address P2TR pkScript in hex
428+
429+
.PP
430+
\fB--txid\fP="": transaction ID containing the deposit output
431+
432+
.PP
433+
\fB--vout\fP="": deposit output index (default: 0)
434+
416435
.SH reservations, r
417436
.PP
418437
manage reservations
@@ -699,4 +718,3 @@ Open a channel to a an existing peer.
699718

700719
.PP
701720
\fB--zero_conf\fP: (optional) whether a zero-conf channel open should be attempted.
702-

docs/loop.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,28 @@ The following flags are supported:
437437
| `--backup_file="…"` | path to an encrypted backup file; if omitted, loopd selects and validates the latest active-network backup candidate | string |
438438
| `--help` (`-h`) | show help | bool | `false` |
439439

440+
### `recoverdeposit` command
441+
442+
recover one static address deposit from on-chain data.
443+
444+
Verifies the provided transaction output on-chain, restores the matching static address, stores the deposit, and starts normal deposit tracking.
445+
446+
Usage:
447+
448+
```bash
449+
$ loop [GLOBAL FLAGS] recoverdeposit [COMMAND FLAGS] [ARGUMENTS...]
450+
```
451+
452+
The following flags are supported:
453+
454+
| Name | Description | Type | Default value |
455+
|----------------------|------------------------------------------------------------------------|--------|:-------------:|
456+
| `--txid="…"` | transaction ID containing the deposit output | string |
457+
| `--vout="…"` | deposit output index | uint | `0` |
458+
| `--height_hint="…"` | block height hint for the deposit transaction | int | `0` |
459+
| `--pkscript_hex="…"` | expected static address P2TR pkScript in hex | string |
460+
| `--help` (`-h`) | show help | bool | `false` |
461+
440462
### `reservations` command (aliases: `r`)
441463

442464
manage reservations.
@@ -768,4 +790,3 @@ The following flags are supported:
768790
| `--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` |
769791
| `--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 | `[]` |
770792
| `--help` (`-h`) | show help | bool | `false` |
771-

loopd/swapclient_server.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,43 @@ func (s *swapClientServer) Recover(ctx context.Context,
12971297
}, nil
12981298
}
12991299

1300+
// RecoverDeposit verifies and restores one static-address deposit from
1301+
// caller-supplied on-chain coordinates.
1302+
func (s *swapClientServer) RecoverDeposit(ctx context.Context,
1303+
req *looprpc.RecoverDepositRequest) (*looprpc.RecoverDepositResponse,
1304+
error) {
1305+
1306+
if s.recoveryService == nil {
1307+
return nil, status.Error(
1308+
codes.Unavailable, "recovery service not configured",
1309+
)
1310+
}
1311+
1312+
result, err := s.recoveryService.RecoverDeposit(
1313+
ctx, &recovery.RecoverDepositRequest{
1314+
TxID: req.GetTxid(),
1315+
VOut: req.GetVout(),
1316+
HeightHint: req.GetHeightHint(),
1317+
PkScriptHex: req.GetPkscriptHex(),
1318+
},
1319+
)
1320+
if err != nil {
1321+
return nil, err
1322+
}
1323+
1324+
return &looprpc.RecoverDepositResponse{
1325+
Outpoint: result.OutPoint,
1326+
Value: int64(result.Value),
1327+
ConfirmationHeight: result.ConfirmationHeight,
1328+
ClientKeyFamily: result.ClientKeyFamily,
1329+
ClientKeyIndex: result.ClientKeyIndex,
1330+
StaticAddress: result.StaticAddress,
1331+
RecoveredAddress: result.RecoveredAddress,
1332+
RecoveredDeposit: result.RecoveredDeposit,
1333+
DepositId: result.DepositID,
1334+
}, nil
1335+
}
1336+
13001337
// GetInfo returns basic information about the loop daemon and details to swaps
13011338
// from the swap store.
13021339
func (s *swapClientServer) GetInfo(ctx context.Context,

loopd/swapclient_server_staticaddr_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ func (s *staticAddrDepositStore) UpdateDeposit(context.Context,
3434
return nil
3535
}
3636

37+
// UpdateRecoveredDeposit satisfies deposit.Store for static-address server
38+
// tests that do not exercise manual recovery persistence.
39+
func (s *staticAddrDepositStore) UpdateRecoveredDeposit(context.Context,
40+
*deposit.Deposit) error {
41+
42+
return nil
43+
}
44+
3745
func (s *staticAddrDepositStore) GetDeposit(context.Context,
3846
deposit.ID) (*deposit.Deposit, error) {
3947

loopd/swapclient_server_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,14 @@ func (s *mockDepositStore) UpdateDeposit(_ context.Context,
10191019
return nil
10201020
}
10211021

1022+
// UpdateRecoveredDeposit satisfies deposit.Store for server tests that only
1023+
// need outpoint lookups.
1024+
func (s *mockDepositStore) UpdateRecoveredDeposit(_ context.Context,
1025+
_ *deposit.Deposit) error {
1026+
1027+
return nil
1028+
}
1029+
10221030
func (s *mockDepositStore) GetDeposit(_ context.Context,
10231031
_ deposit.ID) (*deposit.Deposit, error) {
10241032

loopdb/sqlc/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

loopdb/sqlc/queries/static_address_deposits.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ SET
3232
WHERE
3333
deposits.deposit_id = $1;
3434

35+
-- name: UpdateRecoveredDeposit :exec
36+
UPDATE deposits
37+
SET
38+
tx_hash = $2,
39+
out_index = $3,
40+
amount = $4,
41+
confirmation_height = $5,
42+
timeout_sweep_pk_script = $6,
43+
static_address_id = $7
44+
WHERE
45+
deposits.deposit_id = $1;
46+
3547
-- name: InsertDepositUpdate :exec
3648
INSERT INTO deposit_updates (
3749
deposit_id,

loopdb/sqlc/static_address_deposits.sql.go

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)