mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-29 23:33:37 +00:00
Merge pull request #1906 from nspcc-dev/cli/transfer_param
cli: allow to pass 'data' for nep17 transfer command
This commit is contained in:
commit
8f14c61c34
9 changed files with 180 additions and 24 deletions
|
@ -158,6 +158,22 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
b, _ = e.Chain.GetGoverningTokenBalance(sh)
|
b, _ = e.Chain.GetGoverningTokenBalance(sh)
|
||||||
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
|
||||||
|
e.Run(t, []string{
|
||||||
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
|
||||||
|
"--token", "GAS",
|
||||||
|
"--amount", "1",
|
||||||
|
"--from", validatorAddr,
|
||||||
|
"[", validatorAddr, strconv.Itoa(int(validTil)), "]",
|
||||||
|
}...)
|
||||||
|
e.checkTxPersisted(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEP17MultiTransfer(t *testing.T) {
|
func TestNEP17MultiTransfer(t *testing.T) {
|
||||||
|
|
|
@ -538,7 +538,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
paramsStart++
|
paramsStart++
|
||||||
|
|
||||||
if len(args) > paramsStart {
|
if len(args) > paramsStart {
|
||||||
cosignersOffset, params, err = parseParams(args[paramsStart:], true)
|
cosignersOffset, params, err = ParseParams(args[paramsStart:], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -623,12 +623,12 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseParams extracts array of smartcontract.Parameter from the given args and
|
// ParseParams extracts array of smartcontract.Parameter from the given args and
|
||||||
// returns the number of handled words, the array itself and an error.
|
// returns the number of handled words, the array itself and an error.
|
||||||
// `calledFromMain` denotes whether the method was called from the outside or
|
// `calledFromMain` denotes whether the method was called from the outside or
|
||||||
// recursively and used to check if cosignersSeparator and closing bracket are
|
// recursively and used to check if cosignersSeparator and closing bracket are
|
||||||
// allowed to be in `args` sequence.
|
// allowed to be in `args` sequence.
|
||||||
func parseParams(args []string, calledFromMain bool) (int, []smartcontract.Parameter, error) {
|
func ParseParams(args []string, calledFromMain bool) (int, []smartcontract.Parameter, error) {
|
||||||
res := []smartcontract.Parameter{}
|
res := []smartcontract.Parameter{}
|
||||||
for k := 0; k < len(args); {
|
for k := 0; k < len(args); {
|
||||||
s := args[k]
|
s := args[k]
|
||||||
|
@ -639,7 +639,7 @@ func parseParams(args []string, calledFromMain bool) (int, []smartcontract.Param
|
||||||
}
|
}
|
||||||
return 0, []smartcontract.Parameter{}, errors.New("invalid array syntax: missing closing bracket")
|
return 0, []smartcontract.Parameter{}, errors.New("invalid array syntax: missing closing bracket")
|
||||||
case arrayStartSeparator:
|
case arrayStartSeparator:
|
||||||
numWordsRead, array, err := parseParams(args[k+1:], false)
|
numWordsRead, array, err := ParseParams(args[k+1:], false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("failed to parse array: %w", err)
|
return 0, nil, fmt.Errorf("failed to parse array: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -887,6 +887,26 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDataFromContext returns data parameter from context args.
|
||||||
|
func GetDataFromContext(ctx *cli.Context) (interface{}, *cli.ExitError) {
|
||||||
|
var data interface{}
|
||||||
|
args := ctx.Args()
|
||||||
|
if args.Present() {
|
||||||
|
_, params, err := ParseParams(args, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1)
|
||||||
|
}
|
||||||
|
if len(params) != 1 {
|
||||||
|
return nil, cli.NewExitError("'data' should be represented as a single parameter", 1)
|
||||||
|
}
|
||||||
|
data, err = smartcontract.ExpandParameterToEmitable(params[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, cli.NewExitError(fmt.Sprintf("failed to convert 'data' to emitable type: %s", err.Error()), 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ParseContractConfig reads contract configuration file (.yaml) and returns unmarshalled ProjectConfig.
|
// ParseContractConfig reads contract configuration file (.yaml) and returns unmarshalled ProjectConfig.
|
||||||
func ParseContractConfig(confFile string) (ProjectConfig, error) {
|
func ParseContractConfig(confFile string) (ProjectConfig, error) {
|
||||||
conf := ProjectConfig{}
|
conf := ProjectConfig{}
|
||||||
|
|
|
@ -202,7 +202,7 @@ func TestParseParams_CalledFromItself(t *testing.T) {
|
||||||
|
|
||||||
for str, expected := range testCases {
|
for str, expected := range testCases {
|
||||||
input := strings.Split(str, " ")
|
input := strings.Split(str, " ")
|
||||||
offset, actual, err := parseParams(input, false)
|
offset, actual, err := ParseParams(input, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expected.WordsRead, offset)
|
require.Equal(t, expected.WordsRead, offset)
|
||||||
require.Equal(t, expected.Value, actual)
|
require.Equal(t, expected.Value, actual)
|
||||||
|
@ -218,7 +218,7 @@ func TestParseParams_CalledFromItself(t *testing.T) {
|
||||||
|
|
||||||
for _, str := range errorCases {
|
for _, str := range errorCases {
|
||||||
input := strings.Split(str, " ")
|
input := strings.Split(str, " ")
|
||||||
_, _, err := parseParams(input, false)
|
_, _, err := ParseParams(input, false)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,7 @@ func TestParseParams_CalledFromOutside(t *testing.T) {
|
||||||
}
|
}
|
||||||
for str, expected := range testCases {
|
for str, expected := range testCases {
|
||||||
input := strings.Split(str, " ")
|
input := strings.Split(str, " ")
|
||||||
offset, arr, err := parseParams(input, true)
|
offset, arr, err := ParseParams(input, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expected.WordsRead, offset)
|
require.Equal(t, expected.WordsRead, offset)
|
||||||
require.Equal(t, expected.Parameters, arr)
|
require.Equal(t, expected.Parameters, arr)
|
||||||
|
@ -415,7 +415,7 @@ func TestParseParams_CalledFromOutside(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, str := range errorCases {
|
for _, str := range errorCases {
|
||||||
input := strings.Split(str, " ")
|
input := strings.Split(str, " ")
|
||||||
_, _, err := parseParams(input, true)
|
_, _, err := ParseParams(input, true)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
|
smartcontractcli "github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
||||||
|
@ -111,9 +112,12 @@ 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",
|
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash> --amount string [data]",
|
||||||
Action: transferNEP17,
|
Action: transferNEP17,
|
||||||
Flags: transferFlags,
|
Flags: transferFlags,
|
||||||
|
Description: `Transfers specified NEP17 token amount with optional 'data' parameter attached to the transfer.
|
||||||
|
See 'contract testinvokefunction' documentation for the details about 'data'
|
||||||
|
parameter. If no 'data' is given then default nil value will be used`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "multitransfer",
|
Name: "multitransfer",
|
||||||
|
@ -409,6 +413,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
Token: token.Hash,
|
Token: token.Hash,
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Amount: amount.Int64(),
|
Amount: amount.Int64(),
|
||||||
|
Data: nil,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,17 +461,23 @@ 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 := smartcontractcli.GetDataFromContext(ctx)
|
||||||
|
if extErr != nil {
|
||||||
|
return extErr
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
|
|
||||||
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) 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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ ProtocolConfiguration:
|
||||||
ValidatorsCount: 1
|
ValidatorsCount: 1
|
||||||
VerifyBlocks: true
|
VerifyBlocks: true
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: true
|
||||||
NativeActivations:
|
NativeActivations:
|
||||||
ContractManagement: [0]
|
ContractManagement: [0]
|
||||||
StdLib: [0]
|
StdLib: [0]
|
||||||
|
@ -20,6 +20,7 @@ ProtocolConfiguration:
|
||||||
RoleManagement: [0]
|
RoleManagement: [0]
|
||||||
OracleContract: [0]
|
OracleContract: [0]
|
||||||
NameService: [0]
|
NameService: [0]
|
||||||
|
Notary: [0]
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
# LogPath could be set up in case you need stdout logs to some proper file.
|
# LogPath could be set up in case you need stdout logs to some proper file.
|
||||||
|
|
|
@ -13,11 +13,12 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TransferTarget represents target address and token amount for transfer.
|
// TransferTarget represents target address, token amount and data for transfer.
|
||||||
type TransferTarget struct {
|
type TransferTarget struct {
|
||||||
Token util.Uint160
|
Token util.Uint160
|
||||||
Address util.Uint160
|
Address util.Uint160
|
||||||
Amount int64
|
Amount int64
|
||||||
|
Data interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignerAccount represents combination of the transaction.Signer and the
|
// SignerAccount represents combination of the transaction.Signer and the
|
||||||
|
@ -73,28 +74,22 @@ func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160, tok
|
||||||
{Token: token,
|
{Token: token,
|
||||||
Address: to,
|
Address: to,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
|
Data: data,
|
||||||
},
|
},
|
||||||
}, []interface{}{data})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateNEP17MultiTransferTx creates an invocation transaction for performing NEP17 transfers
|
// CreateNEP17MultiTransferTx creates an invocation transaction for performing NEP17 transfers
|
||||||
// from a single sender to multiple recipients with the given data.
|
// 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) {
|
func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64, recipients []TransferTarget) (*transaction.Transaction, error) {
|
||||||
from, err := address.StringToUint160(acc.Address)
|
from, err := address.StringToUint160(acc.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("bad account address: %w", err)
|
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()
|
w := io.NewBufBinWriter()
|
||||||
for i := range recipients {
|
for i := range recipients {
|
||||||
emit.AppCall(w.BinWriter, recipients[i].Token, "transfer", callflag.All,
|
emit.AppCall(w.BinWriter, recipients[i].Token, "transfer", callflag.All,
|
||||||
from, recipients[i].Address, recipients[i].Amount, data[i])
|
from, recipients[i].Address, recipients[i].Amount, recipients[i].Data)
|
||||||
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
emit.Opcodes(w.BinWriter, opcode.ASSERT)
|
||||||
}
|
}
|
||||||
if w.Err != nil {
|
if w.Err != nil {
|
||||||
|
@ -167,12 +162,12 @@ func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util.
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiTransferNEP17 is similar to TransferNEP17, buf allows to have multiple recipients.
|
// MultiTransferNEP17 is similar to TransferNEP17, buf allows to have multiple recipients.
|
||||||
func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients []TransferTarget, data []interface{}) (util.Uint256, error) {
|
func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients []TransferTarget) (util.Uint256, error) {
|
||||||
if !c.initDone {
|
if !c.initDone {
|
||||||
return util.Uint256{}, errNetworkNotInitialized
|
return util.Uint256{}, errNetworkNotInitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients, data)
|
tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint256{}, err
|
return util.Uint256{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -437,3 +438,28 @@ func NewParameterFromString(in string) (*Parameter, error) {
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExpandParameterToEmitable converts parameter to a type which can be handled as
|
||||||
|
// an array item by emit.Array. It correlates with the way RPC server handles
|
||||||
|
// FuncParams for invoke* calls inside the request.ExpandArrayIntoScript function.
|
||||||
|
func ExpandParameterToEmitable(param Parameter) (interface{}, error) {
|
||||||
|
var err error
|
||||||
|
switch t := param.Type; t {
|
||||||
|
case PublicKeyType:
|
||||||
|
return param.Value.(*keys.PublicKey).Bytes(), nil
|
||||||
|
case ArrayType:
|
||||||
|
arr := param.Value.([]Parameter)
|
||||||
|
res := make([]interface{}, len(arr))
|
||||||
|
for i := range arr {
|
||||||
|
res[i], err = ExpandParameterToEmitable(arr[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
case MapType, InteropInterfaceType, UnknownType, AnyType, VoidType:
|
||||||
|
return nil, fmt.Errorf("unsupported parameter type: %s", t.String())
|
||||||
|
default:
|
||||||
|
return param.Value, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -517,3 +520,85 @@ func hexToBase64(s string) string {
|
||||||
b, _ := hex.DecodeString(s)
|
b, _ := hex.DecodeString(s)
|
||||||
return base64.StdEncoding.EncodeToString(b)
|
return base64.StdEncoding.EncodeToString(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExpandParameterToEmitable(t *testing.T) {
|
||||||
|
pk, _ := keys.NewPrivateKey()
|
||||||
|
testCases := []struct {
|
||||||
|
In Parameter
|
||||||
|
Expected interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
In: Parameter{Type: BoolType, Value: true},
|
||||||
|
Expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: IntegerType, Value: int64(123)},
|
||||||
|
Expected: int64(123),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: ByteArrayType, Value: []byte{1, 2, 3}},
|
||||||
|
Expected: []byte{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: StringType, Value: "writing's on the wall"},
|
||||||
|
Expected: "writing's on the wall",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: Hash160Type, Value: util.Uint160{1, 2, 3}},
|
||||||
|
Expected: util.Uint160{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: Hash256Type, Value: util.Uint256{1, 2, 3}},
|
||||||
|
Expected: util.Uint256{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: PublicKeyType, Value: pk.PublicKey()},
|
||||||
|
Expected: pk.PublicKey().Bytes(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: SignatureType, Value: []byte{1, 2, 3}},
|
||||||
|
Expected: []byte{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
In: Parameter{Type: ArrayType, Value: []Parameter{
|
||||||
|
{
|
||||||
|
Type: IntegerType,
|
||||||
|
Value: int64(123),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: ByteArrayType,
|
||||||
|
Value: []byte{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: ArrayType,
|
||||||
|
Value: []Parameter{
|
||||||
|
{
|
||||||
|
Type: BoolType,
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
Expected: []interface{}{int64(123), []byte{1, 2, 3}, []interface{}{true}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
bw := io.NewBufBinWriter()
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
actual, err := ExpandParameterToEmitable(testCase.In)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, testCase.Expected, actual)
|
||||||
|
|
||||||
|
emit.Array(bw.BinWriter, actual)
|
||||||
|
require.NoError(t, bw.Err)
|
||||||
|
}
|
||||||
|
errCases := []Parameter{
|
||||||
|
{Type: AnyType},
|
||||||
|
{Type: UnknownType},
|
||||||
|
{Type: MapType},
|
||||||
|
{Type: InteropInterfaceType},
|
||||||
|
}
|
||||||
|
for _, errCase := range errCases {
|
||||||
|
_, err := ExpandParameterToEmitable(errCase)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -88,6 +88,8 @@ func Array(w *io.BinWriter, es ...interface{}) {
|
||||||
String(w, e)
|
String(w, e)
|
||||||
case util.Uint160:
|
case util.Uint160:
|
||||||
Bytes(w, e.BytesBE())
|
Bytes(w, e.BytesBE())
|
||||||
|
case util.Uint256:
|
||||||
|
Bytes(w, e.BytesBE())
|
||||||
case []byte:
|
case []byte:
|
||||||
Bytes(w, e)
|
Bytes(w, e)
|
||||||
case bool:
|
case bool:
|
||||||
|
|
Loading…
Reference in a new issue