From 879506c65a0c58a142bfce4bf9115e3809826dde Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 12:41:10 -0400 Subject: [PATCH 01/31] chore: remove flag_loader --- cmd/cdk/cdk.go | 11 +- cmd/contract/cmd.go | 11 +- cmd/dumpblocks/dumpblocks.go | 22 ++-- cmd/ecrecover/ecrecover.go | 25 ++--- cmd/fixnoncegap/fixnoncegap.go | 19 ++-- cmd/flag_loader/flag_loader.go | 78 -------------- cmd/flag_loader/flag_loader_test.go | 155 ---------------------------- cmd/fund/cmd.go | 69 +++++-------- cmd/loadtest/app.go | 22 ++-- cmd/monitor/cmd.go | 19 ++-- cmd/nodekey/nodekey.go | 11 +- cmd/publish/publish.go | 11 +- cmd/root.go | 8 +- cmd/rpcfuzz/cmd.go | 20 ++-- cmd/signer/signer.go | 11 +- cmd/ulxly/ulxly.go | 18 +--- doc/polycli_ecrecover.md | 2 +- util/flag.go | 70 +++++++++++++ 18 files changed, 187 insertions(+), 395 deletions(-) delete mode 100644 cmd/flag_loader/flag_loader.go delete mode 100644 cmd/flag_loader/flag_loader_test.go create mode 100644 util/flag.go diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index 76ac1e6fc..def8920bf 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -11,8 +11,8 @@ import ( "strings" "time" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/custom_marshaller" + "github.com/0xPolygon/polygon-cli/util" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -106,11 +106,12 @@ var CDKCmd = &cobra.Command{ Use: "cdk", Short: "Utilities for interacting with CDK networks", Long: "Basic utility commands for interacting with the cdk contracts", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcURL := flag_loader.GetRpcUrlFlagValue(cmd) - if rpcURL != nil { - cdkInputArgs.rpcURL = *rpcURL + PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { + cdkInputArgs.rpcURL, err = util.GetRPCURL(cmd) + if err != nil { + return err } + return nil }, Args: cobra.NoArgs, } diff --git a/cmd/contract/cmd.go b/cmd/contract/cmd.go index ca9507347..b8441a641 100644 --- a/cmd/contract/cmd.go +++ b/cmd/contract/cmd.go @@ -8,7 +8,7 @@ import ( "math/big" "strings" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" + "github.com/0xPolygon/polygon-cli/util" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -45,9 +45,12 @@ var Cmd = &cobra.Command{ Use: "contract", Short: "Interact with smart contracts and fetch contract information from the blockchain", Long: usage, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcURL := flag_loader.GetRpcUrlFlagValue(cmd) - inputArgs.rpcURL = *rpcURL + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + inputArgs.rpcURL, err = util.GetRPCURL(cmd) + if err != nil { + return err + } + return nil }, RunE: func(cmd *cobra.Command, args []string) error { return contract(cmd) diff --git a/cmd/dumpblocks/dumpblocks.go b/cmd/dumpblocks/dumpblocks.go index 65e6faee9..1d0b672ce 100644 --- a/cmd/dumpblocks/dumpblocks.go +++ b/cmd/dumpblocks/dumpblocks.go @@ -12,7 +12,6 @@ import ( _ "embed" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/proto/gen/pb" "github.com/0xPolygon/polygon-cli/rpctypes" "github.com/0xPolygon/polygon-cli/util" @@ -55,12 +54,12 @@ var DumpblocksCmd = &cobra.Command{ Use: "dumpblocks start end", Short: "Export a range of blocks from a JSON-RPC endpoint.", Long: usage, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcUrlFlagValue := flag_loader.GetRpcUrlFlagValue(cmd) - inputDumpblocks.RpcUrl = *rpcUrlFlagValue - }, - PreRunE: func(cmd *cobra.Command, args []string) error { - return checkFlags() + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + inputDumpblocks.RpcUrl, err = util.GetRPCURL(cmd) + if err != nil { + return err + } + return nil }, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() @@ -196,15 +195,6 @@ func init() { f.StringVarP(&inputDumpblocks.FilterStr, "filter", "F", "{}", "filter output based on tx to and from, not setting a filter means all are allowed") } -func checkFlags() error { - // Check rpc url flag. - if err := util.ValidateUrl(inputDumpblocks.RpcUrl); err != nil { - return err - } - - return nil -} - // writeResponses writes the data to either stdout or a file if one is provided. // The message type can be either "block" or "transaction". The format of the // output is either "json" or "proto" depending on the mode. diff --git a/cmd/ecrecover/ecrecover.go b/cmd/ecrecover/ecrecover.go index d63823a48..1e7a3e9f9 100644 --- a/cmd/ecrecover/ecrecover.go +++ b/cmd/ecrecover/ecrecover.go @@ -7,7 +7,6 @@ import ( "math/big" "os" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/util" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -32,12 +31,12 @@ var EcRecoverCmd = &cobra.Command{ Short: "Recovers and returns the public key of the signature", Long: usage, Args: cobra.NoArgs, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcUrlFlagValue := flag_loader.GetRpcUrlFlagValue(cmd) - rpcUrl = *rpcUrlFlagValue - }, - PreRunE: func(cmd *cobra.Command, args []string) error { - return checkFlags() + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + rpcUrl, err = util.GetRPCURL(cmd) + if err != nil { + return err + } + return nil }, Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() @@ -128,7 +127,7 @@ var EcRecoverCmd = &cobra.Command{ func init() { f := EcRecoverCmd.Flags() - f.StringVarP(&rpcUrl, "rpc-url", "r", "", "the RPC endpoint URL") + f.StringVarP(&rpcUrl, "rpc-url", "r", "", "RPC endpoint URL") f.Uint64VarP(&blockNumber, "block-number", "b", 0, "block number to check the extra data for (default: latest)") f.StringVarP(&filePath, "file", "f", "", "path to a file containing block information in JSON format") f.StringVarP(&txData, "tx", "t", "", "transaction data in hex format") @@ -136,13 +135,3 @@ func init() { // The sources of decoding are mutually exclusive EcRecoverCmd.MarkFlagsMutuallyExclusive("file", "block-number", "tx") } - -func checkFlags() error { - var err error - if rpcUrl != "" { - if err = util.ValidateUrl(rpcUrl); err != nil { - return err - } - } - return err -} diff --git a/cmd/fixnoncegap/fixnoncegap.go b/cmd/fixnoncegap/fixnoncegap.go index 7808273a1..d3fc875bb 100644 --- a/cmd/fixnoncegap/fixnoncegap.go +++ b/cmd/fixnoncegap/fixnoncegap.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" + "github.com/0xPolygon/polygon-cli/util" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -25,19 +25,18 @@ var FixNonceGapCmd = &cobra.Command{ Short: "Send txs to fix the nonce gap for a specific account", Long: fixNonceGapUsage, Args: cobra.NoArgs, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - var err error - rpcURL := flag_loader.GetRpcUrlFlagValue(cmd) - inputFixNonceGapArgs.rpcURL = *rpcURL - privateKey, err := flag_loader.GetRequiredPrivateKeyFlagValue(cmd) + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + inputFixNonceGapArgs.rpcURL, err = util.GetRPCURL(cmd) if err != nil { return err } - inputFixNonceGapArgs.privateKey = *privateKey - return nil + inputFixNonceGapArgs.privateKey, err = util.GetPrivateKey(cmd) + if err != nil { + return err + } + return prepareRpcClient(cmd, args) }, - PreRunE: prepareRpcClient, - RunE: fixNonceGap, + RunE: fixNonceGap, SilenceUsage: true, } diff --git a/cmd/flag_loader/flag_loader.go b/cmd/flag_loader/flag_loader.go deleted file mode 100644 index 30a9fea08..000000000 --- a/cmd/flag_loader/flag_loader.go +++ /dev/null @@ -1,78 +0,0 @@ -package flag_loader - -import ( - "fmt" - "math/big" - "os" - - "github.com/spf13/cobra" -) - -const ( - rpcUrlFlagName, rpcUrlEnvVar = "rpc-url", "ETH_RPC_URL" - privateKeyFlagName, privateKeyEnvVar = "private-key", "PRIVATE_KEY" -) - -type BigIntValue struct { - Val *big.Int -} - -func (b *BigIntValue) String() string { - // Return the decimal representation - return b.Val.String() -} - -func (b *BigIntValue) Set(s string) error { - // Parse the string in base 10 - if _, ok := b.Val.SetString(s, 10); !ok { - return fmt.Errorf("invalid big integer: %q", s) - } - return nil -} - -func (b *BigIntValue) Type() string { - return "big.Int" -} - -func GetRpcUrlFlagValue(cmd *cobra.Command) *string { - v, _ := getFlagValue(cmd, rpcUrlFlagName, rpcUrlEnvVar, false) - return v -} - -func GetRequiredRpcUrlFlagValue(cmd *cobra.Command) (*string, error) { - return getFlagValue(cmd, rpcUrlFlagName, rpcUrlEnvVar, true) -} - -func GetPrivateKeyFlagValue(cmd *cobra.Command) *string { - v, _ := getFlagValue(cmd, privateKeyFlagName, privateKeyEnvVar, false) - return v -} - -func GetRequiredPrivateKeyFlagValue(cmd *cobra.Command) (*string, error) { - return getFlagValue(cmd, privateKeyFlagName, privateKeyEnvVar, true) -} - -func getFlagValue(cmd *cobra.Command, flagName, envVarName string, required bool) (*string, error) { - flag := cmd.Flag(flagName) - var flagValue string - if flag.Changed { - flagValue = flag.Value.String() - } - flagDefaultValue := flag.DefValue - - envVarValue := os.Getenv(envVarName) - - value := flagDefaultValue - if envVarValue != "" { - value = envVarValue - } - if flag.Changed { - value = flagValue - } - - if required && (!flag.Changed && envVarValue == "") { - return nil, fmt.Errorf("required flag(s) \"%s\" not set", flagName) - } - - return &value, nil -} diff --git a/cmd/flag_loader/flag_loader_test.go b/cmd/flag_loader/flag_loader_test.go deleted file mode 100644 index c5765d27f..000000000 --- a/cmd/flag_loader/flag_loader_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package flag_loader - -import ( - "fmt" - "os" - "strconv" - "testing" - - "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" -) - -func TestValuePriority(t *testing.T) { - type testCase struct { - defaultValue *int - envVarValue *int - flagValue *int - required bool - - expectedValue *int - expectedError error - } - - testCases := []testCase{ - { - defaultValue: ptr(1), - envVarValue: ptr(2), - flagValue: ptr(3), - expectedValue: ptr(3), - required: true, - expectedError: nil, - }, - { - defaultValue: ptr(1), - envVarValue: ptr(2), - flagValue: ptr(1), - expectedValue: ptr(1), - required: true, - expectedError: nil, - }, - { - defaultValue: ptr(1), - envVarValue: ptr(2), - flagValue: nil, - expectedValue: ptr(2), - required: true, - expectedError: nil, - }, - { - defaultValue: ptr(1), - envVarValue: nil, - flagValue: ptr(3), - expectedValue: ptr(3), - required: true, - expectedError: nil, - }, - { - defaultValue: nil, - envVarValue: ptr(2), - flagValue: ptr(3), - expectedValue: ptr(3), - required: true, - expectedError: nil, - }, - { - defaultValue: nil, - envVarValue: nil, - flagValue: ptr(3), - expectedValue: ptr(3), - required: true, - expectedError: nil, - }, - { - defaultValue: ptr(1), - envVarValue: nil, - flagValue: nil, - expectedValue: ptr(1), - required: false, - expectedError: nil, - }, - { - defaultValue: nil, - envVarValue: ptr(2), - flagValue: nil, - expectedValue: ptr(2), - required: true, - expectedError: nil, - }, - { - defaultValue: nil, - envVarValue: nil, - flagValue: nil, - expectedValue: ptr(0), - required: false, - expectedError: nil, - }, - { - defaultValue: nil, - envVarValue: nil, - flagValue: nil, - expectedValue: nil, - required: true, - expectedError: fmt.Errorf("required flag(s) \"flag\" not set"), - }, - } - - for _, tc := range testCases { - var value *int - cmd := &cobra.Command{ - Use: "test", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - valueStr, err := getFlagValue(cmd, "flag", "FLAG", tc.required) - if tc.expectedError != nil { - assert.EqualError(t, err, tc.expectedError.Error()) - return - } - assert.NoError(t, err) - valueInt, err := strconv.Atoi(*valueStr) - assert.NoError(t, err) - value = &valueInt - }, - Run: func(cmd *cobra.Command, args []string) { - if tc.expectedValue != nil { - assert.Equal(t, *tc.expectedValue, *value) - } else { - assert.Nil(t, value) - } - }, - } - if tc.defaultValue != nil { - cmd.Flags().Int("flag", *tc.defaultValue, "flag") - } else { - cmd.Flags().Int("flag", 0, "flag") - } - - os.Unsetenv("FLAG") - if tc.envVarValue != nil { - v := strconv.Itoa(*tc.envVarValue) - os.Setenv("FLAG", v) - } - - if tc.flagValue != nil { - v := strconv.Itoa(*tc.flagValue) - cmd.SetArgs([]string{"--flag", v}) - } - - err := cmd.Execute() - assert.Nil(t, err) - } - -} - -func ptr[T any](v T) *T { - return &v -} diff --git a/cmd/fund/cmd.go b/cmd/fund/cmd.go index 62f426e6b..69b3d7db3 100644 --- a/cmd/fund/cmd.go +++ b/cmd/fund/cmd.go @@ -6,7 +6,6 @@ import ( _ "embed" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/util" "github.com/spf13/cobra" ) @@ -48,13 +47,15 @@ var FundCmd = &cobra.Command{ Use: "fund", Short: "Bulk fund crypto wallets automatically.", Long: usage, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcUrl := flag_loader.GetRpcUrlFlagValue(cmd) - params.RpcUrl = *rpcUrl - privateKey := flag_loader.GetPrivateKeyFlagValue(cmd) - params.PrivateKey = *privateKey - }, - PreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + params.RpcUrl, err = util.GetRPCURL(cmd) + if err != nil { + return err + } + params.PrivateKey, err = util.GetPrivateKey(cmd) + if err != nil { + return err + } return checkFlags() }, RunE: func(cmd *cobra.Command, args []string) error { @@ -63,21 +64,20 @@ var FundCmd = &cobra.Command{ } func init() { - p := new(cmdFundParams) f := FundCmd.Flags() - f.StringVarP(&p.RpcUrl, "rpc-url", "r", "http://localhost:8545", "RPC endpoint URL") - f.StringVar(&p.PrivateKey, "private-key", defaultPrivateKey, "hex encoded private key to use for sending transactions") + f.StringVarP(¶ms.RpcUrl, "rpc-url", "r", "http://localhost:8545", "RPC endpoint URL") + f.StringVar(¶ms.PrivateKey, "private-key", defaultPrivateKey, "hex encoded private key to use for sending transactions") // Wallet parameters. - f.Uint64VarP(&p.WalletsNumber, "number", "n", 10, "number of wallets to fund") - f.BoolVar(&p.UseHDDerivation, "hd-derivation", true, "derive wallets to fund from private key in deterministic way") - f.StringSliceVar(&p.WalletAddresses, "addresses", nil, "comma-separated list of wallet addresses to fund") - p.FundingAmountInWei = defaultFundingInWei - f.Var(&flag_loader.BigIntValue{Val: p.FundingAmountInWei}, "eth-amount", "amount of wei to send to each wallet") - f.StringVar(&p.KeyFile, "key-file", "", "file containing accounts private keys, one per line") + f.Uint64VarP(¶ms.WalletsNumber, "number", "n", 10, "number of wallets to fund") + f.BoolVar(¶ms.UseHDDerivation, "hd-derivation", true, "derive wallets to fund from private key in deterministic way") + f.StringSliceVar(¶ms.WalletAddresses, "addresses", nil, "comma-separated list of wallet addresses to fund") + params.FundingAmountInWei = defaultFundingInWei + f.Var(&util.BigIntValue{Val: params.FundingAmountInWei}, "eth-amount", "amount of wei to send to each wallet") + f.StringVar(¶ms.KeyFile, "key-file", "", "file containing accounts private keys, one per line") - f.StringVarP(&p.OutputFile, "file", "f", "wallets.json", "output JSON file path for storing addresses and private keys of funded wallets") + f.StringVarP(¶ms.OutputFile, "file", "f", "wallets.json", "output JSON file path for storing addresses and private keys of funded wallets") // Marking flags as mutually exclusive FundCmd.MarkFlagsMutuallyExclusive("addresses", "number") @@ -86,41 +86,18 @@ func init() { FundCmd.MarkFlagsMutuallyExclusive("key-file", "number") FundCmd.MarkFlagsMutuallyExclusive("key-file", "hd-derivation") - // Funder contract parameters. - f.StringVar(&p.FunderAddress, "contract-address", "", "address of pre-deployed Funder contract") + // Require at least one method to specify target accounts + FundCmd.MarkFlagsOneRequired("addresses", "key-file", "number") - params = *p + // Funder contract parameters. + f.StringVar(¶ms.FunderAddress, "contract-address", "", "address of pre-deployed Funder contract") } func checkFlags() error { - // Check rpc url flag. - if params.RpcUrl == "" { - panic("RPC URL is empty") - } - if err := util.ValidateUrl(params.RpcUrl); err != nil { - return err - } - - // Check private key flag. - if params.PrivateKey == "" { - return errors.New("the private key is empty") - } - - // Check that exactly one method is used to specify target accounts - hasAddresses := len(params.WalletAddresses) > 0 - hasKeyFile := params.KeyFile != "" - hasNumberFlag := params.WalletsNumber > 0 - if !hasAddresses && !hasKeyFile && !hasNumberFlag { - return errors.New("must specify target accounts via --addresses, --key-file, or --number") - } - + // Validate funding amount minValue := big.NewInt(1000000000) if params.FundingAmountInWei != nil && params.FundingAmountInWei.Cmp(minValue) <= 0 { return errors.New("the funding amount must be greater than 1000000000") } - if params.OutputFile == "" { - return errors.New("the output file is not specified") - } - return nil } diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index a8fa3db1b..b63e678d0 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -9,7 +9,6 @@ import ( "sync" "time" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/rpctypes" "github.com/0xPolygon/polygon-cli/util" ethcommon "github.com/ethereum/go-ethereum/common" @@ -172,17 +171,15 @@ var LoadtestCmd = &cobra.Command{ Short: "Run a generic load test against an Eth/EVM style JSON-RPC endpoint.", Long: loadTestUsage, Args: cobra.NoArgs, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcUrl := flag_loader.GetRpcUrlFlagValue(cmd) - privateKey := flag_loader.GetPrivateKeyFlagValue(cmd) - if rpcUrl != nil { - inputLoadTestParams.RPCUrl = *rpcUrl + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + inputLoadTestParams.RPCUrl, err = util.GetRPCURL(cmd) + if err != nil { + return err } - if privateKey != nil { - inputLoadTestParams.PrivateKey = *privateKey + inputLoadTestParams.PrivateKey, err = util.GetPrivateKey(cmd) + if err != nil { + return err } - }, - PreRunE: func(cmd *cobra.Command, args []string) error { zerolog.DurationFieldUnit = time.Second zerolog.DurationFieldInteger = true @@ -200,9 +197,6 @@ func checkLoadtestFlags() error { if ltp.RPCUrl == "" { return fmt.Errorf("RPC URL is empty") } - if err := util.ValidateUrl(ltp.RPCUrl); err != nil { - return err - } if ltp.AdaptiveBackoffFactor <= 0.0 { return fmt.Errorf("the backoff factor needs to be non-zero positive. Given: %f", ltp.AdaptiveBackoffFactor) @@ -276,7 +270,7 @@ func initFlags() { f.Uint64Var(<p.BlobFeeCap, "blob-fee-cap", 100000, "blob fee cap, or maximum blob fee per chunk, in Gwei") f.Uint64Var(<p.SendingAccountsCount, "sending-accounts-count", 0, "number of sending accounts to use (avoids pool account queue)") ltp.AccountFundingAmount = defaultAccountFundingAmount - f.Var(&flag_loader.BigIntValue{Val: ltp.AccountFundingAmount}, "account-funding-amount", "amount in wei to fund sending accounts (set to 0 to disable)") + f.Var(&util.BigIntValue{Val: ltp.AccountFundingAmount}, "account-funding-amount", "amount in wei to fund sending accounts (set to 0 to disable)") f.BoolVar(<p.PreFundSendingAccounts, "pre-fund-sending-accounts", false, "fund all sending accounts at start instead of on first use") f.BoolVar(<p.RefundRemainingFunds, "refund-remaining-funds", false, "refund remaining balance to funding account after completion") f.StringVar(<p.SendingAccountsFile, "sending-accounts-file", "", "file with sending account private keys, one per line (avoids pool queue and preserves accounts across runs)") diff --git a/cmd/monitor/cmd.go b/cmd/monitor/cmd.go index 01822f10d..a5c05b14e 100644 --- a/cmd/monitor/cmd.go +++ b/cmd/monitor/cmd.go @@ -7,7 +7,6 @@ import ( "sync" "time" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/util" "github.com/spf13/cobra" ) @@ -57,21 +56,23 @@ var MonitorCmd = &cobra.Command{ Long: usage, Args: cobra.NoArgs, SilenceUsage: true, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - rpcUrlFlagValue := flag_loader.GetRpcUrlFlagValue(cmd) - rpcUrl = *rpcUrlFlagValue + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + rpcUrl, err = util.GetRPCURL(cmd) + if err != nil { + return err + } + // By default, hide logs from `polycli monitor`. verbosityFlag := cmd.Flag("verbosity") if verbosityFlag != nil && !verbosityFlag.Changed { util.SetLogLevel(util.Silent) } + prettyFlag := cmd.Flag("pretty-logs") if prettyFlag != nil && prettyFlag.Value.String() == "true" { return util.SetLogMode(util.Console) } - return nil - }, - PreRunE: func(cmd *cobra.Command, args []string) error { + return checkFlags() }, RunE: func(cmd *cobra.Command, args []string) error { @@ -89,10 +90,6 @@ func init() { } func checkFlags() (err error) { - if err = util.ValidateUrl(rpcUrl); err != nil { - return - } - interval, err = time.ParseDuration(intervalStr) if err != nil { return err diff --git a/cmd/nodekey/nodekey.go b/cmd/nodekey/nodekey.go index c4291b1e0..60deadc97 100644 --- a/cmd/nodekey/nodekey.go +++ b/cmd/nodekey/nodekey.go @@ -15,10 +15,10 @@ import ( _ "embed" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" gethcrypto "github.com/ethereum/go-ethereum/crypto" gethenode "github.com/ethereum/go-ethereum/p2p/enode" libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto" + "github.com/0xPolygon/polygon-cli/util" libp2ppeer "github.com/libp2p/go-libp2p/core/peer" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -66,9 +66,12 @@ var NodekeyCmd = &cobra.Command{ Use: "nodekey", Short: "Generate node keys for different blockchain clients and protocols.", Long: usage, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - privateKey := flag_loader.GetPrivateKeyFlagValue(cmd) - inputNodeKeyPrivateKey = *privateKey + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + inputNodeKeyPrivateKey, err = util.GetPrivateKey(cmd) + if err != nil { + return err + } + return nil }, RunE: func(cmd *cobra.Command, args []string) error { var nko nodeKeyOut diff --git a/cmd/publish/publish.go b/cmd/publish/publish.go index 8fa7c5702..2676a1c4e 100644 --- a/cmd/publish/publish.go +++ b/cmd/publish/publish.go @@ -5,7 +5,7 @@ import ( _ "embed" "time" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" + "github.com/0xPolygon/polygon-cli/util" "github.com/ethereum/go-ethereum/ethclient" "github.com/rs/zerolog/log" "github.com/spf13/cobra" @@ -26,9 +26,12 @@ var Cmd = &cobra.Command{ Use: "publish", Short: "Publish transactions to the network with high-throughput", Long: cmdUsage, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcURL := flag_loader.GetRpcUrlFlagValue(cmd) - publishInputArgs.rpcURL = *rpcURL + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + publishInputArgs.rpcURL, err = util.GetRPCURL(cmd) + if err != nil { + return err + } + return nil }, RunE: publish, } diff --git a/cmd/root.go b/cmd/root.go index a161e5a1c..d0482052d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -2,10 +2,11 @@ package cmd import ( "fmt" - "github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data" "os" + "strings" "github.com/0xPolygon/polygon-cli/cmd/contract" + "github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data" "github.com/0xPolygon/polygon-cli/cmd/foldtrace" "github.com/0xPolygon/polygon-cli/cmd/publish" "github.com/0xPolygon/polygon-cli/util" @@ -84,6 +85,11 @@ func initConfig() { viper.AutomaticEnv() // read in environment variables that match + // Set up environment variable mappings for common flags + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + viper.BindEnv("rpc-url", "ETH_RPC_URL") + viper.BindEnv("private-key", "PRIVATE_KEY") + // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) diff --git a/cmd/rpcfuzz/cmd.go b/cmd/rpcfuzz/cmd.go index e7d159e2f..b984a15f3 100644 --- a/cmd/rpcfuzz/cmd.go +++ b/cmd/rpcfuzz/cmd.go @@ -6,7 +6,6 @@ import ( "regexp" "strings" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/cmd/rpcfuzz/argfuzz" "github.com/0xPolygon/polygon-cli/util" "github.com/ethereum/go-ethereum/crypto" @@ -42,13 +41,15 @@ var RPCFuzzCmd = &cobra.Command{ Short: "Continually run a variety of RPC calls and fuzzers.", Long: usage, Args: cobra.NoArgs, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - rpcUrlPtr := flag_loader.GetRpcUrlFlagValue(cmd) - rpcUrl = *rpcUrlPtr - privateKeyPtr := flag_loader.GetPrivateKeyFlagValue(cmd) - testPrivateHexKey = *privateKeyPtr - }, - PreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + rpcUrl, err = util.GetRPCURL(cmd) + if err != nil { + return err + } + testPrivateHexKey, err = util.GetPrivateKey(cmd) + if err != nil { + return err + } return checkFlags() }, RunE: func(cmd *cobra.Command, args []string) error { @@ -90,9 +91,6 @@ func checkFlags() (err error) { if rpcUrl == "" { panic("RPC URL is empty") } - if err = util.ValidateUrl(rpcUrl); err != nil { - return - } // Ensure only one streamer type is selected streamerCount := 0 diff --git a/cmd/signer/signer.go b/cmd/signer/signer.go index 5841268c3..56cf9d899 100644 --- a/cmd/signer/signer.go +++ b/cmd/signer/signer.go @@ -24,7 +24,6 @@ import ( kms "cloud.google.com/go/kms/apiv1" "cloud.google.com/go/kms/apiv1/kmspb" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/gethkeystore" accounts2 "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -34,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/google/tink/go/kwp/subtle" "github.com/manifoldco/promptui" + "github.com/0xPolygon/polygon-cli/util" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "google.golang.org/api/iterator" @@ -79,9 +79,12 @@ var SignerCmd = &cobra.Command{ Use: "signer", Short: "Utilities for security signing transactions", Long: signerUsage, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - privateKey := flag_loader.GetPrivateKeyFlagValue(cmd) - inputSignerOpts.privateKey = *privateKey + PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { + inputSignerOpts.privateKey, err = util.GetPrivateKey(cmd) + if err != nil { + return err + } + return nil }, Args: cobra.NoArgs, } diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index ccc897694..97326681c 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -34,8 +34,8 @@ import ( "github.com/0xPolygon/polygon-cli/bindings/tokens" "github.com/0xPolygon/polygon-cli/bindings/ulxly" "github.com/0xPolygon/polygon-cli/bindings/ulxly/polygonrollupmanager" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" smcerror "github.com/0xPolygon/polygon-cli/errors" + "github.com/0xPolygon/polygon-cli/util" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -2077,23 +2077,15 @@ var ULxLyCmd = &cobra.Command{ var ulxlyBridgeAndClaimCmd = &cobra.Command{ Args: cobra.NoArgs, Hidden: true, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - var err error - rpcURL, err := flag_loader.GetRequiredRpcUrlFlagValue(cmd) + PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { + inputUlxlyArgs.rpcURL, err = util.GetRPCURL(cmd) if err != nil { return err } - if rpcURL != nil { - inputUlxlyArgs.rpcURL = *rpcURL - } - - privateKey, err := flag_loader.GetRequiredPrivateKeyFlagValue(cmd) + inputUlxlyArgs.privateKey, err = util.GetPrivateKey(cmd) if err != nil { return err } - if privateKey != nil { - inputUlxlyArgs.privateKey = *privateKey - } return nil }, } @@ -2216,7 +2208,7 @@ const ( ArgInsecure = "insecure" ) -func prepInputs(cmd *cobra.Command, args []string) error { +func prepInputs(cmd *cobra.Command, args []string) (err error) { if inputUlxlyArgs.dryRun && inputUlxlyArgs.gasLimit == 0 { inputUlxlyArgs.gasLimit = uint64(10_000_000) } diff --git a/doc/polycli_ecrecover.md b/doc/polycli_ecrecover.md index 34ec00fde..0d72430e3 100644 --- a/doc/polycli_ecrecover.md +++ b/doc/polycli_ecrecover.md @@ -47,7 +47,7 @@ JSON Data passed in follows object definition [here](https://www.quicknode.com/d -b, --block-number uint block number to check the extra data for (default: latest) -f, --file string path to a file containing block information in JSON format -h, --help help for ecrecover - -r, --rpc-url string the RPC endpoint URL + -r, --rpc-url string RPC endpoint URL -t, --tx string transaction data in hex format ``` diff --git a/util/flag.go b/util/flag.go new file mode 100644 index 000000000..84e71ba9c --- /dev/null +++ b/util/flag.go @@ -0,0 +1,70 @@ +package util + +import ( + "fmt" + "math/big" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +const ( + // FlagRPCURL is the standard flag name for RPC endpoint URLs. + FlagRPCURL = "rpc-url" + // FlagPrivateKey is the standard flag name for private keys. + FlagPrivateKey = "private-key" +) + +// GetRequiredFlag retrieves a flag value from Viper after binding it and marking it as required. +// It binds the flag to enable environment variable fallback via Viper, marks the flag as required, +// and returns the flag's value. +func GetRequiredFlag(cmd *cobra.Command, flagName string) (string, error) { + viper.BindPFlag(flagName, cmd.Flags().Lookup(flagName)) + if err := cmd.MarkFlagRequired(flagName); err != nil { + return "", err + } + return viper.GetString(flagName), nil +} + +// GetRPCURL retrieves the rpc-url flag value from Viper after binding it, marking it as required, +// and validating that it is a valid URL with a supported scheme (http, https, ws, wss). +func GetRPCURL(cmd *cobra.Command) (string, error) { + rpcURL, err := GetRequiredFlag(cmd, FlagRPCURL) + if err != nil { + return "", err + } + if err := ValidateUrl(rpcURL); err != nil { + return "", err + } + return rpcURL, nil +} + +// GetPrivateKey retrieves the private-key flag value from Viper after binding it and marking it as required. +// This is a convenience wrapper around GetRequiredFlag for the standard private key flag. +func GetPrivateKey(cmd *cobra.Command) (string, error) { + return GetRequiredFlag(cmd, FlagPrivateKey) +} + +// BigIntValue is a custom flag type for big.Int values. +// It implements the pflag.Value interface to enable using *big.Int with Cobra flags. +type BigIntValue struct { + Val *big.Int +} + +// String returns the decimal string representation of the big.Int value. +func (b *BigIntValue) String() string { + return b.Val.String() +} + +// Set parses a decimal string and sets the big.Int value. +func (b *BigIntValue) Set(s string) error { + if _, ok := b.Val.SetString(s, 10); !ok { + return fmt.Errorf("invalid big integer: %q", s) + } + return nil +} + +// Type returns the type string for this flag value. +func (b *BigIntValue) Type() string { + return "big.Int" +} From 4a835f5537cdf35370c5b84259f3eae907a35a45 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 12:44:58 -0400 Subject: [PATCH 02/31] fix: revert ecrecover --- cmd/ecrecover/ecrecover.go | 2 +- doc/polycli_ecrecover.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/ecrecover/ecrecover.go b/cmd/ecrecover/ecrecover.go index 1e7a3e9f9..fce988474 100644 --- a/cmd/ecrecover/ecrecover.go +++ b/cmd/ecrecover/ecrecover.go @@ -127,7 +127,7 @@ var EcRecoverCmd = &cobra.Command{ func init() { f := EcRecoverCmd.Flags() - f.StringVarP(&rpcUrl, "rpc-url", "r", "", "RPC endpoint URL") + f.StringVarP(&rpcUrl, "rpc-url", "r", "", "the RPC endpoint URL") f.Uint64VarP(&blockNumber, "block-number", "b", 0, "block number to check the extra data for (default: latest)") f.StringVarP(&filePath, "file", "f", "", "path to a file containing block information in JSON format") f.StringVarP(&txData, "tx", "t", "", "transaction data in hex format") diff --git a/doc/polycli_ecrecover.md b/doc/polycli_ecrecover.md index 0d72430e3..34ec00fde 100644 --- a/doc/polycli_ecrecover.md +++ b/doc/polycli_ecrecover.md @@ -47,7 +47,7 @@ JSON Data passed in follows object definition [here](https://www.quicknode.com/d -b, --block-number uint block number to check the extra data for (default: latest) -f, --file string path to a file containing block information in JSON format -h, --help help for ecrecover - -r, --rpc-url string RPC endpoint URL + -r, --rpc-url string the RPC endpoint URL -t, --tx string transaction data in hex format ``` From d144bbae041c9cfe25c480d020f902ad3c366a7a Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 13:44:50 -0400 Subject: [PATCH 03/31] fix: more flags --- cmd/cdk/cdk.go | 9 +++--- cmd/contract/cmd.go | 10 +++---- cmd/dumpblocks/dumpblocks.go | 3 ++ cmd/ecrecover/ecrecover.go | 3 ++ cmd/fixnoncegap/fixnoncegap.go | 14 +++++---- cmd/fund/cmd.go | 4 +++ cmd/loadtest/app.go | 4 +++ cmd/monitor/cmd.go | 3 ++ cmd/nodekey/nodekey.go | 3 ++ cmd/publish/publish.go | 8 ++--- cmd/rpcfuzz/cmd.go | 4 +++ cmd/signer/signer.go | 6 ++-- util/flag.go | 55 +++++++++++++++++++++++----------- 13 files changed, 87 insertions(+), 39 deletions(-) diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index def8920bf..da4d4787c 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -44,7 +44,6 @@ import ( ) const ( - ArgRpcURL = "rpc-url" ArgForkID = "fork-id" ArgRollupManagerAddress = "rollup-manager-address" @@ -53,9 +52,8 @@ const ( ArgRollupID = "rollup-id" ArgRollupAddress = "rollup-address" ArgBridgeAddress = "bridge-address" - ArgGERAddress = "ger-address" + ArgGERAddress = "ger-address" - defaultRPCURL = "http://localhost:8545" defaultForkId = "12" // forks @@ -637,7 +635,7 @@ func mustPrintLogs(logs []types.Log, contractInstance reflect.Value, contractABI func init() { // cdk f := CDKCmd.PersistentFlags() - f.StringVar(&cdkInputArgs.rpcURL, ArgRpcURL, defaultRPCURL, "RPC URL of network containing CDK contracts") + f.StringVar(&cdkInputArgs.rpcURL, util.FlagRPCURL, util.DefaultRPCURL, "RPC URL of network containing CDK contracts") f.StringVar(&cdkInputArgs.forkID, ArgForkID, defaultForkId, "fork ID of CDK networks") f.StringVar(&cdkInputArgs.rollupManagerAddress, ArgRollupManagerAddress, "", "address of rollup contract") @@ -677,4 +675,7 @@ func init() { gerCmd.AddCommand(gerInspectCmd) gerCmd.AddCommand(gerDumpCmd) gerCmd.AddCommand(gerMonitorCmd) + + // Mark required flags + util.MarkPersistentFlagRequired(CDKCmd, util.FlagRPCURL) } diff --git a/cmd/contract/cmd.go b/cmd/contract/cmd.go index b8441a641..ed5573b80 100644 --- a/cmd/contract/cmd.go +++ b/cmd/contract/cmd.go @@ -17,9 +17,7 @@ import ( ) const ( - ArgRpcURL = "rpc-url" - ArgAddress = "address" - defaultRPCURL = "http://localhost:8545" + ArgAddress = "address" ) var ( @@ -173,8 +171,10 @@ func fetchContractCreationTx(ctx context.Context, client *ethclient.Client, cont func init() { f := Cmd.Flags() - f.StringVar(&inputArgs.rpcURL, ArgRpcURL, defaultRPCURL, "RPC URL of network containing contract") + f.StringVar(&inputArgs.rpcURL, util.FlagRPCURL, util.DefaultRPCURL, "RPC URL of network containing contract") f.StringVar(&inputArgs.address, ArgAddress, "", "contract address") - _ = Cmd.MarkFlagRequired(ArgAddress) + // Mark required flags + util.MarkFlagRequired(Cmd, ArgAddress) + util.MarkFlagRequired(Cmd, util.FlagRPCURL) } diff --git a/cmd/dumpblocks/dumpblocks.go b/cmd/dumpblocks/dumpblocks.go index 1d0b672ce..13bf191d9 100644 --- a/cmd/dumpblocks/dumpblocks.go +++ b/cmd/dumpblocks/dumpblocks.go @@ -193,6 +193,9 @@ func init() { f.StringVarP(&inputDumpblocks.Mode, "mode", "m", "json", "the output format [json, proto]") f.Uint64VarP(&inputDumpblocks.BatchSize, "batch-size", "b", 150, "batch size for requests (most providers cap at 1000)") f.StringVarP(&inputDumpblocks.FilterStr, "filter", "F", "{}", "filter output based on tx to and from, not setting a filter means all are allowed") + + // Mark required flags + util.MarkFlagRequired(DumpblocksCmd, util.FlagRPCURL) } // writeResponses writes the data to either stdout or a file if one is provided. diff --git a/cmd/ecrecover/ecrecover.go b/cmd/ecrecover/ecrecover.go index fce988474..069e11d1d 100644 --- a/cmd/ecrecover/ecrecover.go +++ b/cmd/ecrecover/ecrecover.go @@ -134,4 +134,7 @@ func init() { // The sources of decoding are mutually exclusive EcRecoverCmd.MarkFlagsMutuallyExclusive("file", "block-number", "tx") + + // Mark required flags + util.MarkFlagRequired(EcRecoverCmd, util.FlagRPCURL) } diff --git a/cmd/fixnoncegap/fixnoncegap.go b/cmd/fixnoncegap/fixnoncegap.go index d3fc875bb..236b57cee 100644 --- a/cmd/fixnoncegap/fixnoncegap.go +++ b/cmd/fixnoncegap/fixnoncegap.go @@ -54,10 +54,8 @@ type fixNonceGapArgs struct { var inputFixNonceGapArgs = fixNonceGapArgs{} const ( - ArgPrivateKey = "private-key" - ArgRpcURL = "rpc-url" - ArgReplace = "replace" - ArgMaxNonce = "max-nonce" + ArgReplace = "replace" + ArgMaxNonce = "max-nonce" ) //go:embed FixNonceGapUsage.md @@ -229,10 +227,14 @@ func fixNonceGap(cmd *cobra.Command, args []string) error { func init() { f := FixNonceGapCmd.Flags() - f.StringVarP(&inputFixNonceGapArgs.rpcURL, ArgRpcURL, "r", "http://localhost:8545", "the RPC endpoint URL") - f.StringVar(&inputFixNonceGapArgs.privateKey, ArgPrivateKey, "", "private key to be used when sending txs to fix nonce gap") + f.StringVarP(&inputFixNonceGapArgs.rpcURL, util.FlagRPCURL, "r", "http://localhost:8545", "the RPC endpoint URL") + f.StringVar(&inputFixNonceGapArgs.privateKey, util.FlagPrivateKey, "", "private key to be used when sending txs to fix nonce gap") f.BoolVar(&inputFixNonceGapArgs.replace, ArgReplace, false, "replace the existing txs in the pool") f.Uint64Var(&inputFixNonceGapArgs.maxNonce, ArgMaxNonce, 0, "override max nonce value instead of getting it from the pool") + + // Mark required flags + util.MarkFlagRequired(FixNonceGapCmd, util.FlagRPCURL) + util.MarkFlagRequired(FixNonceGapCmd, util.FlagPrivateKey) } // Wait for the transaction to be mined diff --git a/cmd/fund/cmd.go b/cmd/fund/cmd.go index 69b3d7db3..34e3947b7 100644 --- a/cmd/fund/cmd.go +++ b/cmd/fund/cmd.go @@ -89,6 +89,10 @@ func init() { // Require at least one method to specify target accounts FundCmd.MarkFlagsOneRequired("addresses", "key-file", "number") + // Mark required flags + util.MarkFlagRequired(FundCmd, util.FlagRPCURL) + util.MarkFlagRequired(FundCmd, util.FlagPrivateKey) + // Funder contract parameters. f.StringVar(¶ms.FunderAddress, "contract-address", "", "address of pre-deployed Funder contract") } diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index b63e678d0..876069d23 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -302,6 +302,10 @@ v3, uniswapv3 - perform UniswapV3 swaps`) f.UintVar(<p.ReceiptRetryInitialDelayMs, "receipt-retry-initial-delay-ms", 100, "initial delay in milliseconds for receipt polling (uses exponential backoff with jitter)") // TODO Compression + + // Mark required flags + util.MarkPersistentFlagRequired(LoadtestCmd, util.FlagRPCURL) + util.MarkPersistentFlagRequired(LoadtestCmd, util.FlagPrivateKey) } func initSubCommands() { diff --git a/cmd/monitor/cmd.go b/cmd/monitor/cmd.go index a5c05b14e..c8be27034 100644 --- a/cmd/monitor/cmd.go +++ b/cmd/monitor/cmd.go @@ -87,6 +87,9 @@ func init() { f.IntVarP(&subBatchSize, "sub-batch-size", "s", 50, "number of requests per sub-batch") f.IntVarP(&blockCacheLimit, "cache-limit", "c", 200, "number of cached blocks for the LRU block data structure (Min 100)") f.StringVarP(&intervalStr, "interval", "i", "5s", "amount of time between batch block RPC calls") + + // Mark required flags + util.MarkFlagRequired(MonitorCmd, util.FlagRPCURL) } func checkFlags() (err error) { diff --git a/cmd/nodekey/nodekey.go b/cmd/nodekey/nodekey.go index 60deadc97..ccda48879 100644 --- a/cmd/nodekey/nodekey.go +++ b/cmd/nodekey/nodekey.go @@ -299,4 +299,7 @@ func init() { f.BoolVarP(&inputNodeKeySign, "sign", "s", false, "sign the node record") f.Uint64VarP(&inputNodeKeySeed, "seed", "S", 271828, "a numeric seed value") f.BoolVarP(&inputNodeKeyMarshalProtobuf, "marshal-protobuf", "m", false, "marshal libp2p key to protobuf format instead of raw") + + // Mark required flags + util.MarkFlagRequired(NodekeyCmd, util.FlagPrivateKey) } diff --git a/cmd/publish/publish.go b/cmd/publish/publish.go index 2676a1c4e..16b3d22bc 100644 --- a/cmd/publish/publish.go +++ b/cmd/publish/publish.go @@ -13,10 +13,7 @@ import ( ) const ( - ArgRpcURL = "rpc-url" ArgForkID = "fork-id" - - defaultRPCURL = "http://localhost:8545" ) //go:embed publish.md @@ -141,9 +138,12 @@ func publish(cmd *cobra.Command, args []string) error { func init() { f := Cmd.Flags() - f.StringVar(&publishInputArgs.rpcURL, ArgRpcURL, defaultRPCURL, "RPC URL of network") + f.StringVar(&publishInputArgs.rpcURL, util.FlagRPCURL, util.DefaultRPCURL, "RPC URL of network") f.Uint64VarP(&publishInputArgs.concurrency, "concurrency", "c", 1, "number of txs to send concurrently (default: one at a time)") f.Uint64Var(&publishInputArgs.jobQueueSize, "job-queue-size", 100, "number of jobs we can put in the job queue for workers to process") f.StringVar(&publishInputArgs.inputFileName, "file", "", "provide a filename with transactions to publish") f.Uint64Var(&publishInputArgs.rateLimit, "rate-limit", 0, "rate limit in txs per second (default: no limit)") + + // Mark required flags + util.MarkFlagRequired(Cmd, util.FlagRPCURL) } diff --git a/cmd/rpcfuzz/cmd.go b/cmd/rpcfuzz/cmd.go index b984a15f3..61038e7b5 100644 --- a/cmd/rpcfuzz/cmd.go +++ b/cmd/rpcfuzz/cmd.go @@ -84,6 +84,10 @@ func init() { fuzzer = fuzz.New() fuzzer.Funcs(argfuzz.FuzzRPCArgs) + + // Mark required flags + util.MarkFlagRequired(RPCFuzzCmd, util.FlagRPCURL) + util.MarkFlagRequired(RPCFuzzCmd, util.FlagPrivateKey) } func checkFlags() (err error) { diff --git a/cmd/signer/signer.go b/cmd/signer/signer.go index 56cf9d899..03d84deb5 100644 --- a/cmd/signer/signer.go +++ b/cmd/signer/signer.go @@ -241,9 +241,6 @@ var ImportCmd = &cobra.Command{ if err := sanityCheck(cmd, args); err != nil { return err } - if err := cmd.MarkFlagRequired("private-key"); err != nil { - return err - } return nil }, RunE: func(cmd *cobra.Command, args []string) error { @@ -867,4 +864,7 @@ func init() { f.StringVar(&inputSignerOpts.gcpKeyRingID, "gcp-keyring-id", "polycli-keyring", "GCP keyring ID to be used") f.StringVar(&inputSignerOpts.gcpImportJob, "gcp-import-job-id", "", "GCP import job ID to use when importing key") f.IntVar(&inputSignerOpts.gcpKeyVersion, "gcp-key-version", 1, "GCP crypto key version to use") + + // Mark required flags + util.MarkFlagRequired(SignerCmd, util.FlagPrivateKey) } diff --git a/util/flag.go b/util/flag.go index 84e71ba9c..8abd57bf9 100644 --- a/util/flag.go +++ b/util/flag.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -13,36 +14,56 @@ const ( FlagRPCURL = "rpc-url" // FlagPrivateKey is the standard flag name for private keys. FlagPrivateKey = "private-key" + + // DefaultRPCURL is the default RPC endpoint URL. + DefaultRPCURL = "http://localhost:8545" ) -// GetRequiredFlag retrieves a flag value from Viper after binding it and marking it as required. -// It binds the flag to enable environment variable fallback via Viper, marks the flag as required, -// and returns the flag's value. -func GetRequiredFlag(cmd *cobra.Command, flagName string) (string, error) { +// GetFlag retrieves a flag value from Viper after binding it. +// It binds the flag to enable environment variable fallback via Viper. +func GetFlag(cmd *cobra.Command, flagName string) string { viper.BindPFlag(flagName, cmd.Flags().Lookup(flagName)) - if err := cmd.MarkFlagRequired(flagName); err != nil { - return "", err - } - return viper.GetString(flagName), nil + return viper.GetString(flagName) } -// GetRPCURL retrieves the rpc-url flag value from Viper after binding it, marking it as required, -// and validating that it is a valid URL with a supported scheme (http, https, ws, wss). +// GetRPCURL retrieves the rpc-url flag value from Viper after binding it and validates +// that it is a valid URL with a supported scheme (http, https, ws, wss). func GetRPCURL(cmd *cobra.Command) (string, error) { - rpcURL, err := GetRequiredFlag(cmd, FlagRPCURL) - if err != nil { - return "", err - } + rpcURL := GetFlag(cmd, FlagRPCURL) if err := ValidateUrl(rpcURL); err != nil { return "", err } return rpcURL, nil } -// GetPrivateKey retrieves the private-key flag value from Viper after binding it and marking it as required. -// This is a convenience wrapper around GetRequiredFlag for the standard private key flag. +// GetPrivateKey retrieves the private-key flag value from Viper after binding it. +// This is a convenience wrapper around GetFlag for the standard private key flag. func GetPrivateKey(cmd *cobra.Command) (string, error) { - return GetRequiredFlag(cmd, FlagPrivateKey) + return GetFlag(cmd, FlagPrivateKey), nil +} + +// MarkFlagRequired marks a regular flag as required and logs a fatal error if marking fails. +// This helper ensures consistent error handling across all commands when marking flags as required. +func MarkFlagRequired(cmd *cobra.Command, flagName string) { + if err := cmd.MarkFlagRequired(flagName); err != nil { + log.Fatal(). + Err(err). + Str("flag", flagName). + Str("command", cmd.Name()). + Msg("Failed to mark flag as required") + } +} + +// MarkPersistentFlagRequired marks a persistent flag as required and logs a fatal error if marking fails. +// This helper ensures consistent error handling across all commands when marking persistent flags as required. +func MarkPersistentFlagRequired(cmd *cobra.Command, flagName string) { + if err := cmd.MarkPersistentFlagRequired(flagName); err != nil { + log.Fatal(). + Err(err). + Str("flag", flagName). + Str("command", cmd.Name()). + Msg("Failed to mark persistent flag as required") + } } // BigIntValue is a custom flag type for big.Int values. From 4e62514cb52b0b3f487ffffddfa4206ce47c5ca2 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 13:59:33 -0400 Subject: [PATCH 04/31] feat: flag package --- cmd/cdk/cdk.go | 8 ++++---- cmd/contract/cmd.go | 10 +++++----- cmd/dumpblocks/dumpblocks.go | 5 +++-- cmd/ecrecover/ecrecover.go | 5 +++-- cmd/fixnoncegap/fixnoncegap.go | 14 +++++++------- cmd/fund/cmd.go | 12 ++++++------ cmd/loadtest/app.go | 12 ++++++------ cmd/monitor/cmd.go | 5 +++-- cmd/nodekey/nodekey.go | 6 +++--- cmd/publish/publish.go | 8 ++++---- cmd/rpcfuzz/cmd.go | 10 +++++----- cmd/signer/signer.go | 6 +++--- cmd/ulxly/ulxly.go | 6 +++--- doc/polycli_dumpblocks.md | 2 +- flag/bigint.go | 30 ++++++++++++++++++++++++++++++ {util => flag}/flag.go | 32 +++----------------------------- 16 files changed, 89 insertions(+), 82 deletions(-) create mode 100644 flag/bigint.go rename {util => flag}/flag.go (74%) diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index da4d4787c..f8d9a1587 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -12,7 +12,7 @@ import ( "time" "github.com/0xPolygon/polygon-cli/custom_marshaller" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -105,7 +105,7 @@ var CDKCmd = &cobra.Command{ Short: "Utilities for interacting with CDK networks", Long: "Basic utility commands for interacting with the cdk contracts", PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { - cdkInputArgs.rpcURL, err = util.GetRPCURL(cmd) + cdkInputArgs.rpcURL, err = flag.GetRPCURL(cmd) if err != nil { return err } @@ -635,7 +635,7 @@ func mustPrintLogs(logs []types.Log, contractInstance reflect.Value, contractABI func init() { // cdk f := CDKCmd.PersistentFlags() - f.StringVar(&cdkInputArgs.rpcURL, util.FlagRPCURL, util.DefaultRPCURL, "RPC URL of network containing CDK contracts") + f.StringVar(&cdkInputArgs.rpcURL, flag.FlagRPCURL, flag.DefaultRPCURL, "RPC URL of network containing CDK contracts") f.StringVar(&cdkInputArgs.forkID, ArgForkID, defaultForkId, "fork ID of CDK networks") f.StringVar(&cdkInputArgs.rollupManagerAddress, ArgRollupManagerAddress, "", "address of rollup contract") @@ -677,5 +677,5 @@ func init() { gerCmd.AddCommand(gerMonitorCmd) // Mark required flags - util.MarkPersistentFlagRequired(CDKCmd, util.FlagRPCURL) + flag.MarkPersistentFlagRequired(CDKCmd, flag.FlagRPCURL) } diff --git a/cmd/contract/cmd.go b/cmd/contract/cmd.go index ed5573b80..2ea89da25 100644 --- a/cmd/contract/cmd.go +++ b/cmd/contract/cmd.go @@ -8,7 +8,7 @@ import ( "math/big" "strings" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -44,7 +44,7 @@ var Cmd = &cobra.Command{ Short: "Interact with smart contracts and fetch contract information from the blockchain", Long: usage, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputArgs.rpcURL, err = util.GetRPCURL(cmd) + inputArgs.rpcURL, err = flag.GetRPCURL(cmd) if err != nil { return err } @@ -171,10 +171,10 @@ func fetchContractCreationTx(ctx context.Context, client *ethclient.Client, cont func init() { f := Cmd.Flags() - f.StringVar(&inputArgs.rpcURL, util.FlagRPCURL, util.DefaultRPCURL, "RPC URL of network containing contract") + f.StringVar(&inputArgs.rpcURL, flag.FlagRPCURL, flag.DefaultRPCURL, "RPC URL of network containing contract") f.StringVar(&inputArgs.address, ArgAddress, "", "contract address") // Mark required flags - util.MarkFlagRequired(Cmd, ArgAddress) - util.MarkFlagRequired(Cmd, util.FlagRPCURL) + flag.MarkFlagRequired(Cmd, ArgAddress) + flag.MarkFlagRequired(Cmd, flag.FlagRPCURL) } diff --git a/cmd/dumpblocks/dumpblocks.go b/cmd/dumpblocks/dumpblocks.go index 13bf191d9..003a05484 100644 --- a/cmd/dumpblocks/dumpblocks.go +++ b/cmd/dumpblocks/dumpblocks.go @@ -15,6 +15,7 @@ import ( "github.com/0xPolygon/polygon-cli/proto/gen/pb" "github.com/0xPolygon/polygon-cli/rpctypes" "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" ethrpc "github.com/ethereum/go-ethereum/rpc" "github.com/rs/zerolog/log" "github.com/spf13/cobra" @@ -55,7 +56,7 @@ var DumpblocksCmd = &cobra.Command{ Short: "Export a range of blocks from a JSON-RPC endpoint.", Long: usage, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputDumpblocks.RpcUrl, err = util.GetRPCURL(cmd) + inputDumpblocks.RpcUrl, err = flag.GetRPCURL(cmd) if err != nil { return err } @@ -195,7 +196,7 @@ func init() { f.StringVarP(&inputDumpblocks.FilterStr, "filter", "F", "{}", "filter output based on tx to and from, not setting a filter means all are allowed") // Mark required flags - util.MarkFlagRequired(DumpblocksCmd, util.FlagRPCURL) + flag.MarkFlagRequired(DumpblocksCmd, flag.FlagRPCURL) } // writeResponses writes the data to either stdout or a file if one is provided. diff --git a/cmd/ecrecover/ecrecover.go b/cmd/ecrecover/ecrecover.go index 069e11d1d..a8547ec81 100644 --- a/cmd/ecrecover/ecrecover.go +++ b/cmd/ecrecover/ecrecover.go @@ -8,6 +8,7 @@ import ( "os" "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -32,7 +33,7 @@ var EcRecoverCmd = &cobra.Command{ Long: usage, Args: cobra.NoArgs, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - rpcUrl, err = util.GetRPCURL(cmd) + rpcUrl, err = flag.GetRPCURL(cmd) if err != nil { return err } @@ -136,5 +137,5 @@ func init() { EcRecoverCmd.MarkFlagsMutuallyExclusive("file", "block-number", "tx") // Mark required flags - util.MarkFlagRequired(EcRecoverCmd, util.FlagRPCURL) + flag.MarkFlagRequired(EcRecoverCmd, flag.FlagRPCURL) } diff --git a/cmd/fixnoncegap/fixnoncegap.go b/cmd/fixnoncegap/fixnoncegap.go index 236b57cee..f6480cf6e 100644 --- a/cmd/fixnoncegap/fixnoncegap.go +++ b/cmd/fixnoncegap/fixnoncegap.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -26,11 +26,11 @@ var FixNonceGapCmd = &cobra.Command{ Long: fixNonceGapUsage, Args: cobra.NoArgs, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputFixNonceGapArgs.rpcURL, err = util.GetRPCURL(cmd) + inputFixNonceGapArgs.rpcURL, err = flag.GetRPCURL(cmd) if err != nil { return err } - inputFixNonceGapArgs.privateKey, err = util.GetPrivateKey(cmd) + inputFixNonceGapArgs.privateKey, err = flag.GetPrivateKey(cmd) if err != nil { return err } @@ -227,14 +227,14 @@ func fixNonceGap(cmd *cobra.Command, args []string) error { func init() { f := FixNonceGapCmd.Flags() - f.StringVarP(&inputFixNonceGapArgs.rpcURL, util.FlagRPCURL, "r", "http://localhost:8545", "the RPC endpoint URL") - f.StringVar(&inputFixNonceGapArgs.privateKey, util.FlagPrivateKey, "", "private key to be used when sending txs to fix nonce gap") + f.StringVarP(&inputFixNonceGapArgs.rpcURL, flag.FlagRPCURL, "r", "http://localhost:8545", "the RPC endpoint URL") + f.StringVar(&inputFixNonceGapArgs.privateKey, flag.FlagPrivateKey, "", "private key to be used when sending txs to fix nonce gap") f.BoolVar(&inputFixNonceGapArgs.replace, ArgReplace, false, "replace the existing txs in the pool") f.Uint64Var(&inputFixNonceGapArgs.maxNonce, ArgMaxNonce, 0, "override max nonce value instead of getting it from the pool") // Mark required flags - util.MarkFlagRequired(FixNonceGapCmd, util.FlagRPCURL) - util.MarkFlagRequired(FixNonceGapCmd, util.FlagPrivateKey) + flag.MarkFlagRequired(FixNonceGapCmd, flag.FlagRPCURL) + flag.MarkFlagRequired(FixNonceGapCmd, flag.FlagPrivateKey) } // Wait for the transaction to be mined diff --git a/cmd/fund/cmd.go b/cmd/fund/cmd.go index 34e3947b7..f01a9cbc0 100644 --- a/cmd/fund/cmd.go +++ b/cmd/fund/cmd.go @@ -6,7 +6,7 @@ import ( _ "embed" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/spf13/cobra" ) @@ -48,11 +48,11 @@ var FundCmd = &cobra.Command{ Short: "Bulk fund crypto wallets automatically.", Long: usage, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - params.RpcUrl, err = util.GetRPCURL(cmd) + params.RpcUrl, err = flag.GetRPCURL(cmd) if err != nil { return err } - params.PrivateKey, err = util.GetPrivateKey(cmd) + params.PrivateKey, err = flag.GetPrivateKey(cmd) if err != nil { return err } @@ -74,7 +74,7 @@ func init() { f.BoolVar(¶ms.UseHDDerivation, "hd-derivation", true, "derive wallets to fund from private key in deterministic way") f.StringSliceVar(¶ms.WalletAddresses, "addresses", nil, "comma-separated list of wallet addresses to fund") params.FundingAmountInWei = defaultFundingInWei - f.Var(&util.BigIntValue{Val: params.FundingAmountInWei}, "eth-amount", "amount of wei to send to each wallet") + f.Var(&flag.BigIntValue{Val: params.FundingAmountInWei}, "eth-amount", "amount of wei to send to each wallet") f.StringVar(¶ms.KeyFile, "key-file", "", "file containing accounts private keys, one per line") f.StringVarP(¶ms.OutputFile, "file", "f", "wallets.json", "output JSON file path for storing addresses and private keys of funded wallets") @@ -90,8 +90,8 @@ func init() { FundCmd.MarkFlagsOneRequired("addresses", "key-file", "number") // Mark required flags - util.MarkFlagRequired(FundCmd, util.FlagRPCURL) - util.MarkFlagRequired(FundCmd, util.FlagPrivateKey) + flag.MarkFlagRequired(FundCmd, flag.FlagRPCURL) + flag.MarkFlagRequired(FundCmd, flag.FlagPrivateKey) // Funder contract parameters. f.StringVar(¶ms.FunderAddress, "contract-address", "", "address of pre-deployed Funder contract") diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index 876069d23..980df5b40 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -10,7 +10,7 @@ import ( "time" "github.com/0xPolygon/polygon-cli/rpctypes" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" "github.com/spf13/cobra" @@ -172,11 +172,11 @@ var LoadtestCmd = &cobra.Command{ Long: loadTestUsage, Args: cobra.NoArgs, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputLoadTestParams.RPCUrl, err = util.GetRPCURL(cmd) + inputLoadTestParams.RPCUrl, err = flag.GetRPCURL(cmd) if err != nil { return err } - inputLoadTestParams.PrivateKey, err = util.GetPrivateKey(cmd) + inputLoadTestParams.PrivateKey, err = flag.GetPrivateKey(cmd) if err != nil { return err } @@ -270,7 +270,7 @@ func initFlags() { f.Uint64Var(<p.BlobFeeCap, "blob-fee-cap", 100000, "blob fee cap, or maximum blob fee per chunk, in Gwei") f.Uint64Var(<p.SendingAccountsCount, "sending-accounts-count", 0, "number of sending accounts to use (avoids pool account queue)") ltp.AccountFundingAmount = defaultAccountFundingAmount - f.Var(&util.BigIntValue{Val: ltp.AccountFundingAmount}, "account-funding-amount", "amount in wei to fund sending accounts (set to 0 to disable)") + f.Var(&flag.BigIntValue{Val: ltp.AccountFundingAmount}, "account-funding-amount", "amount in wei to fund sending accounts (set to 0 to disable)") f.BoolVar(<p.PreFundSendingAccounts, "pre-fund-sending-accounts", false, "fund all sending accounts at start instead of on first use") f.BoolVar(<p.RefundRemainingFunds, "refund-remaining-funds", false, "refund remaining balance to funding account after completion") f.StringVar(<p.SendingAccountsFile, "sending-accounts-file", "", "file with sending account private keys, one per line (avoids pool queue and preserves accounts across runs)") @@ -304,8 +304,8 @@ v3, uniswapv3 - perform UniswapV3 swaps`) // TODO Compression // Mark required flags - util.MarkPersistentFlagRequired(LoadtestCmd, util.FlagRPCURL) - util.MarkPersistentFlagRequired(LoadtestCmd, util.FlagPrivateKey) + flag.MarkPersistentFlagRequired(LoadtestCmd, flag.FlagRPCURL) + flag.MarkPersistentFlagRequired(LoadtestCmd, flag.FlagPrivateKey) } func initSubCommands() { diff --git a/cmd/monitor/cmd.go b/cmd/monitor/cmd.go index c8be27034..3ffc1184c 100644 --- a/cmd/monitor/cmd.go +++ b/cmd/monitor/cmd.go @@ -8,6 +8,7 @@ import ( "time" "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/spf13/cobra" ) @@ -57,7 +58,7 @@ var MonitorCmd = &cobra.Command{ Args: cobra.NoArgs, SilenceUsage: true, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - rpcUrl, err = util.GetRPCURL(cmd) + rpcUrl, err = flag.GetRPCURL(cmd) if err != nil { return err } @@ -89,7 +90,7 @@ func init() { f.StringVarP(&intervalStr, "interval", "i", "5s", "amount of time between batch block RPC calls") // Mark required flags - util.MarkFlagRequired(MonitorCmd, util.FlagRPCURL) + flag.MarkFlagRequired(MonitorCmd, flag.FlagRPCURL) } func checkFlags() (err error) { diff --git a/cmd/nodekey/nodekey.go b/cmd/nodekey/nodekey.go index ccda48879..92ab5d5f2 100644 --- a/cmd/nodekey/nodekey.go +++ b/cmd/nodekey/nodekey.go @@ -18,7 +18,7 @@ import ( gethcrypto "github.com/ethereum/go-ethereum/crypto" gethenode "github.com/ethereum/go-ethereum/p2p/enode" libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" libp2ppeer "github.com/libp2p/go-libp2p/core/peer" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -67,7 +67,7 @@ var NodekeyCmd = &cobra.Command{ Short: "Generate node keys for different blockchain clients and protocols.", Long: usage, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputNodeKeyPrivateKey, err = util.GetPrivateKey(cmd) + inputNodeKeyPrivateKey, err = flag.GetPrivateKey(cmd) if err != nil { return err } @@ -301,5 +301,5 @@ func init() { f.BoolVarP(&inputNodeKeyMarshalProtobuf, "marshal-protobuf", "m", false, "marshal libp2p key to protobuf format instead of raw") // Mark required flags - util.MarkFlagRequired(NodekeyCmd, util.FlagPrivateKey) + flag.MarkFlagRequired(NodekeyCmd, flag.FlagPrivateKey) } diff --git a/cmd/publish/publish.go b/cmd/publish/publish.go index 16b3d22bc..73eaf019d 100644 --- a/cmd/publish/publish.go +++ b/cmd/publish/publish.go @@ -5,7 +5,7 @@ import ( _ "embed" "time" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/ethereum/go-ethereum/ethclient" "github.com/rs/zerolog/log" "github.com/spf13/cobra" @@ -24,7 +24,7 @@ var Cmd = &cobra.Command{ Short: "Publish transactions to the network with high-throughput", Long: cmdUsage, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - publishInputArgs.rpcURL, err = util.GetRPCURL(cmd) + publishInputArgs.rpcURL, err = flag.GetRPCURL(cmd) if err != nil { return err } @@ -138,12 +138,12 @@ func publish(cmd *cobra.Command, args []string) error { func init() { f := Cmd.Flags() - f.StringVar(&publishInputArgs.rpcURL, util.FlagRPCURL, util.DefaultRPCURL, "RPC URL of network") + f.StringVar(&publishInputArgs.rpcURL, flag.FlagRPCURL, flag.DefaultRPCURL, "RPC URL of network") f.Uint64VarP(&publishInputArgs.concurrency, "concurrency", "c", 1, "number of txs to send concurrently (default: one at a time)") f.Uint64Var(&publishInputArgs.jobQueueSize, "job-queue-size", 100, "number of jobs we can put in the job queue for workers to process") f.StringVar(&publishInputArgs.inputFileName, "file", "", "provide a filename with transactions to publish") f.Uint64Var(&publishInputArgs.rateLimit, "rate-limit", 0, "rate limit in txs per second (default: no limit)") // Mark required flags - util.MarkFlagRequired(Cmd, util.FlagRPCURL) + flag.MarkFlagRequired(Cmd, flag.FlagRPCURL) } diff --git a/cmd/rpcfuzz/cmd.go b/cmd/rpcfuzz/cmd.go index 61038e7b5..1a6acbb8d 100644 --- a/cmd/rpcfuzz/cmd.go +++ b/cmd/rpcfuzz/cmd.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/0xPolygon/polygon-cli/cmd/rpcfuzz/argfuzz" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/ethereum/go-ethereum/crypto" fuzz "github.com/google/gofuzz" "github.com/rs/zerolog/log" @@ -42,11 +42,11 @@ var RPCFuzzCmd = &cobra.Command{ Long: usage, Args: cobra.NoArgs, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - rpcUrl, err = util.GetRPCURL(cmd) + rpcUrl, err = flag.GetRPCURL(cmd) if err != nil { return err } - testPrivateHexKey, err = util.GetPrivateKey(cmd) + testPrivateHexKey, err = flag.GetPrivateKey(cmd) if err != nil { return err } @@ -86,8 +86,8 @@ func init() { fuzzer.Funcs(argfuzz.FuzzRPCArgs) // Mark required flags - util.MarkFlagRequired(RPCFuzzCmd, util.FlagRPCURL) - util.MarkFlagRequired(RPCFuzzCmd, util.FlagPrivateKey) + flag.MarkFlagRequired(RPCFuzzCmd, flag.FlagRPCURL) + flag.MarkFlagRequired(RPCFuzzCmd, flag.FlagPrivateKey) } func checkFlags() (err error) { diff --git a/cmd/signer/signer.go b/cmd/signer/signer.go index 03d84deb5..aed2ccea8 100644 --- a/cmd/signer/signer.go +++ b/cmd/signer/signer.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/google/tink/go/kwp/subtle" "github.com/manifoldco/promptui" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "google.golang.org/api/iterator" @@ -80,7 +80,7 @@ var SignerCmd = &cobra.Command{ Short: "Utilities for security signing transactions", Long: signerUsage, PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputSignerOpts.privateKey, err = util.GetPrivateKey(cmd) + inputSignerOpts.privateKey, err = flag.GetPrivateKey(cmd) if err != nil { return err } @@ -866,5 +866,5 @@ func init() { f.IntVar(&inputSignerOpts.gcpKeyVersion, "gcp-key-version", 1, "GCP crypto key version to use") // Mark required flags - util.MarkFlagRequired(SignerCmd, util.FlagPrivateKey) + flag.MarkFlagRequired(SignerCmd, flag.FlagPrivateKey) } diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 97326681c..570883d9a 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -35,7 +35,7 @@ import ( "github.com/0xPolygon/polygon-cli/bindings/ulxly" "github.com/0xPolygon/polygon-cli/bindings/ulxly/polygonrollupmanager" smcerror "github.com/0xPolygon/polygon-cli/errors" - "github.com/0xPolygon/polygon-cli/util" + "github.com/0xPolygon/polygon-cli/flag" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -2078,11 +2078,11 @@ var ulxlyBridgeAndClaimCmd = &cobra.Command{ Args: cobra.NoArgs, Hidden: true, PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputUlxlyArgs.rpcURL, err = util.GetRPCURL(cmd) + inputUlxlyArgs.rpcURL, err = flag.GetRPCURL(cmd) if err != nil { return err } - inputUlxlyArgs.privateKey, err = util.GetPrivateKey(cmd) + inputUlxlyArgs.privateKey, err = flag.GetPrivateKey(cmd) if err != nil { return err } diff --git a/doc/polycli_dumpblocks.md b/doc/polycli_dumpblocks.md index ce5aa98fc..114fd6fe7 100644 --- a/doc/polycli_dumpblocks.md +++ b/doc/polycli_dumpblocks.md @@ -79,7 +79,7 @@ To solve this, add the unknown fields to the `.proto` files and recompile them ( -B, --dump-blocks dump blocks to output (default true) --dump-receipts dump receipts to output (default true) -f, --filename string where to write the output to (default stdout) - -F, --filter string filter output based on tx to and from (not setting a filter means all are allowed) (default "{}") + -F, --filter string filter output based on tx to and from, not setting a filter means all are allowed (default "{}") -h, --help help for dumpblocks -m, --mode string the output format [json, proto] (default "json") -r, --rpc-url string the RPC endpoint URL (default "http://localhost:8545") diff --git a/flag/bigint.go b/flag/bigint.go new file mode 100644 index 000000000..09ad027f6 --- /dev/null +++ b/flag/bigint.go @@ -0,0 +1,30 @@ +package flag + +import ( + "fmt" + "math/big" +) + +// BigIntValue is a custom flag type for big.Int values. +// It implements the pflag.Value interface to enable using *big.Int with Cobra flags. +type BigIntValue struct { + Val *big.Int +} + +// String returns the decimal string representation of the big.Int value. +func (b *BigIntValue) String() string { + return b.Val.String() +} + +// Set parses a decimal string and sets the big.Int value. +func (b *BigIntValue) Set(s string) error { + if _, ok := b.Val.SetString(s, 10); !ok { + return fmt.Errorf("invalid big integer: %q", s) + } + return nil +} + +// Type returns the type string for this flag value. +func (b *BigIntValue) Type() string { + return "big.Int" +} diff --git a/util/flag.go b/flag/flag.go similarity index 74% rename from util/flag.go rename to flag/flag.go index 8abd57bf9..5b9c8b737 100644 --- a/util/flag.go +++ b/flag/flag.go @@ -1,9 +1,7 @@ -package util +package flag import ( - "fmt" - "math/big" - + "github.com/0xPolygon/polygon-cli/util" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -30,7 +28,7 @@ func GetFlag(cmd *cobra.Command, flagName string) string { // that it is a valid URL with a supported scheme (http, https, ws, wss). func GetRPCURL(cmd *cobra.Command) (string, error) { rpcURL := GetFlag(cmd, FlagRPCURL) - if err := ValidateUrl(rpcURL); err != nil { + if err := util.ValidateUrl(rpcURL); err != nil { return "", err } return rpcURL, nil @@ -65,27 +63,3 @@ func MarkPersistentFlagRequired(cmd *cobra.Command, flagName string) { Msg("Failed to mark persistent flag as required") } } - -// BigIntValue is a custom flag type for big.Int values. -// It implements the pflag.Value interface to enable using *big.Int with Cobra flags. -type BigIntValue struct { - Val *big.Int -} - -// String returns the decimal string representation of the big.Int value. -func (b *BigIntValue) String() string { - return b.Val.String() -} - -// Set parses a decimal string and sets the big.Int value. -func (b *BigIntValue) Set(s string) error { - if _, ok := b.Val.SetString(s, 10); !ok { - return fmt.Errorf("invalid big integer: %q", s) - } - return nil -} - -// Type returns the type string for this flag value. -func (b *BigIntValue) Type() string { - return "big.Int" -} From 97fcfc5ebd60b9725a9d089ff240bf6d67244b13 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 14:04:37 -0400 Subject: [PATCH 05/31] fix: lint --- cmd/root.go | 9 +++++++-- flag/flag.go | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index d0482052d..918afe12e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -19,6 +19,7 @@ import ( "github.com/0xPolygon/polygon-cli/cmd/fork" "github.com/0xPolygon/polygon-cli/cmd/p2p" "github.com/0xPolygon/polygon-cli/cmd/parseethwallet" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -87,8 +88,12 @@ func initConfig() { // Set up environment variable mappings for common flags viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) - viper.BindEnv("rpc-url", "ETH_RPC_URL") - viper.BindEnv("private-key", "PRIVATE_KEY") + if err := viper.BindEnv("rpc-url", "ETH_RPC_URL"); err != nil { + log.Fatal().Err(err).Msg("Failed to bind rpc-url environment variable") + } + if err := viper.BindEnv("private-key", "PRIVATE_KEY"); err != nil { + log.Fatal().Err(err).Msg("Failed to bind private-key environment variable") + } // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { diff --git a/flag/flag.go b/flag/flag.go index 5b9c8b737..d46f71294 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -20,7 +20,9 @@ const ( // GetFlag retrieves a flag value from Viper after binding it. // It binds the flag to enable environment variable fallback via Viper. func GetFlag(cmd *cobra.Command, flagName string) string { - viper.BindPFlag(flagName, cmd.Flags().Lookup(flagName)) + if err := viper.BindPFlag(flagName, cmd.Flags().Lookup(flagName)); err != nil { + log.Fatal().Err(err).Str("flag", flagName).Msg("Failed to bind flag to viper") + } return viper.GetString(flagName) } From 68662d81f160380c27fadd9f399e8778b975afdb Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 14:05:28 -0400 Subject: [PATCH 06/31] fix: fmt cdk.go --- cmd/cdk/cdk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index f8d9a1587..32ab30a47 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -52,7 +52,7 @@ const ( ArgRollupID = "rollup-id" ArgRollupAddress = "rollup-address" ArgBridgeAddress = "bridge-address" - ArgGERAddress = "ger-address" + ArgGERAddress = "ger-address" defaultForkId = "12" From f627a6ac8d9d34560d60b5c954e2a9fd025e6e6c Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 14:09:42 -0400 Subject: [PATCH 07/31] fix: rename flag names --- cmd/cdk/cdk.go | 4 ++-- cmd/contract/cmd.go | 4 ++-- cmd/dumpblocks/dumpblocks.go | 2 +- cmd/ecrecover/ecrecover.go | 2 +- cmd/fixnoncegap/fixnoncegap.go | 8 ++++---- cmd/fund/cmd.go | 4 ++-- cmd/loadtest/app.go | 4 ++-- cmd/monitor/cmd.go | 2 +- cmd/nodekey/nodekey.go | 2 +- cmd/publish/publish.go | 4 ++-- cmd/rpcfuzz/cmd.go | 4 ++-- cmd/signer/signer.go | 2 +- flag/flag.go | 12 ++++++------ 13 files changed, 27 insertions(+), 27 deletions(-) diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index 32ab30a47..8b5ca4d20 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -635,7 +635,7 @@ func mustPrintLogs(logs []types.Log, contractInstance reflect.Value, contractABI func init() { // cdk f := CDKCmd.PersistentFlags() - f.StringVar(&cdkInputArgs.rpcURL, flag.FlagRPCURL, flag.DefaultRPCURL, "RPC URL of network containing CDK contracts") + f.StringVar(&cdkInputArgs.rpcURL, flag.RPCURL, flag.DefaultRPCURL, "RPC URL of network containing CDK contracts") f.StringVar(&cdkInputArgs.forkID, ArgForkID, defaultForkId, "fork ID of CDK networks") f.StringVar(&cdkInputArgs.rollupManagerAddress, ArgRollupManagerAddress, "", "address of rollup contract") @@ -677,5 +677,5 @@ func init() { gerCmd.AddCommand(gerMonitorCmd) // Mark required flags - flag.MarkPersistentFlagRequired(CDKCmd, flag.FlagRPCURL) + flag.MarkPersistentFlagRequired(CDKCmd, flag.RPCURL) } diff --git a/cmd/contract/cmd.go b/cmd/contract/cmd.go index 2ea89da25..fb70fc6f9 100644 --- a/cmd/contract/cmd.go +++ b/cmd/contract/cmd.go @@ -171,10 +171,10 @@ func fetchContractCreationTx(ctx context.Context, client *ethclient.Client, cont func init() { f := Cmd.Flags() - f.StringVar(&inputArgs.rpcURL, flag.FlagRPCURL, flag.DefaultRPCURL, "RPC URL of network containing contract") + f.StringVar(&inputArgs.rpcURL, flag.RPCURL, flag.DefaultRPCURL, "RPC URL of network containing contract") f.StringVar(&inputArgs.address, ArgAddress, "", "contract address") // Mark required flags flag.MarkFlagRequired(Cmd, ArgAddress) - flag.MarkFlagRequired(Cmd, flag.FlagRPCURL) + flag.MarkFlagRequired(Cmd, flag.RPCURL) } diff --git a/cmd/dumpblocks/dumpblocks.go b/cmd/dumpblocks/dumpblocks.go index 003a05484..1f51358f3 100644 --- a/cmd/dumpblocks/dumpblocks.go +++ b/cmd/dumpblocks/dumpblocks.go @@ -196,7 +196,7 @@ func init() { f.StringVarP(&inputDumpblocks.FilterStr, "filter", "F", "{}", "filter output based on tx to and from, not setting a filter means all are allowed") // Mark required flags - flag.MarkFlagRequired(DumpblocksCmd, flag.FlagRPCURL) + flag.MarkFlagRequired(DumpblocksCmd, flag.RPCURL) } // writeResponses writes the data to either stdout or a file if one is provided. diff --git a/cmd/ecrecover/ecrecover.go b/cmd/ecrecover/ecrecover.go index a8547ec81..ee595f04b 100644 --- a/cmd/ecrecover/ecrecover.go +++ b/cmd/ecrecover/ecrecover.go @@ -137,5 +137,5 @@ func init() { EcRecoverCmd.MarkFlagsMutuallyExclusive("file", "block-number", "tx") // Mark required flags - flag.MarkFlagRequired(EcRecoverCmd, flag.FlagRPCURL) + flag.MarkFlagRequired(EcRecoverCmd, flag.RPCURL) } diff --git a/cmd/fixnoncegap/fixnoncegap.go b/cmd/fixnoncegap/fixnoncegap.go index f6480cf6e..c5197f41f 100644 --- a/cmd/fixnoncegap/fixnoncegap.go +++ b/cmd/fixnoncegap/fixnoncegap.go @@ -227,14 +227,14 @@ func fixNonceGap(cmd *cobra.Command, args []string) error { func init() { f := FixNonceGapCmd.Flags() - f.StringVarP(&inputFixNonceGapArgs.rpcURL, flag.FlagRPCURL, "r", "http://localhost:8545", "the RPC endpoint URL") - f.StringVar(&inputFixNonceGapArgs.privateKey, flag.FlagPrivateKey, "", "private key to be used when sending txs to fix nonce gap") + f.StringVarP(&inputFixNonceGapArgs.rpcURL, flag.RPCURL, "r", "http://localhost:8545", "the RPC endpoint URL") + f.StringVar(&inputFixNonceGapArgs.privateKey, flag.PrivateKey, "", "private key to be used when sending txs to fix nonce gap") f.BoolVar(&inputFixNonceGapArgs.replace, ArgReplace, false, "replace the existing txs in the pool") f.Uint64Var(&inputFixNonceGapArgs.maxNonce, ArgMaxNonce, 0, "override max nonce value instead of getting it from the pool") // Mark required flags - flag.MarkFlagRequired(FixNonceGapCmd, flag.FlagRPCURL) - flag.MarkFlagRequired(FixNonceGapCmd, flag.FlagPrivateKey) + flag.MarkFlagRequired(FixNonceGapCmd, flag.RPCURL) + flag.MarkFlagRequired(FixNonceGapCmd, flag.PrivateKey) } // Wait for the transaction to be mined diff --git a/cmd/fund/cmd.go b/cmd/fund/cmd.go index f01a9cbc0..6c1ed08ff 100644 --- a/cmd/fund/cmd.go +++ b/cmd/fund/cmd.go @@ -90,8 +90,8 @@ func init() { FundCmd.MarkFlagsOneRequired("addresses", "key-file", "number") // Mark required flags - flag.MarkFlagRequired(FundCmd, flag.FlagRPCURL) - flag.MarkFlagRequired(FundCmd, flag.FlagPrivateKey) + flag.MarkFlagRequired(FundCmd, flag.RPCURL) + flag.MarkFlagRequired(FundCmd, flag.PrivateKey) // Funder contract parameters. f.StringVar(¶ms.FunderAddress, "contract-address", "", "address of pre-deployed Funder contract") diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index 980df5b40..19a7521b2 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -304,8 +304,8 @@ v3, uniswapv3 - perform UniswapV3 swaps`) // TODO Compression // Mark required flags - flag.MarkPersistentFlagRequired(LoadtestCmd, flag.FlagRPCURL) - flag.MarkPersistentFlagRequired(LoadtestCmd, flag.FlagPrivateKey) + flag.MarkPersistentFlagRequired(LoadtestCmd, flag.RPCURL) + flag.MarkPersistentFlagRequired(LoadtestCmd, flag.PrivateKey) } func initSubCommands() { diff --git a/cmd/monitor/cmd.go b/cmd/monitor/cmd.go index 3ffc1184c..93ffa98d3 100644 --- a/cmd/monitor/cmd.go +++ b/cmd/monitor/cmd.go @@ -90,7 +90,7 @@ func init() { f.StringVarP(&intervalStr, "interval", "i", "5s", "amount of time between batch block RPC calls") // Mark required flags - flag.MarkFlagRequired(MonitorCmd, flag.FlagRPCURL) + flag.MarkFlagRequired(MonitorCmd, flag.RPCURL) } func checkFlags() (err error) { diff --git a/cmd/nodekey/nodekey.go b/cmd/nodekey/nodekey.go index 92ab5d5f2..7b00a257d 100644 --- a/cmd/nodekey/nodekey.go +++ b/cmd/nodekey/nodekey.go @@ -301,5 +301,5 @@ func init() { f.BoolVarP(&inputNodeKeyMarshalProtobuf, "marshal-protobuf", "m", false, "marshal libp2p key to protobuf format instead of raw") // Mark required flags - flag.MarkFlagRequired(NodekeyCmd, flag.FlagPrivateKey) + flag.MarkFlagRequired(NodekeyCmd, flag.PrivateKey) } diff --git a/cmd/publish/publish.go b/cmd/publish/publish.go index 73eaf019d..d64ec58c7 100644 --- a/cmd/publish/publish.go +++ b/cmd/publish/publish.go @@ -138,12 +138,12 @@ func publish(cmd *cobra.Command, args []string) error { func init() { f := Cmd.Flags() - f.StringVar(&publishInputArgs.rpcURL, flag.FlagRPCURL, flag.DefaultRPCURL, "RPC URL of network") + f.StringVar(&publishInputArgs.rpcURL, flag.RPCURL, flag.DefaultRPCURL, "RPC URL of network") f.Uint64VarP(&publishInputArgs.concurrency, "concurrency", "c", 1, "number of txs to send concurrently (default: one at a time)") f.Uint64Var(&publishInputArgs.jobQueueSize, "job-queue-size", 100, "number of jobs we can put in the job queue for workers to process") f.StringVar(&publishInputArgs.inputFileName, "file", "", "provide a filename with transactions to publish") f.Uint64Var(&publishInputArgs.rateLimit, "rate-limit", 0, "rate limit in txs per second (default: no limit)") // Mark required flags - flag.MarkFlagRequired(Cmd, flag.FlagRPCURL) + flag.MarkFlagRequired(Cmd, flag.RPCURL) } diff --git a/cmd/rpcfuzz/cmd.go b/cmd/rpcfuzz/cmd.go index 1a6acbb8d..e6719405e 100644 --- a/cmd/rpcfuzz/cmd.go +++ b/cmd/rpcfuzz/cmd.go @@ -86,8 +86,8 @@ func init() { fuzzer.Funcs(argfuzz.FuzzRPCArgs) // Mark required flags - flag.MarkFlagRequired(RPCFuzzCmd, flag.FlagRPCURL) - flag.MarkFlagRequired(RPCFuzzCmd, flag.FlagPrivateKey) + flag.MarkFlagRequired(RPCFuzzCmd, flag.RPCURL) + flag.MarkFlagRequired(RPCFuzzCmd, flag.PrivateKey) } func checkFlags() (err error) { diff --git a/cmd/signer/signer.go b/cmd/signer/signer.go index aed2ccea8..42718d5c4 100644 --- a/cmd/signer/signer.go +++ b/cmd/signer/signer.go @@ -866,5 +866,5 @@ func init() { f.IntVar(&inputSignerOpts.gcpKeyVersion, "gcp-key-version", 1, "GCP crypto key version to use") // Mark required flags - flag.MarkFlagRequired(SignerCmd, flag.FlagPrivateKey) + flag.MarkFlagRequired(SignerCmd, flag.PrivateKey) } diff --git a/flag/flag.go b/flag/flag.go index d46f71294..83c510e87 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -8,10 +8,10 @@ import ( ) const ( - // FlagRPCURL is the standard flag name for RPC endpoint URLs. - FlagRPCURL = "rpc-url" - // FlagPrivateKey is the standard flag name for private keys. - FlagPrivateKey = "private-key" + // RPCURL is the standard flag name for RPC endpoint URLs. + RPCURL = "rpc-url" + // PrivateKey is the standard flag name for private keys. + PrivateKey = "private-key" // DefaultRPCURL is the default RPC endpoint URL. DefaultRPCURL = "http://localhost:8545" @@ -29,7 +29,7 @@ func GetFlag(cmd *cobra.Command, flagName string) string { // GetRPCURL retrieves the rpc-url flag value from Viper after binding it and validates // that it is a valid URL with a supported scheme (http, https, ws, wss). func GetRPCURL(cmd *cobra.Command) (string, error) { - rpcURL := GetFlag(cmd, FlagRPCURL) + rpcURL := GetFlag(cmd, RPCURL) if err := util.ValidateUrl(rpcURL); err != nil { return "", err } @@ -39,7 +39,7 @@ func GetRPCURL(cmd *cobra.Command) (string, error) { // GetPrivateKey retrieves the private-key flag value from Viper after binding it. // This is a convenience wrapper around GetFlag for the standard private key flag. func GetPrivateKey(cmd *cobra.Command) (string, error) { - return GetFlag(cmd, FlagPrivateKey), nil + return GetFlag(cmd, PrivateKey), nil } // MarkFlagRequired marks a regular flag as required and logs a fatal error if marking fails. From 365447f91c49a81da87020e83eedfaa0359411d1 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 14:31:27 -0400 Subject: [PATCH 08/31] fix: remove rpc check --- cmd/loadtest/app.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index 19a7521b2..721f88aa8 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -9,8 +9,8 @@ import ( "sync" "time" - "github.com/0xPolygon/polygon-cli/rpctypes" "github.com/0xPolygon/polygon-cli/flag" + "github.com/0xPolygon/polygon-cli/rpctypes" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" "github.com/spf13/cobra" @@ -193,11 +193,6 @@ var LoadtestCmd = &cobra.Command{ func checkLoadtestFlags() error { ltp := inputLoadTestParams - // Check `rpc-url` flag. - if ltp.RPCUrl == "" { - return fmt.Errorf("RPC URL is empty") - } - if ltp.AdaptiveBackoffFactor <= 0.0 { return fmt.Errorf("the backoff factor needs to be non-zero positive. Given: %f", ltp.AdaptiveBackoffFactor) } From 1b481418963a4135ddbdbba815dc3a0e29922887 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 14:39:32 -0400 Subject: [PATCH 09/31] fix: typo --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 70ed2ba4f..acf59c390 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -179,7 +179,7 @@ jobs: sudo apt-get install ethereum geth --version fi - - name: Run loadtest againt ${{ matrix.tool }} + - name: Run loadtest against ${{ matrix.tool }} run: | ${{ matrix.tool }} --version make ${{ matrix.tool }} & From a6f712c2c3e9503695671da2596ee3e0e9909516 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 14:58:58 -0400 Subject: [PATCH 10/31] fix: remove as required if there is a default --- cmd/cdk/cdk.go | 3 --- cmd/contract/cmd.go | 1 - cmd/dumpblocks/dumpblocks.go | 3 --- cmd/fixnoncegap/fixnoncegap.go | 1 - cmd/fund/cmd.go | 4 ---- cmd/loadtest/app.go | 4 ---- cmd/metricsToDash/metricsToDash.go | 2 +- cmd/monitor/cmd.go | 3 --- cmd/publish/publish.go | 3 --- cmd/root.go | 4 ++-- cmd/rpcfuzz/cmd.go | 4 ---- 11 files changed, 3 insertions(+), 29 deletions(-) diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index 8b5ca4d20..adad1656e 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -675,7 +675,4 @@ func init() { gerCmd.AddCommand(gerInspectCmd) gerCmd.AddCommand(gerDumpCmd) gerCmd.AddCommand(gerMonitorCmd) - - // Mark required flags - flag.MarkPersistentFlagRequired(CDKCmd, flag.RPCURL) } diff --git a/cmd/contract/cmd.go b/cmd/contract/cmd.go index fb70fc6f9..cc00e07ec 100644 --- a/cmd/contract/cmd.go +++ b/cmd/contract/cmd.go @@ -176,5 +176,4 @@ func init() { // Mark required flags flag.MarkFlagRequired(Cmd, ArgAddress) - flag.MarkFlagRequired(Cmd, flag.RPCURL) } diff --git a/cmd/dumpblocks/dumpblocks.go b/cmd/dumpblocks/dumpblocks.go index 1f51358f3..1af1ea429 100644 --- a/cmd/dumpblocks/dumpblocks.go +++ b/cmd/dumpblocks/dumpblocks.go @@ -194,9 +194,6 @@ func init() { f.StringVarP(&inputDumpblocks.Mode, "mode", "m", "json", "the output format [json, proto]") f.Uint64VarP(&inputDumpblocks.BatchSize, "batch-size", "b", 150, "batch size for requests (most providers cap at 1000)") f.StringVarP(&inputDumpblocks.FilterStr, "filter", "F", "{}", "filter output based on tx to and from, not setting a filter means all are allowed") - - // Mark required flags - flag.MarkFlagRequired(DumpblocksCmd, flag.RPCURL) } // writeResponses writes the data to either stdout or a file if one is provided. diff --git a/cmd/fixnoncegap/fixnoncegap.go b/cmd/fixnoncegap/fixnoncegap.go index c5197f41f..d88f598fb 100644 --- a/cmd/fixnoncegap/fixnoncegap.go +++ b/cmd/fixnoncegap/fixnoncegap.go @@ -233,7 +233,6 @@ func init() { f.Uint64Var(&inputFixNonceGapArgs.maxNonce, ArgMaxNonce, 0, "override max nonce value instead of getting it from the pool") // Mark required flags - flag.MarkFlagRequired(FixNonceGapCmd, flag.RPCURL) flag.MarkFlagRequired(FixNonceGapCmd, flag.PrivateKey) } diff --git a/cmd/fund/cmd.go b/cmd/fund/cmd.go index 6c1ed08ff..bb32878c6 100644 --- a/cmd/fund/cmd.go +++ b/cmd/fund/cmd.go @@ -89,10 +89,6 @@ func init() { // Require at least one method to specify target accounts FundCmd.MarkFlagsOneRequired("addresses", "key-file", "number") - // Mark required flags - flag.MarkFlagRequired(FundCmd, flag.RPCURL) - flag.MarkFlagRequired(FundCmd, flag.PrivateKey) - // Funder contract parameters. f.StringVar(¶ms.FunderAddress, "contract-address", "", "address of pre-deployed Funder contract") } diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index 721f88aa8..65d8771c4 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -297,10 +297,6 @@ v3, uniswapv3 - perform UniswapV3 swaps`) f.UintVar(<p.ReceiptRetryInitialDelayMs, "receipt-retry-initial-delay-ms", 100, "initial delay in milliseconds for receipt polling (uses exponential backoff with jitter)") // TODO Compression - - // Mark required flags - flag.MarkPersistentFlagRequired(LoadtestCmd, flag.RPCURL) - flag.MarkPersistentFlagRequired(LoadtestCmd, flag.PrivateKey) } func initSubCommands() { diff --git a/cmd/metricsToDash/metricsToDash.go b/cmd/metricsToDash/metricsToDash.go index 7e3c35f2f..52fe94638 100644 --- a/cmd/metricsToDash/metricsToDash.go +++ b/cmd/metricsToDash/metricsToDash.go @@ -1,4 +1,4 @@ -package metricsToDash +package metricstodash import ( "fmt" diff --git a/cmd/monitor/cmd.go b/cmd/monitor/cmd.go index 93ffa98d3..97a4d39ec 100644 --- a/cmd/monitor/cmd.go +++ b/cmd/monitor/cmd.go @@ -88,9 +88,6 @@ func init() { f.IntVarP(&subBatchSize, "sub-batch-size", "s", 50, "number of requests per sub-batch") f.IntVarP(&blockCacheLimit, "cache-limit", "c", 200, "number of cached blocks for the LRU block data structure (Min 100)") f.StringVarP(&intervalStr, "interval", "i", "5s", "amount of time between batch block RPC calls") - - // Mark required flags - flag.MarkFlagRequired(MonitorCmd, flag.RPCURL) } func checkFlags() (err error) { diff --git a/cmd/publish/publish.go b/cmd/publish/publish.go index d64ec58c7..2fb857443 100644 --- a/cmd/publish/publish.go +++ b/cmd/publish/publish.go @@ -143,7 +143,4 @@ func init() { f.Uint64Var(&publishInputArgs.jobQueueSize, "job-queue-size", 100, "number of jobs we can put in the job queue for workers to process") f.StringVar(&publishInputArgs.inputFileName, "file", "", "provide a filename with transactions to publish") f.Uint64Var(&publishInputArgs.rateLimit, "rate-limit", 0, "rate limit in txs per second (default: no limit)") - - // Mark required flags - flag.MarkFlagRequired(Cmd, flag.RPCURL) } diff --git a/cmd/root.go b/cmd/root.go index 918afe12e..740c1674d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -32,7 +32,7 @@ import ( "github.com/0xPolygon/polygon-cli/cmd/fund" "github.com/0xPolygon/polygon-cli/cmd/hash" "github.com/0xPolygon/polygon-cli/cmd/loadtest" - "github.com/0xPolygon/polygon-cli/cmd/metricsToDash" + "github.com/0xPolygon/polygon-cli/cmd/metricstodash" "github.com/0xPolygon/polygon-cli/cmd/mnemonic" "github.com/0xPolygon/polygon-cli/cmd/monitor" "github.com/0xPolygon/polygon-cli/cmd/monitorv2" @@ -153,7 +153,7 @@ func NewPolycliCommand() *cobra.Command { fund.FundCmd, hash.HashCmd, loadtest.LoadtestCmd, - metricsToDash.MetricsToDashCmd, + metricstodash.MetricsToDashCmd, mnemonic.MnemonicCmd, monitor.MonitorCmd, monitorv2.MonitorV2Cmd, diff --git a/cmd/rpcfuzz/cmd.go b/cmd/rpcfuzz/cmd.go index e6719405e..99ae7304e 100644 --- a/cmd/rpcfuzz/cmd.go +++ b/cmd/rpcfuzz/cmd.go @@ -84,10 +84,6 @@ func init() { fuzzer = fuzz.New() fuzzer.Funcs(argfuzz.FuzzRPCArgs) - - // Mark required flags - flag.MarkFlagRequired(RPCFuzzCmd, flag.RPCURL) - flag.MarkFlagRequired(RPCFuzzCmd, flag.PrivateKey) } func checkFlags() (err error) { From 503a67fee767cea25f1128c42fb59e7bf13f42e3 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 15:04:10 -0400 Subject: [PATCH 11/31] fix: use helper functions --- cmd/p2p/nodelist/nodelist.go | 6 ++---- cmd/p2p/query/query.go | 6 ++---- cmd/p2p/sensor/sensor.go | 9 +++------ cmd/ulxly/ulxly.go | 18 +++++++++--------- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/cmd/p2p/nodelist/nodelist.go b/cmd/p2p/nodelist/nodelist.go index ca6d90542..9ede54573 100644 --- a/cmd/p2p/nodelist/nodelist.go +++ b/cmd/p2p/nodelist/nodelist.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" + "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/p2p/database" - "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -61,7 +61,5 @@ func init() { f.IntVarP(&inputNodeListParams.Limit, "limit", "l", 100, "number of unique nodes to return") f.StringVarP(&inputNodeListParams.ProjectID, "project-id", "p", "", "GCP project ID") f.StringVarP(&inputNodeListParams.DatabaseID, "database-id", "d", "", "datastore database ID") - if err := NodeListCmd.MarkFlagRequired("project-id"); err != nil { - log.Error().Err(err).Msg("Failed to mark project-id as required flag") - } + flag.MarkFlagRequired(NodeListCmd, "project-id") } diff --git a/cmd/p2p/query/query.go b/cmd/p2p/query/query.go index 1bd967cef..37324d126 100644 --- a/cmd/p2p/query/query.go +++ b/cmd/p2p/query/query.go @@ -6,9 +6,9 @@ import ( "net" "github.com/ethereum/go-ethereum/eth/protocols/eth" - "github.com/rs/zerolog/log" "github.com/spf13/cobra" + "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/p2p" ) @@ -132,7 +132,5 @@ func init() { f.StringVarP(&inputQueryParams.KeyFile, "key-file", "k", "", "private key file (cannot be set with --key)") f.StringVar(&inputQueryParams.PrivateKey, "key", "", "hex-encoded private key (cannot be set with --key-file)") QueryCmd.MarkFlagsMutuallyExclusive("key-file", "key") - if err := QueryCmd.MarkFlagRequired("start-block"); err != nil { - log.Error().Err(err).Msg("Failed to mark start-block as required flag") - } + flag.MarkFlagRequired(QueryCmd, "start-block") } diff --git a/cmd/p2p/sensor/sensor.go b/cmd/p2p/sensor/sensor.go index a9fa5de0d..cbcf2498d 100644 --- a/cmd/p2p/sensor/sensor.go +++ b/cmd/p2p/sensor/sensor.go @@ -28,6 +28,7 @@ import ( "github.com/rs/zerolog/log" "github.com/spf13/cobra" + "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/p2p" "github.com/0xPolygon/polygon-cli/p2p/database" "github.com/0xPolygon/polygon-cli/rpctypes" @@ -419,15 +420,11 @@ func init() { f := SensorCmd.Flags() f.StringVarP(&inputSensorParams.Bootnodes, "bootnodes", "b", "", "comma separated nodes used for bootstrapping") f.Uint64VarP(&inputSensorParams.NetworkID, "network-id", "n", 0, "filter discovered nodes by this network ID") - if err := SensorCmd.MarkFlagRequired("network-id"); err != nil { - log.Error().Err(err).Msg("Failed to mark network-id as required persistent flag") - } + flag.MarkFlagRequired(SensorCmd, "network-id") f.StringVarP(&inputSensorParams.ProjectID, "project-id", "p", "", "GCP project ID") f.StringVarP(&inputSensorParams.DatabaseID, "database-id", "d", "", "datastore database ID") f.StringVarP(&inputSensorParams.SensorID, "sensor-id", "s", "", "sensor ID when writing block/tx events") - if err := SensorCmd.MarkFlagRequired("sensor-id"); err != nil { - log.Error().Err(err).Msg("Failed to mark sensor-id as required persistent flag") - } + flag.MarkFlagRequired(SensorCmd, "sensor-id") f.IntVarP(&inputSensorParams.MaxPeers, "max-peers", "m", 2000, "maximum number of peers to connect to") f.IntVarP(&inputSensorParams.MaxDatabaseConcurrency, "max-db-concurrency", "D", 10000, `maximum number of concurrent database operations to perform (increasing this diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 570883d9a..d4acf358e 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -2307,9 +2307,9 @@ func (o *GetEvent) AddFlags(cmd *cobra.Command) { f.Uint64VarP(&o.ToBlock, ArgToBlock, "t", 0, "end of the range of blocks to retrieve") f.Uint64VarP(&o.FilterSize, ArgFilterSize, "i", 1000, "batch size for individual filter queries") f.BoolVarP(&o.Insecure, ArgInsecure, "", false, "skip TLS certificate verification") - fatalIfError(cmd.MarkFlagRequired(ArgFromBlock)) - fatalIfError(cmd.MarkFlagRequired(ArgToBlock)) - fatalIfError(cmd.MarkFlagRequired(ArgRPCURL)) + flag.MarkFlagRequired(cmd, ArgFromBlock) + flag.MarkFlagRequired(cmd, ArgToBlock) + flag.MarkFlagRequired(cmd, ArgRPCURL) } type GetSmcOptions struct { @@ -2547,7 +2547,7 @@ or if it's actually an intermediate hash.`, fBridgeAndClaim.StringVar(&inputUlxlyArgs.gasPrice, ArgGasPrice, "", "gas price to use") fBridgeAndClaim.BoolVar(&inputUlxlyArgs.dryRun, ArgDryRun, false, "do all of the transaction steps but do not send the transaction") fBridgeAndClaim.BoolVar(&inputUlxlyArgs.insecure, ArgInsecure, false, "skip TLS certificate verification") - fatalIfError(ulxlyBridgeAndClaimCmd.MarkPersistentFlagRequired(ArgBridgeAddress)) + flag.MarkPersistentFlagRequired(ulxlyBridgeAndClaimCmd, ArgBridgeAddress) // bridge specific args fBridge := ulxlyBridgeCmd.PersistentFlags() @@ -2557,7 +2557,7 @@ or if it's actually an intermediate hash.`, fBridge.StringVar(&inputUlxlyArgs.tokenAddress, ArgTokenAddress, "0x0000000000000000000000000000000000000000", "address of ERC20 token to use") fBridge.StringVar(&inputUlxlyArgs.callData, ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") fBridge.StringVar(&inputUlxlyArgs.callDataFile, ArgCallDataFile, "", "a file containing hex encoded call data") - fatalIfError(ulxlyBridgeCmd.MarkPersistentFlagRequired(ArgDestNetwork)) + flag.MarkPersistentFlagRequired(ulxlyBridgeCmd, ArgDestNetwork) // Claim specific args fClaim := ulxlyClaimCmd.PersistentFlags() @@ -2566,9 +2566,9 @@ or if it's actually an intermediate hash.`, fClaim.StringVar(&inputUlxlyArgs.bridgeServiceURL, ArgBridgeServiceURL, "", "URL of the bridge service") fClaim.StringVar(&inputUlxlyArgs.globalIndex, ArgGlobalIndex, "", "an override of the global index value") fClaim.DurationVar(&inputUlxlyArgs.wait, ArgWait, time.Duration(0), "retry claiming until deposit is ready, up to specified duration (available for claim asset and claim message)") - fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositCount)) - fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgDepositNetwork)) - fatalIfError(ulxlyClaimCmd.MarkPersistentFlagRequired(ArgBridgeServiceURL)) + flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgDepositCount) + flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgDepositNetwork) + flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgBridgeServiceURL) // Claim Everything Helper Command fClaimEverything := claimEverythingCommand.Flags() @@ -2577,7 +2577,7 @@ or if it's actually an intermediate hash.`, fClaimEverything.IntVar(&inputUlxlyArgs.bridgeOffset, ArgBridgeOffset, 0, "offset to specify for pagination of underlying bridge service deposits") fClaimEverything.UintVar(&inputUlxlyArgs.concurrency, ArgConcurrency, 1, "worker pool size for claims") - fatalIfError(claimEverythingCommand.MarkFlagRequired(ArgBridgeMappings)) + flag.MarkFlagRequired(claimEverythingCommand, ArgBridgeMappings) // Top Level ULxLyCmd.AddCommand(ulxlyBridgeAndClaimCmd) From 8eac7c476f10e6264115d6f8f011c2875e1693f3 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 15:06:47 -0400 Subject: [PATCH 12/31] fix: remove fatalIfError --- cmd/ulxly/ulxly.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index d4acf358e..8a6613d2b 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -2244,13 +2244,6 @@ func prepInputs(cmd *cobra.Command, args []string) (err error) { return nil } -func fatalIfError(err error) { - if err == nil { - return - } - log.Fatal().Err(err).Msg("Unexpected error occurred") -} - type FileOptions struct { FileName string } From 2375c5a1eee799638d89d34e131bfc901109aada Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 15:14:19 -0400 Subject: [PATCH 13/31] fix: missing import --- cmd/p2p/query/query.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/p2p/query/query.go b/cmd/p2p/query/query.go index 37324d126..588c017b0 100644 --- a/cmd/p2p/query/query.go +++ b/cmd/p2p/query/query.go @@ -6,6 +6,7 @@ import ( "net" "github.com/ethereum/go-ethereum/eth/protocols/eth" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/0xPolygon/polygon-cli/flag" From d033c595feb628f0d58980045bb7e9084d830806 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Fri, 3 Oct 2025 15:25:08 -0400 Subject: [PATCH 14/31] fix: metricsToDash --- cmd/metricsToDash/metricsToDash.go | 2 +- cmd/root.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/metricsToDash/metricsToDash.go b/cmd/metricsToDash/metricsToDash.go index 52fe94638..7e3c35f2f 100644 --- a/cmd/metricsToDash/metricsToDash.go +++ b/cmd/metricsToDash/metricsToDash.go @@ -1,4 +1,4 @@ -package metricstodash +package metricsToDash import ( "fmt" diff --git a/cmd/root.go b/cmd/root.go index 740c1674d..918afe12e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -32,7 +32,7 @@ import ( "github.com/0xPolygon/polygon-cli/cmd/fund" "github.com/0xPolygon/polygon-cli/cmd/hash" "github.com/0xPolygon/polygon-cli/cmd/loadtest" - "github.com/0xPolygon/polygon-cli/cmd/metricstodash" + "github.com/0xPolygon/polygon-cli/cmd/metricsToDash" "github.com/0xPolygon/polygon-cli/cmd/mnemonic" "github.com/0xPolygon/polygon-cli/cmd/monitor" "github.com/0xPolygon/polygon-cli/cmd/monitorv2" @@ -153,7 +153,7 @@ func NewPolycliCommand() *cobra.Command { fund.FundCmd, hash.HashCmd, loadtest.LoadtestCmd, - metricstodash.MetricsToDashCmd, + metricsToDash.MetricsToDashCmd, mnemonic.MnemonicCmd, monitor.MonitorCmd, monitorv2.MonitorV2Cmd, From 694be374eefe1ad02c58764d7046a93290432b77 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:05:26 -0400 Subject: [PATCH 15/31] chore: refactor flag_loader --- flag/flag.go | 93 ++++++++++++++++------- flag/flag_test.go | 186 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+), 25 deletions(-) create mode 100644 flag/flag_test.go diff --git a/flag/flag.go b/flag/flag.go index 83c510e87..21760662e 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -1,45 +1,88 @@ +// Package flag provides utilities for managing command flags with environment variable fallback support. +// It implements a priority system: flag value > environment variable > default value. package flag import ( - "github.com/0xPolygon/polygon-cli/util" + "fmt" + "os" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "github.com/spf13/viper" ) const ( - // RPCURL is the standard flag name for RPC endpoint URLs. + // RPCURL is the flag name for RPC URL RPCURL = "rpc-url" - // PrivateKey is the standard flag name for private keys. - PrivateKey = "private-key" - - // DefaultRPCURL is the default RPC endpoint URL. + // RPCURLEnvVar is the environment variable name for RPC URL + RPCURLEnvVar = "ETH_RPC_URL" + // DefaultRPCURL is the default RPC URL when no flag or env var is set DefaultRPCURL = "http://localhost:8545" + // PrivateKey is the flag name for private key + PrivateKey = "private-key" + // PrivateKeyEnvVar is the environment variable name for private key + PrivateKeyEnvVar = "PRIVATE_KEY" ) -// GetFlag retrieves a flag value from Viper after binding it. -// It binds the flag to enable environment variable fallback via Viper. -func GetFlag(cmd *cobra.Command, flagName string) string { - if err := viper.BindPFlag(flagName, cmd.Flags().Lookup(flagName)); err != nil { - log.Fatal().Err(err).Str("flag", flagName).Msg("Failed to bind flag to viper") - } - return viper.GetString(flagName) +// GetRPCURL retrieves the RPC URL from the command flag or environment variable. +// Returns the flag value if set, otherwise the environment variable value, otherwise the default. +// Returns empty string and nil error if none are set. +func GetRPCURL(cmd *cobra.Command) (string, error) { + return getValue(cmd, RPCURL, RPCURLEnvVar, false) } -// GetRPCURL retrieves the rpc-url flag value from Viper after binding it and validates -// that it is a valid URL with a supported scheme (http, https, ws, wss). -func GetRPCURL(cmd *cobra.Command) (string, error) { - rpcURL := GetFlag(cmd, RPCURL) - if err := util.ValidateUrl(rpcURL); err != nil { - return "", err - } - return rpcURL, nil +// GetRequiredRPCURL retrieves the RPC URL from the command flag or environment variable. +// Returns an error if the value is not set or empty. +func GetRequiredRPCURL(cmd *cobra.Command) (string, error) { + return getValue(cmd, RPCURL, RPCURLEnvVar, true) } -// GetPrivateKey retrieves the private-key flag value from Viper after binding it. -// This is a convenience wrapper around GetFlag for the standard private key flag. +// GetPrivateKey retrieves the private key from the command flag or environment variable. +// Returns the flag value if set, otherwise the environment variable value, otherwise the default. +// Returns empty string and nil error if none are set. func GetPrivateKey(cmd *cobra.Command) (string, error) { - return GetFlag(cmd, PrivateKey), nil + return getValue(cmd, PrivateKey, PrivateKeyEnvVar, false) +} + +// GetRequiredPrivateKey retrieves the private key from the command flag or environment variable. +// Returns an error if the value is not set or empty. +func GetRequiredPrivateKey(cmd *cobra.Command) (string, error) { + return getValue(cmd, PrivateKey, PrivateKeyEnvVar, true) +} + +// getValue retrieves a flag value with environment variable fallback support. +// It implements a priority system where flag values take precedence over environment variables, +// which take precedence over default values. +// +// Parameters: +// - cmd: The cobra command to retrieve the flag from +// - flagName: The name of the flag to retrieve +// - envVarName: The environment variable name to check as fallback +// - required: Whether the value is required (returns error if empty) +// +// Returns the resolved value and an error if required validation fails. +func getValue(cmd *cobra.Command, flagName, envVarName string, required bool) (string, error) { + flag := cmd.Flag(flagName) + if flag == nil { + return "", fmt.Errorf("flag %q not found", flagName) + } + + // Priority: flag > env var > default + value := flag.DefValue + + envVarValue := os.Getenv(envVarName) + if envVarValue != "" { + value = envVarValue + } + + if flag.Changed { + value = flag.Value.String() + } + + if required && value == "" { + return "", fmt.Errorf("required flag(s) %q not set", flagName) + } + + return value, nil } // MarkFlagRequired marks a regular flag as required and logs a fatal error if marking fails. diff --git a/flag/flag_test.go b/flag/flag_test.go new file mode 100644 index 000000000..3fb4df716 --- /dev/null +++ b/flag/flag_test.go @@ -0,0 +1,186 @@ +package flag + +import ( + "fmt" + "os" + "strconv" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" +) + +// TestValuePriority tests the priority system for flag value resolution. +// It verifies that flag values take precedence over environment variables, +// which take precedence over default values. It also tests the required +// flag validation logic. +func TestValuePriority(t *testing.T) { + type testCase struct { + defaultValue *int + envVarValue *int + flagValue *int + required bool + + expectedValue *int + expectedError error + } + + testCases := []testCase{ + // Test case: All three sources set - flag should win + { + defaultValue: ptr(1), + envVarValue: ptr(2), + flagValue: ptr(3), + expectedValue: ptr(3), + required: true, + expectedError: nil, + }, + // Test case: Flag set to same value as default - flag should still win + { + defaultValue: ptr(1), + envVarValue: ptr(2), + flagValue: ptr(1), + expectedValue: ptr(1), + required: true, + expectedError: nil, + }, + // Test case: Default and env var set - env var should win + { + defaultValue: ptr(1), + envVarValue: ptr(2), + flagValue: nil, + expectedValue: ptr(2), + required: true, + expectedError: nil, + }, + // Test case: Default and flag set - flag should win + { + defaultValue: ptr(1), + envVarValue: nil, + flagValue: ptr(3), + expectedValue: ptr(3), + required: true, + expectedError: nil, + }, + // Test case: Env var and flag set - flag should win + { + defaultValue: nil, + envVarValue: ptr(2), + flagValue: ptr(3), + expectedValue: ptr(3), + required: true, + expectedError: nil, + }, + // Test case: Only flag set + { + defaultValue: nil, + envVarValue: nil, + flagValue: ptr(3), + expectedValue: ptr(3), + required: true, + expectedError: nil, + }, + // Test case: Only default set (non-required) + { + defaultValue: ptr(1), + envVarValue: nil, + flagValue: nil, + expectedValue: ptr(1), + required: false, + expectedError: nil, + }, + // Test case: Only default set (required) - default should satisfy requirement + { + defaultValue: ptr(1), + envVarValue: nil, + flagValue: nil, + expectedValue: ptr(1), + required: true, + expectedError: nil, + }, + // Test case: Only env var set + { + defaultValue: nil, + envVarValue: ptr(2), + flagValue: nil, + expectedValue: ptr(2), + required: true, + expectedError: nil, + }, + // Test case: Nothing set (non-required) - should return empty + { + defaultValue: nil, + envVarValue: nil, + flagValue: nil, + expectedValue: nil, + required: false, + expectedError: nil, + }, + // Test case: Nothing set (required) - should return error + { + defaultValue: nil, + envVarValue: nil, + flagValue: nil, + expectedValue: nil, + required: true, + expectedError: fmt.Errorf("required flag(s) \"flag\" not set"), + }, + } + + for _, tc := range testCases { + var value *int + cmd := &cobra.Command{ + Use: "test", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + valueStr, err := getValue(cmd, "flag", "FLAG", tc.required) + if tc.expectedError != nil { + assert.EqualError(t, err, tc.expectedError.Error()) + return + } + assert.NoError(t, err) + if valueStr != "" { + valueInt, err := strconv.Atoi(valueStr) + assert.NoError(t, err) + value = &valueInt + } + }, + Run: func(cmd *cobra.Command, args []string) { + if tc.expectedValue != nil { + assert.NotNil(t, value) + if value != nil { + assert.Equal(t, *tc.expectedValue, *value) + } + } else { + assert.Nil(t, value) + } + }, + } + if tc.defaultValue != nil { + cmd.Flags().Int("flag", *tc.defaultValue, "flag") + } else { + cmd.Flags().String("flag", "", "flag") + } + + os.Unsetenv("FLAG") + if tc.envVarValue != nil { + v := strconv.Itoa(*tc.envVarValue) + os.Setenv("FLAG", v) + } + + if tc.flagValue != nil { + v := strconv.Itoa(*tc.flagValue) + cmd.SetArgs([]string{"--flag", v}) + } + + err := cmd.Execute() + assert.Nil(t, err) + } + +} + +// ptr is a helper function to create a pointer to a value. +// This is useful for test cases where we need to distinguish between +// nil (not set) and a zero value (explicitly set to 0). +func ptr[T any](v T) *T { + return &v +} From 91c3fd50e1d8456f36c57b41683d190dd2cbe393 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:10:16 -0400 Subject: [PATCH 16/31] chore: mark some stuff --- cmd/dumpblocks/dumpblocks.go | 2 +- cmd/ecrecover/ecrecover.go | 2 +- cmd/fund/cmd.go | 4 ++-- cmd/loadtest/app.go | 4 ++-- cmd/monitor/cmd.go | 2 +- cmd/monitorv2/monitorv2.go | 3 ++- cmd/nodekey/nodekey.go | 4 ++-- cmd/root.go | 5 +++-- cmd/rpcfuzz/cmd.go | 4 ++-- cmd/signer/signer.go | 2 +- cmd/ulxly/ulxly.go | 12 ++++-------- flag/flag.go | 36 ++++++++++++++++++++---------------- 12 files changed, 41 insertions(+), 39 deletions(-) diff --git a/cmd/dumpblocks/dumpblocks.go b/cmd/dumpblocks/dumpblocks.go index 1af1ea429..ae795f69c 100644 --- a/cmd/dumpblocks/dumpblocks.go +++ b/cmd/dumpblocks/dumpblocks.go @@ -186,7 +186,7 @@ var DumpblocksCmd = &cobra.Command{ func init() { f := DumpblocksCmd.Flags() - f.StringVarP(&inputDumpblocks.RpcUrl, "rpc-url", "r", "http://localhost:8545", "the RPC endpoint URL") + f.StringVarP(&inputDumpblocks.RpcUrl, flag.RPCURL, "r", flag.DefaultRPCURL, "the RPC endpoint URL") f.UintVarP(&inputDumpblocks.Threads, "concurrency", "c", 1, "how many go routines to leverage") f.BoolVarP(&inputDumpblocks.ShouldDumpBlocks, "dump-blocks", "B", true, "dump blocks to output") f.BoolVar(&inputDumpblocks.ShouldDumpReceipts, "dump-receipts", true, "dump receipts to output") diff --git a/cmd/ecrecover/ecrecover.go b/cmd/ecrecover/ecrecover.go index ee595f04b..501ad5f09 100644 --- a/cmd/ecrecover/ecrecover.go +++ b/cmd/ecrecover/ecrecover.go @@ -128,7 +128,7 @@ var EcRecoverCmd = &cobra.Command{ func init() { f := EcRecoverCmd.Flags() - f.StringVarP(&rpcUrl, "rpc-url", "r", "", "the RPC endpoint URL") + f.StringVarP(&rpcUrl, flag.RPCURL, "r", "", "the RPC endpoint URL") f.Uint64VarP(&blockNumber, "block-number", "b", 0, "block number to check the extra data for (default: latest)") f.StringVarP(&filePath, "file", "f", "", "path to a file containing block information in JSON format") f.StringVarP(&txData, "tx", "t", "", "transaction data in hex format") diff --git a/cmd/fund/cmd.go b/cmd/fund/cmd.go index bb32878c6..ef8537f78 100644 --- a/cmd/fund/cmd.go +++ b/cmd/fund/cmd.go @@ -66,8 +66,8 @@ var FundCmd = &cobra.Command{ func init() { f := FundCmd.Flags() - f.StringVarP(¶ms.RpcUrl, "rpc-url", "r", "http://localhost:8545", "RPC endpoint URL") - f.StringVar(¶ms.PrivateKey, "private-key", defaultPrivateKey, "hex encoded private key to use for sending transactions") + f.StringVarP(¶ms.RpcUrl, flag.RPCURL, "r", flag.DefaultRPCURL, "RPC endpoint URL") + f.StringVar(¶ms.PrivateKey, flag.PrivateKey, defaultPrivateKey, "hex encoded private key to use for sending transactions") // Wallet parameters. f.Uint64VarP(¶ms.WalletsNumber, "number", "n", 10, "number of wallets to fund") diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index 65d8771c4..73cdaa9ca 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -229,11 +229,11 @@ func initFlags() { // Persistent flags. pf := LoadtestCmd.PersistentFlags() - pf.StringVarP(<p.RPCUrl, "rpc-url", "r", "http://localhost:8545", "the RPC endpoint URL") + pf.StringVarP(<p.RPCUrl, flag.RPCURL, "r", flag.DefaultRPCURL, "the RPC endpoint URL") pf.Int64VarP(<p.Requests, "requests", "n", 1, "number of requests to perform for the benchmarking session (default of 1 leads to non-representative results)") pf.Int64VarP(<p.Concurrency, "concurrency", "c", 1, "number of requests to perform concurrently (default: one at a time)") pf.Int64VarP(<p.TimeLimit, "time-limit", "t", -1, "maximum seconds to spend benchmarking (default: no limit)") - pf.StringVar(<p.PrivateKey, "private-key", codeQualityPrivateKey, "hex encoded private key to use for sending transactions") + pf.StringVar(<p.PrivateKey, flag.PrivateKey, codeQualityPrivateKey, "hex encoded private key to use for sending transactions") pf.Uint64Var(<p.ChainID, "chain-id", 0, "chain ID for the transactions") pf.StringVar(<p.ToAddress, "to-address", "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", "recipient address for transactions") pf.BoolVar(<p.RandomRecipients, "random-recipients", false, "send to random addresses instead of fixed address in transfer tests") diff --git a/cmd/monitor/cmd.go b/cmd/monitor/cmd.go index 97a4d39ec..d8a992c62 100644 --- a/cmd/monitor/cmd.go +++ b/cmd/monitor/cmd.go @@ -83,7 +83,7 @@ var MonitorCmd = &cobra.Command{ func init() { f := MonitorCmd.Flags() - f.StringVarP(&rpcUrl, "rpc-url", "r", "http://localhost:8545", "the RPC endpoint URL") + f.StringVarP(&rpcUrl, flag.RPCURL, "r", flag.DefaultRPCURL, "the RPC endpoint URL") f.StringVarP(&batchSizeValue, "batch-size", "b", "auto", "number of requests per batch") f.IntVarP(&subBatchSize, "sub-batch-size", "s", 50, "number of requests per sub-batch") f.IntVarP(&blockCacheLimit, "cache-limit", "c", 200, "number of cached blocks for the LRU block data structure (Min 100)") diff --git a/cmd/monitorv2/monitorv2.go b/cmd/monitorv2/monitorv2.go index e60af0083..3d59fb938 100644 --- a/cmd/monitorv2/monitorv2.go +++ b/cmd/monitorv2/monitorv2.go @@ -8,6 +8,7 @@ import ( "github.com/0xPolygon/polygon-cli/chainstore" "github.com/0xPolygon/polygon-cli/cmd/monitorv2/renderer" + "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/indexer" "github.com/0xPolygon/polygon-cli/util" "github.com/rs/zerolog/log" @@ -92,7 +93,7 @@ var MonitorV2Cmd = &cobra.Command{ } func init() { - MonitorV2Cmd.Flags().StringVar(&rpcURL, "rpc-url", "", "RPC endpoint URL (required)") + MonitorV2Cmd.Flags().StringVar(&rpcURL, flag.RPCURL, "", "RPC endpoint URL (required)") MonitorV2Cmd.Flags().StringVar(&rendererType, "renderer", "tui", "renderer type (json, tview, tui)") MonitorV2Cmd.Flags().StringVar(&pprofAddr, "pprof", "", "pprof server address (e.g. 127.0.0.1:6060)") } diff --git a/cmd/nodekey/nodekey.go b/cmd/nodekey/nodekey.go index 7b00a257d..3635a6906 100644 --- a/cmd/nodekey/nodekey.go +++ b/cmd/nodekey/nodekey.go @@ -287,9 +287,9 @@ func generateLibp2pNodeKey(keyType int, seed bool) (nodeKeyOut, error) { func init() { f := NodekeyCmd.Flags() - f.StringVar(&inputNodeKeyPrivateKey, "private-key", "", "use the provided private key (in hex format)") + f.StringVar(&inputNodeKeyPrivateKey, flag.PrivateKey, "", "use the provided private key (in hex format)") f.StringVarP(&inputNodeKeyFile, "file", "f", "", "a file with the private nodekey (in hex format)") - NodekeyCmd.MarkFlagsMutuallyExclusive("private-key", "file") + NodekeyCmd.MarkFlagsMutuallyExclusive(flag.PrivateKey, "file") f.StringVar(&inputNodeKeyProtocol, "protocol", "devp2p", "devp2p|libp2p|pex|seed-libp2p") f.StringVar(&inputNodeKeyType, "key-type", "ed25519", "ed25519|secp256k1|ecdsa|rsa") diff --git a/cmd/root.go b/cmd/root.go index 918afe12e..c85a3f982 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -9,6 +9,7 @@ import ( "github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data" "github.com/0xPolygon/polygon-cli/cmd/foldtrace" "github.com/0xPolygon/polygon-cli/cmd/publish" + "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/util" "github.com/0xPolygon/polygon-cli/cmd/cdk" @@ -88,10 +89,10 @@ func initConfig() { // Set up environment variable mappings for common flags viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) - if err := viper.BindEnv("rpc-url", "ETH_RPC_URL"); err != nil { + if err := viper.BindEnv(flag.RPCURL, flag.RPCURLEnvVar); err != nil { log.Fatal().Err(err).Msg("Failed to bind rpc-url environment variable") } - if err := viper.BindEnv("private-key", "PRIVATE_KEY"); err != nil { + if err := viper.BindEnv(flag.PrivateKey, flag.PrivateKeyEnvVar); err != nil { log.Fatal().Err(err).Msg("Failed to bind private-key environment variable") } diff --git a/cmd/rpcfuzz/cmd.go b/cmd/rpcfuzz/cmd.go index 99ae7304e..9d5084a12 100644 --- a/cmd/rpcfuzz/cmd.go +++ b/cmd/rpcfuzz/cmd.go @@ -60,8 +60,8 @@ var RPCFuzzCmd = &cobra.Command{ func init() { f := RPCFuzzCmd.Flags() - f.StringVarP(&rpcUrl, "rpc-url", "r", "http://localhost:8545", "RPC endpoint URL") - f.StringVar(&testPrivateHexKey, "private-key", codeQualityPrivateKey, "hex encoded private key to use for sending transactions") + f.StringVarP(&rpcUrl, flag.RPCURL, "r", flag.DefaultRPCURL, "RPC endpoint URL") + f.StringVar(&testPrivateHexKey, flag.PrivateKey, codeQualityPrivateKey, "hex encoded private key to use for sending transactions") f.StringVar(&testContractAddress, "contract-address", "", "address of contract to use for testing (if not specified, contract will be deployed automatically)") f.StringVar(&testNamespaces, "namespaces", fmt.Sprintf("eth,web3,net,debug,%s", rpcTestRawHTTPNamespace), "comma separated list of RPC namespaces to test") f.BoolVar(&testFuzz, "fuzz", false, "flag to indicate whether to fuzz input or not") diff --git a/cmd/signer/signer.go b/cmd/signer/signer.go index 42718d5c4..a59b09080 100644 --- a/cmd/signer/signer.go +++ b/cmd/signer/signer.go @@ -847,7 +847,7 @@ func init() { f := SignerCmd.Flags() f.StringVar(&inputSignerOpts.keystore, "keystore", "", "use keystore in given folder or file") - f.StringVar(&inputSignerOpts.privateKey, "private-key", "", "use provided hex encoded private key") + f.StringVar(&inputSignerOpts.privateKey, flag.PrivateKey, "", "use provided hex encoded private key") f.StringVar(&inputSignerOpts.kms, "kms", "", "AWS or GCP if key is stored in cloud") f.StringVar(&inputSignerOpts.keyID, "key-id", "", "ID of key to be used for signing") f.StringVar(&inputSignerOpts.unsafePassword, "unsafe-password", "", "non-interactively specified password for unlocking keystore") diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 8a6613d2b..716d223e4 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -2173,9 +2173,9 @@ var ( const ( ArgGasLimit = "gas-limit" ArgChainID = "chain-id" - ArgPrivateKey = "private-key" + ArgPrivateKey = flag.PrivateKey ArgValue = "value" - ArgRPCURL = "rpc-url" + ArgRPCURL = flag.RPCURL ArgBridgeAddress = "bridge-address" ArgRollupManagerAddress = "rollup-manager-address" ArgDestNetwork = "destination-network" @@ -2300,9 +2300,7 @@ func (o *GetEvent) AddFlags(cmd *cobra.Command) { f.Uint64VarP(&o.ToBlock, ArgToBlock, "t", 0, "end of the range of blocks to retrieve") f.Uint64VarP(&o.FilterSize, ArgFilterSize, "i", 1000, "batch size for individual filter queries") f.BoolVarP(&o.Insecure, ArgInsecure, "", false, "skip TLS certificate verification") - flag.MarkFlagRequired(cmd, ArgFromBlock) - flag.MarkFlagRequired(cmd, ArgToBlock) - flag.MarkFlagRequired(cmd, ArgRPCURL) + flag.MarkFlagRequired(cmd, ArgFromBlock, ArgToBlock, ArgRPCURL) } type GetSmcOptions struct { @@ -2559,9 +2557,7 @@ or if it's actually an intermediate hash.`, fClaim.StringVar(&inputUlxlyArgs.bridgeServiceURL, ArgBridgeServiceURL, "", "URL of the bridge service") fClaim.StringVar(&inputUlxlyArgs.globalIndex, ArgGlobalIndex, "", "an override of the global index value") fClaim.DurationVar(&inputUlxlyArgs.wait, ArgWait, time.Duration(0), "retry claiming until deposit is ready, up to specified duration (available for claim asset and claim message)") - flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgDepositCount) - flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgDepositNetwork) - flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgBridgeServiceURL) + flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgDepositCount, ArgDepositNetwork, ArgBridgeServiceURL) // Claim Everything Helper Command fClaimEverything := claimEverythingCommand.Flags() diff --git a/flag/flag.go b/flag/flag.go index 21760662e..27c55462d 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -85,26 +85,30 @@ func getValue(cmd *cobra.Command, flagName, envVarName string, required bool) (s return value, nil } -// MarkFlagRequired marks a regular flag as required and logs a fatal error if marking fails. +// MarkFlagRequired marks one or more regular flags as required and logs a fatal error if marking fails. // This helper ensures consistent error handling across all commands when marking flags as required. -func MarkFlagRequired(cmd *cobra.Command, flagName string) { - if err := cmd.MarkFlagRequired(flagName); err != nil { - log.Fatal(). - Err(err). - Str("flag", flagName). - Str("command", cmd.Name()). - Msg("Failed to mark flag as required") +func MarkFlagRequired(cmd *cobra.Command, flagNames ...string) { + for _, flagName := range flagNames { + if err := cmd.MarkFlagRequired(flagName); err != nil { + log.Fatal(). + Err(err). + Str("flag", flagName). + Str("command", cmd.Name()). + Msg("Failed to mark flag as required") + } } } -// MarkPersistentFlagRequired marks a persistent flag as required and logs a fatal error if marking fails. +// MarkPersistentFlagRequired marks one or more persistent flags as required and logs a fatal error if marking fails. // This helper ensures consistent error handling across all commands when marking persistent flags as required. -func MarkPersistentFlagRequired(cmd *cobra.Command, flagName string) { - if err := cmd.MarkPersistentFlagRequired(flagName); err != nil { - log.Fatal(). - Err(err). - Str("flag", flagName). - Str("command", cmd.Name()). - Msg("Failed to mark persistent flag as required") +func MarkPersistentFlagRequired(cmd *cobra.Command, flagNames ...string) { + for _, flagName := range flagNames { + if err := cmd.MarkPersistentFlagRequired(flagName); err != nil { + log.Fatal(). + Err(err). + Str("flag", flagName). + Str("command", cmd.Name()). + Msg("Failed to mark persistent flag as required") + } } } From de18bb075e3e3004974cbc5e58dfcfbdb279d662 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:12:05 -0400 Subject: [PATCH 17/31] fix: ecrecover --- cmd/ecrecover/ecrecover.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmd/ecrecover/ecrecover.go b/cmd/ecrecover/ecrecover.go index 501ad5f09..1dd4df5f3 100644 --- a/cmd/ecrecover/ecrecover.go +++ b/cmd/ecrecover/ecrecover.go @@ -7,8 +7,8 @@ import ( "math/big" "os" - "github.com/0xPolygon/polygon-cli/util" "github.com/0xPolygon/polygon-cli/flag" + "github.com/0xPolygon/polygon-cli/util" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" @@ -132,10 +132,5 @@ func init() { f.Uint64VarP(&blockNumber, "block-number", "b", 0, "block number to check the extra data for (default: latest)") f.StringVarP(&filePath, "file", "f", "", "path to a file containing block information in JSON format") f.StringVarP(&txData, "tx", "t", "", "transaction data in hex format") - - // The sources of decoding are mutually exclusive EcRecoverCmd.MarkFlagsMutuallyExclusive("file", "block-number", "tx") - - // Mark required flags - flag.MarkFlagRequired(EcRecoverCmd, flag.RPCURL) } From 1a39a24605d50226a2f5ee260028f3aa90dd8806 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:13:46 -0400 Subject: [PATCH 18/31] fix: fixnoncegap --- cmd/fixnoncegap/fixnoncegap.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cmd/fixnoncegap/fixnoncegap.go b/cmd/fixnoncegap/fixnoncegap.go index d88f598fb..e19f62118 100644 --- a/cmd/fixnoncegap/fixnoncegap.go +++ b/cmd/fixnoncegap/fixnoncegap.go @@ -30,13 +30,13 @@ var FixNonceGapCmd = &cobra.Command{ if err != nil { return err } - inputFixNonceGapArgs.privateKey, err = flag.GetPrivateKey(cmd) + inputFixNonceGapArgs.privateKey, err = flag.GetRequiredPrivateKey(cmd) if err != nil { return err } return prepareRpcClient(cmd, args) }, - RunE: fixNonceGap, + RunE: fixNonceGap, SilenceUsage: true, } @@ -227,13 +227,10 @@ func fixNonceGap(cmd *cobra.Command, args []string) error { func init() { f := FixNonceGapCmd.Flags() - f.StringVarP(&inputFixNonceGapArgs.rpcURL, flag.RPCURL, "r", "http://localhost:8545", "the RPC endpoint URL") + f.StringVarP(&inputFixNonceGapArgs.rpcURL, flag.RPCURL, "r", flag.DefaultRPCURL, "the RPC endpoint URL") f.StringVar(&inputFixNonceGapArgs.privateKey, flag.PrivateKey, "", "private key to be used when sending txs to fix nonce gap") f.BoolVar(&inputFixNonceGapArgs.replace, ArgReplace, false, "replace the existing txs in the pool") f.Uint64Var(&inputFixNonceGapArgs.maxNonce, ArgMaxNonce, 0, "override max nonce value instead of getting it from the pool") - - // Mark required flags - flag.MarkFlagRequired(FixNonceGapCmd, flag.PrivateKey) } // Wait for the transaction to be mined From 31a41078dba749894255a157efe936f9042bb5f6 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:15:13 -0400 Subject: [PATCH 19/31] fix: mark flag required --- cmd/contract/cmd.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/contract/cmd.go b/cmd/contract/cmd.go index cc00e07ec..860b1785d 100644 --- a/cmd/contract/cmd.go +++ b/cmd/contract/cmd.go @@ -173,7 +173,5 @@ func init() { f := Cmd.Flags() f.StringVar(&inputArgs.rpcURL, flag.RPCURL, flag.DefaultRPCURL, "RPC URL of network containing contract") f.StringVar(&inputArgs.address, ArgAddress, "", "contract address") - - // Mark required flags flag.MarkFlagRequired(Cmd, ArgAddress) } From d8366cff27a54f29f4d4b12adc955bb84e3c8c49 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:35:08 -0400 Subject: [PATCH 20/31] fix: validate url --- cmd/monitorv2/monitorv2.go | 8 ++- cmd/nodekey/nodekey.go | 5 +- flag/flag.go | 31 ++++++++-- flag/flag_test.go | 115 +++++++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 10 deletions(-) diff --git a/cmd/monitorv2/monitorv2.go b/cmd/monitorv2/monitorv2.go index 3d59fb938..b3ca9307c 100644 --- a/cmd/monitorv2/monitorv2.go +++ b/cmd/monitorv2/monitorv2.go @@ -31,12 +31,18 @@ var MonitorV2Cmd = &cobra.Command{ Use: "monitorv2", Short: "Monitor v2 command stub", Long: usage, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + PreRunE: func(cmd *cobra.Command, args []string) (err error) { // Set default verbosity to Error level (300) if not explicitly set by user verbosityFlag := cmd.Flag("verbosity") if verbosityFlag != nil && !verbosityFlag.Changed { util.SetLogLevel(300) // Error level } + + rpcURL, err = flag.GetRequiredRPCURL(cmd) + if err != nil { + return err + } + return nil }, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/nodekey/nodekey.go b/cmd/nodekey/nodekey.go index 3635a6906..3db1f746f 100644 --- a/cmd/nodekey/nodekey.go +++ b/cmd/nodekey/nodekey.go @@ -15,10 +15,10 @@ import ( _ "embed" + "github.com/0xPolygon/polygon-cli/flag" gethcrypto "github.com/ethereum/go-ethereum/crypto" gethenode "github.com/ethereum/go-ethereum/p2p/enode" libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto" - "github.com/0xPolygon/polygon-cli/flag" libp2ppeer "github.com/libp2p/go-libp2p/core/peer" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -299,7 +299,4 @@ func init() { f.BoolVarP(&inputNodeKeySign, "sign", "s", false, "sign the node record") f.Uint64VarP(&inputNodeKeySeed, "seed", "S", 271828, "a numeric seed value") f.BoolVarP(&inputNodeKeyMarshalProtobuf, "marshal-protobuf", "m", false, "marshal libp2p key to protobuf format instead of raw") - - // Mark required flags - flag.MarkFlagRequired(NodekeyCmd, flag.PrivateKey) } diff --git a/flag/flag.go b/flag/flag.go index 27c55462d..d659155e5 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -6,6 +6,7 @@ import ( "fmt" "os" + "github.com/0xPolygon/polygon-cli/util" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -24,16 +25,36 @@ const ( ) // GetRPCURL retrieves the RPC URL from the command flag or environment variable. -// Returns the flag value if set, otherwise the environment variable value, otherwise the default. -// Returns empty string and nil error if none are set. +// Returns the flag value if set, otherwise the environment variable value, otherwise empty string. +// Validates the URL format if a non-empty value is provided and returns an error if validation fails. +// Returns empty string and nil error if no value is set. func GetRPCURL(cmd *cobra.Command) (string, error) { - return getValue(cmd, RPCURL, RPCURLEnvVar, false) + value, err := getValue(cmd, RPCURL, RPCURLEnvVar, false) + if err != nil || value == "" { + return value, err + } + + if err := util.ValidateUrl(value); err != nil { + return "", err + } + + return value, nil } // GetRequiredRPCURL retrieves the RPC URL from the command flag or environment variable. -// Returns an error if the value is not set or empty. +// Returns the flag value if set, otherwise the environment variable value. +// Validates the URL format and returns an error if the value is not set, empty, or invalid. func GetRequiredRPCURL(cmd *cobra.Command) (string, error) { - return getValue(cmd, RPCURL, RPCURLEnvVar, true) + value, err := getValue(cmd, RPCURL, RPCURLEnvVar, true) + if err != nil { + return "", err + } + + if err := util.ValidateUrl(value); err != nil { + return "", err + } + + return value, nil } // GetPrivateKey retrieves the private key from the command flag or environment variable. diff --git a/flag/flag_test.go b/flag/flag_test.go index 3fb4df716..bc12e7147 100644 --- a/flag/flag_test.go +++ b/flag/flag_test.go @@ -6,6 +6,7 @@ import ( "strconv" "testing" + "github.com/0xPolygon/polygon-cli/util" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" ) @@ -184,3 +185,117 @@ func TestValuePriority(t *testing.T) { func ptr[T any](v T) *T { return &v } + +// TestValidateURL tests the URL validation function. +func TestValidateURL(t *testing.T) { + testCases := []struct { + name string + url string + expectError bool + }{ + { + name: "Valid HTTP URL", + url: "http://localhost:8545", + expectError: false, + }, + { + name: "Valid HTTPS URL", + url: "https://eth-mainnet.example.com", + expectError: false, + }, + { + name: "Valid WS URL", + url: "ws://localhost:8546", + expectError: false, + }, + { + name: "Valid WSS URL", + url: "wss://eth-mainnet.example.com", + expectError: false, + }, + { + name: "URL with path", + url: "https://example.com/rpc/v1", + expectError: false, + }, + { + name: "URL with port", + url: "http://localhost:8545", + expectError: false, + }, + { + name: "Empty URL", + url: "", + expectError: true, + }, + { + name: "URL without scheme", + url: "localhost:8545", + expectError: true, + }, + { + name: "URL without host", + url: "http://", + expectError: false, // util.ValidateUrl only checks scheme, not host + }, + { + name: "Invalid URL format", + url: "ht!tp://invalid", + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := util.ValidateUrl(tc.url) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +// TestGetRPCURLValidation tests that GetRPCURL validates URLs. +func TestGetRPCURLValidation(t *testing.T) { + testCases := []struct { + name string + flagValue string + expectError bool + }{ + { + name: "Valid RPC URL", + flagValue: "http://localhost:8545", + expectError: false, + }, + { + name: "Invalid RPC URL - no scheme", + flagValue: "localhost:8545", + expectError: true, + }, + { + name: "Invalid RPC URL - no host", + flagValue: "http://", + expectError: false, // util.ValidateUrl only checks scheme, not host + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cmd := &cobra.Command{Use: "test"} + cmd.Flags().String(RPCURL, DefaultRPCURL, "test rpc url") + if tc.flagValue != "" { + cmd.SetArgs([]string{"--" + RPCURL, tc.flagValue}) + _ = cmd.Execute() + } + + _, err := GetRPCURL(cmd) + if tc.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} From b6035c39f88382d4d5bdfcd5c848f63a1d4dc426 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:42:39 -0400 Subject: [PATCH 21/31] fix: ulxly --- cmd/signer/signer.go | 31 ++++++++++++++----------------- cmd/ulxly/ulxly.go | 5 ++--- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/cmd/signer/signer.go b/cmd/signer/signer.go index a59b09080..2eb02a1d2 100644 --- a/cmd/signer/signer.go +++ b/cmd/signer/signer.go @@ -24,6 +24,7 @@ import ( kms "cloud.google.com/go/kms/apiv1" "cloud.google.com/go/kms/apiv1/kmspb" + "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/gethkeystore" accounts2 "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -33,7 +34,6 @@ import ( "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/google/tink/go/kwp/subtle" "github.com/manifoldco/promptui" - "github.com/0xPolygon/polygon-cli/flag" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "google.golang.org/api/iterator" @@ -80,7 +80,7 @@ var SignerCmd = &cobra.Command{ Short: "Utilities for security signing transactions", Long: signerUsage, PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputSignerOpts.privateKey, err = flag.GetPrivateKey(cmd) + inputSignerOpts.privateKey, err = flag.GetRequiredPrivateKey(cmd) if err != nil { return err } @@ -115,7 +115,7 @@ var SignCmd = &cobra.Command{ for _, a := range accounts { accountStrings += a.Address.String() + " " } - return fmt.Errorf("the account with address <%s> could not be found in list [%s]", inputSignerOpts.keyID, accountStrings) + return fmt.Errorf("account with address %s not found in list [%s]", inputSignerOpts.keyID, accountStrings) } password, err := getKeystorePassword() if err != nil { @@ -270,7 +270,7 @@ var ImportCmd = &cobra.Command{ func getTxDataToSign() (*ethtypes.Transaction, error) { if inputSignerOpts.dataFile == "" { - return nil, fmt.Errorf("no datafile was specified to sign") + return nil, fmt.Errorf("datafile not specified") } dataToSign, err := os.ReadFile(inputSignerOpts.dataFile) if err != nil { @@ -561,7 +561,7 @@ func wrapKeyForGCPKMS(ctx context.Context, client *kms.KeyManagementClient) ([]b PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)}, //nolint:staticcheck }) if err != nil { - return nil, fmt.Errorf("unable to marshal private key %w", err) + return nil, fmt.Errorf("unable to marshal private key: %w", err) } keyBytes, err := asn1.Marshal(privKey) if err != nil { @@ -676,13 +676,13 @@ func (g *GCPKMS) Sign(ctx context.Context, tx *ethtypes.Transaction) error { // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: // https://cloud.google.com/kms/docs/data-integrity-guidelines if !result.VerifiedDigestCrc32C { - return fmt.Errorf("AsymmetricSign: request corrupted in-transit") + return fmt.Errorf("asymmetric sign: request corrupted in-transit") } if result.Name != req.Name { - return fmt.Errorf("AsymmetricSign: request corrupted in-transit") + return fmt.Errorf("asymmetric sign: request corrupted in-transit") } if int64(crc32c(result.Signature)) != result.SignatureCrc32C.Value { - return fmt.Errorf("AsymmetricSign: response corrupted in-transit") + return fmt.Errorf("asymmetric sign: response corrupted in-transit") } gcpPubKey, err := getPublicKeyByName(ctx, client, name) @@ -782,7 +782,7 @@ func sanityCheck(cmd *cobra.Command, args []string) error { keyStoreMethods += 1 } if keyStoreMethods > 1 { - return fmt.Errorf("Multiple conflicting keystore sources were specified") + return fmt.Errorf("multiple conflicting keystore sources were specified") } pwErr := passwordValidation(inputSignerOpts.unsafePassword) if inputSignerOpts.unsafePassword != "" && pwErr != nil { @@ -791,18 +791,18 @@ func sanityCheck(cmd *cobra.Command, args []string) error { if inputSignerOpts.kms == "GCP" { if inputSignerOpts.gcpProjectID == "" { - return fmt.Errorf("a GCP project id must be specified") + return fmt.Errorf("GCP project id must be specified") } if inputSignerOpts.gcpRegion == "" { - return fmt.Errorf("a location is required") + return fmt.Errorf("location is required") } if inputSignerOpts.gcpKeyRingID == "" { - return fmt.Errorf("a GCP Keyring ID is needed") + return fmt.Errorf("GCP keyring ID is required") } if inputSignerOpts.keyID == "" && cmd.Name() != "list" { - return fmt.Errorf("a key id is required") + return fmt.Errorf("key id is required") } } @@ -811,7 +811,7 @@ func sanityCheck(cmd *cobra.Command, args []string) error { func passwordValidation(inputPw string) error { if len(inputPw) < 6 { - return fmt.Errorf("Password only had %d character. 8 or more required", len(inputPw)) + return fmt.Errorf("password only had %d characters, 8 or more required", len(inputPw)) } return nil } @@ -864,7 +864,4 @@ func init() { f.StringVar(&inputSignerOpts.gcpKeyRingID, "gcp-keyring-id", "polycli-keyring", "GCP keyring ID to be used") f.StringVar(&inputSignerOpts.gcpImportJob, "gcp-import-job-id", "", "GCP import job ID to use when importing key") f.IntVar(&inputSignerOpts.gcpKeyVersion, "gcp-key-version", 1, "GCP crypto key version to use") - - // Mark required flags - flag.MarkFlagRequired(SignerCmd, flag.PrivateKey) } diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index 716d223e4..377c842f2 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -2078,11 +2078,11 @@ var ulxlyBridgeAndClaimCmd = &cobra.Command{ Args: cobra.NoArgs, Hidden: true, PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { - inputUlxlyArgs.rpcURL, err = flag.GetRPCURL(cmd) + inputUlxlyArgs.rpcURL, err = flag.GetRequiredRPCURL(cmd) if err != nil { return err } - inputUlxlyArgs.privateKey, err = flag.GetPrivateKey(cmd) + inputUlxlyArgs.privateKey, err = flag.GetRequiredPrivateKey(cmd) if err != nil { return err } @@ -2565,7 +2565,6 @@ or if it's actually an intermediate hash.`, fClaimEverything.IntVar(&inputUlxlyArgs.bridgeLimit, ArgBridgeLimit, 25, "limit the number or responses returned by the bridge service when claiming") fClaimEverything.IntVar(&inputUlxlyArgs.bridgeOffset, ArgBridgeOffset, 0, "offset to specify for pagination of underlying bridge service deposits") fClaimEverything.UintVar(&inputUlxlyArgs.concurrency, ArgConcurrency, 1, "worker pool size for claims") - flag.MarkFlagRequired(claimEverythingCommand, ArgBridgeMappings) // Top Level From 27b050ddfc1e14f3dd0411affb44cc19f4eb4c06 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:53:00 -0400 Subject: [PATCH 22/31] fix: merge --- cmd/cdk/cdk.go | 2 +- cmd/ulxly/ulxly.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index d05201046..0bda5a308 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/0xPolygon/polygon-cli/custom_marshaller" + "github.com/0xPolygon/polygon-cli/custommarshaller" "github.com/0xPolygon/polygon-cli/flag" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index f018030fe..dd883c4ed 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -24,10 +24,10 @@ import ( "github.com/0xPolygon/polygon-cli/bindings/tokens" "github.com/0xPolygon/polygon-cli/bindings/ulxly" "github.com/0xPolygon/polygon-cli/bindings/ulxly/polygonrollupmanager" - "github.com/0xPolygon/polygon-cli/cmd/flag_loader" "github.com/0xPolygon/polygon-cli/cmd/ulxly/bridge_service" bridge_service_factory "github.com/0xPolygon/polygon-cli/cmd/ulxly/bridge_service/factory" smcerror "github.com/0xPolygon/polygon-cli/errors" + "github.com/0xPolygon/polygon-cli/flag" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" From ee1a753324d4e79953dcdd41cfea5e2e0fb3f819 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:54:18 -0400 Subject: [PATCH 23/31] docs: make gen-doc --- README.md | 2 +- doc/polycli.md | 2 +- doc/polycli_cdk.md | 4 ++-- doc/polycli_cdk_bridge.md | 2 +- doc/polycli_cdk_ger.md | 2 +- doc/polycli_cdk_rollup-manager.md | 2 +- doc/polycli_cdk_rollup.md | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 639e2f7c6..128830b69 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Note: Do not modify this section! It is auto-generated by `cobra` using `make ge - [polycli abi](doc/polycli_abi.md) - Provides encoding and decoding functionalities with contract signatures and ABI. -- [polycli cdk](doc/polycli_cdk.md) - Utilities for interacting with CDK networks. +- [polycli cdk](doc/polycli_cdk.md) - Utilities for interacting with CDK networks - [polycli contract](doc/polycli_contract.md) - Interact with smart contracts and fetch contract information from the blockchain. diff --git a/doc/polycli.md b/doc/polycli.md index 01506c548..afdbf554c 100644 --- a/doc/polycli.md +++ b/doc/polycli.md @@ -38,7 +38,7 @@ Polycli is a collection of tools that are meant to be useful while building, tes - [polycli abi](polycli_abi.md) - Provides encoding and decoding functionalities with contract signatures and ABI. -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks - [polycli contract](polycli_contract.md) - Interact with smart contracts and fetch contract information from the blockchain. diff --git a/doc/polycli_cdk.md b/doc/polycli_cdk.md index 4812390d6..aac7146b9 100644 --- a/doc/polycli_cdk.md +++ b/doc/polycli_cdk.md @@ -11,11 +11,11 @@ ## Description -Utilities for interacting with CDK networks. +Utilities for interacting with CDK networks ## Usage -Basic utility commands for interacting with the cdk contracts. +Basic utility commands for interacting with the cdk contracts ## Flags ```bash diff --git a/doc/polycli_cdk_bridge.md b/doc/polycli_cdk_bridge.md index b9565ac4a..f1f8eaa25 100644 --- a/doc/polycli_cdk_bridge.md +++ b/doc/polycli_cdk_bridge.md @@ -41,7 +41,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks - [polycli cdk bridge dump](polycli_cdk_bridge_dump.md) - List detailed information about the bridge. - [polycli cdk bridge inspect](polycli_cdk_bridge_inspect.md) - List some basic information about the bridge. diff --git a/doc/polycli_cdk_ger.md b/doc/polycli_cdk_ger.md index d107b0ac2..e3f60efd3 100644 --- a/doc/polycli_cdk_ger.md +++ b/doc/polycli_cdk_ger.md @@ -41,7 +41,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks - [polycli cdk ger dump](polycli_cdk_ger_dump.md) - List detailed information about the global exit root manager. - [polycli cdk ger inspect](polycli_cdk_ger_inspect.md) - List some basic information about the global exit root manager. diff --git a/doc/polycli_cdk_rollup-manager.md b/doc/polycli_cdk_rollup-manager.md index 3f7ff5055..be9c1dfe0 100644 --- a/doc/polycli_cdk_rollup-manager.md +++ b/doc/polycli_cdk_rollup-manager.md @@ -40,7 +40,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks - [polycli cdk rollup-manager dump](polycli_cdk_rollup-manager_dump.md) - List detailed information about the rollup manager. - [polycli cdk rollup-manager inspect](polycli_cdk_rollup-manager_inspect.md) - List some basic information about the rollup manager. diff --git a/doc/polycli_cdk_rollup.md b/doc/polycli_cdk_rollup.md index 4b209546a..0889bf69c 100644 --- a/doc/polycli_cdk_rollup.md +++ b/doc/polycli_cdk_rollup.md @@ -43,7 +43,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks - [polycli cdk rollup dump](polycli_cdk_rollup_dump.md) - List detailed information about a specific rollup. - [polycli cdk rollup inspect](polycli_cdk_rollup_inspect.md) - List some basic information about a specific rollup. From 98c6a7f590badcacd3b4e556a160bc992386121f Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 14:55:55 -0400 Subject: [PATCH 24/31] fix: don't bind env --- cmd/root.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 58baa9796..d813a306c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,8 +6,8 @@ import ( "strings" "github.com/0xPolygon/polygon-cli/cmd/contract" - "github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data" "github.com/0xPolygon/polygon-cli/cmd/foldtrace" + "github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data" "github.com/0xPolygon/polygon-cli/cmd/publish" "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/util" @@ -87,15 +87,6 @@ func initConfig() { viper.AutomaticEnv() // read in environment variables that match - // Set up environment variable mappings for common flags - viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) - if err := viper.BindEnv(flag.RPCURL, flag.RPCURLEnvVar); err != nil { - log.Fatal().Err(err).Msg("Failed to bind rpc-url environment variable") - } - if err := viper.BindEnv(flag.PrivateKey, flag.PrivateKeyEnvVar); err != nil { - log.Fatal().Err(err).Msg("Failed to bind private-key environment variable") - } - // If a config file is found, read it in. if err := viper.ReadInConfig(); err == nil { fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) From c2ec6103d45efeefb106983e1a20354e7894206e Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 15:02:27 -0400 Subject: [PATCH 25/31] chore: order root imports --- cmd/root.go | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index d813a306c..77f3c1d4b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -3,33 +3,21 @@ package cmd import ( "fmt" "os" - "strings" - "github.com/0xPolygon/polygon-cli/cmd/contract" - "github.com/0xPolygon/polygon-cli/cmd/foldtrace" - "github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data" - "github.com/0xPolygon/polygon-cli/cmd/publish" - "github.com/0xPolygon/polygon-cli/flag" - "github.com/0xPolygon/polygon-cli/util" - - "github.com/0xPolygon/polygon-cli/cmd/cdk" - "github.com/0xPolygon/polygon-cli/cmd/fixnoncegap" - "github.com/0xPolygon/polygon-cli/cmd/retest" - "github.com/0xPolygon/polygon-cli/cmd/ulxly" - - "github.com/0xPolygon/polygon-cli/cmd/fork" - "github.com/0xPolygon/polygon-cli/cmd/p2p" - "github.com/0xPolygon/polygon-cli/cmd/parseethwallet" - "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/0xPolygon/polygon-cli/cmd/abi" + "github.com/0xPolygon/polygon-cli/cmd/cdk" + "github.com/0xPolygon/polygon-cli/cmd/contract" "github.com/0xPolygon/polygon-cli/cmd/dbbench" "github.com/0xPolygon/polygon-cli/cmd/dockerlogger" "github.com/0xPolygon/polygon-cli/cmd/dumpblocks" "github.com/0xPolygon/polygon-cli/cmd/ecrecover" "github.com/0xPolygon/polygon-cli/cmd/enr" + "github.com/0xPolygon/polygon-cli/cmd/fixnoncegap" + "github.com/0xPolygon/polygon-cli/cmd/foldtrace" + "github.com/0xPolygon/polygon-cli/cmd/fork" "github.com/0xPolygon/polygon-cli/cmd/fund" "github.com/0xPolygon/polygon-cli/cmd/hash" "github.com/0xPolygon/polygon-cli/cmd/loadtest" @@ -38,11 +26,18 @@ import ( "github.com/0xPolygon/polygon-cli/cmd/monitor" "github.com/0xPolygon/polygon-cli/cmd/monitorv2" "github.com/0xPolygon/polygon-cli/cmd/nodekey" + "github.com/0xPolygon/polygon-cli/cmd/p2p" + "github.com/0xPolygon/polygon-cli/cmd/parsebatchl2data" + "github.com/0xPolygon/polygon-cli/cmd/parseethwallet" + "github.com/0xPolygon/polygon-cli/cmd/publish" + "github.com/0xPolygon/polygon-cli/cmd/retest" "github.com/0xPolygon/polygon-cli/cmd/rpcfuzz" "github.com/0xPolygon/polygon-cli/cmd/signer" + "github.com/0xPolygon/polygon-cli/cmd/ulxly" "github.com/0xPolygon/polygon-cli/cmd/version" "github.com/0xPolygon/polygon-cli/cmd/wallet" "github.com/0xPolygon/polygon-cli/cmd/wrapcontract" + "github.com/0xPolygon/polygon-cli/util" ) var ( From b2c9c2883f02690454571b00e7a52ea79d030689 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 15:06:53 -0400 Subject: [PATCH 26/31] docs: cdk --- README.md | 2 +- cmd/cdk/cdk.go | 2 +- doc/polycli.md | 2 +- doc/polycli_cdk.md | 2 +- doc/polycli_cdk_bridge.md | 2 +- doc/polycli_cdk_ger.md | 2 +- doc/polycli_cdk_rollup-manager.md | 2 +- doc/polycli_cdk_rollup.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 128830b69..639e2f7c6 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Note: Do not modify this section! It is auto-generated by `cobra` using `make ge - [polycli abi](doc/polycli_abi.md) - Provides encoding and decoding functionalities with contract signatures and ABI. -- [polycli cdk](doc/polycli_cdk.md) - Utilities for interacting with CDK networks +- [polycli cdk](doc/polycli_cdk.md) - Utilities for interacting with CDK networks. - [polycli contract](doc/polycli_contract.md) - Interact with smart contracts and fetch contract information from the blockchain. diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index 0bda5a308..54eebd562 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -102,7 +102,7 @@ var ( var CDKCmd = &cobra.Command{ Use: "cdk", - Short: "Utilities for interacting with CDK networks", + Short: "Utilities for interacting with CDK networks.", Long: "Basic utility commands for interacting with the cdk contracts", PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { cdkInputArgs.rpcURL, err = flag.GetRPCURL(cmd) diff --git a/doc/polycli.md b/doc/polycli.md index afdbf554c..01506c548 100644 --- a/doc/polycli.md +++ b/doc/polycli.md @@ -38,7 +38,7 @@ Polycli is a collection of tools that are meant to be useful while building, tes - [polycli abi](polycli_abi.md) - Provides encoding and decoding functionalities with contract signatures and ABI. -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. - [polycli contract](polycli_contract.md) - Interact with smart contracts and fetch contract information from the blockchain. diff --git a/doc/polycli_cdk.md b/doc/polycli_cdk.md index aac7146b9..bbf3f91c8 100644 --- a/doc/polycli_cdk.md +++ b/doc/polycli_cdk.md @@ -11,7 +11,7 @@ ## Description -Utilities for interacting with CDK networks +Utilities for interacting with CDK networks. ## Usage diff --git a/doc/polycli_cdk_bridge.md b/doc/polycli_cdk_bridge.md index f1f8eaa25..b9565ac4a 100644 --- a/doc/polycli_cdk_bridge.md +++ b/doc/polycli_cdk_bridge.md @@ -41,7 +41,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. - [polycli cdk bridge dump](polycli_cdk_bridge_dump.md) - List detailed information about the bridge. - [polycli cdk bridge inspect](polycli_cdk_bridge_inspect.md) - List some basic information about the bridge. diff --git a/doc/polycli_cdk_ger.md b/doc/polycli_cdk_ger.md index e3f60efd3..d107b0ac2 100644 --- a/doc/polycli_cdk_ger.md +++ b/doc/polycli_cdk_ger.md @@ -41,7 +41,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. - [polycli cdk ger dump](polycli_cdk_ger_dump.md) - List detailed information about the global exit root manager. - [polycli cdk ger inspect](polycli_cdk_ger_inspect.md) - List some basic information about the global exit root manager. diff --git a/doc/polycli_cdk_rollup-manager.md b/doc/polycli_cdk_rollup-manager.md index be9c1dfe0..3f7ff5055 100644 --- a/doc/polycli_cdk_rollup-manager.md +++ b/doc/polycli_cdk_rollup-manager.md @@ -40,7 +40,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. - [polycli cdk rollup-manager dump](polycli_cdk_rollup-manager_dump.md) - List detailed information about the rollup manager. - [polycli cdk rollup-manager inspect](polycli_cdk_rollup-manager_inspect.md) - List some basic information about the rollup manager. diff --git a/doc/polycli_cdk_rollup.md b/doc/polycli_cdk_rollup.md index 0889bf69c..4b209546a 100644 --- a/doc/polycli_cdk_rollup.md +++ b/doc/polycli_cdk_rollup.md @@ -43,7 +43,7 @@ The command also inherits flags from parent commands. ## See also -- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks +- [polycli cdk](polycli_cdk.md) - Utilities for interacting with CDK networks. - [polycli cdk rollup dump](polycli_cdk_rollup_dump.md) - List detailed information about a specific rollup. - [polycli cdk rollup inspect](polycli_cdk_rollup_inspect.md) - List some basic information about a specific rollup. From fa21fc3851922b02fdd2f0af0a3aa297235c6350 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 15:09:36 -0400 Subject: [PATCH 27/31] fix: docs --- cmd/cdk/cdk.go | 2 +- cmd/dumpblocks/dumpblocks.go | 4 ++-- doc/polycli_cdk.md | 2 +- doc/polycli_dumpblocks.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/cdk/cdk.go b/cmd/cdk/cdk.go index 54eebd562..5c4166098 100644 --- a/cmd/cdk/cdk.go +++ b/cmd/cdk/cdk.go @@ -103,7 +103,7 @@ var ( var CDKCmd = &cobra.Command{ Use: "cdk", Short: "Utilities for interacting with CDK networks.", - Long: "Basic utility commands for interacting with the cdk contracts", + Long: "Basic utility commands for interacting with the cdk contracts.", PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { cdkInputArgs.rpcURL, err = flag.GetRPCURL(cmd) if err != nil { diff --git a/cmd/dumpblocks/dumpblocks.go b/cmd/dumpblocks/dumpblocks.go index ae795f69c..4864fa661 100644 --- a/cmd/dumpblocks/dumpblocks.go +++ b/cmd/dumpblocks/dumpblocks.go @@ -12,10 +12,10 @@ import ( _ "embed" + "github.com/0xPolygon/polygon-cli/flag" "github.com/0xPolygon/polygon-cli/proto/gen/pb" "github.com/0xPolygon/polygon-cli/rpctypes" "github.com/0xPolygon/polygon-cli/util" - "github.com/0xPolygon/polygon-cli/flag" ethrpc "github.com/ethereum/go-ethereum/rpc" "github.com/rs/zerolog/log" "github.com/spf13/cobra" @@ -193,7 +193,7 @@ func init() { f.StringVarP(&inputDumpblocks.Filename, "filename", "f", "", "where to write the output to (default stdout)") f.StringVarP(&inputDumpblocks.Mode, "mode", "m", "json", "the output format [json, proto]") f.Uint64VarP(&inputDumpblocks.BatchSize, "batch-size", "b", 150, "batch size for requests (most providers cap at 1000)") - f.StringVarP(&inputDumpblocks.FilterStr, "filter", "F", "{}", "filter output based on tx to and from, not setting a filter means all are allowed") + f.StringVarP(&inputDumpblocks.FilterStr, "filter", "F", "{}", "filter output based on tx to and from (not setting a filter means all are allowed)") } // writeResponses writes the data to either stdout or a file if one is provided. diff --git a/doc/polycli_cdk.md b/doc/polycli_cdk.md index bbf3f91c8..4812390d6 100644 --- a/doc/polycli_cdk.md +++ b/doc/polycli_cdk.md @@ -15,7 +15,7 @@ Utilities for interacting with CDK networks. ## Usage -Basic utility commands for interacting with the cdk contracts +Basic utility commands for interacting with the cdk contracts. ## Flags ```bash diff --git a/doc/polycli_dumpblocks.md b/doc/polycli_dumpblocks.md index 114fd6fe7..ce5aa98fc 100644 --- a/doc/polycli_dumpblocks.md +++ b/doc/polycli_dumpblocks.md @@ -79,7 +79,7 @@ To solve this, add the unknown fields to the `.proto` files and recompile them ( -B, --dump-blocks dump blocks to output (default true) --dump-receipts dump receipts to output (default true) -f, --filename string where to write the output to (default stdout) - -F, --filter string filter output based on tx to and from, not setting a filter means all are allowed (default "{}") + -F, --filter string filter output based on tx to and from (not setting a filter means all are allowed) (default "{}") -h, --help help for dumpblocks -m, --mode string the output format [json, proto] (default "json") -r, --rpc-url string the RPC endpoint URL (default "http://localhost:8545") From 31c9b1bcb8282d47820b51970d773d6b2fa0ea6e Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 15:24:14 -0400 Subject: [PATCH 28/31] fix: monitor prerun --- cmd/monitor/cmd.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/monitor/cmd.go b/cmd/monitor/cmd.go index d8a992c62..9d205e1c4 100644 --- a/cmd/monitor/cmd.go +++ b/cmd/monitor/cmd.go @@ -7,8 +7,8 @@ import ( "sync" "time" - "github.com/0xPolygon/polygon-cli/util" "github.com/0xPolygon/polygon-cli/flag" + "github.com/0xPolygon/polygon-cli/util" "github.com/spf13/cobra" ) @@ -71,7 +71,9 @@ var MonitorCmd = &cobra.Command{ prettyFlag := cmd.Flag("pretty-logs") if prettyFlag != nil && prettyFlag.Value.String() == "true" { - return util.SetLogMode(util.Console) + if err = util.SetLogMode(util.Console); err != nil { + return err + } } return checkFlags() From 8f1aa403f9d4c545a6c4fd97082101534a8bbbb5 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Mon, 6 Oct 2025 15:36:45 -0400 Subject: [PATCH 29/31] docs: make gen-doc --- doc/polycli_ulxly_bridge.md | 1 + doc/polycli_ulxly_bridge_asset.md | 1 + doc/polycli_ulxly_bridge_message.md | 1 + doc/polycli_ulxly_bridge_weth.md | 1 + doc/polycli_ulxly_claim-everything.md | 1 + doc/polycli_ulxly_claim.md | 1 + doc/polycli_ulxly_claim_asset.md | 1 + doc/polycli_ulxly_claim_message.md | 1 + 8 files changed, 8 insertions(+) diff --git a/doc/polycli_ulxly_bridge.md b/doc/polycli_ulxly_bridge.md index 251553d1f..ff8eead5b 100644 --- a/doc/polycli_ulxly_bridge.md +++ b/doc/polycli_ulxly_bridge.md @@ -36,6 +36,7 @@ The command also inherits flags from parent commands. --gas-limit uint force specific gas limit for transaction --gas-price string gas price to use --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --rpc-url string RPC URL to send the transaction diff --git a/doc/polycli_ulxly_bridge_asset.md b/doc/polycli_ulxly_bridge_asset.md index f87d87912..ba5f55067 100644 --- a/doc/polycli_ulxly_bridge_asset.md +++ b/doc/polycli_ulxly_bridge_asset.md @@ -110,6 +110,7 @@ The command also inherits flags from parent commands. --gas-limit uint force specific gas limit for transaction --gas-price string gas price to use --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --rpc-url string RPC URL to send the transaction diff --git a/doc/polycli_ulxly_bridge_message.md b/doc/polycli_ulxly_bridge_message.md index db95f6080..473959701 100644 --- a/doc/polycli_ulxly_bridge_message.md +++ b/doc/polycli_ulxly_bridge_message.md @@ -107,6 +107,7 @@ The command also inherits flags from parent commands. --gas-limit uint force specific gas limit for transaction --gas-price string gas price to use --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --rpc-url string RPC URL to send the transaction diff --git a/doc/polycli_ulxly_bridge_weth.md b/doc/polycli_ulxly_bridge_weth.md index 94a2ab702..1d4a56cc6 100644 --- a/doc/polycli_ulxly_bridge_weth.md +++ b/doc/polycli_ulxly_bridge_weth.md @@ -76,6 +76,7 @@ The command also inherits flags from parent commands. --gas-limit uint force specific gas limit for transaction --gas-price string gas price to use --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --rpc-url string RPC URL to send the transaction diff --git a/doc/polycli_ulxly_claim-everything.md b/doc/polycli_ulxly_claim-everything.md index 947b64b9c..12be105fb 100644 --- a/doc/polycli_ulxly_claim-everything.md +++ b/doc/polycli_ulxly_claim-everything.md @@ -37,6 +37,7 @@ The command also inherits flags from parent commands. --gas-limit uint force specific gas limit for transaction --gas-price string gas price to use --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --rpc-url string RPC URL to send the transaction diff --git a/doc/polycli_ulxly_claim.md b/doc/polycli_ulxly_claim.md index 0120fba3c..b531ba35e 100644 --- a/doc/polycli_ulxly_claim.md +++ b/doc/polycli_ulxly_claim.md @@ -36,6 +36,7 @@ The command also inherits flags from parent commands. --gas-limit uint force specific gas limit for transaction --gas-price string gas price to use --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --rpc-url string RPC URL to send the transaction diff --git a/doc/polycli_ulxly_claim_asset.md b/doc/polycli_ulxly_claim_asset.md index b0bd8887f..f40f948bb 100644 --- a/doc/polycli_ulxly_claim_asset.md +++ b/doc/polycli_ulxly_claim_asset.md @@ -120,6 +120,7 @@ The command also inherits flags from parent commands. --gas-price string gas price to use --global-index string an override of the global index value --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --proof-ger string if specified and using legacy mode, the proof will be generated against this GER diff --git a/doc/polycli_ulxly_claim_message.md b/doc/polycli_ulxly_claim_message.md index 3d908d9a3..c62269a70 100644 --- a/doc/polycli_ulxly_claim_message.md +++ b/doc/polycli_ulxly_claim_message.md @@ -125,6 +125,7 @@ The command also inherits flags from parent commands. --gas-price string gas price to use --global-index string an override of the global index value --insecure skip TLS certificate verification + --legacy force usage of legacy bridge service (default true) --pretty-logs output logs in pretty format instead of JSON (default true) --private-key string hex encoded private key for sending transaction --proof-ger string if specified and using legacy mode, the proof will be generated against this GER From bce58b291fd5ceda6efe4b6ae07c891a6127c3e0 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Tue, 7 Oct 2025 10:17:59 -0400 Subject: [PATCH 30/31] fix: make rpc fuzz required --- cmd/rpcfuzz/cmd.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmd/rpcfuzz/cmd.go b/cmd/rpcfuzz/cmd.go index 9d5084a12..7fd59ded3 100644 --- a/cmd/rpcfuzz/cmd.go +++ b/cmd/rpcfuzz/cmd.go @@ -42,7 +42,7 @@ var RPCFuzzCmd = &cobra.Command{ Long: usage, Args: cobra.NoArgs, PreRunE: func(cmd *cobra.Command, args []string) (err error) { - rpcUrl, err = flag.GetRPCURL(cmd) + rpcUrl, err = flag.GetRequiredRPCURL(cmd) if err != nil { return err } @@ -87,11 +87,6 @@ func init() { } func checkFlags() (err error) { - // Check rpc-url flag. - if rpcUrl == "" { - panic("RPC URL is empty") - } - // Ensure only one streamer type is selected streamerCount := 0 if streamJSON { From e90994749589a18aae8594bb08477e3bbdeae1bf Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Tue, 7 Oct 2025 10:22:26 -0400 Subject: [PATCH 31/31] chore: rename marking flags funcs --- cmd/contract/cmd.go | 2 +- cmd/p2p/nodelist/nodelist.go | 2 +- cmd/p2p/query/query.go | 2 +- cmd/p2p/sensor/sensor.go | 4 ++-- cmd/ulxly/ulxly.go | 10 +++++----- flag/flag.go | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cmd/contract/cmd.go b/cmd/contract/cmd.go index 0205dd380..f913c4dcb 100644 --- a/cmd/contract/cmd.go +++ b/cmd/contract/cmd.go @@ -173,5 +173,5 @@ func init() { f := Cmd.Flags() f.StringVar(&inputArgs.rpcURL, flag.RPCURL, flag.DefaultRPCURL, "RPC URL of network containing contract") f.StringVar(&inputArgs.address, ArgAddress, "", "contract address") - flag.MarkFlagRequired(Cmd, ArgAddress) + flag.MarkFlagsRequired(Cmd, ArgAddress) } diff --git a/cmd/p2p/nodelist/nodelist.go b/cmd/p2p/nodelist/nodelist.go index 8cf004b12..533cd2abc 100644 --- a/cmd/p2p/nodelist/nodelist.go +++ b/cmd/p2p/nodelist/nodelist.go @@ -61,5 +61,5 @@ func init() { f.IntVarP(&inputNodeListParams.Limit, "limit", "l", 100, "number of unique nodes to return") f.StringVarP(&inputNodeListParams.ProjectID, "project-id", "p", "", "GCP project ID") f.StringVarP(&inputNodeListParams.DatabaseID, "database-id", "d", "", "datastore database ID") - flag.MarkFlagRequired(NodeListCmd, "project-id") + flag.MarkFlagsRequired(NodeListCmd, "project-id") } diff --git a/cmd/p2p/query/query.go b/cmd/p2p/query/query.go index 588c017b0..02395d208 100644 --- a/cmd/p2p/query/query.go +++ b/cmd/p2p/query/query.go @@ -133,5 +133,5 @@ func init() { f.StringVarP(&inputQueryParams.KeyFile, "key-file", "k", "", "private key file (cannot be set with --key)") f.StringVar(&inputQueryParams.PrivateKey, "key", "", "hex-encoded private key (cannot be set with --key-file)") QueryCmd.MarkFlagsMutuallyExclusive("key-file", "key") - flag.MarkFlagRequired(QueryCmd, "start-block") + flag.MarkFlagsRequired(QueryCmd, "start-block") } diff --git a/cmd/p2p/sensor/sensor.go b/cmd/p2p/sensor/sensor.go index cbcf2498d..4fc85b846 100644 --- a/cmd/p2p/sensor/sensor.go +++ b/cmd/p2p/sensor/sensor.go @@ -420,11 +420,11 @@ func init() { f := SensorCmd.Flags() f.StringVarP(&inputSensorParams.Bootnodes, "bootnodes", "b", "", "comma separated nodes used for bootstrapping") f.Uint64VarP(&inputSensorParams.NetworkID, "network-id", "n", 0, "filter discovered nodes by this network ID") - flag.MarkFlagRequired(SensorCmd, "network-id") + flag.MarkFlagsRequired(SensorCmd, "network-id") f.StringVarP(&inputSensorParams.ProjectID, "project-id", "p", "", "GCP project ID") f.StringVarP(&inputSensorParams.DatabaseID, "database-id", "d", "", "datastore database ID") f.StringVarP(&inputSensorParams.SensorID, "sensor-id", "s", "", "sensor ID when writing block/tx events") - flag.MarkFlagRequired(SensorCmd, "sensor-id") + flag.MarkFlagsRequired(SensorCmd, "sensor-id") f.IntVarP(&inputSensorParams.MaxPeers, "max-peers", "m", 2000, "maximum number of peers to connect to") f.IntVarP(&inputSensorParams.MaxDatabaseConcurrency, "max-db-concurrency", "D", 10000, `maximum number of concurrent database operations to perform (increasing this diff --git a/cmd/ulxly/ulxly.go b/cmd/ulxly/ulxly.go index d85887048..074929e46 100644 --- a/cmd/ulxly/ulxly.go +++ b/cmd/ulxly/ulxly.go @@ -2215,7 +2215,7 @@ func (o *GetEvent) AddFlags(cmd *cobra.Command) { f.Uint64VarP(&o.ToBlock, ArgToBlock, "t", 0, "end of the range of blocks to retrieve") f.Uint64VarP(&o.FilterSize, ArgFilterSize, "i", 1000, "batch size for individual filter queries") f.BoolVarP(&o.Insecure, ArgInsecure, "", false, "skip TLS certificate verification") - flag.MarkFlagRequired(cmd, ArgFromBlock, ArgToBlock, ArgRPCURL) + flag.MarkFlagsRequired(cmd, ArgFromBlock, ArgToBlock, ArgRPCURL) } type GetSmcOptions struct { @@ -2454,7 +2454,7 @@ or if it's actually an intermediate hash.`, fBridgeAndClaim.BoolVar(&inputUlxlyArgs.dryRun, ArgDryRun, false, "do all of the transaction steps but do not send the transaction") fBridgeAndClaim.BoolVar(&inputUlxlyArgs.insecure, ArgInsecure, false, "skip TLS certificate verification") fBridgeAndClaim.BoolVar(&inputUlxlyArgs.legacy, ArgLegacy, true, "force usage of legacy bridge service") - flag.MarkPersistentFlagRequired(ulxlyBridgeAndClaimCmd, ArgBridgeAddress) + flag.MarkPersistentFlagsRequired(ulxlyBridgeAndClaimCmd, ArgBridgeAddress) // bridge specific args fBridge := ulxlyBridgeCmd.PersistentFlags() @@ -2464,7 +2464,7 @@ or if it's actually an intermediate hash.`, fBridge.StringVar(&inputUlxlyArgs.tokenAddress, ArgTokenAddress, "0x0000000000000000000000000000000000000000", "address of ERC20 token to use") fBridge.StringVar(&inputUlxlyArgs.callData, ArgCallData, "0x", "call data to be passed directly with bridge-message or as an ERC20 Permit") fBridge.StringVar(&inputUlxlyArgs.callDataFile, ArgCallDataFile, "", "a file containing hex encoded call data") - flag.MarkPersistentFlagRequired(ulxlyBridgeCmd, ArgDestNetwork) + flag.MarkPersistentFlagsRequired(ulxlyBridgeCmd, ArgDestNetwork) // Claim specific args fClaim := ulxlyClaimCmd.PersistentFlags() @@ -2474,7 +2474,7 @@ or if it's actually an intermediate hash.`, fClaim.StringVar(&inputUlxlyArgs.globalIndex, ArgGlobalIndex, "", "an override of the global index value") fClaim.DurationVar(&inputUlxlyArgs.wait, ArgWait, time.Duration(0), "retry claiming until deposit is ready, up to specified duration (available for claim asset and claim message)") fClaim.StringVar(&inputUlxlyArgs.proofGER, ArgProofGER, "", "if specified and using legacy mode, the proof will be generated against this GER") - flag.MarkPersistentFlagRequired(ulxlyClaimCmd, ArgDepositCount, ArgDepositNetwork, ArgBridgeServiceURL) + flag.MarkPersistentFlagsRequired(ulxlyClaimCmd, ArgDepositCount, ArgDepositNetwork, ArgBridgeServiceURL) // Claim Everything Helper Command fClaimEverything := claimEverythingCommand.Flags() @@ -2482,7 +2482,7 @@ or if it's actually an intermediate hash.`, fClaimEverything.IntVar(&inputUlxlyArgs.bridgeLimit, ArgBridgeLimit, 25, "limit the number or responses returned by the bridge service when claiming") fClaimEverything.IntVar(&inputUlxlyArgs.bridgeOffset, ArgBridgeOffset, 0, "offset to specify for pagination of underlying bridge service deposits") fClaimEverything.UintVar(&inputUlxlyArgs.concurrency, ArgConcurrency, 1, "worker pool size for claims") - flag.MarkFlagRequired(claimEverythingCommand, ArgBridgeMappings) + flag.MarkFlagsRequired(claimEverythingCommand, ArgBridgeMappings) // Top Level ULxLyCmd.AddCommand(ulxlyBridgeAndClaimCmd) diff --git a/flag/flag.go b/flag/flag.go index d659155e5..24d87a237 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -106,9 +106,9 @@ func getValue(cmd *cobra.Command, flagName, envVarName string, required bool) (s return value, nil } -// MarkFlagRequired marks one or more regular flags as required and logs a fatal error if marking fails. +// MarkFlagsRequired marks one or more regular flags as required and logs a fatal error if marking fails. // This helper ensures consistent error handling across all commands when marking flags as required. -func MarkFlagRequired(cmd *cobra.Command, flagNames ...string) { +func MarkFlagsRequired(cmd *cobra.Command, flagNames ...string) { for _, flagName := range flagNames { if err := cmd.MarkFlagRequired(flagName); err != nil { log.Fatal(). @@ -120,9 +120,9 @@ func MarkFlagRequired(cmd *cobra.Command, flagNames ...string) { } } -// MarkPersistentFlagRequired marks one or more persistent flags as required and logs a fatal error if marking fails. +// MarkPersistentFlagsRequired marks one or more persistent flags as required and logs a fatal error if marking fails. // This helper ensures consistent error handling across all commands when marking persistent flags as required. -func MarkPersistentFlagRequired(cmd *cobra.Command, flagNames ...string) { +func MarkPersistentFlagsRequired(cmd *cobra.Command, flagNames ...string) { for _, flagName := range flagNames { if err := cmd.MarkPersistentFlagRequired(flagName); err != nil { log.Fatal().