github.com/decred/dcrlnd@v0.7.6/cmd/dcrlncli/cmd_invoice.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"strconv"
     7  
     8  	"github.com/decred/dcrlnd/lnrpc"
     9  	"github.com/urfave/cli"
    10  )
    11  
    12  var addInvoiceCommand = cli.Command{
    13  	Name:     "addinvoice",
    14  	Category: "Invoices",
    15  	Usage:    "Add a new invoice.",
    16  	Description: `
    17  	Add a new invoice, expressing intent for a future payment.
    18  
    19  	Invoices without an amount can be created by not supplying any
    20  	parameters or providing an amount of 0. These invoices allow the payee
    21  	to specify the amount of atoms they wish to send.`,
    22  	ArgsUsage: "value preimage",
    23  	Flags: []cli.Flag{
    24  		cli.StringFlag{
    25  			Name: "memo",
    26  			Usage: "A description of the payment to attach along " +
    27  				"with the invoice (default=\"\")",
    28  		},
    29  		cli.StringFlag{
    30  			Name: "preimage",
    31  			Usage: "The hex-encoded preimage (32 byte) which will " +
    32  				"allow settling an incoming HTLC payable to this " +
    33  				"preimage. If not set, a random preimage will be " +
    34  				"created.",
    35  		},
    36  		cli.Int64Flag{
    37  			Name:  "amt",
    38  			Usage: "The amount of atoms in this invoice",
    39  		},
    40  		cli.Int64Flag{
    41  			Name:  "amt_matoms",
    42  			Usage: "The amount of milliatoms in this invoice",
    43  		},
    44  		cli.StringFlag{
    45  			Name: "description_hash",
    46  			Usage: "SHA-256 hash of the description of the payment. " +
    47  				"Used if the purpose of payment cannot naturally " +
    48  				"fit within the memo. If provided this will be " +
    49  				"used instead of the description(memo) field in " +
    50  				"the encoded invoice.",
    51  		},
    52  		cli.StringFlag{
    53  			Name: "fallback_addr",
    54  			Usage: "Fallback on-chain address that can be used in " +
    55  				"case the lightning payment fails",
    56  		},
    57  		cli.Int64Flag{
    58  			Name: "expiry",
    59  			Usage: "The invoice's expiry time in seconds. If not " +
    60  				"specified an expiry of 3600 seconds (1 hour) " +
    61  				"is implied.",
    62  		},
    63  		cli.BoolTFlag{
    64  			Name: "private",
    65  			Usage: "Encode routing hints in the invoice with " +
    66  				"private channels in order to assist the " +
    67  				"payer in reaching you",
    68  		},
    69  		cli.BoolFlag{
    70  			Name: "ignore_max_inbound_amt",
    71  			Usage: "Ignore check for available inbound capacity " +
    72  				"in directly connected channels and create the " +
    73  				"invoice anyway.",
    74  		},
    75  		cli.BoolFlag{
    76  			Name: "amp",
    77  			Usage: "creates an AMP invoice. If true, preimage " +
    78  				"should not be set.",
    79  		},
    80  	},
    81  	Action: actionDecorator(addInvoice),
    82  }
    83  
    84  func addInvoice(ctx *cli.Context) error {
    85  	var (
    86  		preimage  []byte
    87  		descHash  []byte
    88  		amt       int64
    89  		amtMAtoms int64
    90  		err       error
    91  	)
    92  	ctxc := getContext()
    93  	client, cleanUp := getClient(ctx)
    94  	defer cleanUp()
    95  
    96  	args := ctx.Args()
    97  
    98  	amt = ctx.Int64("amt")
    99  	amtMAtoms = ctx.Int64("amt_matoms")
   100  	if !ctx.IsSet("amt") && !ctx.IsSet("amt_matoms") && args.Present() {
   101  		amt, err = strconv.ParseInt(args.First(), 10, 64)
   102  		args = args.Tail()
   103  		if err != nil {
   104  			return fmt.Errorf("unable to decode amt argument: %v", err)
   105  		}
   106  	}
   107  
   108  	switch {
   109  	case ctx.IsSet("preimage"):
   110  		preimage, err = hex.DecodeString(ctx.String("preimage"))
   111  	case args.Present():
   112  		preimage, err = hex.DecodeString(args.First())
   113  	}
   114  
   115  	if err != nil {
   116  		return fmt.Errorf("unable to parse preimage: %v", err)
   117  	}
   118  
   119  	descHash, err = hex.DecodeString(ctx.String("description_hash"))
   120  	if err != nil {
   121  		return fmt.Errorf("unable to parse description_hash: %v", err)
   122  	}
   123  
   124  	invoice := &lnrpc.Invoice{
   125  		Memo:                ctx.String("memo"),
   126  		RPreimage:           preimage,
   127  		Value:               amt,
   128  		ValueMAtoms:         amtMAtoms,
   129  		DescriptionHash:     descHash,
   130  		FallbackAddr:        ctx.String("fallback_addr"),
   131  		Expiry:              ctx.Int64("expiry"),
   132  		Private:             ctx.Bool("private"),
   133  		IgnoreMaxInboundAmt: ctx.Bool("ignore_max_inbound_amt"),
   134  		IsAmp:               ctx.Bool("amp"),
   135  	}
   136  
   137  	resp, err := client.AddInvoice(ctxc, invoice)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	printRespJSON(resp)
   143  
   144  	return nil
   145  }
   146  
   147  var lookupInvoiceCommand = cli.Command{
   148  	Name:      "lookupinvoice",
   149  	Category:  "Invoices",
   150  	Usage:     "Lookup an existing invoice by its payment hash.",
   151  	ArgsUsage: "rhash",
   152  	Flags: []cli.Flag{
   153  		cli.StringFlag{
   154  			Name: "rhash",
   155  			Usage: "The 32 byte payment hash of the invoice to query for, the hash " +
   156  				"should be a hex-encoded string",
   157  		},
   158  	},
   159  	Action: actionDecorator(lookupInvoice),
   160  }
   161  
   162  func lookupInvoice(ctx *cli.Context) error {
   163  	ctxc := getContext()
   164  	client, cleanUp := getClient(ctx)
   165  	defer cleanUp()
   166  
   167  	var (
   168  		rHash []byte
   169  		err   error
   170  	)
   171  
   172  	switch {
   173  	case ctx.IsSet("rhash"):
   174  		rHash, err = hex.DecodeString(ctx.String("rhash"))
   175  	case ctx.Args().Present():
   176  		rHash, err = hex.DecodeString(ctx.Args().First())
   177  	default:
   178  		return fmt.Errorf("rhash argument missing")
   179  	}
   180  
   181  	if err != nil {
   182  		return fmt.Errorf("unable to decode rhash argument: %v", err)
   183  	}
   184  
   185  	req := &lnrpc.PaymentHash{
   186  		RHash: rHash,
   187  	}
   188  
   189  	invoice, err := client.LookupInvoice(ctxc, req)
   190  	if err != nil {
   191  		return err
   192  	}
   193  
   194  	printRespJSON(invoice)
   195  
   196  	return nil
   197  }
   198  
   199  var listInvoicesCommand = cli.Command{
   200  	Name:     "listinvoices",
   201  	Category: "Invoices",
   202  	Usage: "List all invoices currently stored within the database. Any " +
   203  		"active debug invoices are ignored.",
   204  	Description: `
   205  	This command enables the retrieval of all invoices currently stored
   206  	within the database. It has full support for paginationed responses,
   207  	allowing users to query for specific invoices through their 'add_index'.
   208  	This can be done by using either the 'first_index_offset' or
   209  	'last_index_offset' fields included in the response as the 'index_offset' of
   210  	the next request. Backward pagination is enabled by default to receive
   211  	current invoices first. If you wish to paginate forwards, set the 
   212  	'paginate-forwards' flag. If none of the parameters are specified, then 
   213  	the last 100 invoices will be returned.
   214  
   215  	For example: if you have 200 invoices, 'dcrlncli listinvoices' will return
   216  	the last 100 created. If you wish to retrieve the previous 100, the
   217  	'first_offset_index' of the response can be used as the 'index_offset' of
   218  	the next listinvoices request.`,
   219  	Flags: []cli.Flag{
   220  		cli.BoolFlag{
   221  			Name: "pending_only",
   222  			Usage: "Toggles if all invoices should be returned, " +
   223  				"or only those that are currently unsettled",
   224  		},
   225  		cli.Uint64Flag{
   226  			Name: "index_offset",
   227  			Usage: "The index of an invoice that will be used as " +
   228  				"either the start or end of a query to " +
   229  				"determine which invoices should be returned " +
   230  				"in the response",
   231  		},
   232  		cli.Uint64Flag{
   233  			Name:  "max_invoices",
   234  			Usage: "The max number of invoices to return",
   235  		},
   236  		cli.BoolFlag{
   237  			Name: "paginate-forwards",
   238  			Usage: "If set, invoices succeeding the " +
   239  				"'index_offset' will be returned",
   240  		},
   241  	},
   242  	Action: actionDecorator(listInvoices),
   243  }
   244  
   245  func listInvoices(ctx *cli.Context) error {
   246  	ctxc := getContext()
   247  	client, cleanUp := getClient(ctx)
   248  	defer cleanUp()
   249  
   250  	req := &lnrpc.ListInvoiceRequest{
   251  		PendingOnly:    ctx.Bool("pending_only"),
   252  		IndexOffset:    ctx.Uint64("index_offset"),
   253  		NumMaxInvoices: ctx.Uint64("max_invoices"),
   254  		Reversed:       !ctx.Bool("paginate-forwards"),
   255  	}
   256  
   257  	invoices, err := client.ListInvoices(ctxc, req)
   258  	if err != nil {
   259  		return err
   260  	}
   261  
   262  	printRespJSON(invoices)
   263  
   264  	return nil
   265  }
   266  
   267  var decodePayReqCommand = cli.Command{
   268  	Name:        "decodepayreq",
   269  	Category:    "Invoices",
   270  	Usage:       "Decode a payment request.",
   271  	Description: "Decode the passed payment request revealing the destination, payment hash and value of the payment request",
   272  	ArgsUsage:   "pay_req",
   273  	Flags: []cli.Flag{
   274  		cli.StringFlag{
   275  			Name:  "pay_req",
   276  			Usage: "The bech32 encoded payment request",
   277  		},
   278  	},
   279  	Action: actionDecorator(decodePayReq),
   280  }
   281  
   282  func decodePayReq(ctx *cli.Context) error {
   283  	ctxc := getContext()
   284  	client, cleanUp := getClient(ctx)
   285  	defer cleanUp()
   286  
   287  	var payreq string
   288  
   289  	switch {
   290  	case ctx.IsSet("pay_req"):
   291  		payreq = ctx.String("pay_req")
   292  	case ctx.Args().Present():
   293  		payreq = ctx.Args().First()
   294  	default:
   295  		return fmt.Errorf("pay_req argument missing")
   296  	}
   297  
   298  	resp, err := client.DecodePayReq(ctxc, &lnrpc.PayReqString{
   299  		PayReq: payreq,
   300  	})
   301  	if err != nil {
   302  		return err
   303  	}
   304  
   305  	printRespJSON(resp)
   306  	return nil
   307  }