diff --git a/cmd/loop/debug.go b/cmd/loop/debug.go index fb978ece..b96423dd 100644 --- a/cmd/loop/debug.go +++ b/cmd/loop/debug.go @@ -7,7 +7,7 @@ import ( "context" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) func init() { @@ -15,7 +15,7 @@ func init() { commands = append(commands, forceAutoloopCmd) } -var forceAutoloopCmd = cli.Command{ +var forceAutoloopCmd = &cli.Command{ Name: "forceautoloop", Usage: ` Forces to trigger an autoloop step, regardless of the current internal @@ -25,16 +25,14 @@ var forceAutoloopCmd = cli.Command{ Hidden: true, } -func forceAutoloop(ctx *cli.Context) error { - client, cleanup, err := getDebugClient(ctx) +func forceAutoloop(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getDebugClient(ctx, cmd) if err != nil { return err } defer cleanup() - cfg, err := client.ForceAutoLoop( - context.Background(), &looprpc.ForceAutoLoopRequest{}, - ) + cfg, err := client.ForceAutoLoop(ctx, &looprpc.ForceAutoLoopRequest{}) if err != nil { return err } @@ -44,13 +42,13 @@ func forceAutoloop(ctx *cli.Context) error { return nil } -func getDebugClient(ctx *cli.Context) (looprpc.DebugClient, func(), error) { - rpcServer := ctx.GlobalString("rpcserver") - tlsCertPath, macaroonPath, err := extractPathArgs(ctx) +func getDebugClient(ctx context.Context, cmd *cli.Command) (looprpc.DebugClient, func(), error) { + rpcServer := cmd.String("rpcserver") + tlsCertPath, macaroonPath, err := extractPathArgs(cmd) if err != nil { return nil, nil, err } - conn, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) + conn, err := getClientConn(ctx, rpcServer, tlsCertPath, macaroonPath) if err != nil { return nil, nil, err } diff --git a/cmd/loop/info.go b/cmd/loop/info.go index 1fbdae24..b2f3c118 100644 --- a/cmd/loop/info.go +++ b/cmd/loop/info.go @@ -4,10 +4,10 @@ import ( "context" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var getInfoCommand = cli.Command{ +var getInfoCommand = &cli.Command{ Name: "getinfo", Usage: "show general information about the loop daemon", Description: "Displays general information about the daemon like " + @@ -16,16 +16,14 @@ var getInfoCommand = cli.Command{ Action: getInfo, } -func getInfo(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func getInfo(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() - cfg, err := client.GetInfo( - context.Background(), &looprpc.GetInfoRequest{}, - ) + cfg, err := client.GetInfo(ctx, &looprpc.GetInfoRequest{}) if err != nil { return err } diff --git a/cmd/loop/instantout.go b/cmd/loop/instantout.go index 699e5006..cffc094e 100644 --- a/cmd/loop/instantout.go +++ b/cmd/loop/instantout.go @@ -9,10 +9,10 @@ import ( "github.com/lightninglabs/loop/instantout/reservation" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var instantOutCommand = cli.Command{ +var instantOutCommand = &cli.Command{ Name: "instantout", Usage: "perform an instant off-chain to on-chain swap (looping out)", Description: ` @@ -20,12 +20,12 @@ var instantOutCommand = cli.Command{ will be chosen via the cli. `, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "channel", Usage: "the comma-separated list of short " + "channel IDs of the channels to loop out", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "addr", Usage: "the optional address that the looped out funds " + "should be sent to, if let blank the funds " + @@ -35,13 +35,13 @@ var instantOutCommand = cli.Command{ Action: instantOut, } -func instantOut(ctx *cli.Context) error { +func instantOut(ctx context.Context, cmd *cli.Command) error { // Parse outgoing channel set. Don't string split if the flag is empty. // Otherwise, strings.Split returns a slice of length one with an empty // element. var outgoingChanSet []uint64 - if ctx.IsSet("channel") { - chanStrings := strings.Split(ctx.String("channel"), ",") + if cmd.IsSet("channel") { + chanStrings := strings.Split(cmd.String("channel"), ",") for _, chanString := range chanStrings { chanID, err := strconv.ParseUint(chanString, 10, 64) if err != nil { @@ -53,7 +53,7 @@ func instantOut(ctx *cli.Context) error { } // First set up the swap client itself. - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } @@ -61,7 +61,7 @@ func instantOut(ctx *cli.Context) error { // Now we fetch all the confirmed reservations. reservations, err := client.ListReservations( - context.Background(), &looprpc.ListReservationsRequest{}, + ctx, &looprpc.ListReservationsRequest{}, ) if err != nil { return err @@ -156,7 +156,7 @@ func instantOut(ctx *cli.Context) error { // Now that we have the selected reservations we can estimate the // fee-rates. quote, err := client.InstantOutQuote( - context.Background(), &looprpc.InstantOutQuoteRequest{ + ctx, &looprpc.InstantOutQuoteRequest{ Amt: selectedAmt, ReservationIds: selectedReservations, }, @@ -180,11 +180,11 @@ func instantOut(ctx *cli.Context) error { // Now we can request the instant out swap. instantOutRes, err := client.InstantOut( - context.Background(), + ctx, &looprpc.InstantOutRequest{ ReservationIds: selectedReservations, OutgoingChanSet: outgoingChanSet, - DestAddr: ctx.String("addr"), + DestAddr: cmd.String("addr"), }, ) if err != nil { @@ -202,7 +202,7 @@ func instantOut(ctx *cli.Context) error { return nil } -var listInstantOutsCommand = cli.Command{ +var listInstantOutsCommand = &cli.Command{ Name: "listinstantouts", Usage: "list all instant out swaps", Description: ` @@ -211,16 +211,16 @@ var listInstantOutsCommand = cli.Command{ Action: listInstantOuts, } -func listInstantOuts(ctx *cli.Context) error { +func listInstantOuts(ctx context.Context, cmd *cli.Command) error { // First set up the swap client itself. - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.ListInstantOuts( - context.Background(), &looprpc.ListInstantOutsRequest{}, + ctx, &looprpc.ListInstantOutsRequest{}, ) if err != nil { return err diff --git a/cmd/loop/l402.go b/cmd/loop/l402.go index 5e1669a8..106011cf 100644 --- a/cmd/loop/l402.go +++ b/cmd/loop/l402.go @@ -7,7 +7,7 @@ import ( "time" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "gopkg.in/macaroon.v2" ) @@ -24,22 +24,22 @@ type printableToken struct { FileName string `json:"file_name"` } -var listAuthCommand = cli.Command{ +var listAuthCommand = &cli.Command{ Name: "listauth", Usage: "list all L402 tokens", Description: "Shows a list of all L402 tokens that loopd has paid for", Action: listAuth, } -func listAuth(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func listAuth(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.GetL402Tokens( - context.Background(), &looprpc.TokensRequest{}, + ctx, &looprpc.TokensRequest{}, ) if err != nil { return err @@ -74,7 +74,7 @@ func listAuth(ctx *cli.Context) error { return nil } -var fetchL402Command = cli.Command{ +var fetchL402Command = &cli.Command{ Name: "fetchl402", Usage: "fetches a new L402 authentication token from the server", Description: "Fetches a new L402 authentication token from the server. " + @@ -84,15 +84,15 @@ var fetchL402Command = cli.Command{ Action: fetchL402, } -func fetchL402(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func fetchL402(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() res, err := client.FetchL402Token( - context.Background(), &looprpc.FetchL402TokenRequest{}, + ctx, &looprpc.FetchL402TokenRequest{}, ) if err != nil { return err diff --git a/cmd/loop/liquidity.go b/cmd/loop/liquidity.go index 3d58060e..88ae1f88 100644 --- a/cmd/loop/liquidity.go +++ b/cmd/loop/liquidity.go @@ -10,12 +10,12 @@ import ( "github.com/lightninglabs/loop/liquidity" "github.com/lightninglabs/loop/looprpc" "github.com/lightningnetwork/lnd/routing/route" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) -var getLiquidityParamsCommand = cli.Command{ +var getLiquidityParamsCommand = &cli.Command{ Name: "getparams", Usage: "show liquidity manager parameters", Description: "Displays the current set of parameters that are set " + @@ -23,15 +23,15 @@ var getLiquidityParamsCommand = cli.Command{ Action: getParams, } -func getParams(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func getParams(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() cfg, err := client.GetLiquidityParams( - context.Background(), &looprpc.GetLiquidityParamsRequest{}, + ctx, &looprpc.GetLiquidityParamsRequest{}, ) if err != nil { return err @@ -42,13 +42,13 @@ func getParams(ctx *cli.Context) error { return nil } -var setLiquidityRuleCommand = cli.Command{ +var setLiquidityRuleCommand = &cli.Command{ Name: "setrule", Usage: "set liquidity manager rule for a channel/peer", Description: "Update or remove the liquidity rule for a channel/peer.", ArgsUsage: "{shortchanid | peerpubkey}", Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "type", Usage: "the type of swap to perform, set to 'out' " + "for acquiring inbound liquidity or 'in' for " + @@ -56,18 +56,18 @@ var setLiquidityRuleCommand = cli.Command{ Value: "out", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "incoming_threshold", Usage: "the minimum percentage of incoming liquidity " + "to total capacity beneath which to " + "recommend loop out to acquire incoming.", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "outgoing_threshold", Usage: "the minimum percentage of outbound liquidity " + "that we do not want to drop below.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "clear", Usage: "remove the rule currently set for the " + "channel/peer.", @@ -76,9 +76,9 @@ var setLiquidityRuleCommand = cli.Command{ Action: setRule, } -func setRule(ctx *cli.Context) error { +func setRule(ctx context.Context, cmd *cli.Command) error { // We require that a channel ID is set for this rule update. - if ctx.NArg() != 1 { + if cmd.NArg() != 1 { return fmt.Errorf("please set a channel id or peer pubkey " + "for the rule update") } @@ -87,9 +87,9 @@ func setRule(ctx *cli.Context) error { pubkey route.Vertex pubkeyRule bool ) - chanID, err := strconv.ParseUint(ctx.Args().First(), 10, 64) + chanID, err := strconv.ParseUint(cmd.Args().First(), 10, 64) if err != nil { - pubkey, err = route.NewVertexFromStr(ctx.Args().First()) + pubkey, err = route.NewVertexFromStr(cmd.Args().First()) if err != nil { return fmt.Errorf("please provide a valid pubkey: "+ "%v, or short channel ID", err) @@ -97,7 +97,7 @@ func setRule(ctx *cli.Context) error { pubkeyRule = true } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } @@ -107,15 +107,15 @@ func setRule(ctx *cli.Context) error { // SetParameters. To allow users to set only individual fields on the // cli, we lookup our current params, then update individual values. params, err := client.GetLiquidityParams( - context.Background(), &looprpc.GetLiquidityParamsRequest{}, + ctx, &looprpc.GetLiquidityParamsRequest{}, ) if err != nil { return err } var ( - inboundSet = ctx.IsSet("incoming_threshold") - outboundSet = ctx.IsSet("outgoing_threshold") + inboundSet = cmd.IsSet("incoming_threshold") + outboundSet = cmd.IsSet("outgoing_threshold") ruleSet bool otherRules []*looprpc.LiquidityRule ) @@ -144,7 +144,7 @@ func setRule(ctx *cli.Context) error { // If we want to clear the rule for this channel, check that we had a // rule set in the first place, and set our parameters to the current // set excluding the channel specified. - if ctx.IsSet("clear") { + if cmd.IsSet("clear") { if !ruleSet { return fmt.Errorf("cannot clear channel: %v, no rule "+ "set at present", chanID) @@ -157,7 +157,7 @@ func setRule(ctx *cli.Context) error { params.Rules = otherRules _, err = client.SetLiquidityParams( - context.Background(), + ctx, &looprpc.SetLiquidityParamsRequest{ Parameters: params, }, @@ -177,8 +177,8 @@ func setRule(ctx *cli.Context) error { ChannelId: chanID, Type: looprpc.LiquidityRuleType_THRESHOLD, } - if ctx.IsSet("type") { - switch ctx.String("type") { + if cmd.IsSet("type") { + switch cmd.String("type") { case "in": newRule.SwapType = looprpc.SwapType_LOOP_IN @@ -196,13 +196,13 @@ func setRule(ctx *cli.Context) error { if inboundSet { newRule.IncomingThreshold = uint32( - ctx.Int("incoming_threshold"), + cmd.Int("incoming_threshold"), ) } if outboundSet { newRule.OutgoingThreshold = uint32( - ctx.Int("outgoing_threshold"), + cmd.Int("outgoing_threshold"), ) } @@ -213,7 +213,7 @@ func setRule(ctx *cli.Context) error { // Update our parameters to the existing set, plus our new rule. _, err = client.SetLiquidityParams( - context.Background(), + ctx, &looprpc.SetLiquidityParamsRequest{ Parameters: params, }, @@ -222,7 +222,7 @@ func setRule(ctx *cli.Context) error { return err } -var setParamsCommand = cli.Command{ +var setParamsCommand = &cli.Command{ Name: "setparams", Usage: "update the parameters set for the liquidity manager", Description: "Updates the parameters set for the liquidity manager. " + @@ -230,69 +230,69 @@ var setParamsCommand = cli.Command{ "of setting them again upon loopd restart. To get the default" + "values, use `getparams` before any `setparams`.", Flags: []cli.Flag{ - cli.IntFlag{ + &cli.IntFlag{ Name: "sweeplimit", Usage: "the limit placed on our estimated sweep fee " + "in sat/vByte.", }, - cli.Float64Flag{ + &cli.Float64Flag{ Name: "feepercent", Usage: "the maximum percentage of swap amount to be " + "used across all fee categories", }, - cli.Float64Flag{ + &cli.Float64Flag{ Name: "maxswapfee", Usage: "the maximum percentage of swap volume we are " + "willing to pay in server fees.", }, - cli.Float64Flag{ + &cli.Float64Flag{ Name: "maxroutingfee", Usage: "the maximum percentage of off-chain payment " + "volume that we are willing to pay in routing" + "fees.", }, - cli.Float64Flag{ + &cli.Float64Flag{ Name: "maxprepayfee", Usage: "the maximum percentage of off-chain prepay " + "volume that we are willing to pay in " + "routing fees.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "maxprepay", Usage: "the maximum no-show (prepay) in satoshis that " + "swap suggestions should be limited to.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "maxminer", Usage: "the maximum miner fee in satoshis that swap " + "suggestions should be limited to.", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "sweepconf", Usage: "the number of blocks from htlc height that " + "swap suggestion sweeps should target, used " + "to estimate max miner fee.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "failurebackoff", Usage: "the amount of time, in seconds, that " + "should pass before a channel that " + "previously had a failed swap will be " + "included in suggestions.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "autoloop", Usage: "set to true to enable automated dispatch " + "of swaps, limited to the budget set by " + "autobudget.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "destaddr", Usage: "custom address to be used as destination for " + "autoloop loop out, set to \"default\" in " + "order to revert to default behavior.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "account", Usage: "the name of the account to generate a new " + "address from. You can list the names of " + @@ -300,74 +300,74 @@ var setParamsCommand = cli.Command{ "instance with \"lncli wallet accounts list\".", Value: "", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "account_addr_type", Usage: "the address type of the extended public key " + "specified in account. Currently only " + "pay-to-taproot-pubkey(p2tr) is supported", Value: "p2tr", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "autobudget", Usage: "the maximum amount of fees in satoshis that " + "automatically dispatched loop out swaps may " + "spend.", }, - cli.DurationFlag{ + &cli.DurationFlag{ Name: "autobudgetrefreshperiod", Usage: "the time period over which the automated " + "loop budget is refreshed.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "autoinflight", Usage: "the maximum number of automatically " + "dispatched swaps that we allow to be in " + "flight.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "minamt", Usage: "the minimum amount in satoshis that the " + "autoloop client will dispatch per-swap.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "maxamt", Usage: "the maximum amount in satoshis that the " + "autoloop client will dispatch per-swap.", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "htlc_conf", Usage: "the confirmation target for loop in on-chain " + "htlcs.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "easyautoloop", Usage: "set to true to enable easy autoloop, which " + "will automatically dispatch swaps in order " + "to meet the target local balance.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "localbalancesat", Usage: "the target size of total local balance in " + "satoshis, used by easy autoloop.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "asset_easyautoloop", Usage: "set to true to enable asset easy autoloop, which " + "will automatically dispatch asset swaps in order " + "to meet the target local balance.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "asset_id", Usage: "If set to a valid asset ID, the easyautoloop " + "and localbalancesat flags will be set for the " + "specified asset.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "asset_localbalance", Usage: "the target size of total local balance in " + "asset units, used by asset easy autoloop.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "fast", Usage: "if set new swaps are expected to be " + "published immediately, paying a potentially " + @@ -381,8 +381,8 @@ var setParamsCommand = cli.Command{ Action: setParams, } -func setParams(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func setParams(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } @@ -392,7 +392,7 @@ func setParams(ctx *cli.Context) error { // SetParameters. To allow users to set only individual fields on the // cli, we lookup our current params, then update individual values. params, err := client.GetLiquidityParams( - context.Background(), &looprpc.GetLiquidityParamsRequest{}, + ctx, &looprpc.GetLiquidityParamsRequest{}, ) if err != nil { return err @@ -403,8 +403,8 @@ func setParams(ctx *cli.Context) error { // Update our existing parameters with the values provided by cli flags. // Our fee categories and fee percentage are exclusive, so track which // flags are set to ensure that we don't have nonsensical overlap. - if ctx.IsSet("maxswapfee") { - feeRate := ctx.Float64("maxswapfee") + if cmd.IsSet("maxswapfee") { + feeRate := cmd.Float64("maxswapfee") params.MaxSwapFeePpm, err = ppmFromPercentage(feeRate) if err != nil { return err @@ -414,16 +414,16 @@ func setParams(ctx *cli.Context) error { categoriesSet = true } - if ctx.IsSet("sweeplimit") { - satPerVByte := ctx.Int("sweeplimit") + if cmd.IsSet("sweeplimit") { + satPerVByte := cmd.Int("sweeplimit") params.SweepFeeRateSatPerVbyte = uint64(satPerVByte) flagSet = true categoriesSet = true } - if ctx.IsSet("feepercent") { - feeRate := ctx.Float64("feepercent") + if cmd.IsSet("feepercent") { + feeRate := cmd.Float64("feepercent") params.FeePpm, err = ppmFromPercentage(feeRate) if err != nil { return err @@ -433,8 +433,8 @@ func setParams(ctx *cli.Context) error { feePercentSet = true } - if ctx.IsSet("maxroutingfee") { - feeRate := ctx.Float64("maxroutingfee") + if cmd.IsSet("maxroutingfee") { + feeRate := cmd.Float64("maxroutingfee") params.MaxRoutingFeePpm, err = ppmFromPercentage(feeRate) if err != nil { return err @@ -444,8 +444,8 @@ func setParams(ctx *cli.Context) error { categoriesSet = true } - if ctx.IsSet("maxprepayfee") { - feeRate := ctx.Float64("maxprepayfee") + if cmd.IsSet("maxprepayfee") { + feeRate := cmd.Float64("maxprepayfee") params.MaxPrepayRoutingFeePpm, err = ppmFromPercentage(feeRate) if err != nil { return err @@ -455,59 +455,59 @@ func setParams(ctx *cli.Context) error { categoriesSet = true } - if ctx.IsSet("maxprepay") { - params.MaxPrepaySat = ctx.Uint64("maxprepay") + if cmd.IsSet("maxprepay") { + params.MaxPrepaySat = cmd.Uint64("maxprepay") flagSet = true categoriesSet = true } - if ctx.IsSet("maxminer") { - params.MaxMinerFeeSat = ctx.Uint64("maxminer") + if cmd.IsSet("maxminer") { + params.MaxMinerFeeSat = cmd.Uint64("maxminer") flagSet = true categoriesSet = true } - if ctx.IsSet("sweepconf") { - params.SweepConfTarget = int32(ctx.Int("sweepconf")) + if cmd.IsSet("sweepconf") { + params.SweepConfTarget = int32(cmd.Int("sweepconf")) flagSet = true } - if ctx.IsSet("failurebackoff") { - params.FailureBackoffSec = ctx.Uint64("failurebackoff") + if cmd.IsSet("failurebackoff") { + params.FailureBackoffSec = cmd.Uint64("failurebackoff") flagSet = true } - if ctx.IsSet("autoloop") { - params.Autoloop = ctx.Bool("autoloop") + if cmd.IsSet("autoloop") { + params.Autoloop = cmd.Bool("autoloop") flagSet = true } - if ctx.IsSet("autobudget") { - params.AutoloopBudgetSat = ctx.Uint64("autobudget") + if cmd.IsSet("autobudget") { + params.AutoloopBudgetSat = cmd.Uint64("autobudget") flagSet = true } switch { - case ctx.IsSet("destaddr") && ctx.IsSet("account"): + case cmd.IsSet("destaddr") && cmd.IsSet("account"): return fmt.Errorf("cannot set destaddr and account at the " + "same time") - case ctx.IsSet("destaddr"): - params.AutoloopDestAddress = ctx.String("destaddr") + case cmd.IsSet("destaddr"): + params.AutoloopDestAddress = cmd.String("destaddr") params.Account = "" flagSet = true - case ctx.IsSet("account") != ctx.IsSet("account_addr_type"): + case cmd.IsSet("account") != cmd.IsSet("account_addr_type"): return liquidity.ErrAccountAndAddrType - case ctx.IsSet("account"): - params.Account = ctx.String("account") + case cmd.IsSet("account"): + params.Account = cmd.String("account") params.AutoloopDestAddress = "" flagSet = true } - if ctx.IsSet("account_addr_type") { - switch ctx.String("account_addr_type") { + if cmd.IsSet("account_addr_type") { + switch cmd.String("account_addr_type") { case "p2tr": params.AccountAddrType = looprpc.AddressType_TAPROOT_PUBKEY @@ -516,78 +516,78 @@ func setParams(ctx *cli.Context) error { } } - if ctx.IsSet("autobudgetrefreshperiod") { + if cmd.IsSet("autobudgetrefreshperiod") { params.AutoloopBudgetRefreshPeriodSec = - uint64(ctx.Duration("autobudgetrefreshperiod").Seconds()) + uint64(cmd.Duration("autobudgetrefreshperiod").Seconds()) flagSet = true } - if ctx.IsSet("autoinflight") { - params.AutoMaxInFlight = ctx.Uint64("autoinflight") + if cmd.IsSet("autoinflight") { + params.AutoMaxInFlight = cmd.Uint64("autoinflight") flagSet = true } - if ctx.IsSet("minamt") { - params.MinSwapAmount = ctx.Uint64("minamt") + if cmd.IsSet("minamt") { + params.MinSwapAmount = cmd.Uint64("minamt") flagSet = true } - if ctx.IsSet("maxamt") { - params.MaxSwapAmount = ctx.Uint64("maxamt") + if cmd.IsSet("maxamt") { + params.MaxSwapAmount = cmd.Uint64("maxamt") flagSet = true } - if ctx.IsSet("htlc_conf") { - params.HtlcConfTarget = int32(ctx.Int("htlc_conf")) + if cmd.IsSet("htlc_conf") { + params.HtlcConfTarget = int32(cmd.Int("htlc_conf")) flagSet = true } // If we are setting easy autoloop parameters, we need to ensure that // the asset ID is set, and that we have a valid entry in our params // map. - if ctx.IsSet("asset_id") { + if cmd.IsSet("asset_id") { if params.EasyAssetParams == nil { params.EasyAssetParams = make( map[string]*looprpc.EasyAssetAutoloopParams, ) } - if _, ok := params.EasyAssetParams[ctx.String("asset_id")]; !ok { //nolint:lll - params.EasyAssetParams[ctx.String("asset_id")] = + if _, ok := params.EasyAssetParams[cmd.String("asset_id")]; !ok { //nolint:lll + params.EasyAssetParams[cmd.String("asset_id")] = &looprpc.EasyAssetAutoloopParams{} } } - if ctx.IsSet("easyautoloop") { - params.EasyAutoloop = ctx.Bool("easyautoloop") + if cmd.IsSet("easyautoloop") { + params.EasyAutoloop = cmd.Bool("easyautoloop") flagSet = true } - if ctx.IsSet("localbalancesat") { - params.EasyAutoloopLocalTargetSat = ctx.Uint64("localbalancesat") + if cmd.IsSet("localbalancesat") { + params.EasyAutoloopLocalTargetSat = cmd.Uint64("localbalancesat") flagSet = true } - if ctx.IsSet("asset_easyautoloop") { - if !ctx.IsSet("asset_id") { + if cmd.IsSet("asset_easyautoloop") { + if !cmd.IsSet("asset_id") { return fmt.Errorf("asset_id must be set to use " + "asset_easyautoloop") } - params.EasyAssetParams[ctx.String("asset_id")]. - Enabled = ctx.Bool("asset_easyautoloop") + params.EasyAssetParams[cmd.String("asset_id")]. + Enabled = cmd.Bool("asset_easyautoloop") flagSet = true } - if ctx.IsSet("asset_localbalance") { - if !ctx.IsSet("asset_id") { + if cmd.IsSet("asset_localbalance") { + if !cmd.IsSet("asset_id") { return fmt.Errorf("asset_id must be set to use " + "asset_localbalance") } - params.EasyAssetParams[ctx.String("asset_id")]. - LocalTargetAssetAmt = ctx.Uint64("asset_localbalance") + params.EasyAssetParams[cmd.String("asset_id")]. + LocalTargetAssetAmt = cmd.Uint64("asset_localbalance") flagSet = true } - if ctx.IsSet("fast") { + if cmd.IsSet("fast") { params.FastSwapPublication = true } @@ -619,7 +619,7 @@ func setParams(ctx *cli.Context) error { } // Update our parameters to our mutated values. _, err = client.SetLiquidityParams( - context.Background(), &looprpc.SetLiquidityParamsRequest{ + ctx, &looprpc.SetLiquidityParamsRequest{ Parameters: params, }, ) @@ -637,7 +637,7 @@ func ppmFromPercentage(percentage float64) (uint64, error) { return uint64(percentage / 100 * liquidity.FeeBase), nil } -var suggestSwapCommand = cli.Command{ +var suggestSwapCommand = &cli.Command{ Name: "suggestswaps", Usage: "show a list of suggested swaps", Description: "Displays a list of suggested swaps that aim to obtain " + @@ -646,15 +646,15 @@ var suggestSwapCommand = cli.Command{ Action: suggestSwap, } -func suggestSwap(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func suggestSwap(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.SuggestSwaps( - context.Background(), &looprpc.SuggestSwapsRequest{}, + ctx, &looprpc.SuggestSwapsRequest{}, ) if err == nil { printRespJSON(resp) diff --git a/cmd/loop/loopin.go b/cmd/loop/loopin.go index 1a732484..177cd0aa 100644 --- a/cmd/loop/loopin.go +++ b/cmd/loop/loopin.go @@ -9,47 +9,47 @@ import ( "github.com/lightninglabs/loop/labels" "github.com/lightninglabs/loop/looprpc" "github.com/lightningnetwork/lnd/routing/route" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) var ( - lastHopFlag = cli.StringFlag{ + lastHopFlag = &cli.StringFlag{ Name: "last_hop", Usage: "the pubkey of the last hop to use for this swap", } - confTargetFlag = cli.Uint64Flag{ + confTargetFlag = &cli.Uint64Flag{ Name: "conf_target", Usage: "the target number of blocks the on-chain htlc " + "broadcast by the swap client should confirm within", } - labelFlag = cli.StringFlag{ + labelFlag = &cli.StringFlag{ Name: "label", Usage: fmt.Sprintf("an optional label for this swap,"+ "limited to %v characters. The label may not start "+ "with our reserved prefix: %v.", labels.MaxLength, labels.Reserved), } - routeHintsFlag = cli.StringSliceFlag{ + routeHintsFlag = &cli.StringSliceFlag{ Name: "route_hints", Usage: "route hints that can each be individually used " + "to assist in reaching the invoice's destination", } - privateFlag = cli.BoolFlag{ + privateFlag = &cli.BoolFlag{ Name: "private", Usage: "generates and passes routehints. Should be used if " + "the connected node is only reachable via private " + "channels", } - forceFlag = cli.BoolFlag{ + forceFlag = &cli.BoolFlag{ Name: "force, f", Usage: "Assumes yes during confirmation. Using this option " + "will result in an immediate swap", } - loopInCommand = cli.Command{ + loopInCommand = &cli.Command{ Name: "in", Usage: "perform an on-chain to off-chain swap (loop in)", ArgsUsage: "amt", @@ -66,14 +66,14 @@ var ( conf_target flag. `, Flags: []cli.Flag{ - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "amt", Usage: "the amount in satoshis to loop in. " + "To check for the minimum and " + "maximum amounts to loop " + "in please consult \"loop terms\"", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "external", Usage: "expect htlc to be published externally", }, @@ -89,18 +89,18 @@ var ( } ) -func loopIn(ctx *cli.Context) error { - args := ctx.Args() +func loopIn(ctx context.Context, cmd *cli.Command) error { + args := cmd.Args() var amtStr string switch { - case ctx.IsSet("amt"): - amtStr = strconv.FormatUint(ctx.Uint64("amt"), 10) - case ctx.NArg() == 1: - amtStr = args[0] + case cmd.IsSet("amt"): + amtStr = strconv.FormatUint(cmd.Uint64("amt"), 10) + case cmd.NArg() == 1: + amtStr = args.First() default: // Show command help if no arguments and flags were provided. - return cli.ShowCommandHelp(ctx, "in") + return showCommandHelp(ctx, cmd) } amt, err := parseAmt(amtStr) @@ -108,14 +108,14 @@ func loopIn(ctx *cli.Context) error { return err } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() - external := ctx.Bool("external") - htlcConfTarget := int32(ctx.Uint64(confTargetFlag.Name)) + external := cmd.Bool("external") + htlcConfTarget := int32(cmd.Uint64(confTargetFlag.Name)) // External and confirmation target are mutually exclusive; either the // on chain htlc is being externally broadcast, or we are creating the @@ -126,15 +126,15 @@ func loopIn(ctx *cli.Context) error { } // Validate our label early so that we can fail before getting a quote. - label := ctx.String(labelFlag.Name) + label := cmd.String(labelFlag.Name) if err := labels.Validate(label); err != nil { return err } var lastHop []byte - if ctx.IsSet(lastHopFlag.Name) { + if cmd.IsSet(lastHopFlag.Name) { lastHopVertex, err := route.NewVertexFromStr( - ctx.String(lastHopFlag.Name), + cmd.String(lastHopFlag.Name), ) if err != nil { return err @@ -145,7 +145,7 @@ func loopIn(ctx *cli.Context) error { // Private and routehints are mutually exclusive as setting private // means we retrieve our own routehints from the connected node. - hints, err := validateRouteHints(ctx) + hints, err := validateRouteHints(cmd) if err != nil { return err } @@ -156,10 +156,10 @@ func loopIn(ctx *cli.Context) error { ExternalHtlc: external, LoopInLastHop: lastHop, LoopInRouteHints: hints, - Private: ctx.Bool(privateFlag.Name), + Private: cmd.Bool(privateFlag.Name), } - quote, err := client.GetLoopInQuote(context.Background(), quoteReq) + quote, err := client.GetLoopInQuote(ctx, quoteReq) if err != nil { return err } @@ -181,8 +181,8 @@ func loopIn(ctx *cli.Context) error { limits := getInLimits(quote) // Skip showing details if configured - if !(ctx.Bool("force") || ctx.Bool("f")) { - err = displayInDetails(quoteReq, quote, ctx.Bool("verbose")) + if !(cmd.Bool("force") || cmd.Bool("f")) { + err = displayInDetails(quoteReq, quote, cmd.Bool("verbose")) if err != nil { return err } @@ -198,10 +198,10 @@ func loopIn(ctx *cli.Context) error { Initiator: defaultInitiator, LastHop: lastHop, RouteHints: hints, - Private: ctx.Bool(privateFlag.Name), + Private: cmd.Bool(privateFlag.Name), } - resp, err := client.LoopIn(context.Background(), req) + resp, err := client.LoopIn(ctx, req) if err != nil { return err } diff --git a/cmd/loop/loopout.go b/cmd/loop/loopout.go index f70579be..37dedd2e 100644 --- a/cmd/loop/loopout.go +++ b/cmd/loop/loopout.go @@ -14,17 +14,17 @@ import ( "github.com/lightninglabs/loop/labels" "github.com/lightninglabs/loop/loopdb" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) var ( - channelFlag = cli.StringFlag{ + channelFlag = &cli.StringFlag{ Name: "channel", Usage: "the comma-separated list of short " + "channel IDs of the channels to loop out", } ) -var loopOutCommand = cli.Command{ +var loopOutCommand = &cli.Command{ Name: "out", Usage: "perform an off-chain to on-chain swap (looping out)", ArgsUsage: "amt [addr]", @@ -37,13 +37,13 @@ var loopOutCommand = cli.Command{ Optionally a BASE58/bech32 encoded bitcoin destination address may be specified. If not specified, a new wallet address will be generated.`, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "addr", Usage: "the optional address that the looped out funds " + "should be sent to, if let blank the funds " + "will go to lnd's wallet", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "account", Usage: "the name of the account to generate a new " + "address from. You can list the names of " + @@ -51,40 +51,40 @@ var loopOutCommand = cli.Command{ "instance with \"lncli wallet accounts list\"", Value: "", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "account_addr_type", Usage: "the address type of the extended public key " + "specified in account. Currently only " + "pay-to-taproot-pubkey(p2tr) is supported", Value: "p2tr", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "amt", Usage: "the amount in satoshis to loop out. To check " + "for the minimum and maximum amounts to loop " + "out please consult \"loop terms\"", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "htlc_confs", Usage: "the number of confirmations (in blocks) " + "that we require for the htlc extended by " + "the server before we reveal the preimage", Value: uint64(loopdb.DefaultLoopOutHtlcConfirmations), }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "conf_target", Usage: "the number of blocks from the swap " + "initiation height that the on-chain HTLC " + "should be swept within", Value: uint64(loop.DefaultSweepConfTarget), }, - cli.Int64Flag{ + &cli.Int64Flag{ Name: "max_swap_routing_fee", Usage: "the max off-chain swap routing fee in " + "satoshis, if not specified, a default max " + "fee will be used", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "fast", Usage: "indicate you want to swap immediately, " + "paying potentially a higher fee. If not " + @@ -94,7 +94,7 @@ var loopOutCommand = cli.Command{ "Not setting this flag therefore might " + "result in a lower swap fee", }, - cli.DurationFlag{ + &cli.DurationFlag{ Name: "payment_timeout", Usage: "the timeout for each individual off-chain " + "payment attempt. If not set, the default " + @@ -102,14 +102,14 @@ var loopOutCommand = cli.Command{ "payment might be retried, the actual total " + "time may be longer", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "asset_id", Usage: "the asset ID of the asset to loop out, " + "if this is set, the loop daemon will " + "require a connection to a taproot assets " + "daemon", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "asset_edge_node", Usage: "the pubkey of the edge node of the asset to " + "loop out, this is required if the taproot " + @@ -124,19 +124,22 @@ var loopOutCommand = cli.Command{ Action: loopOut, } -func loopOut(ctx *cli.Context) error { - args := ctx.Args() +func loopOut(ctx context.Context, cmd *cli.Command) error { + args := cmd.Args() - var amtStr string + var ( + amtStr string + remaining []string + ) switch { - case ctx.IsSet("amt"): - amtStr = strconv.FormatUint(ctx.Uint64("amt"), 10) - case ctx.NArg() == 1 || ctx.NArg() == 2: - amtStr = args[0] - args = args.Tail() + case cmd.IsSet("amt"): + amtStr = strconv.FormatUint(cmd.Uint64("amt"), 10) + case cmd.NArg() == 1 || cmd.NArg() == 2: + amtStr = args.First() + remaining = args.Tail() default: // Show command help if no arguments and flags were provided. - return cli.ShowCommandHelp(ctx, "out") + return showCommandHelp(ctx, cmd) } amt, err := parseAmt(amtStr) @@ -148,12 +151,12 @@ func loopOut(ctx *cli.Context) error { // Otherwise, strings.Split returns a slice of length one with an empty // element. var outgoingChanSet []uint64 - if ctx.IsSet("channel") { - if ctx.IsSet("asset_id") { + if cmd.IsSet("channel") { + if cmd.IsSet("asset_id") { return fmt.Errorf("channel flag is not supported when " + "looping out assets") } - chanStrings := strings.Split(ctx.String("channel"), ",") + chanStrings := strings.Split(cmd.String("channel"), ",") for _, chanString := range chanStrings { chanID, err := strconv.ParseUint(chanString, 10, 64) if err != nil { @@ -165,12 +168,12 @@ func loopOut(ctx *cli.Context) error { } // Validate our label early so that we can fail before getting a quote. - label := ctx.String(labelFlag.Name) + label := cmd.String(labelFlag.Name) if err := labels.Validate(label); err != nil { return err } - if ctx.IsSet("addr") && ctx.IsSet("account") { + if cmd.IsSet("addr") && cmd.IsSet("account") { return fmt.Errorf("cannot set --addr and --account at the " + "same time. Please specify only one source for a new " + "address to sweep the loop amount to") @@ -181,24 +184,24 @@ func loopOut(ctx *cli.Context) error { account string ) switch { - case ctx.IsSet("addr"): - destAddr = ctx.String("addr") + case cmd.IsSet("addr"): + destAddr = cmd.String("addr") - case ctx.IsSet("account"): - account = ctx.String("account") + case cmd.IsSet("account"): + account = cmd.String("account") - case args.Present(): - destAddr = args.First() + case len(remaining) > 0: + destAddr = remaining[0] } - if ctx.IsSet("account") != ctx.IsSet("account_addr_type") { + if cmd.IsSet("account") != cmd.IsSet("account_addr_type") { return fmt.Errorf("cannot set account without specifying " + "account address type and vice versa") } var accountAddrType looprpc.AddressType - if ctx.IsSet("account_addr_type") { - switch ctx.String("account_addr_type") { + if cmd.IsSet("account_addr_type") { + switch cmd.String("account_addr_type") { case "p2tr": accountAddrType = looprpc.AddressType_TAPROOT_PUBKEY @@ -210,19 +213,19 @@ func loopOut(ctx *cli.Context) error { var assetLoopOutInfo *looprpc.AssetLoopOutRequest var assetId []byte - if ctx.IsSet("asset_id") { - if !ctx.IsSet("asset_edge_node") { + if cmd.IsSet("asset_id") { + if !cmd.IsSet("asset_edge_node") { return fmt.Errorf("asset edge node is required when " + "assetid is set") } - assetId, err = hex.DecodeString(ctx.String("asset_id")) + assetId, err = hex.DecodeString(cmd.String("asset_id")) if err != nil { return err } assetEdgeNode, err := hex.DecodeString( - ctx.String("asset_edge_node"), + cmd.String("asset_edge_node"), ) if err != nil { return err @@ -234,7 +237,7 @@ func loopOut(ctx *cli.Context) error { } } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } @@ -242,14 +245,14 @@ func loopOut(ctx *cli.Context) error { // Set our maximum swap wait time. If a fast swap is requested we set // it to now, otherwise to 30 minutes in the future. - fast := ctx.Bool("fast") + fast := cmd.Bool("fast") swapDeadline := time.Now() if !fast { swapDeadline = time.Now().Add(defaultSwapWaitTime) } - sweepConfTarget := int32(ctx.Uint64("conf_target")) - htlcConfs := int32(ctx.Uint64("htlc_confs")) + sweepConfTarget := int32(cmd.Uint64("conf_target")) + htlcConfs := int32(cmd.Uint64("htlc_confs")) if htlcConfs == 0 { return fmt.Errorf("at least 1 confirmation required for htlcs") } @@ -260,7 +263,7 @@ func loopOut(ctx *cli.Context) error { SwapPublicationDeadline: uint64(swapDeadline.Unix()), AssetInfo: assetLoopOutInfo, } - quote, err := client.LoopOutQuote(context.Background(), quoteReq) + quote, err := client.LoopOutQuote(ctx, quoteReq) if err != nil { return err } @@ -277,16 +280,16 @@ func loopOut(ctx *cli.Context) error { limits := getOutLimits(amt, quote) // If configured, use the specified maximum swap routing fee. - if ctx.IsSet("max_swap_routing_fee") { + if cmd.IsSet("max_swap_routing_fee") { limits.maxSwapRoutingFee = btcutil.Amount( - ctx.Int64("max_swap_routing_fee"), + cmd.Int64("max_swap_routing_fee"), ) } // Skip showing details if configured - if !(ctx.Bool("force") || ctx.Bool("f")) { + if !(cmd.Bool("force") || cmd.Bool("f")) { err = displayOutDetails( - limits, warning, quoteReq, quote, ctx.Bool("verbose"), + limits, warning, quoteReq, quote, cmd.Bool("verbose"), ) if err != nil { return err @@ -294,8 +297,8 @@ func loopOut(ctx *cli.Context) error { } var paymentTimeout int64 - if ctx.IsSet("payment_timeout") { - parsedTimeout := ctx.Duration("payment_timeout") + if cmd.IsSet("payment_timeout") { + parsedTimeout := cmd.Duration("payment_timeout") if parsedTimeout.Truncate(time.Second) != parsedTimeout { return fmt.Errorf("payment timeout must be a " + "whole number of seconds") @@ -312,7 +315,7 @@ func loopOut(ctx *cli.Context) error { } } - resp, err := client.LoopOut(context.Background(), &looprpc.LoopOutRequest{ + resp, err := client.LoopOut(ctx, &looprpc.LoopOutRequest{ Amt: int64(amt), Dest: destAddr, IsExternalAddr: destAddr != "", diff --git a/cmd/loop/main.go b/cmd/loop/main.go index bc19727e..cf71c882 100644 --- a/cmd/loop/main.go +++ b/cmd/loop/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -21,7 +22,7 @@ import ( "github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/macaroons" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/protobuf/proto" @@ -50,38 +51,39 @@ var ( // user agent string we send when using the command line utility. defaultInitiator = "loop-cli" - loopDirFlag = cli.StringFlag{ - Name: "loopdir", - Value: loopd.LoopDirBase, - Usage: "path to loop's base directory", - EnvVar: envVarLoopDir, + loopDirFlag = &cli.StringFlag{ + Name: "loopdir", + Value: loopd.LoopDirBase, + Usage: "path to loop's base directory", + Sources: cli.EnvVars(envVarLoopDir), } - networkFlag = cli.StringFlag{ - Name: "network, n", - Usage: "the network loop is running on e.g. mainnet, " + - "testnet, etc.", - Value: loopd.DefaultNetwork, - EnvVar: envVarNetwork, + networkFlag = &cli.StringFlag{ + Name: "network", + Aliases: []string{"n"}, + Usage: "the network loop is running on e.g. mainnet, testnet, etc.", + Value: loopd.DefaultNetwork, + Sources: cli.EnvVars(envVarNetwork), } - tlsCertFlag = cli.StringFlag{ - Name: "tlscertpath", - Usage: "path to loop's TLS certificate", - Value: loopd.DefaultTLSCertPath, - EnvVar: envVarTLSCertPath, + tlsCertFlag = &cli.StringFlag{ + Name: "tlscertpath", + Usage: "path to loop's TLS certificate", + Value: loopd.DefaultTLSCertPath, + Sources: cli.EnvVars(envVarTLSCertPath), } - macaroonPathFlag = cli.StringFlag{ - Name: "macaroonpath", - Usage: "path to macaroon file", - Value: loopd.DefaultMacaroonPath, - EnvVar: envVarMacaroonPath, + macaroonPathFlag = &cli.StringFlag{ + Name: "macaroonpath", + Usage: "path to macaroon file", + Value: loopd.DefaultMacaroonPath, + Sources: cli.EnvVars(envVarMacaroonPath), } - verboseFlag = cli.BoolFlag{ - Name: "verbose, v", - Usage: "show expanded details", + verboseFlag = &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"v"}, + Usage: "show expanded details", } - commands = []cli.Command{ + commands = []*cli.Command{ loopOutCommand, loopInCommand, termsCommand, monitorCommand, quoteCommand, listAuthCommand, fetchL402Command, listSwapsCommand, swapInfoCommand, getLiquidityParamsCommand, @@ -160,38 +162,40 @@ func fatal(err error) { } func main() { - app := cli.NewApp() - - app.Version = loop.RichVersion() - app.Name = "loop" - app.Usage = "control plane for your loopd" - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "rpcserver", - Value: "localhost:11010", - Usage: "loopd daemon address host:port", - EnvVar: envVarRPCServer, + rootCmd := &cli.Command{ + Name: "loop", + Usage: "control plane for your loopd", + Version: loop.RichVersion(), + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "rpcserver", + Value: "localhost:11010", + Usage: "loopd daemon address host:port", + Sources: cli.EnvVars(envVarRPCServer), + }, + networkFlag, + loopDirFlag, + tlsCertFlag, + macaroonPathFlag, + }, + Commands: commands, + Action: func(ctx context.Context, cmd *cli.Command) error { + return cli.ShowRootCommandHelp(cmd) }, - networkFlag, - loopDirFlag, - tlsCertFlag, - macaroonPathFlag, } - app.Commands = commands - err := app.Run(os.Args) - if err != nil { + if err := rootCmd.Run(context.Background(), os.Args); err != nil { fatal(err) } } -func getClient(ctx *cli.Context) (looprpc.SwapClientClient, func(), error) { - rpcServer := ctx.GlobalString("rpcserver") - tlsCertPath, macaroonPath, err := extractPathArgs(ctx) +func getClient(ctx context.Context, cmd *cli.Command) (looprpc.SwapClientClient, func(), error) { + rpcServer := cmd.String("rpcserver") + tlsCertPath, macaroonPath, err := extractPathArgs(cmd) if err != nil { return nil, nil, err } - conn, err := getClientConn(rpcServer, tlsCertPath, macaroonPath) + conn, err := getClientConn(ctx, rpcServer, tlsCertPath, macaroonPath) if err != nil { return nil, nil, err } @@ -207,11 +211,11 @@ func getMaxRoutingFee(amt btcutil.Amount) btcutil.Amount { // extractPathArgs parses the TLS certificate and macaroon paths from the // command. -func extractPathArgs(ctx *cli.Context) (string, string, error) { +func extractPathArgs(cmd *cli.Command) (string, string, error) { // We'll start off by parsing the network. This is needed to determine // the correct path to the TLS certificate and macaroon when not // specified. - networkStr := strings.ToLower(ctx.GlobalString("network")) + networkStr := strings.ToLower(cmd.String("network")) _, err := lndclient.Network(networkStr).ChainParams() if err != nil { return "", "", err @@ -220,12 +224,12 @@ func extractPathArgs(ctx *cli.Context) (string, string, error) { // We'll now fetch the loopdir so we can make a decision on how to // properly read the macaroons and also the cert. This will either be // the default, or will have been overwritten by the end user. - loopDir := lncfg.CleanAndExpandPath(ctx.GlobalString(loopDirFlag.Name)) + loopDir := lncfg.CleanAndExpandPath(cmd.String(loopDirFlag.Name)) - tlsCertPathRaw := ctx.GlobalString(tlsCertFlag.Name) + tlsCertPathRaw := cmd.String(tlsCertFlag.Name) tlsCertPath := lncfg.CleanAndExpandPath(tlsCertPathRaw) - macPathRaw := ctx.GlobalString(macaroonPathFlag.Name) + macPathRaw := cmd.String(macaroonPathFlag.Name) macPath := lncfg.CleanAndExpandPath(macPathRaw) // If a custom loop directory or network was set, we'll also check if @@ -410,7 +414,7 @@ func logSwap(swap *looprpc.SwapStatus) { fmt.Println() } -func getClientConn(address, tlsCertPath, macaroonPath string) (*grpc.ClientConn, +func getClientConn(ctx context.Context, address, tlsCertPath, macaroonPath string) (*grpc.ClientConn, error) { // We always need to send a macaroon. @@ -432,7 +436,7 @@ func getClientConn(address, tlsCertPath, macaroonPath string) (*grpc.ClientConn, opts = append(opts, grpc.WithTransportCredentials(creds)) - conn, err := grpc.Dial(address, opts...) + conn, err := grpc.DialContext(ctx, address, opts...) if err != nil { return nil, fmt.Errorf("unable to connect to RPC server: %v", err) diff --git a/cmd/loop/monitor.go b/cmd/loop/monitor.go index 7247cf82..28794edb 100644 --- a/cmd/loop/monitor.go +++ b/cmd/loop/monitor.go @@ -5,25 +5,25 @@ import ( "fmt" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var monitorCommand = cli.Command{ +var monitorCommand = &cli.Command{ Name: "monitor", Usage: "monitor progress of any active swaps", Description: "Allows the user to monitor progress of any active swaps", Action: monitor, } -func monitor(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func monitor(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() stream, err := client.Monitor( - context.Background(), &looprpc.MonitorRequest{}) + ctx, &looprpc.MonitorRequest{}) if err != nil { return err } diff --git a/cmd/loop/quote.go b/cmd/loop/quote.go index 22b5a0d8..db23304c 100644 --- a/cmd/loop/quote.go +++ b/cmd/loop/quote.go @@ -14,23 +14,23 @@ import ( "github.com/lightninglabs/taproot-assets/taprpc/rfqrpc" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/routing/route" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var quoteCommand = cli.Command{ - Name: "quote", - Usage: "get a quote for the cost of a swap", - Subcommands: []cli.Command{quoteInCommand, quoteOutCommand}, +var quoteCommand = &cli.Command{ + Name: "quote", + Usage: "get a quote for the cost of a swap", + Commands: []*cli.Command{quoteInCommand, quoteOutCommand}, } -var quoteInCommand = cli.Command{ +var quoteInCommand = &cli.Command{ Name: "in", Usage: "get a quote for the cost of a loop in swap", ArgsUsage: "amt", Description: "Allows to determine the cost of a swap up front." + "Either specify an amount or deposit outpoints.", Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: lastHopFlag.Name, Usage: "the pubkey of the last hop to use for the " + "quote", @@ -39,7 +39,7 @@ var quoteInCommand = cli.Command{ verboseFlag, privateFlag, routeHintsFlag, - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "deposit_outpoint", Usage: "one or more static address deposit outpoints " + "to quote for. Deposit outpoints are not to " + @@ -51,10 +51,10 @@ var quoteInCommand = cli.Command{ Action: quoteIn, } -func quoteIn(ctx *cli.Context) error { +func quoteIn(ctx context.Context, cmd *cli.Command) error { // Show command help if the incorrect number arguments was provided. - if ctx.NArg() != 1 && !ctx.IsSet("deposit_outpoint") { - return cli.ShowCommandHelp(ctx, "in") + if cmd.NArg() != 1 && !cmd.IsSet("deposit_outpoint") { + return showCommandHelp(ctx, cmd) } var ( @@ -62,18 +62,17 @@ func quoteIn(ctx *cli.Context) error { depositAmt btcutil.Amount depositOutpoints []string err error - ctxb = context.Background() ) - if ctx.NArg() == 1 { - args := ctx.Args() - manualAmt, err = parseAmt(args[0]) + if cmd.NArg() == 1 { + args := cmd.Args() + manualAmt, err = parseAmt(args.First()) if err != nil { return err } } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } @@ -81,14 +80,14 @@ func quoteIn(ctx *cli.Context) error { // Private and routehints are mutually exclusive as setting private // means we retrieve our own routehints from the connected node. - hints, err := validateRouteHints(ctx) + hints, err := validateRouteHints(cmd) if err != nil { return err } - if ctx.IsSet("deposit_outpoint") { - depositOutpoints = ctx.StringSlice("deposit_outpoint") - depositAmt, err = depositAmount(ctxb, client, depositOutpoints) + if cmd.IsSet("deposit_outpoint") { + depositOutpoints = cmd.StringSlice("deposit_outpoint") + depositAmt, err = depositAmount(ctx, client, depositOutpoints) if err != nil { return err } @@ -96,15 +95,15 @@ func quoteIn(ctx *cli.Context) error { quoteReq := &looprpc.QuoteRequest{ Amt: int64(manualAmt), - ConfTarget: int32(ctx.Uint64("conf_target")), + ConfTarget: int32(cmd.Uint64("conf_target")), LoopInRouteHints: hints, - Private: ctx.Bool(privateFlag.Name), + Private: cmd.Bool(privateFlag.Name), DepositOutpoints: depositOutpoints, } - if ctx.IsSet(lastHopFlag.Name) { + if cmd.IsSet(lastHopFlag.Name) { lastHopVertex, err := route.NewVertexFromStr( - ctx.String(lastHopFlag.Name), + cmd.String(lastHopFlag.Name), ) if err != nil { return err @@ -113,7 +112,7 @@ func quoteIn(ctx *cli.Context) error { quoteReq.LoopInLastHop = lastHopVertex[:] } - quoteResp, err := client.GetLoopInQuote(ctxb, quoteReq) + quoteResp, err := client.GetLoopInQuote(ctx, quoteReq) if err != nil { return err } @@ -136,7 +135,7 @@ func quoteIn(ctx *cli.Context) error { if manualAmt == 0 { quoteReq.Amt = int64(depositAmt) } - printQuoteInResp(quoteReq, quoteResp, ctx.Bool("verbose")) + printQuoteInResp(quoteReq, quoteResp, cmd.Bool("verbose")) return nil } @@ -160,20 +159,20 @@ func depositAmount(ctx context.Context, client looprpc.SwapClientClient, return depositAmt, nil } -var quoteOutCommand = cli.Command{ +var quoteOutCommand = &cli.Command{ Name: "out", Usage: "get a quote for the cost of a loop out swap", ArgsUsage: "amt", Description: "Allows to determine the cost of a swap up front", Flags: []cli.Flag{ - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "conf_target", Usage: "the number of blocks from the swap " + "initiation height that the on-chain HTLC " + "should be swept within in a Loop Out", Value: uint64(loop.DefaultSweepConfTarget), }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "fast", Usage: "Indicate you want to swap immediately, " + "paying potentially a higher fee. If not " + @@ -188,42 +187,41 @@ var quoteOutCommand = cli.Command{ Action: quoteOut, } -func quoteOut(ctx *cli.Context) error { +func quoteOut(ctx context.Context, cmd *cli.Command) error { // Show command help if the incorrect number arguments was provided. - if ctx.NArg() != 1 { - return cli.ShowCommandHelp(ctx, "out") + if cmd.NArg() != 1 { + return showCommandHelp(ctx, cmd) } - args := ctx.Args() - amt, err := parseAmt(args[0]) + args := cmd.Args() + amt, err := parseAmt(args.First()) if err != nil { return err } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() - fast := ctx.Bool("fast") + fast := cmd.Bool("fast") swapDeadline := time.Now() if !fast { swapDeadline = time.Now().Add(defaultSwapWaitTime) } - ctxb := context.Background() quoteReq := &looprpc.QuoteRequest{ Amt: int64(amt), - ConfTarget: int32(ctx.Uint64("conf_target")), + ConfTarget: int32(cmd.Uint64("conf_target")), SwapPublicationDeadline: uint64(swapDeadline.Unix()), } - quoteResp, err := client.LoopOutQuote(ctxb, quoteReq) + quoteResp, err := client.LoopOutQuote(ctx, quoteReq) if err != nil { return err } - printQuoteOutResp(quoteReq, quoteResp, ctx.Bool("verbose")) + printQuoteOutResp(quoteReq, quoteResp, cmd.Bool("verbose")) return nil } diff --git a/cmd/loop/reservations.go b/cmd/loop/reservations.go index 9f5c123d..4e26fc04 100644 --- a/cmd/loop/reservations.go +++ b/cmd/loop/reservations.go @@ -4,29 +4,29 @@ import ( "context" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var reservationsCommands = cli.Command{ +var reservationsCommands = &cli.Command{ - Name: "reservations", - ShortName: "r", - Usage: "manage reservations", + Name: "reservations", + Aliases: []string{"r"}, + Usage: "manage reservations", Description: ` With loopd running, you can use this command to manage your reservations. Reservations are 2-of-2 multisig utxos that the loop server can open to clients. The reservations are used to enable instant swaps. `, - Subcommands: []cli.Command{ + Commands: []*cli.Command{ listReservationsCommand, }, } var ( - listReservationsCommand = cli.Command{ + listReservationsCommand = &cli.Command{ Name: "list", - ShortName: "l", + Aliases: []string{"l"}, Usage: "list all reservations", ArgsUsage: "", Description: ` @@ -36,15 +36,15 @@ var ( } ) -func listReservations(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func listReservations(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.ListReservations( - context.Background(), &looprpc.ListReservationsRequest{}, + ctx, &looprpc.ListReservationsRequest{}, ) if err != nil { return err diff --git a/cmd/loop/staticaddr.go b/cmd/loop/staticaddr.go index 1423aa26..27e07433 100644 --- a/cmd/loop/staticaddr.go +++ b/cmd/loop/staticaddr.go @@ -15,18 +15,18 @@ import ( "github.com/lightninglabs/loop/staticaddr/loopin" "github.com/lightninglabs/loop/swapserverrpc" "github.com/lightningnetwork/lnd/routing/route" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) func init() { commands = append(commands, staticAddressCommands) } -var staticAddressCommands = cli.Command{ - Name: "static", - ShortName: "s", - Usage: "perform on-chain to off-chain swaps using static addresses.", - Subcommands: []cli.Command{ +var staticAddressCommands = &cli.Command{ + Name: "static", + Aliases: []string{"s"}, + Usage: "perform on-chain to off-chain swaps using static addresses.", + Commands: []*cli.Command{ newStaticAddressCommand, listUnspentCommand, listDepositsCommand, @@ -38,10 +38,10 @@ var staticAddressCommands = cli.Command{ }, } -var newStaticAddressCommand = cli.Command{ - Name: "new", - ShortName: "n", - Usage: "Create a new static loop in address.", +var newStaticAddressCommand = &cli.Command{ + Name: "new", + Aliases: []string{"n"}, + Usage: "Create a new static loop in address.", Description: ` Requests a new static loop in address from the server. Funds that are sent to this address will be locked by a 2:2 multisig between us and the @@ -52,10 +52,9 @@ var newStaticAddressCommand = cli.Command{ Action: newStaticAddress, } -func newStaticAddress(ctx *cli.Context) error { - ctxb := context.Background() - if ctx.NArg() > 0 { - return cli.ShowCommandHelp(ctx, "new") +func newStaticAddress(ctx context.Context, cmd *cli.Command) error { + if cmd.NArg() > 0 { + return showCommandHelp(ctx, cmd) } err := displayNewAddressWarning() @@ -63,14 +62,14 @@ func newStaticAddress(ctx *cli.Context) error { return err } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.NewStaticAddress( - ctxb, &looprpc.NewStaticAddressRequest{}, + ctx, &looprpc.NewStaticAddressRequest{}, ) if err != nil { return err @@ -81,20 +80,20 @@ func newStaticAddress(ctx *cli.Context) error { return nil } -var listUnspentCommand = cli.Command{ - Name: "listunspent", - ShortName: "l", - Usage: "List unspent static address outputs.", +var listUnspentCommand = &cli.Command{ + Name: "listunspent", + Aliases: []string{"l"}, + Usage: "List unspent static address outputs.", Description: ` List all unspent static address outputs. `, Flags: []cli.Flag{ - cli.IntFlag{ + &cli.IntFlag{ Name: "min_confs", Usage: "The minimum amount of confirmations an " + "output should have to be listed.", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "max_confs", Usage: "The maximum number of confirmations an " + "output could have to be listed.", @@ -103,22 +102,21 @@ var listUnspentCommand = cli.Command{ Action: listUnspent, } -func listUnspent(ctx *cli.Context) error { - ctxb := context.Background() - if ctx.NArg() > 0 { - return cli.ShowCommandHelp(ctx, "listunspent") +func listUnspent(ctx context.Context, cmd *cli.Command) error { + if cmd.NArg() > 0 { + return showCommandHelp(ctx, cmd) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.ListUnspentDeposits( - ctxb, &looprpc.ListUnspentDepositsRequest{ - MinConfs: int32(ctx.Int("min_confs")), - MaxConfs: int32(ctx.Int("max_confs")), + ctx, &looprpc.ListUnspentDepositsRequest{ + MinConfs: int32(cmd.Int("min_confs")), + MaxConfs: int32(cmd.Int("max_confs")), }) if err != nil { return err @@ -129,37 +127,37 @@ func listUnspent(ctx *cli.Context) error { return nil } -var withdrawalCommand = cli.Command{ - Name: "withdraw", - ShortName: "w", - Usage: "Withdraw from static address deposits.", +var withdrawalCommand = &cli.Command{ + Name: "withdraw", + Aliases: []string{"w"}, + Usage: "Withdraw from static address deposits.", Description: ` Withdraws from all or selected static address deposits by sweeping them to the internal wallet or an external address. `, Flags: []cli.Flag{ - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "utxo", Usage: "specify utxos as outpoints(tx:idx) which will" + "be withdrawn.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "all", Usage: "withdraws all static address deposits.", }, - cli.StringFlag{ + &cli.StringFlag{ Name: "dest_addr", Usage: "the optional address that the withdrawn " + "funds should be sent to, if let blank the " + "funds will go to lnd's wallet", }, - cli.Int64Flag{ + &cli.Int64Flag{ Name: "sat_per_vbyte", Usage: "(optional) a manual fee expressed in " + "sat/vbyte that should be used when crafting " + "the transaction", }, - cli.IntFlag{ + &cli.IntFlag{ Name: "amount", Usage: "the number of satoshis that should be " + "withdrawn from the selected deposits. The " + @@ -169,22 +167,21 @@ var withdrawalCommand = cli.Command{ Action: withdraw, } -func withdraw(ctx *cli.Context) error { - if ctx.NArg() > 0 { - return cli.ShowCommandHelp(ctx, "withdraw") +func withdraw(ctx context.Context, cmd *cli.Command) error { + if cmd.NArg() > 0 { + return showCommandHelp(ctx, cmd) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() var ( - isAllSelected = ctx.IsSet("all") - isUtxoSelected = ctx.IsSet("utxo") + isAllSelected = cmd.IsSet("all") + isUtxoSelected = cmd.IsSet("utxo") outpoints []*looprpc.OutPoint - ctxb = context.Background() destAddr string ) @@ -194,7 +191,7 @@ func withdraw(ctx *cli.Context) error { case isAllSelected: case isUtxoSelected: - utxos := ctx.StringSlice("utxo") + utxos := cmd.StringSlice("utxo") outpoints, err = utxosToOutpoints(utxos) if err != nil { return err @@ -204,17 +201,17 @@ func withdraw(ctx *cli.Context) error { return fmt.Errorf("unknown withdrawal request") } - if ctx.IsSet("dest_addr") { - destAddr = ctx.String("dest_addr") + if cmd.IsSet("dest_addr") { + destAddr = cmd.String("dest_addr") } - resp, err := client.WithdrawDeposits(ctxb, + resp, err := client.WithdrawDeposits(ctx, &looprpc.WithdrawDepositsRequest{ Outpoints: outpoints, All: isAllSelected, DestAddr: destAddr, - SatPerVbyte: int64(ctx.Uint64("sat_per_vbyte")), - Amount: ctx.Int64("amount"), + SatPerVbyte: int64(cmd.Uint64("sat_per_vbyte")), + Amount: cmd.Int64("amount"), }) if err != nil { return err @@ -225,14 +222,14 @@ func withdraw(ctx *cli.Context) error { return nil } -var listDepositsCommand = cli.Command{ +var listDepositsCommand = &cli.Command{ Name: "listdeposits", Usage: "Displays static address deposits. A filter can be applied to " + "only show deposits in a specific state.", Description: ` `, Flags: []cli.Flag{ - cli.StringFlag{ + &cli.StringFlag{ Name: "filter", Usage: "specify a filter to only display deposits in " + "the specified state. Leaving out the filter " + @@ -248,20 +245,19 @@ var listDepositsCommand = cli.Command{ Action: listDeposits, } -func listDeposits(ctx *cli.Context) error { - ctxb := context.Background() - if ctx.NArg() > 0 { - return cli.ShowCommandHelp(ctx, "listdeposits") +func listDeposits(ctx context.Context, cmd *cli.Command) error { + if cmd.NArg() > 0 { + return showCommandHelp(ctx, cmd) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() var filterState looprpc.DepositState - switch ctx.String("filter") { + switch cmd.String("filter") { case "": // If no filter is specified, we'll default to showing all. @@ -300,7 +296,7 @@ func listDeposits(ctx *cli.Context) error { } resp, err := client.ListStaticAddressDeposits( - ctxb, &looprpc.ListStaticAddressDepositsRequest{ + ctx, &looprpc.ListStaticAddressDepositsRequest{ StateFilter: filterState, }, ) @@ -313,7 +309,7 @@ func listDeposits(ctx *cli.Context) error { return nil } -var listWithdrawalsCommand = cli.Command{ +var listWithdrawalsCommand = &cli.Command{ Name: "listwithdrawals", Usage: "Display a summary of past withdrawals.", Description: ` @@ -321,20 +317,19 @@ var listWithdrawalsCommand = cli.Command{ Action: listWithdrawals, } -func listWithdrawals(ctx *cli.Context) error { - ctxb := context.Background() - if ctx.NArg() > 0 { - return cli.ShowCommandHelp(ctx, "withdrawals") +func listWithdrawals(ctx context.Context, cmd *cli.Command) error { + if cmd.NArg() > 0 { + return showCommandHelp(ctx, cmd) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.ListStaticAddressWithdrawals( - ctxb, &looprpc.ListStaticAddressWithdrawalRequest{}, + ctx, &looprpc.ListStaticAddressWithdrawalRequest{}, ) if err != nil { return err @@ -345,7 +340,7 @@ func listWithdrawals(ctx *cli.Context) error { return nil } -var listStaticAddressSwapsCommand = cli.Command{ +var listStaticAddressSwapsCommand = &cli.Command{ Name: "listswaps", Usage: "Shows a list of finalized static address swaps.", Description: ` @@ -353,20 +348,19 @@ var listStaticAddressSwapsCommand = cli.Command{ Action: listStaticAddressSwaps, } -func listStaticAddressSwaps(ctx *cli.Context) error { - ctxb := context.Background() - if ctx.NArg() > 0 { - return cli.ShowCommandHelp(ctx, "listswaps") +func listStaticAddressSwaps(ctx context.Context, cmd *cli.Command) error { + if cmd.NArg() > 0 { + return showCommandHelp(ctx, cmd) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.ListStaticAddressSwaps( - ctxb, &looprpc.ListStaticAddressSwapsRequest{}, + ctx, &looprpc.ListStaticAddressSwapsRequest{}, ) if err != nil { return err @@ -377,10 +371,10 @@ func listStaticAddressSwaps(ctx *cli.Context) error { return nil } -var summaryCommand = cli.Command{ - Name: "summary", - ShortName: "s", - Usage: "Display a summary of static address related information.", +var summaryCommand = &cli.Command{ + Name: "summary", + Aliases: []string{"s"}, + Usage: "Display a summary of static address related information.", Description: ` Displays various static address related information about deposits, withdrawals and swaps. @@ -388,20 +382,19 @@ var summaryCommand = cli.Command{ Action: summary, } -func summary(ctx *cli.Context) error { - ctxb := context.Background() - if ctx.NArg() > 0 { - return cli.ShowCommandHelp(ctx, "summary") +func summary(ctx context.Context, cmd *cli.Command) error { + if cmd.NArg() > 0 { + return showCommandHelp(ctx, cmd) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.GetStaticAddressSummary( - ctxb, &looprpc.StaticAddressSummaryRequest{}, + ctx, &looprpc.StaticAddressSummaryRequest{}, ) if err != nil { return err @@ -452,9 +445,10 @@ func NewProtoOutPoint(op string) (*looprpc.OutPoint, error) { }, nil } -var staticAddressLoopInCommand = cli.Command{ - Name: "in", - Usage: "Loop in funds from static address deposits.", +var staticAddressLoopInCommand = &cli.Command{ + Name: "in", + Usage: "Loop in funds from static address deposits.", + ArgsUsage: "[amt] [--all | --utxo xxx:xx]", Description: ` Requests a loop-in swap based on static address deposits. After the creation of a static address funds can be sent to it. Once the funds are @@ -462,30 +456,30 @@ var staticAddressLoopInCommand = cli.Command{ funds are not needed they can we withdrawn back to the local lnd wallet. `, Flags: []cli.Flag{ - cli.StringSliceFlag{ + &cli.StringSliceFlag{ Name: "utxo", Usage: "specify the utxos of deposits as " + "outpoints(tx:idx) that should be looped in.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "all", Usage: "loop in all static address deposits.", }, - cli.DurationFlag{ + &cli.DurationFlag{ Name: "payment_timeout", Usage: "the maximum time in seconds that the server " + "is allowed to take for the swap payment. " + "The client can retry the swap with adjusted " + "parameters after the payment timed out.", }, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "amount", Usage: "the number of satoshis that should be " + "swapped from the selected deposits. If there" + "is change it is sent back to the static " + "address.", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "fast", Usage: "Usage: complete the swap faster by paying a " + "higher fee, so the change output is " + @@ -501,40 +495,39 @@ var staticAddressLoopInCommand = cli.Command{ Action: staticAddressLoopIn, } -func staticAddressLoopIn(ctx *cli.Context) error { - if ctx.NumFlags() == 0 && ctx.NArg() == 0 { - return cli.ShowCommandHelp(ctx, "in") +func staticAddressLoopIn(ctx context.Context, cmd *cli.Command) error { + if cmd.NumFlags() == 0 && cmd.NArg() == 0 { + return showCommandHelp(ctx, cmd) } var selectedAmount int64 switch { - case ctx.NArg() == 1: - amt, err := parseAmt(ctx.Args().Get(0)) + case cmd.NArg() == 1: + amt, err := parseAmt(cmd.Args().Get(0)) if err != nil { return err } selectedAmount = int64(amt) - case ctx.NArg() > 1: + case cmd.NArg() > 1: return fmt.Errorf("only a single positional argument is " + "allowed") default: - selectedAmount = ctx.Int64("amount") + selectedAmount = cmd.Int64("amount") } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() var ( - ctxb = context.Background() - isAllSelected = ctx.IsSet("all") - isUtxoSelected = ctx.IsSet("utxo") + isAllSelected = cmd.IsSet("all") + isUtxoSelected = cmd.IsSet("utxo") autoSelectDepositsForQuote bool - label = ctx.String(labelFlag.Name) + label = cmd.String(labelFlag.Name) hints []*swapserverrpc.RouteHint lastHop []byte paymentTimeoutSeconds = uint32(loopin.DefaultPaymentTimeoutSeconds) @@ -547,14 +540,14 @@ func staticAddressLoopIn(ctx *cli.Context) error { // Private and route hints are mutually exclusive as setting private // means we retrieve our own route hints from the connected node. - hints, err = validateRouteHints(ctx) + hints, err = validateRouteHints(cmd) if err != nil { return err } - if ctx.IsSet(lastHopFlag.Name) { + if cmd.IsSet(lastHopFlag.Name) { lastHopVertex, err := route.NewVertexFromStr( - ctx.String(lastHopFlag.Name), + cmd.String(lastHopFlag.Name), ) if err != nil { return err @@ -565,7 +558,7 @@ func staticAddressLoopIn(ctx *cli.Context) error { // Get the amount we need to quote for. depositList, err := client.ListStaticAddressDeposits( - ctxb, &looprpc.ListStaticAddressDepositsRequest{ + ctx, &looprpc.ListStaticAddressDepositsRequest{ StateFilter: looprpc.DepositState_DEPOSITED, }, ) @@ -592,7 +585,7 @@ func staticAddressLoopIn(ctx *cli.Context) error { depositOutpoints = depositsToOutpoints(allDeposits) case isUtxoSelected: - depositOutpoints = ctx.StringSlice("utxo") + depositOutpoints = cmd.StringSlice("utxo") case selectedAmount > 0: // If only an amount is selected, we will trigger coin @@ -614,27 +607,27 @@ func staticAddressLoopIn(ctx *cli.Context) error { Amt: selectedAmount, LoopInRouteHints: hints, LoopInLastHop: lastHop, - Private: ctx.Bool(privateFlag.Name), + Private: cmd.Bool(privateFlag.Name), DepositOutpoints: depositOutpoints, AutoSelectDeposits: autoSelectDepositsForQuote, - Fast: ctx.Bool("fast"), + Fast: cmd.Bool("fast"), } - quote, err := client.GetLoopInQuote(ctxb, quoteReq) + quote, err := client.GetLoopInQuote(ctx, quoteReq) if err != nil { return err } limits := getInLimits(quote) - if !(ctx.Bool("force") || ctx.Bool("f")) { - err = displayInDetails(quoteReq, quote, ctx.Bool("verbose")) + if !(cmd.Bool("force") || cmd.Bool("f")) { + err = displayInDetails(quoteReq, quote, cmd.Bool("verbose")) if err != nil { return err } } - if ctx.IsSet("payment_timeout") { - paymentTimeoutSeconds = uint32(ctx.Duration("payment_timeout").Seconds()) + if cmd.IsSet("payment_timeout") { + paymentTimeoutSeconds = uint32(cmd.Duration("payment_timeout").Seconds()) } req := &looprpc.StaticAddressLoopInRequest{ @@ -645,12 +638,12 @@ func staticAddressLoopIn(ctx *cli.Context) error { Label: label, Initiator: defaultInitiator, RouteHints: hints, - Private: ctx.Bool("private"), + Private: cmd.Bool("private"), PaymentTimeoutSeconds: paymentTimeoutSeconds, - Fast: ctx.Bool("fast"), + Fast: cmd.Bool("fast"), } - resp, err := client.StaticAddressLoopIn(ctxb, req) + resp, err := client.StaticAddressLoopIn(ctx, req) if err != nil { return err } diff --git a/cmd/loop/swaps.go b/cmd/loop/swaps.go index fd901827..899925e9 100644 --- a/cmd/loop/swaps.go +++ b/cmd/loop/swaps.go @@ -10,36 +10,36 @@ import ( "github.com/lightninglabs/loop/looprpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/routing/route" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var listSwapsCommand = cli.Command{ +var listSwapsCommand = &cli.Command{ Name: "listswaps", Usage: "list all swaps in the local database", Description: "Allows the user to get a list of all swaps that are " + "currently stored in the database", Action: listSwaps, Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "loop_out_only", Usage: "only list swaps that are loop out swaps", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "loop_in_only", Usage: "only list swaps that are loop in swaps", }, - cli.BoolFlag{ + &cli.BoolFlag{ Name: "pending_only", Usage: "only list pending swaps", }, labelFlag, channelFlag, lastHopFlag, - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "max_swaps", Usage: "Max number of swaps to return after filtering", }, - cli.Int64Flag{ + &cli.Int64Flag{ Name: "start_time_ns", Usage: "Unix timestamp in nanoseconds to select swaps initiated " + "after this time", @@ -47,14 +47,14 @@ var listSwapsCommand = cli.Command{ }, } -func listSwaps(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func listSwaps(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() - if ctx.Bool("loop_out_only") && ctx.Bool("loop_in_only") { + if cmd.Bool("loop_out_only") && cmd.Bool("loop_in_only") { return fmt.Errorf("only one of loop_out_only and loop_in_only " + "can be set") } @@ -63,21 +63,21 @@ func listSwaps(ctx *cli.Context) error { // Set the swap type filter. switch { - case ctx.Bool("loop_out_only"): + case cmd.Bool("loop_out_only"): filter.SwapType = looprpc.ListSwapsFilter_LOOP_OUT - case ctx.Bool("loop_in_only"): + case cmd.Bool("loop_in_only"): filter.SwapType = looprpc.ListSwapsFilter_LOOP_IN } // Set the pending only filter. - filter.PendingOnly = ctx.Bool("pending_only") + filter.PendingOnly = cmd.Bool("pending_only") // Parse outgoing channel set. Don't string split if the flag is empty. // Otherwise, strings.Split returns a slice of length one with an empty // element. var outgoingChanSet []uint64 - if ctx.IsSet(channelFlag.Name) { - chanStrings := strings.Split(ctx.String(channelFlag.Name), ",") + if cmd.IsSet(channelFlag.Name) { + chanStrings := strings.Split(cmd.String(channelFlag.Name), ",") for _, chanString := range chanStrings { chanID, err := strconv.ParseUint(chanString, 10, 64) if err != nil { @@ -91,9 +91,9 @@ func listSwaps(ctx *cli.Context) error { // Parse last hop. var lastHop []byte - if ctx.IsSet(lastHopFlag.Name) { + if cmd.IsSet(lastHopFlag.Name) { lastHopVertex, err := route.NewVertexFromStr( - ctx.String(lastHopFlag.Name), + cmd.String(lastHopFlag.Name), ) if err != nil { return err @@ -104,19 +104,19 @@ func listSwaps(ctx *cli.Context) error { } // Parse label. - if ctx.IsSet(labelFlag.Name) { - filter.Label = ctx.String(labelFlag.Name) + if cmd.IsSet(labelFlag.Name) { + filter.Label = cmd.String(labelFlag.Name) } // Parse start timestamp if set. - if ctx.IsSet("start_time_ns") { - filter.StartTimestampNs = ctx.Int64("start_time_ns") + if cmd.IsSet("start_time_ns") { + filter.StartTimestampNs = cmd.Int64("start_time_ns") } resp, err := client.ListSwaps( - context.Background(), &looprpc.ListSwapsRequest{ + ctx, &looprpc.ListSwapsRequest{ ListSwapFilter: filter, - MaxSwaps: ctx.Uint64("max_swaps"), + MaxSwaps: cmd.Uint64("max_swaps"), }, ) if err != nil { @@ -127,14 +127,14 @@ func listSwaps(ctx *cli.Context) error { return nil } -var swapInfoCommand = cli.Command{ +var swapInfoCommand = &cli.Command{ Name: "swapinfo", Usage: "show the status of a swap", ArgsUsage: "id", Description: "Allows the user to get the status of a single swap " + "currently stored in the database", Flags: []cli.Flag{ - cli.Uint64Flag{ + &cli.Uint64Flag{ Name: "id", Usage: "the ID of the swap", }, @@ -142,19 +142,18 @@ var swapInfoCommand = cli.Command{ Action: swapInfo, } -func swapInfo(ctx *cli.Context) error { - args := ctx.Args() +func swapInfo(ctx context.Context, cmd *cli.Command) error { + args := cmd.Args() var id string switch { - case ctx.IsSet("id"): - id = ctx.String("id") - case ctx.NArg() > 0: - id = args[0] - args = args.Tail() // nolint:wastedassign + case cmd.IsSet("id"): + id = cmd.String("id") + case cmd.NArg() > 0: + id = args.First() default: // Show command help if no arguments and flags were provided. - return cli.ShowCommandHelp(ctx, "swapinfo") + return showCommandHelp(ctx, cmd) } if len(id) != hex.EncodedLen(lntypes.HashSize) { @@ -165,14 +164,14 @@ func swapInfo(ctx *cli.Context) error { return fmt.Errorf("cannot hex decode id: %v", err) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() resp, err := client.SwapInfo( - context.Background(), &looprpc.SwapInfoRequest{Id: idBytes}, + ctx, &looprpc.SwapInfoRequest{Id: idBytes}, ) if err != nil { return err @@ -182,7 +181,7 @@ func swapInfo(ctx *cli.Context) error { return nil } -var abandonSwapCommand = cli.Command{ +var abandonSwapCommand = &cli.Command{ Name: "abandonswap", Usage: "abandon a swap with a given swap hash", Description: "This command overrides the database and abandons a " + @@ -193,7 +192,7 @@ var abandonSwapCommand = cli.Command{ "no funds are locked by the swap.", ArgsUsage: "ID", Flags: []cli.Flag{ - cli.BoolFlag{ + &cli.BoolFlag{ Name: "i_know_what_i_am_doing", Usage: "Specify this flag if you made sure that you " + "read and understood the following " + @@ -203,21 +202,20 @@ var abandonSwapCommand = cli.Command{ Action: abandonSwap, } -func abandonSwap(ctx *cli.Context) error { - args := ctx.Args() +func abandonSwap(ctx context.Context, cmd *cli.Command) error { + args := cmd.Args() var id string switch { - case ctx.IsSet("id"): - id = ctx.String("id") + case cmd.IsSet("id"): + id = cmd.String("id") - case ctx.NArg() > 0: - id = args[0] - args = args.Tail() // nolint:wastedassign + case cmd.NArg() > 0: + id = args.First() default: // Show command help if no arguments and flags were provided. - return cli.ShowCommandHelp(ctx, "abandonswap") + return showCommandHelp(ctx, cmd) } if len(id) != hex.EncodedLen(lntypes.HashSize) { @@ -228,20 +226,20 @@ func abandonSwap(ctx *cli.Context) error { return fmt.Errorf("cannot hex decode id: %v", err) } - client, cleanup, err := getClient(ctx) + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } defer cleanup() - if !ctx.Bool("i_know_what_i_am_doing") { - return cli.ShowCommandHelp(ctx, "abandonswap") + if !cmd.Bool("i_know_what_i_am_doing") { + return showCommandHelp(ctx, cmd) } resp, err := client.AbandonSwap( - context.Background(), &looprpc.AbandonSwapRequest{ + ctx, &looprpc.AbandonSwapRequest{ Id: idBytes, - IKnowWhatIAmDoing: ctx.Bool("i_know_what_i_am_doing"), + IKnowWhatIAmDoing: cmd.Bool("i_know_what_i_am_doing"), }, ) if err != nil { diff --git a/cmd/loop/terms.go b/cmd/loop/terms.go index 506408f8..c7230ada 100644 --- a/cmd/loop/terms.go +++ b/cmd/loop/terms.go @@ -6,17 +6,17 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/lightninglabs/loop/looprpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) -var termsCommand = cli.Command{ +var termsCommand = &cli.Command{ Name: "terms", Usage: "Display the current swap terms imposed by the server.", Action: terms, } -func terms(ctx *cli.Context) error { - client, cleanup, err := getClient(ctx) +func terms(ctx context.Context, cmd *cli.Command) error { + client, cleanup, err := getClient(ctx, cmd) if err != nil { return err } @@ -31,7 +31,7 @@ func terms(ctx *cli.Context) error { fmt.Println("Loop Out") fmt.Println("--------") req := &looprpc.TermsRequest{} - loopOutTerms, err := client.LoopOutTerms(context.Background(), req) + loopOutTerms, err := client.LoopOutTerms(ctx, req) if err != nil { fmt.Println(err) } else { @@ -49,7 +49,7 @@ func terms(ctx *cli.Context) error { fmt.Println("Loop In") fmt.Println("------") loopInTerms, err := client.GetLoopInTerms( - context.Background(), &looprpc.TermsRequest{}, + ctx, &looprpc.TermsRequest{}, ) if err != nil { fmt.Println(err) diff --git a/cmd/loop/utils.go b/cmd/loop/utils.go index eaf98efa..07a6016a 100644 --- a/cmd/loop/utils.go +++ b/cmd/loop/utils.go @@ -1,28 +1,41 @@ package main import ( + "context" "encoding/json" "fmt" "github.com/lightninglabs/loop/swapserverrpc" - "github.com/urfave/cli" + "github.com/urfave/cli/v3" ) +// showCommandHelp prints help for the current command by delegating to the +// parent command when available. This ensures help output renders even when +// invoked from inside a subcommand's action. +func showCommandHelp(ctx context.Context, cmd *cli.Command) error { + lineage := cmd.Lineage() + if len(lineage) > 1 { + parent := lineage[1] + return cli.ShowCommandHelp(ctx, parent, cmd.Name) + } + return cli.ShowCommandHelp(ctx, cmd, cmd.Name) +} + // validateRouteHints ensures that the Private flag isn't set along with // the RouteHints flag. We don't allow both options to be set as these options // are alternatives to each other. Private autogenerates hopHints while // RouteHints are manually passed. -func validateRouteHints(ctx *cli.Context) ([]*swapserverrpc.RouteHint, error) { +func validateRouteHints(cmd *cli.Command) ([]*swapserverrpc.RouteHint, error) { var hints []*swapserverrpc.RouteHint - if ctx.IsSet(routeHintsFlag.Name) { - if ctx.IsSet(privateFlag.Name) { + if cmd.IsSet(routeHintsFlag.Name) { + if cmd.IsSet(privateFlag.Name) { return nil, fmt.Errorf( "private and route_hints both set", ) } - jsonHints := ctx.StringSlice(routeHintsFlag.Name) + jsonHints := cmd.StringSlice(routeHintsFlag.Name) hints := make([]*swapserverrpc.RouteHint, len(jsonHints)) for i, jsonHint := range jsonHints { diff --git a/go.mod b/go.mod index 3b4768b9..162d9496 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/lightningnetwork/lnd/tor v1.1.6 github.com/ory/dockertest/v3 v3.10.0 github.com/stretchr/testify v1.10.0 - github.com/urfave/cli v1.22.14 + github.com/urfave/cli/v3 v3.4.1 go.etcd.io/bbolt v1.3.11 golang.org/x/sync v0.12.0 google.golang.org/grpc v1.64.1 @@ -72,7 +72,6 @@ require ( github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/lru v1.1.2 // indirect github.com/docker/cli v28.0.1+incompatible // indirect @@ -150,7 +149,6 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/fastuuid v1.2.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/spf13/pflag v1.0.6 // indirect diff --git a/go.sum b/go.sum index 3781a9c6..0fdaba69 100644 --- a/go.sum +++ b/go.sum @@ -600,7 +600,6 @@ git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3p github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -737,8 +736,6 @@ github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pq github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= @@ -1266,8 +1263,6 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7 github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -1306,7 +1301,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= @@ -1315,8 +1309,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02 h1:tcJ6OjwOMvExLlzrAVZute09ocAGa7KqOON60++Gz4E= github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY= -github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= -github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +github.com/urfave/cli/v3 v3.4.1 h1:1M9UOCy5bLmGnuu1yn3t3CB4rG79Rtoxuv1sPhnm6qM= +github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=