2020-04-07 00:21:38 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
|
|
|
var addInvoiceCommand = cli.Command{
|
|
|
|
Name: "addinvoice",
|
2020-04-04 02:40:34 +03:00
|
|
|
Category: "Invoices",
|
2020-04-07 00:21:38 +03:00
|
|
|
Usage: "Add a new invoice.",
|
|
|
|
Description: `
|
|
|
|
Add a new invoice, expressing intent for a future payment.
|
|
|
|
|
|
|
|
Invoices without an amount can be created by not supplying any
|
|
|
|
parameters or providing an amount of 0. These invoices allow the payee
|
|
|
|
to specify the amount of satoshis they wish to send.`,
|
|
|
|
ArgsUsage: "value preimage",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "memo",
|
|
|
|
Usage: "a description of the payment to attach along " +
|
|
|
|
"with the invoice (default=\"\")",
|
|
|
|
},
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "preimage",
|
|
|
|
Usage: "the hex-encoded preimage (32 byte) which will " +
|
|
|
|
"allow settling an incoming HTLC payable to this " +
|
|
|
|
"preimage. If not set, a random preimage will be " +
|
|
|
|
"created.",
|
|
|
|
},
|
|
|
|
cli.Int64Flag{
|
|
|
|
Name: "amt",
|
|
|
|
Usage: "the amt of satoshis in this invoice",
|
|
|
|
},
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "description_hash",
|
|
|
|
Usage: "SHA-256 hash of the description of the payment. " +
|
|
|
|
"Used if the purpose of payment cannot naturally " +
|
|
|
|
"fit within the memo. If provided this will be " +
|
|
|
|
"used instead of the description(memo) field in " +
|
|
|
|
"the encoded invoice.",
|
|
|
|
},
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "fallback_addr",
|
|
|
|
Usage: "fallback on-chain address that can be used in " +
|
|
|
|
"case the lightning payment fails",
|
|
|
|
},
|
|
|
|
cli.Int64Flag{
|
|
|
|
Name: "expiry",
|
|
|
|
Usage: "the invoice's expiry time in seconds. If not " +
|
|
|
|
"specified an expiry of 3600 seconds (1 hour) " +
|
|
|
|
"is implied.",
|
|
|
|
},
|
|
|
|
cli.BoolTFlag{
|
|
|
|
Name: "private",
|
|
|
|
Usage: "encode routing hints in the invoice with " +
|
|
|
|
"private channels in order to assist the " +
|
|
|
|
"payer in reaching you",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: actionDecorator(addInvoice),
|
|
|
|
}
|
|
|
|
|
|
|
|
func addInvoice(ctx *cli.Context) error {
|
|
|
|
var (
|
|
|
|
preimage []byte
|
|
|
|
descHash []byte
|
|
|
|
amt int64
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
client, cleanUp := getClient(ctx)
|
|
|
|
defer cleanUp()
|
|
|
|
|
|
|
|
args := ctx.Args()
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case ctx.IsSet("amt"):
|
|
|
|
amt = ctx.Int64("amt")
|
|
|
|
case args.Present():
|
|
|
|
amt, err = strconv.ParseInt(args.First(), 10, 64)
|
|
|
|
args = args.Tail()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to decode amt argument: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case ctx.IsSet("preimage"):
|
|
|
|
preimage, err = hex.DecodeString(ctx.String("preimage"))
|
|
|
|
case args.Present():
|
|
|
|
preimage, err = hex.DecodeString(args.First())
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to parse preimage: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
descHash, err = hex.DecodeString(ctx.String("description_hash"))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to parse description_hash: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
invoice := &lnrpc.Invoice{
|
|
|
|
Memo: ctx.String("memo"),
|
|
|
|
RPreimage: preimage,
|
|
|
|
Value: amt,
|
|
|
|
DescriptionHash: descHash,
|
|
|
|
FallbackAddr: ctx.String("fallback_addr"),
|
|
|
|
Expiry: ctx.Int64("expiry"),
|
|
|
|
Private: ctx.Bool("private"),
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := client.AddInvoice(context.Background(), invoice)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
printRespJSON(resp)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var lookupInvoiceCommand = cli.Command{
|
|
|
|
Name: "lookupinvoice",
|
2020-04-04 02:40:34 +03:00
|
|
|
Category: "Invoices",
|
2020-04-07 00:21:38 +03:00
|
|
|
Usage: "Lookup an existing invoice by its payment hash.",
|
|
|
|
ArgsUsage: "rhash",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "rhash",
|
|
|
|
Usage: "the 32 byte payment hash of the invoice to query for, the hash " +
|
|
|
|
"should be a hex-encoded string",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: actionDecorator(lookupInvoice),
|
|
|
|
}
|
|
|
|
|
|
|
|
func lookupInvoice(ctx *cli.Context) error {
|
|
|
|
client, cleanUp := getClient(ctx)
|
|
|
|
defer cleanUp()
|
|
|
|
|
|
|
|
var (
|
|
|
|
rHash []byte
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case ctx.IsSet("rhash"):
|
|
|
|
rHash, err = hex.DecodeString(ctx.String("rhash"))
|
|
|
|
case ctx.Args().Present():
|
|
|
|
rHash, err = hex.DecodeString(ctx.Args().First())
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("rhash argument missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to decode rhash argument: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req := &lnrpc.PaymentHash{
|
|
|
|
RHash: rHash,
|
|
|
|
}
|
|
|
|
|
|
|
|
invoice, err := client.LookupInvoice(context.Background(), req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
printRespJSON(invoice)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var listInvoicesCommand = cli.Command{
|
|
|
|
Name: "listinvoices",
|
2020-04-04 02:40:34 +03:00
|
|
|
Category: "Invoices",
|
2020-04-07 00:21:38 +03:00
|
|
|
Usage: "List all invoices currently stored within the database. Any " +
|
|
|
|
"active debug invoices are ignored.",
|
|
|
|
Description: `
|
|
|
|
This command enables the retrieval of all invoices currently stored
|
|
|
|
within the database. It has full support for paginationed responses,
|
|
|
|
allowing users to query for specific invoices through their add_index.
|
|
|
|
This can be done by using either the first_index_offset or
|
|
|
|
last_index_offset fields included in the response as the index_offset of
|
|
|
|
the next request. Backward pagination is enabled by default to receive
|
|
|
|
current invoices first. If you wish to paginate forwards, set the
|
|
|
|
paginate-forwards flag. If none of the parameters are specified, then
|
|
|
|
the last 100 invoices will be returned.
|
|
|
|
|
|
|
|
For example: if you have 200 invoices, "lncli listinvoices" will return
|
|
|
|
the last 100 created. If you wish to retrieve the previous 100, the
|
|
|
|
first_offset_index of the response can be used as the index_offset of
|
|
|
|
the next listinvoices request.`,
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "pending_only",
|
|
|
|
Usage: "toggles if all invoices should be returned, " +
|
|
|
|
"or only those that are currently unsettled",
|
|
|
|
},
|
|
|
|
cli.Uint64Flag{
|
|
|
|
Name: "index_offset",
|
|
|
|
Usage: "the index of an invoice that will be used as " +
|
|
|
|
"either the start or end of a query to " +
|
|
|
|
"determine which invoices should be returned " +
|
|
|
|
"in the response",
|
|
|
|
},
|
|
|
|
cli.Uint64Flag{
|
|
|
|
Name: "max_invoices",
|
|
|
|
Usage: "the max number of invoices to return",
|
|
|
|
},
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "paginate-forwards",
|
|
|
|
Usage: "if set, invoices succeeding the " +
|
|
|
|
"index_offset will be returned",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: actionDecorator(listInvoices),
|
|
|
|
}
|
|
|
|
|
|
|
|
func listInvoices(ctx *cli.Context) error {
|
|
|
|
client, cleanUp := getClient(ctx)
|
|
|
|
defer cleanUp()
|
|
|
|
|
|
|
|
req := &lnrpc.ListInvoiceRequest{
|
|
|
|
PendingOnly: ctx.Bool("pending_only"),
|
|
|
|
IndexOffset: ctx.Uint64("index_offset"),
|
|
|
|
NumMaxInvoices: ctx.Uint64("max_invoices"),
|
|
|
|
Reversed: !ctx.Bool("paginate-forwards"),
|
|
|
|
}
|
|
|
|
|
|
|
|
invoices, err := client.ListInvoices(context.Background(), req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
printRespJSON(invoices)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var decodePayReqCommand = cli.Command{
|
|
|
|
Name: "decodepayreq",
|
2020-04-04 02:40:34 +03:00
|
|
|
Category: "Invoices",
|
2020-04-07 00:21:38 +03:00
|
|
|
Usage: "Decode a payment request.",
|
|
|
|
Description: "Decode the passed payment request revealing the destination, payment hash and value of the payment request",
|
|
|
|
ArgsUsage: "pay_req",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "pay_req",
|
|
|
|
Usage: "the bech32 encoded payment request",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: actionDecorator(decodePayReq),
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodePayReq(ctx *cli.Context) error {
|
|
|
|
ctxb := context.Background()
|
|
|
|
client, cleanUp := getClient(ctx)
|
|
|
|
defer cleanUp()
|
|
|
|
|
|
|
|
var payreq string
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case ctx.IsSet("pay_req"):
|
|
|
|
payreq = ctx.String("pay_req")
|
|
|
|
case ctx.Args().Present():
|
|
|
|
payreq = ctx.Args().First()
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("pay_req argument missing")
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := client.DecodePayReq(ctxb, &lnrpc.PayReqString{
|
|
|
|
PayReq: payreq,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
printRespJSON(resp)
|
|
|
|
return nil
|
|
|
|
}
|