cli: add Required flag for CLI parameters

Required field is added for CLI commands. MarkRequired function change
required parameter.

Closes #2861

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
Ekaterina Pavlova 2023-12-21 15:33:30 +03:00
parent de98b39a95
commit 8503a9f54e
15 changed files with 226 additions and 154 deletions

View file

@ -1,6 +1,10 @@
package flags
import "strings"
import (
"strings"
"github.com/urfave/cli"
)
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
@ -9,3 +13,28 @@ func eachName(longName string, fn func(string)) {
fn(name)
}
}
// MarkRequired marks flags with specified names as required.
func MarkRequired(flagSet []cli.Flag, names ...string) []cli.Flag {
updatedflagSet := make([]cli.Flag, 0, len(flagSet))
for _, flag := range flagSet {
for _, n := range names {
if n == flag.GetName() {
switch f := (flag).(type) {
case cli.StringFlag:
f.Required = true
flag = f
case cli.IntFlag:
f.Required = true
flag = f
case cli.BoolFlag:
f.Required = true
flag = f
}
break
}
}
updatedflagSet = append(updatedflagSet, flag)
}
return updatedflagSet
}

View file

@ -228,12 +228,10 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
// ownerOf: missing contract hash
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOf",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
}
e.RunWithError(t, cmdOwnerOf...)
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
"--token", h.StringLE()}
// ownerOf: missing token ID
e.RunWithError(t, cmdOwnerOf...)
// ownerOf: bad token ID
e.RunWithError(t, append(cmdOwnerOf, "--id", "test")...)
cmdOwnerOf = append(cmdOwnerOf, "--id", hex.EncodeToString(tokenID))
// ownerOf: good
@ -259,12 +257,10 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdProperties := []string{
"neo-go", "wallet", "nep11", "properties",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
}
e.RunWithError(t, cmdProperties...)
cmdProperties = append(cmdProperties, "--token", h.StringLE())
"--token", h.StringLE()}
// properties: no token ID
e.RunWithError(t, cmdProperties...)
// properties: bad token ID
e.RunWithError(t, append(cmdProperties, "--id", "test")...)
cmdProperties = append(cmdProperties, "--id", hex.EncodeToString(tokenID))
// properties: ok
@ -312,12 +308,12 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
// transfer: unimported token with symbol id specified
e.In.WriteString(nftOwnerPass + "\r")
e.RunWithError(t, append(cmdTransfer,
"--token", "HASHY")...)
"--token", "HASHY", "--id", "test")...)
cmdTransfer = append(cmdTransfer, "--token", h.StringLE())
// transfer: no id specified
// transfer: bad id
e.In.WriteString(nftOwnerPass + "\r")
e.RunWithError(t, cmdTransfer...)
e.RunWithError(t, append(cmdTransfer, "--id", "test")...)
// transfer: good
e.In.WriteString(nftOwnerPass + "\r")
@ -506,10 +502,10 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
cmdOwnerOf := []string{"neo-go", "wallet", "nep11", "ownerOfD",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
}
e.RunWithError(t, cmdOwnerOf...)
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE())
e.RunWithError(t, append(cmdOwnerOf, "--id", "")...)
cmdOwnerOf = append(cmdOwnerOf, "--token", h.StringLE(), "--id", "")
// ownerOfD: missing token ID
// ownerOfD: bad token ID
e.RunWithError(t, cmdOwnerOf...)
cmdOwnerOf = append(cmdOwnerOf, "--id", hex.EncodeToString(token1ID))
@ -539,11 +535,11 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
"neo-go", "wallet", "nep11", "properties",
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
}
e.RunWithError(t, cmdProperties...)
e.RunWithError(t, append(cmdProperties, "--id", "")...)
cmdProperties = append(cmdProperties, "--token", h.StringLE())
// properties: no token ID
e.RunWithError(t, cmdProperties...)
// properties: bad token ID
e.RunWithError(t, append(cmdProperties, "--id", "")...)
cmdProperties = append(cmdProperties, "--id", hex.EncodeToString(token2ID))
// properties: additional parameter
@ -596,12 +592,12 @@ func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
// transfer: unimported token with symbol id specified
e.In.WriteString(testcli.ValidatorPass + "\r")
e.RunWithError(t, append(cmdTransfer,
"--token", "NFSO")...)
"--token", "NFSO", "--id", "")...)
cmdTransfer = append(cmdTransfer, "--token", h.StringLE())
// transfer: no id specified
// transfer: bad id specified
e.In.WriteString(testcli.ValidatorPass + "\r")
e.RunWithError(t, cmdTransfer...)
e.RunWithError(t, append(cmdTransfer, "--id", "")...)
// transfer: good
e.In.WriteString(testcli.ValidatorPass + "\r")

View file

@ -111,7 +111,7 @@ func TestNEP17Balance(t *testing.T) {
e.CheckEOF(t)
})
t.Run("Bad wallet", func(t *testing.T) {
e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null")...)
e.RunWithError(t, append(cmdbalance, "--wallet", "/dev/null", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])...)
})
}

View file

@ -43,35 +43,36 @@ func NewCommands() []cli.Command {
Usage: "Get candidates and votes",
UsageText: "neo-go query candidates -r endpoint [-s timeout]",
Action: queryCandidates,
Flags: options.RPC,
Flags: flags.MarkRequired(options.RPC,
options.RPCEndpointFlag+", r"),
},
{
Name: "committee",
Usage: "Get committee list",
UsageText: "neo-go query committee -r endpoint [-s timeout]",
Action: queryCommittee,
Flags: options.RPC,
Flags: flags.MarkRequired(options.RPC, options.RPCEndpointFlag+", r"),
},
{
Name: "height",
Usage: "Get node height",
UsageText: "neo-go query height -r endpoint [-s timeout]",
Action: queryHeight,
Flags: options.RPC,
Flags: flags.MarkRequired(options.RPC, options.RPCEndpointFlag+", r"),
},
{
Name: "tx",
Usage: "Query transaction status",
UsageText: "neo-go query tx <hash> -r endpoint [-s timeout] [-v]",
Action: queryTx,
Flags: queryTxFlags,
Flags: flags.MarkRequired(queryTxFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "voter",
Usage: "Print NEO holder account state",
UsageText: "neo-go query voter <address> -r endpoint [-s timeout]",
Action: queryVoter,
Flags: options.RPC,
Flags: flags.MarkRequired(options.RPC, options.RPCEndpointFlag+", r"),
},
},
}}

View file

@ -54,16 +54,18 @@ func NewCommands() []cli.Command {
Usage: "block number to start from (default: 0)",
},
cli.StringFlag{
Name: "out, o",
Usage: "Output file (stdout if not given)",
Name: "out, o",
Required: true,
Usage: "Output file (stdout if not given)",
},
)
var cfgCountInFlags = make([]cli.Flag, len(cfgWithCountFlags))
copy(cfgCountInFlags, cfgWithCountFlags)
cfgCountInFlags = append(cfgCountInFlags,
cli.StringFlag{
Name: "in, i",
Usage: "Input file (stdin if not given)",
Name: "in, i",
Required: true,
Usage: "Input file (stdin if not given)",
},
cli.StringFlag{
Name: "dump",

View file

@ -30,6 +30,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"
"gopkg.in/yaml.v3"
)
@ -58,10 +59,10 @@ func TestCalcHash(t *testing.T) {
e.RunWithError(t, append(cmd, "--in", nefPath, "--manifest", manifestPath)...)
})
t.Run("no nef file", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--manifest", manifestPath)...)
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--manifest", manifestPath, "--in", "")...)
})
t.Run("no manifest file", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...)
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath, "--manifest", "")...)
})
t.Run("invalid nef path", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(),
@ -220,9 +221,6 @@ func TestContractInitAndCompile(t *testing.T) {
tmpDir := t.TempDir()
e := testcli.NewExecutor(t, false)
t.Run("no path is provided", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "init")
})
t.Run("invalid path", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "init", "--name", "\x00")
})
@ -244,9 +242,6 @@ func TestContractInitAndCompile(t *testing.T) {
nefPath := filepath.Join(tmpDir, "testcontract.nef")
manifestPath := filepath.Join(tmpDir, "testcontract.manifest.json")
cmd := []string{"neo-go", "contract", "compile"}
t.Run("missing source", func(t *testing.T) {
e.RunWithError(t, cmd...)
})
cmd = append(cmd, "--in", srcPath, "--out", nefPath, "--manifest", manifestPath)
t.Run("missing config, but require manifest", func(t *testing.T) {
@ -447,7 +442,7 @@ func TestDeployWithSigners(t *testing.T) {
})
t.Run("missing RPC", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "deploy",
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
"--wallet", testcli.ValidatorWallet, "-r", "", "--address", testcli.ValidatorAddr,
"--in", nefName, "--manifest", manifestName,
"[", "str1", "str2", "]")
})
@ -477,28 +472,28 @@ func TestContractManifestGroups(t *testing.T) {
"--out", nefName, "--manifest", manifestName)
t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group")
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group", "-s", "test", "--nef", "test", "--manifest", "test")
})
t.Run("invalid wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", t.TempDir())
"--wallet", t.TempDir(), "-s", "test", "--nef", "test", "--manifest", "test")
})
t.Run("invalid sender", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
"--sender", "not-a-sender")
"--sender", "not-a-sender", "--nef", "test", "--manifest", "test")
})
t.Run("invalid NEF file", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
"--sender", testcli.TestWalletAccount, "--nef", tmpDir)
"--sender", testcli.TestWalletAccount, "--nef", tmpDir, "--manifest", "test")
})
t.Run("corrupted NEF file", func(t *testing.T) {
f := filepath.Join(tmpDir, "invalid.nef")
require.NoError(t, os.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
"--wallet", testcli.TestWalletPath, "--address", testcli.TestWalletAccount,
"--sender", testcli.TestWalletAccount, "--nef", f)
"--sender", testcli.TestWalletAccount, "--nef", f, "--manifest", "test")
})
t.Run("invalid manifest file", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
@ -558,10 +553,6 @@ func TestContract_TestInvokeScript(t *testing.T) {
"--config", "testdata/deploy/neo-go.yml",
"--out", goodNef, "--manifest", manifestName)
t.Run("missing in", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
})
t.Run("unexisting in", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
@ -683,10 +674,6 @@ func TestComlileAndInvokeFunction(t *testing.T) {
t.Run("invalid cosigner", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--", "notahash")...)
})
t.Run("missing RPC address", func(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "testinvokefunction",
h.StringLE(), "getValue")
})
e.Run(t, cmd...)
@ -960,9 +947,6 @@ func TestContractInspect(t *testing.T) {
"--out", nefName, "--manifest", manifestName)
cmd := []string{"neo-go", "contract", "inspect"}
t.Run("missing input", func(t *testing.T) {
e.RunWithError(t, cmd...)
})
t.Run("with raw '.go'", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--in", srcPath)...)
e.Run(t, append(cmd, "--in", srcPath, "--compile")...)
@ -1095,3 +1079,52 @@ func TestContractCompile_NEFSizeCheck(t *testing.T) {
e.RunWithError(t, "neo-go", "contract", "compile", "--in", in)
require.NoFileExists(t, filepath.Join(tmpDir, "main.nef"))
}
func TestSmartcontractCommands(t *testing.T) {
tmpDir := t.TempDir()
app := cli.NewApp()
app.Commands = smartcontract.NewCommands()
app.ExitErrHandler = func(*cli.Context, error) {}
manifestF := filepath.Join(tmpDir, "manifest.json")
bindingF := filepath.Join(tmpDir, "binding.yml")
nefF := filepath.Join(tmpDir, "out.nef")
checkError := func(t *testing.T, msg string, args ...string) {
// cli.ExitError doesn't implement wraping properly, so we check for an error message.
err := app.Run(append([]string{"", "contract"}, args...))
require.True(t, strings.Contains(err.Error(), msg), "got: %v", err)
}
cmd := []string{"compile",
"--manifest", manifestF,
"--bindings", bindingF,
"--out", nefF,
}
t.Run("contract compile missing in", func(t *testing.T) {
checkError(t, "Required flag \"in\" not set", cmd...)
})
cmd = []string{"deploy",
"-r", "test",
"-w", "test",
}
t.Run("contract deploy missing in, manifest", func(t *testing.T) {
checkError(t, "Required flags \"in, manifest\" not set", cmd...)
})
cmd = []string{"testinvokescript",
"-r", "test"}
t.Run("contract testinvokescript missing in", func(t *testing.T) {
checkError(t, "Required flag \"in\" not set", cmd...)
})
t.Run("contract init missing name", func(t *testing.T) {
checkError(t, "Required flag \"name\" not set", "init", "--skip")
})
t.Run("contract inspect missing in, manifest", func(t *testing.T) {
checkError(t, "Required flags \"in, manifest\" not set", "calc-hash", "--s", random.Uint160().StringLE())
})
t.Run("contract manifest add-group missing in, manifest", func(t *testing.T) {
checkError(t, "Required flags \"sender, nef, manifest\" not set", "manifest", "add-group", "-w", random.Uint160().StringLE())
})
}

View file

@ -75,51 +75,56 @@ func RuntimeNotify(args []any) {
// NewCommands returns 'contract' command.
func NewCommands() []cli.Command {
testInvokeScriptFlags := []cli.Flag{
testInvokeScriptFlags := append([]cli.Flag{
cli.StringFlag{
Name: "in, i",
Usage: "Input location of the .nef file that needs to be invoked",
Name: "in, i",
Required: true,
Usage: "Input location of the .nef file that needs to be invoked",
},
options.Historic,
}
testInvokeScriptFlags = append(testInvokeScriptFlags, options.RPC...)
testInvokeFunctionFlags := []cli.Flag{options.Historic}
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
invokeFunctionFlags := []cli.Flag{
}, options.RPC...)
testInvokeFunctionFlags := append([]cli.Flag{options.Historic}, options.RPC...)
invokeFunctionFlags := append([]cli.Flag{
addressFlag,
txctx.GasFlag,
txctx.SysGasFlag,
txctx.OutFlag,
txctx.ForceFlag,
}
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
}, options.Wallet...)
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
deployFlags := append(invokeFunctionFlags, []cli.Flag{
cli.StringFlag{
Name: "in, i",
Usage: "Input file for the smart contract (*.nef)",
Name: "in, i",
Required: true,
Usage: "Input file for the smart contract (*.nef)",
},
cli.StringFlag{
Name: "manifest, m",
Usage: "Manifest input file (*.manifest.json)",
Name: "manifest, m",
Required: true,
Usage: "Manifest input file (*.manifest.json)",
},
}...)
manifestAddGroupFlags := append([]cli.Flag{
cli.StringFlag{
Name: "sender, s",
Usage: "deploy transaction sender",
Name: "sender, s",
Required: true,
Usage: "deploy transaction sender",
},
flags.AddressFlag{
Name: addressFlagName, // use the same name for handler code unification.
Usage: "account to sign group with",
},
cli.StringFlag{
Name: "nef, n",
Usage: "path to the NEF file",
Name: "nef, n",
Required: true,
Usage: "path to the NEF file",
},
cli.StringFlag{
Name: "manifest, m",
Usage: "path to the manifest",
Name: "manifest, m",
Required: true,
Usage: "path to the manifest",
},
}, options.Wallet...)
return []cli.Command{{
@ -140,8 +145,9 @@ func NewCommands() []cli.Command {
Action: contractCompile,
Flags: []cli.Flag{
cli.StringFlag{
Name: "in, i",
Usage: "Input file for the smart contract to be compiled (*.go file or directory)",
Name: "in, i",
Required: true,
Usage: "Input file for the smart contract to be compiled (*.go file or directory)",
},
cli.StringFlag{
Name: "out, o",
@ -188,20 +194,20 @@ func NewCommands() []cli.Command {
{
Name: "deploy",
Usage: "deploy a smart contract (.nef with description)",
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [data]",
UsageText: "neo-go contract deploy -r endpoint -w wallet [--wallet-config path] [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [data]",
Description: `Deploys given contract into the chain. The gas parameter is for additional
gas to be added as a network fee to prioritize the transaction. The data
parameter is an optional parameter to be passed to '_deploy' method.
`,
Action: contractDeploy,
Flags: deployFlags,
Flags: flags.MarkRequired(deployFlags, options.RPCEndpointFlag+", r"),
},
generateWrapperCmd,
generateRPCWrapperCmd,
{
Name: "invokefunction",
Usage: "invoke deployed contract on the blockchain",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] scripthash [method] [arguments...] [--] [signers...]",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [--wallet-config path] [-a address] [-g gas] [-e sysgas] [--out file] [--force] scripthash [method] [arguments...] [--] [signers...]",
Description: `Executes given (as a script hash) deployed script with the given method,
arguments and signers. Sender is included in the list of signers by default
with None witness scope. If you'd like to change default sender's scope,
@ -210,7 +216,7 @@ func NewCommands() []cli.Command {
command sends an invocation transaction to the network.
`,
Action: invokeFunction,
Flags: invokeFunctionFlags,
Flags: flags.MarkRequired(invokeFunctionFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "testinvokefunction",
@ -230,7 +236,7 @@ func NewCommands() []cli.Command {
` + cmdargs.SignersParsingDoc + `
`,
Action: testInvokeFunction,
Flags: testInvokeFunctionFlags,
Flags: flags.MarkRequired(testInvokeFunctionFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "testinvokescript",
@ -241,7 +247,7 @@ func NewCommands() []cli.Command {
for the details about parameters.
`,
Action: testInvokeScript,
Flags: testInvokeScriptFlags,
Flags: flags.MarkRequired(testInvokeScriptFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "init",
@ -250,8 +256,9 @@ func NewCommands() []cli.Command {
Action: initSmartContract,
Flags: []cli.Flag{
cli.StringFlag{
Name: "name, n",
Usage: "name of the smart-contract to be initialized",
Name: "name, n",
Required: true,
Usage: "name of the smart-contract to be initialized",
},
cli.BoolFlag{
Name: "skip-details, skip",
@ -270,8 +277,9 @@ func NewCommands() []cli.Command {
Usage: "compile input file (it should be go code then)",
},
cli.StringFlag{
Name: "in, i",
Usage: "input file of the program (either .go or .nef)",
Name: "in, i",
Required: true,
Usage: "input file of the program (either .go or .nef)",
},
},
},
@ -286,12 +294,14 @@ func NewCommands() []cli.Command {
Usage: "sender script hash or address",
},
cli.StringFlag{
Name: "in",
Usage: "path to NEF file",
Name: "in",
Required: true,
Usage: "path to NEF file",
},
cli.StringFlag{
Name: "manifest, m",
Usage: "path to manifest file",
Name: "manifest, m",
Required: true,
Usage: "path to manifest file",
},
},
},

View file

@ -67,7 +67,7 @@ flag is included, the specified value is added to the resulting conflicting tran
in both scenarios.
`,
Action: cancelTx,
Flags: txCancelFlags,
Flags: flags.MarkRequired(txCancelFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "txdump",

View file

@ -153,8 +153,8 @@ func TestRegisterCandidate(t *testing.T) {
vs, err = e.Chain.GetEnrollments()
require.Equal(t, 0, len(vs))
// query voter: missing address
e.RunWithError(t, "neo-go", "query", "voter")
// query voter: bad address
e.RunWithError(t, "neo-go", "query", "voter", "-r", "")
// Excessive parameters.
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")

View file

@ -80,11 +80,11 @@ func TestSignMultisigTx(t *testing.T) {
"--out", txPath)
// missing wallet
e.RunWithError(t, "neo-go", "wallet", "sign")
e.RunWithError(t, "neo-go", "wallet", "sign", "--in", "")
// missing in
e.RunWithError(t, "neo-go", "wallet", "sign",
"--wallet", wallet2Path)
"--wallet", wallet2Path, "--in", "")
// missing address
e.RunWithError(t, "neo-go", "wallet", "sign",

View file

@ -66,14 +66,14 @@ func newNEP11Commands() []cli.Command {
account (if they use the same names/symbols).
`,
Action: getNEP11Balance,
Flags: balanceFlags,
Flags: flags.MarkRequired(balanceFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "import",
Usage: "import NEP-11 token to a wallet",
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>",
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --token <hash>",
Action: importNEP11Token,
Flags: importFlags,
Flags: flags.MarkRequired(importFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "info",
@ -103,7 +103,7 @@ func newNEP11Commands() []cli.Command {
Usage: "transfer NEP-11 tokens",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP11,
Flags: transferFlags,
Flags: flags.MarkRequired(transferFlags, options.RPCEndpointFlag+", r", "from", "to", tokenID.GetName(), tokenFlag.GetName()),
Description: `Transfers specified NEP-11 token with optional cosigners list attached to
the transfer. Amount should be specified for divisible NEP-11
tokens and omitted for non-divisible NEP-11 tokens. See
@ -118,54 +118,54 @@ func newNEP11Commands() []cli.Command {
Usage: "print properties of NEP-11 token",
UsageText: "properties --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
Action: printNEP11Properties,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
tokenAddressFlag,
tokenID,
options.Historic,
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r", tokenID.GetName()),
},
{
Name: "ownerOf",
Usage: "print owner of non-divisible NEP-11 token with the specified ID",
UsageText: "ownerOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
Action: printNEP11NDOwner,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
tokenAddressFlag,
tokenID,
options.Historic,
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r", tokenID.GetName()),
},
{
Name: "ownerOfD",
Usage: "print set of owners of divisible NEP-11 token with the specified ID (" + maxIters + " will be printed at max)",
UsageText: "ownerOfD --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
Action: printNEP11DOwner,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
tokenAddressFlag,
tokenID,
options.Historic,
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r", tokenID.GetName()),
},
{
Name: "tokensOf",
Usage: "print list of tokens IDs for the specified NFT owner (" + maxIters + " will be printed at max)",
UsageText: "tokensOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --address <addr> [--historic <block/hash>]",
Action: printNEP11TokensOf,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
tokenAddressFlag,
ownerAddressFlag,
options.Historic,
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r"),
},
{
Name: "tokens",
Usage: "print list of tokens IDs minted by the specified NFT (optional method; " + maxIters + " will be printed at max)",
UsageText: "tokens --rpc-endpoint <node> [--timeout <time>] --token <hash> [--historic <block/hash>]",
Action: printNEP11Tokens,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
tokenAddressFlag,
options.Historic,
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r"),
},
}
}

View file

@ -112,14 +112,14 @@ func newNEP17Commands() []cli.Command {
account (if they use the same names/symbols).
`,
Action: getNEP17Balance,
Flags: balanceFlags,
Flags: flags.MarkRequired(balanceFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "import",
Usage: "import NEP-17 token to a wallet",
UsageText: "import -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --token <hash>",
Action: importNEP17Token,
Flags: importFlags,
Flags: flags.MarkRequired(importFlags, options.RPCEndpointFlag+", r"),
},
{
Name: "info",
@ -147,9 +147,9 @@ func newNEP17Commands() []cli.Command {
{
Name: "transfer",
Usage: "transfer NEP-17 tokens",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP17,
Flags: transferFlags,
Flags: flags.MarkRequired(transferFlags, options.RPCEndpointFlag+", r", "from", "to", "amount"),
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
list attached to the transfer. See 'contract testinvokefunction' documentation
for the details about 'data' parameter and cosigners syntax. If no 'data' is
@ -160,10 +160,10 @@ func newNEP17Commands() []cli.Command {
{
Name: "multitransfer",
Usage: "transfer NEP-17 tokens to multiple recipients",
UsageText: `multitransfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr>` +
UsageText: `multitransfer -w wallet [--wallet-config path] --rpc-endpoint <node> [--timeout <time>] --from <addr>` +
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
Action: multiTransferNEP17,
Flags: multiTransferFlags,
Flags: flags.MarkRequired(multiTransferFlags, options.RPCEndpointFlag+", r", "from"),
},
}
}

View file

@ -22,7 +22,7 @@ func newValidatorCommands() []cli.Command {
Usage: "register as a new candidate",
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
Action: handleRegister,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
walletPathFlag,
walletConfigFlag,
txctx.GasFlag,
@ -33,14 +33,14 @@ func newValidatorCommands() []cli.Command {
Name: "address, a",
Usage: "Address to register",
},
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r"),
},
{
Name: "unregister",
Usage: "unregister self as a candidate",
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
Action: handleUnregister,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
walletPathFlag,
walletConfigFlag,
txctx.GasFlag,
@ -51,7 +51,7 @@ func newValidatorCommands() []cli.Command {
Name: "address, a",
Usage: "Address to unregister",
},
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r"),
},
{
Name: "vote",
@ -61,7 +61,7 @@ func newValidatorCommands() []cli.Command {
contract. Do not provide candidate argument to perform unvoting.
`,
Action: handleVote,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
walletPathFlag,
walletConfigFlag,
txctx.GasFlag,
@ -76,7 +76,7 @@ func newValidatorCommands() []cli.Command {
Name: "candidate, c",
Usage: "Public key of candidate to vote for",
},
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r"),
},
}
}

View file

@ -56,16 +56,18 @@ var (
Usage: "Path to the wallet config file; conflicts with --wallet flag.",
}
wifFlag = cli.StringFlag{
Name: "wif",
Usage: "WIF to import",
Name: "wif",
Required: true,
Usage: "WIF to import",
}
decryptFlag = cli.BoolFlag{
Name: "decrypt, d",
Usage: "Decrypt encrypted keys.",
}
inFlag = cli.StringFlag{
Name: "in",
Usage: "file with JSON transaction",
Name: "in",
Required: true,
Usage: "file with JSON transaction",
}
fromAddrFlag = flags.AddressFlag{
Name: "from",
@ -150,8 +152,9 @@ func NewCommands() []cli.Command {
walletPathFlag,
walletConfigFlag,
cli.StringFlag{
Name: "out, o",
Usage: "where to write converted wallet",
Name: "out, o",
Required: true,
Usage: "where to write converted wallet",
},
},
},
@ -246,17 +249,18 @@ func NewCommands() []cli.Command {
Usage: "Optional account name",
},
cli.IntFlag{
Name: "min, m",
Usage: "Minimal number of signatures",
Name: "min, m",
Required: true,
Usage: "Minimal number of signatures",
},
},
},
{
Name: "import-deployed",
Usage: "import deployed contract",
UsageText: "import-deployed -w wallet [--wallet-config path] --wif <wif> --contract <hash> [--name <account_name>]",
UsageText: "import-deployed -w wallet [--wallet-config path] --wif <wif> --contract <hash> [--name <account_name>], -r <endpoint>",
Action: importDeployed,
Flags: append([]cli.Flag{
Flags: flags.MarkRequired(append([]cli.Flag{
walletPathFlag,
walletConfigFlag,
wifFlag,
@ -268,7 +272,7 @@ func NewCommands() []cli.Command {
Name: "contract, c",
Usage: "Contract hash or address",
},
}, options.RPC...),
}, options.RPC...), options.RPCEndpointFlag+", r"),
},
{
Name: "remove",

View file

@ -260,7 +260,7 @@ func TestWalletInit(t *testing.T) {
t.Run("Import", func(t *testing.T) {
t.Run("WIF", func(t *testing.T) {
t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import")
e.RunWithError(t, "neo-go", "wallet", "import", "--wif", "")
})
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
@ -425,25 +425,25 @@ func TestWalletInit(t *testing.T) {
})
t.Run("Multisig", func(t *testing.T) {
t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-multisig")
e.RunWithError(t, "neo-go", "wallet", "import-multisig", "--wif", "", "--min", "2")
})
t.Run("insufficient pubs", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-multisig",
"--wallet", walletPath,
"--min", "2")
"--min", "2", "--wif", "")
})
privs, pubs := testcli.GenerateKeys(t, 4)
cmd := []string{"neo-go", "wallet", "import-multisig",
"--wallet", walletPath,
"--min", "2"}
t.Run("invalid pub encoding", func(t *testing.T) {
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
e.RunWithError(t, append(cmd, "--wif", "", hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()),
"not-a-pub")...)
})
t.Run("missing WIF", func(t *testing.T) {
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
t.Run("bad WIF", func(t *testing.T) {
e.RunWithError(t, append(cmd, "--wif", "", hex.EncodeToString(pubs[0].Bytes()),
hex.EncodeToString(pubs[1].Bytes()),
hex.EncodeToString(pubs[2].Bytes()),
hex.EncodeToString(pubs[3].Bytes()))...)
@ -618,22 +618,19 @@ func TestWalletImportDeployed(t *testing.T) {
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed")
t.Run("bad wallet", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed", "--wallet", "", "--wif", priv.WIF(), "--contract", h.StringLE(), "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
})
t.Run("missing contract sh", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
"--wallet", walletPath)
"--wallet", walletPath, "--wif", priv.WIF(), "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
})
t.Run("missing WIF", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
"--wallet", walletPath, "--contract", h.StringLE())
t.Run("bad WIF", func(t *testing.T) {
e.RunWithError(t, "neo-go", "wallet", "import-deployed", "--wallet", walletPath, "--wif", "", "--contract", h.StringLE(), "--rpc-endpoint", "http://"+e.RPC.Addresses()[0])
})
t.Run("missing endpoint", func(t *testing.T) {
t.Run("bad endpoint", func(t *testing.T) {
e.In.WriteString("acc\rpass\rpass\r")
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
"--wallet", walletPath, "--contract", h.StringLE(),
"--wif", priv.WIF())
e.RunWithError(t, "neo-go", "wallet", "import-deployed", "--wallet", walletPath, "--wif", priv.WIF(), "--contract", h.StringLE(), "--rpc-endpoint", "")
})
t.Run("unknown contract", func(t *testing.T) {
e.In.WriteString("acc\rpass\rpass\r")
@ -965,11 +962,11 @@ func TestWalletConvert(t *testing.T) {
outPath := filepath.Join(tmpDir, "wallet.json")
cmd := []string{"neo-go", "wallet", "convert"}
t.Run("missing wallet", func(t *testing.T) {
e.RunWithError(t, cmd...)
e.RunWithError(t, append(cmd, "-w", "", "--out", "")...)
})
cmd = append(cmd, "--wallet", "testdata/testwallet_NEO2.json")
t.Run("missing out path", func(t *testing.T) {
e.RunWithError(t, cmd...)
e.RunWithError(t, append(cmd, "--out", "")...)
})
t.Run("invalid out path", func(t *testing.T) {
dir := t.TempDir()