cli: allow to provide cosigners for 'wallet nep17 transfer'

This commit is contained in:
Anna Shaleva 2021-04-21 12:50:04 +03:00
parent 127d0ad2ba
commit f848783d5d
3 changed files with 81 additions and 41 deletions

View file

@ -226,6 +226,33 @@ func TestContractDeployWithData(t *testing.T) {
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value()) require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
} }
func deployVerifyContract(t *testing.T, e *executor) util.Uint160 {
tmpDir := path.Join(os.TempDir(), "neogo.test.deployverifycontract")
require.NoError(t, os.Mkdir(tmpDir, os.ModePerm))
t.Cleanup(func() {
os.RemoveAll(tmpDir)
})
// deploy verification contract
nefName := path.Join(tmpDir, "verify.nef")
manifestName := path.Join(tmpDir, "verify.manifest.json")
e.Run(t, "neo-go", "contract", "compile",
"--in", "testdata/verify.go",
"--config", "testdata/verify.yml",
"--out", nefName, "--manifest", manifestName)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "contract", "deploy",
"--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet, "--address", validatorAddr,
"--in", nefName, "--manifest", manifestName)
line, err := e.Out.ReadString('\n')
require.NoError(t, err)
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
hVerify, err := util.Uint160DecodeStringLE(line)
require.NoError(t, err)
e.checkTxPersisted(t)
return hVerify
}
func TestComlileAndInvokeFunction(t *testing.T) { func TestComlileAndInvokeFunction(t *testing.T) {
e := newExecutor(t, true) e := newExecutor(t, true)
@ -315,23 +342,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
require.Equal(t, []byte("on create|sub create"), res.Stack[0].Value()) require.Equal(t, []byte("on create|sub create"), res.Stack[0].Value())
// deploy verification contract // deploy verification contract
nefName = path.Join(tmpDir, "verify.nef") hVerify := deployVerifyContract(t, e)
manifestName = path.Join(tmpDir, "verify.manifest.json")
e.Run(t, "neo-go", "contract", "compile",
"--in", "testdata/verify.go",
"--config", "testdata/verify.yml",
"--out", nefName, "--manifest", manifestName)
e.In.WriteString("one\r")
e.Run(t, "neo-go", "contract", "deploy",
"--rpc-endpoint", "http://"+e.RPC.Addr,
"--wallet", validatorWallet, "--address", validatorAddr,
"--in", nefName, "--manifest", manifestName)
line, err = e.Out.ReadString('\n')
require.NoError(t, err)
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
hVerify, err := util.Uint160DecodeStringLE(line)
require.NoError(t, err)
e.checkTxPersisted(t)
t.Run("real invoke", func(t *testing.T) { t.Run("real invoke", func(t *testing.T) {
cmd := []string{"neo-go", "contract", "invokefunction", cmd := []string{"neo-go", "contract", "invokefunction",

View file

@ -132,6 +132,8 @@ func TestNEP17Transfer(t *testing.T) {
b, _ := e.Chain.GetGoverningTokenBalance(sh) b, _ := e.Chain.GetGoverningTokenBalance(sh)
require.Equal(t, big.NewInt(1), b) require.Equal(t, big.NewInt(1), b)
hVerify := deployVerifyContract(t, e)
t.Run("default address", func(t *testing.T) { t.Run("default address", func(t *testing.T) {
const validatorDefault = "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo" const validatorDefault = "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo"
e.In.WriteString("one\r") e.In.WriteString("one\r")
@ -159,10 +161,8 @@ func TestNEP17Transfer(t *testing.T) {
require.Equal(t, big.NewInt(41), b) require.Equal(t, big.NewInt(41), b)
}) })
t.Run("with data", func(t *testing.T) {
e.In.WriteString("one\r")
validTil := e.Chain.BlockHeight() + 100 validTil := e.Chain.BlockHeight() + 100
e.Run(t, []string{ cmd := []string{
"neo-go", "wallet", "nep17", "transfer", "neo-go", "wallet", "nep17", "transfer",
"--rpc-endpoint", "http://" + e.RPC.Addr, "--rpc-endpoint", "http://" + e.RPC.Addr,
"--wallet", validatorWallet, "--wallet", validatorWallet,
@ -170,10 +170,30 @@ func TestNEP17Transfer(t *testing.T) {
"--token", "GAS", "--token", "GAS",
"--amount", "1", "--amount", "1",
"--from", validatorAddr, "--from", validatorAddr,
"[", validatorAddr, strconv.Itoa(int(validTil)), "]", "[", validatorAddr, strconv.Itoa(int(validTil)), "]"}
}...)
t.Run("with data", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, cmd...)
e.checkTxPersisted(t) e.checkTxPersisted(t)
}) })
t.Run("with data and signers", func(t *testing.T) {
t.Run("invalid sender's scope", func(t *testing.T) {
e.In.WriteString("one\r")
e.RunWithError(t, append(cmd, "--", validatorAddr+":None")...)
})
t.Run("good", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, append(cmd, "--", validatorAddr+":Global")...) // CalledByEntry is enough, but it's the default value, so check something else
e.checkTxPersisted(t)
})
t.Run("several signers", func(t *testing.T) {
e.In.WriteString("one\r")
e.Run(t, append(cmd, "--", validatorAddr, hVerify.StringLE())...)
e.checkTxPersisted(t)
})
})
} }
func TestNEP17MultiTransfer(t *testing.T) { func TestNEP17MultiTransfer(t *testing.T) {

View file

@ -112,12 +112,15 @@ func newNEP17Commands() []cli.Command {
{ {
Name: "transfer", Name: "transfer",
Usage: "transfer NEP17 tokens", Usage: "transfer NEP17 tokens",
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash> --amount string [data]", UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
Action: transferNEP17, Action: transferNEP17,
Flags: transferFlags, Flags: transferFlags,
Description: `Transfers specified NEP17 token amount with optional 'data' parameter attached to the transfer. Description: `Transfers specified NEP17 token amount with optional 'data' parameter and cosigners
See 'contract testinvokefunction' documentation for the details about 'data' list attached to the transfer. See 'contract testinvokefunction' documentation
parameter. If no 'data' is given then default nil value will be used`, for the details about 'data' parameter and cosigners syntax. If no 'data' is
given then default nil value will be used. If no cosigners are given then the
sender with CalledByEntry scope will be used as the only signer.
`,
}, },
{ {
Name: "multitransfer", Name: "multitransfer",
@ -417,7 +420,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
}) })
} }
return signAndSendTransfer(ctx, c, acc, recipients) return signAndSendTransfer(ctx, c, acc, recipients, nil)
} }
func transferNEP17(ctx *cli.Context) error { func transferNEP17(ctx *cli.Context) error {
@ -461,23 +464,32 @@ func transferNEP17(ctx *cli.Context) error {
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
} }
_, data, extErr := cmdargs.GetDataFromContext(ctx) cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
if extErr != nil { if extErr != nil {
return extErr return extErr
} }
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
if extErr != nil {
return extErr
}
cosignersAccounts, err := cmdargs.GetSignersAccounts(wall, cosigners)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create NEP17 transfer transaction: %w", err), 1)
}
return signAndSendTransfer(ctx, c, acc, []client.TransferTarget{{ return signAndSendTransfer(ctx, c, acc, []client.TransferTarget{{
Token: token.Hash, Token: token.Hash,
Address: to, Address: to,
Amount: amount.Int64(), Amount: amount.Int64(),
Data: data, Data: data,
}}) }}, cosignersAccounts)
} }
func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, recipients []client.TransferTarget) error { func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, recipients []client.TransferTarget, cosigners []client.SignerAccount) error {
gas := flags.Fixed8FromContext(ctx, "gas") gas := flags.Fixed8FromContext(ctx, "gas")
tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients, nil) tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients, cosigners)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -487,13 +499,10 @@ func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
} else { } else {
_ = acc.SignTx(c.GetNetwork(), tx) _, err := c.SignAndPushTx(tx, acc, cosigners)
res, err := c.SendRawTransaction(tx)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
fmt.Fprintln(ctx.App.Writer, res.StringLE())
return nil
} }
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE()) fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())