@@ -2,6 +2,7 @@ package main
22
33import (
44 "encoding/hex"
5+ "errors"
56 "fmt"
67 "os"
78 "strconv"
@@ -26,6 +27,8 @@ var accountsCommands = []cli.Command{
2627 Subcommands : []cli.Command {
2728 createAccountCommand ,
2829 updateAccountCommand ,
30+ creditCommand ,
31+ debitCommand ,
2932 listAccountsCommand ,
3033 accountInfoCommand ,
3134 removeAccountCommand ,
@@ -232,6 +235,123 @@ func updateAccount(cli *cli.Context) error {
232235 return nil
233236}
234237
238+ var creditCommand = cli.Command {
239+ Name : "credit" ,
240+ Usage : "Increase an account's balance by the given amount." ,
241+ ArgsUsage : "[id | label] amount" ,
242+ Description : "Increases an existing off-chain account's balance by " +
243+ "the given amount." ,
244+ Flags : []cli.Flag {
245+ cli.StringFlag {
246+ Name : idName ,
247+ Usage : "The ID of the account to credit." ,
248+ },
249+ cli.StringFlag {
250+ Name : labelName ,
251+ Usage : "(optional) The unique label of the account." ,
252+ },
253+ cli.Uint64Flag {
254+ Name : "amount" ,
255+ Usage : "The amount to credit the account." ,
256+ },
257+ },
258+ Action : creditBalance ,
259+ }
260+
261+ func creditBalance (cli * cli.Context ) error {
262+ return updateBalance (cli , true )
263+ }
264+
265+ var debitCommand = cli.Command {
266+ Name : "debit" ,
267+ Usage : "Decrease an account's balance by the given amount." ,
268+ ArgsUsage : "[id | label] amount" ,
269+ Description : "Decreases an existing off-chain account's balance by " +
270+ "the given amount." ,
271+ Flags : []cli.Flag {
272+ cli.StringFlag {
273+ Name : idName ,
274+ Usage : "The ID of the account to debit." ,
275+ },
276+ cli.StringFlag {
277+ Name : labelName ,
278+ Usage : "(optional) The unique label of the account." ,
279+ },
280+ cli.Uint64Flag {
281+ Name : "amount" ,
282+ Usage : "The amount to debit the account." ,
283+ },
284+ },
285+ Action : debitBalance ,
286+ }
287+
288+ func debitBalance (cli * cli.Context ) error {
289+ return updateBalance (cli , false )
290+ }
291+
292+ func updateBalance (cli * cli.Context , add bool ) error {
293+ ctx := getContext ()
294+ clientConn , cleanup , err := connectClient (cli , false )
295+ if err != nil {
296+ return err
297+ }
298+ defer cleanup ()
299+ client := litrpc .NewAccountsClient (clientConn )
300+
301+ account , args , err := parseAccountIdentifier (cli )
302+ if err != nil {
303+ return err
304+ }
305+
306+ if (! cli .IsSet ("amount" ) && len (args ) != 1 ) ||
307+ (cli .IsSet ("amount" ) && len (args ) != 0 ) {
308+
309+ return errors .New ("invalid number of arguments" )
310+ }
311+
312+ var amount uint64
313+ switch {
314+ case cli .IsSet ("amount" ):
315+ amount = cli .Uint64 ("amount" )
316+ case args .Present ():
317+ amount , err = strconv .ParseUint (args .First (), 10 , 64 )
318+ if err != nil {
319+ return fmt .Errorf ("unable to decode amount %v" , err )
320+ }
321+ args = args .Tail ()
322+ default :
323+ return errors .New ("must set a value for amount" )
324+ }
325+
326+ if add {
327+ req := & litrpc.CreditAccountRequest {
328+ Account : account ,
329+ Amount : amount ,
330+ }
331+
332+ resp , err := client .CreditAccount (ctx , req )
333+ if err != nil {
334+ return err
335+ }
336+
337+ printRespJSON (resp )
338+ } else {
339+ req := & litrpc.DebitAccountRequest {
340+ Account : account ,
341+ Amount : amount ,
342+ }
343+
344+ resp , err := client .DebitAccount (ctx , req )
345+ if err != nil {
346+ return err
347+ }
348+
349+ printRespJSON (resp )
350+ }
351+
352+ return nil
353+ }
354+
235355var listAccountsCommand = cli.Command {
236356 Name : "list" ,
237357 ShortName : "l" ,
@@ -348,6 +468,39 @@ func removeAccount(cli *cli.Context) error {
348468 return err
349469}
350470
471+ // parseAccountIdentifier parses either the id or label from the command line,
472+ // and returns the account identifier.
473+ func parseAccountIdentifier (ctx * cli.Context ) (
474+ * litrpc.AccountIdentifier , cli.Args , error ) {
475+
476+ id , label , args , err := parseIDOrLabel (ctx )
477+ if err != nil {
478+ return nil , nil , err
479+ }
480+
481+ if id == "" && label == "" {
482+ return nil , nil , fmt .Errorf ("id argument missing" )
483+ }
484+
485+ if id != "" {
486+ identifier := & litrpc.AccountIdentifier {
487+ Identifier : & litrpc.AccountIdentifier_Id {
488+ Id : id ,
489+ },
490+ }
491+
492+ return identifier , args , nil
493+ } else {
494+ identifier := & litrpc.AccountIdentifier {
495+ Identifier : & litrpc.AccountIdentifier_Label {
496+ Label : label ,
497+ },
498+ }
499+
500+ return identifier , args , nil
501+ }
502+ }
503+
351504// parseIDOrLabel parses either the id or label from the command line.
352505func parseIDOrLabel (ctx * cli.Context ) (string , string , cli.Args , error ) {
353506 var (
0 commit comments