From 7896ef0640152908843965cee52652cbef43c3bc Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 9 Feb 2021 11:12:44 +0300 Subject: [PATCH] rpc: allow client to send nep17 transfer with data --- cli/wallet/nep17.go | 2 +- cli/wallet/wallet.go | 2 +- pkg/rpc/client/nep17.go | 41 ++++++++++++++++++++++------------- pkg/rpc/server/client_test.go | 2 +- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/cli/wallet/nep17.go b/cli/wallet/nep17.go index 7378d6375..007845368 100644 --- a/cli/wallet/nep17.go +++ b/cli/wallet/nep17.go @@ -468,7 +468,7 @@ func transferNEP17(ctx *cli.Context) error { func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, recipients []client.TransferTarget) error { gas := flags.Fixed8FromContext(ctx, "gas") - tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients...) + tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients, nil) if err != nil { return cli.NewExitError(err, 1) } diff --git a/cli/wallet/wallet.go b/cli/wallet/wallet.go index 204b050da..c384178e7 100644 --- a/cli/wallet/wallet.go +++ b/cli/wallet/wallet.go @@ -239,7 +239,7 @@ func claimGas(ctx *cli.Context) error { if err != nil { return cli.NewExitError(err, 1) } - hash, err := c.TransferNEP17(acc, scriptHash, neoContractHash, 0, 0) + hash, err := c.TransferNEP17(acc, scriptHash, neoContractHash, 0, 0, nil) if err != nil { return cli.NewExitError(err, 1) } diff --git a/pkg/rpc/client/nep17.go b/pkg/rpc/client/nep17.go index 250432ef1..6257b58b6 100644 --- a/pkg/rpc/client/nep17.go +++ b/pkg/rpc/client/nep17.go @@ -104,27 +104,38 @@ func (c *Client) NEP17TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) { // method of a given contract (token) to move specified amount of NEP17 assets // (in FixedN format using contract's number of decimals) to given account and // returns it. The returned transaction is not signed. -func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (*transaction.Transaction, error) { - return c.CreateNEP17MultiTransferTx(acc, gas, TransferTarget{ - Token: token, - Address: to, - Amount: amount, - }) +func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64, data interface{}) (*transaction.Transaction, error) { + return c.CreateNEP17MultiTransferTx(acc, gas, []TransferTarget{ + {Token: token, + Address: to, + Amount: amount, + }, + }, []interface{}{data}) } // CreateNEP17MultiTransferTx creates an invocation transaction for performing NEP17 transfers -// from a single sender to multiple recipients. -func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64, recipients ...TransferTarget) (*transaction.Transaction, error) { +// from a single sender to multiple recipients with the given data. +func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64, recipients []TransferTarget, data []interface{}) (*transaction.Transaction, error) { from, err := address.StringToUint160(acc.Address) if err != nil { return nil, fmt.Errorf("bad account address: %w", err) } + if data == nil { + data = make([]interface{}, len(recipients)) + } else { + if len(data) != len(recipients) { + return nil, fmt.Errorf("data and recipients number mismatch: %d vs %d", len(data), len(recipients)) + } + } w := io.NewBufBinWriter() for i := range recipients { emit.AppCall(w.BinWriter, recipients[i].Token, "transfer", - callflag.WriteStates|callflag.AllowCall|callflag.AllowNotify, from, recipients[i].Address, recipients[i].Amount, nil) + callflag.WriteStates|callflag.AllowCall|callflag.AllowNotify, from, recipients[i].Address, recipients[i].Amount, data[i]) emit.Opcodes(w.BinWriter, opcode.ASSERT) } + if w.Err != nil { + return nil, fmt.Errorf("failed to create transfer script: %w", w.Err) + } accAddr, err := address.StringToUint160(acc.Address) if err != nil { return nil, fmt.Errorf("bad account address: %v", err) @@ -178,10 +189,10 @@ func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, sysFee, // TransferNEP17 creates an invocation transaction that invokes 'transfer' method // on a given token to move specified amount of NEP17 assets (in FixedN format -// using contract's number of decimals) to given account and sends it to the -// network returning just a hash of it. -func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64) (util.Uint256, error) { - tx, err := c.CreateNEP17TransferTx(acc, to, token, amount, gas) +// using contract's number of decimals) to given account with data specified and +// sends it to the network returning just a hash of it. +func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util.Uint160, amount int64, gas int64, data interface{}) (util.Uint256, error) { + tx, err := c.CreateNEP17TransferTx(acc, to, token, amount, gas, data) if err != nil { return util.Uint256{}, err } @@ -194,8 +205,8 @@ func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util. } // MultiTransferNEP17 is similar to TransferNEP17, buf allows to have multiple recipients. -func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients ...TransferTarget) (util.Uint256, error) { - tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients...) +func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients []TransferTarget, data []interface{}) (util.Uint256, error) { + tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients, data) if err != nil { return util.Uint256{}, err } diff --git a/pkg/rpc/server/client_test.go b/pkg/rpc/server/client_test.go index c99bdfe5c..c7980e571 100644 --- a/pkg/rpc/server/client_test.go +++ b/pkg/rpc/server/client_test.go @@ -272,7 +272,7 @@ func TestCreateNEP17TransferTx(t *testing.T) { gasContractHash, err := c.GetNativeContractHash(nativenames.Gas) require.NoError(t, err) - tx, err := c.CreateNEP17TransferTx(acc, util.Uint160{}, gasContractHash, 1000, 0) + tx, err := c.CreateNEP17TransferTx(acc, util.Uint160{}, gasContractHash, 1000, 0, nil) require.NoError(t, err) require.NoError(t, acc.SignTx(tx)) require.NoError(t, chain.VerifyTx(tx))