Skip to content

Commit d776174

Browse files
authored
Merge pull request #8955 from yyforyongyu/cr-8516-240729-sendcoins
Allow selecting coins in `sendcoins`
2 parents b63e5de + dcd8269 commit d776174

File tree

20 files changed

+3524
-3090
lines changed

20 files changed

+3524
-3090
lines changed

cmd/lncli/cmd_open_channel.go

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ func openChannel(ctx *cli.Context) error {
406406
if ctx.IsSet("utxo") {
407407
utxos := ctx.StringSlice("utxo")
408408

409-
outpoints, err := utxosToOutpoints(utxos)
409+
outpoints, err := UtxosToOutpoints(utxos)
410410
if err != nil {
411411
return fmt.Errorf("unable to decode utxos: %w", err)
412412
}
@@ -1141,21 +1141,3 @@ func decodePsbt(psbt string) ([]byte, error) {
11411141
return nil, fmt.Errorf("not a PSBT")
11421142
}
11431143
}
1144-
1145-
// parseUtxos parses a comma separated list of utxos into outpoints that are
1146-
// passed to the server.
1147-
func utxosToOutpoints(utxos []string) ([]*lnrpc.OutPoint, error) {
1148-
var outpoints []*lnrpc.OutPoint
1149-
if len(utxos) == 0 {
1150-
return nil, fmt.Errorf("no utxos specified")
1151-
}
1152-
for _, utxo := range utxos {
1153-
outpoint, err := NewProtoOutPoint(utxo)
1154-
if err != nil {
1155-
return nil, err
1156-
}
1157-
outpoints = append(outpoints, outpoint)
1158-
}
1159-
1160-
return outpoints, nil
1161-
}

cmd/lncli/commands.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,11 @@ var sendCoinsCommand = cli.Command{
288288
},
289289
cli.BoolFlag{
290290
Name: "sweepall",
291-
Usage: "if set, then the amount field will be ignored, " +
292-
"and the wallet will attempt to sweep all " +
293-
"outputs within the wallet to the target " +
294-
"address",
291+
Usage: "if set, then the amount field should be " +
292+
"unset. This indicates that the wallet will " +
293+
"attempt to sweep all outputs within the " +
294+
"wallet or all funds in select utxos (when " +
295+
"supplied) to the target address",
295296
},
296297
cli.Int64Flag{
297298
Name: "amt",
@@ -330,16 +331,28 @@ var sendCoinsCommand = cli.Command{
330331
"scripts",
331332
},
332333
coinSelectionStrategyFlag,
334+
cli.StringSliceFlag{
335+
Name: "utxo",
336+
Usage: "a utxo specified as outpoint(tx:idx) which " +
337+
"will be used as input for the transaction. " +
338+
"This flag can be repeatedly used to specify " +
339+
"multiple utxos as inputs. The selected " +
340+
"utxos can either be entirely spent by " +
341+
"specifying the sweepall flag or a specified " +
342+
"amount can be spent in the utxos through " +
343+
"the amt flag",
344+
},
333345
txLabelFlag,
334346
},
335347
Action: actionDecorator(sendCoins),
336348
}
337349

338350
func sendCoins(ctx *cli.Context) error {
339351
var (
340-
addr string
341-
amt int64
342-
err error
352+
addr string
353+
amt int64
354+
err error
355+
outpoints []*lnrpc.OutPoint
343356
)
344357
ctxc := getContext()
345358
args := ctx.Args()
@@ -417,6 +430,15 @@ func sendCoins(ctx *cli.Context) error {
417430
displayAmt = balanceResponse.GetConfirmedBalance()
418431
}
419432

433+
if ctx.IsSet("utxo") {
434+
utxos := ctx.StringSlice("utxo")
435+
436+
outpoints, err = UtxosToOutpoints(utxos)
437+
if err != nil {
438+
return fmt.Errorf("unable to decode utxos: %w", err)
439+
}
440+
}
441+
420442
// Ask for confirmation if we're on an actual terminal and the output is
421443
// not being redirected to another command. This prevents existing shell
422444
// scripts from breaking.
@@ -440,6 +462,7 @@ func sendCoins(ctx *cli.Context) error {
440462
MinConfs: minConfs,
441463
SpendUnconfirmed: minConfs == 0,
442464
CoinSelectionStrategy: coinSelectionStrategy,
465+
Outpoints: outpoints,
443466
}
444467
txid, err := client.SendCoins(ctxc, req)
445468
if err != nil {

cmd/lncli/types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,22 @@ func NewFailedUpdateFromProto(update *lnrpc.FailedUpdate) *FailedUpdate {
8585
UpdateError: update.UpdateError,
8686
}
8787
}
88+
89+
// UtxosToOutpoints converts a slice of UTXO strings into a slice of OutPoint
90+
// protobuf objects. It returns an error if no UTXOs are specified or if any
91+
// UTXO string cannot be parsed into an OutPoint.
92+
func UtxosToOutpoints(utxos []string) ([]*lnrpc.OutPoint, error) {
93+
var outpoints []*lnrpc.OutPoint
94+
if len(utxos) == 0 {
95+
return nil, fmt.Errorf("no utxos specified")
96+
}
97+
for _, utxo := range utxos {
98+
outpoint, err := NewProtoOutPoint(utxo)
99+
if err != nil {
100+
return nil, err
101+
}
102+
outpoints = append(outpoints, outpoint)
103+
}
104+
105+
return outpoints, nil
106+
}

docs/release-notes/release-notes-0.18.3.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,36 @@ commitment when the channel was force closed.
5858
send payment stream context, or automatically at the end of the timeout period
5959
if the user provided `timeout_seconds`.
6060

61+
* The [SendCoinsRequest](https://github.com/lightningnetwork/lnd/pull/8955) now
62+
takes an optional param `Outpoints`, which is a list of `*lnrpc.OutPoint`
63+
that specifies the coins from the wallet to be spent in this RPC call. To
64+
send selected coins to a given address with a given amount,
65+
```go
66+
req := &lnrpc.SendCoinsRequest{
67+
Addr: ...,
68+
Amount: ...,
69+
Outpoints: []*lnrpc.OutPoint{
70+
selected_wallet_utxo_1,
71+
selected_wallet_utxo_2,
72+
},
73+
}
74+
75+
SendCoins(req)
76+
```
77+
To send selected coins to a given address without change output,
78+
```go
79+
req := &lnrpc.SendCoinsRequest{
80+
Addr: ...,
81+
SendAll: true,
82+
Outpoints: []*lnrpc.OutPoint{
83+
selected_wallet_utxo_1,
84+
selected_wallet_utxo_2,
85+
},
86+
}
87+
88+
SendCoins(req)
89+
```
90+
6191
## lncli Additions
6292

6393
* [Added](https://github.com/lightningnetwork/lnd/pull/8491) the `cltv_expiry`
@@ -68,6 +98,18 @@ commitment when the channel was force closed.
6898
command returns the fee rate estimate for on-chain transactions in sat/kw and
6999
sat/vb to achieve a given confirmation target.
70100

101+
* [`sendcoins` now takes an optional utxo
102+
flag](https://github.com/lightningnetwork/lnd/pull/8955). This allows users
103+
to specify the coins that they want to use as inputs for the transaction. To
104+
send selected coins to a given address with a given amount,
105+
```sh
106+
sendcoins --addr YOUR_ADDR --amt YOUR_AMT --utxo selected_wallet_utxo1 --utxo selected_wallet_utxo2
107+
```
108+
To send selected coins to a given address without change output,
109+
```sh
110+
sendcoins --addr YOUR_ADDR --utxo selected_wallet_utxo1 --utxo selected_wallet_utxo2 --sweepall
111+
```
112+
71113
# Improvements
72114
## Functional Updates
73115

itest/list_on_test.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,16 @@ var allTestCases = []*lntest.TestCase{
4646
TestFunc: testDataLossProtection,
4747
},
4848
{
49-
Name: "sweep coins",
50-
TestFunc: testSweepAllCoins,
49+
Name: "send all coins",
50+
TestFunc: testSendAllCoins,
51+
},
52+
{
53+
Name: "send selected coins",
54+
TestFunc: testSendSelectedCoins,
55+
},
56+
{
57+
Name: "send selected coins channel reserve",
58+
TestFunc: testSendSelectedCoinsChannelReserve,
5159
},
5260
{
5361
Name: "disconnecting target peer",

0 commit comments

Comments
 (0)