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 }