forked from TrueCloudLab/neoneo-go
cli: add nep11 transfer
command
This commit is contained in:
parent
35ba3d97e6
commit
7ea15f02c6
4 changed files with 278 additions and 38 deletions
|
@ -227,30 +227,33 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func deployVerifyContract(t *testing.T, e *executor) util.Uint160 {
|
func deployVerifyContract(t *testing.T, e *executor) util.Uint160 {
|
||||||
tmpDir := path.Join(os.TempDir(), "neogo.test.deployverifycontract")
|
return deployContract(t, e, "testdata/verify.go", "testdata/verify.yml", validatorWallet, validatorAddr, "one")
|
||||||
require.NoError(t, os.Mkdir(tmpDir, os.ModePerm))
|
}
|
||||||
|
|
||||||
|
func deployContract(t *testing.T, e *executor, inPath, configPath, wallet, address, pass string) util.Uint160 {
|
||||||
|
tmpDir, err := ioutil.TempDir(os.TempDir(), "neogo.test.deploycontract*")
|
||||||
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
os.RemoveAll(tmpDir)
|
os.RemoveAll(tmpDir)
|
||||||
})
|
})
|
||||||
// deploy verification contract
|
nefName := path.Join(tmpDir, "contract.nef")
|
||||||
nefName := path.Join(tmpDir, "verify.nef")
|
manifestName := path.Join(tmpDir, "contract.manifest.json")
|
||||||
manifestName := path.Join(tmpDir, "verify.manifest.json")
|
|
||||||
e.Run(t, "neo-go", "contract", "compile",
|
e.Run(t, "neo-go", "contract", "compile",
|
||||||
"--in", "testdata/verify.go",
|
"--in", inPath,
|
||||||
"--config", "testdata/verify.yml",
|
"--config", configPath,
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString(pass + "\r")
|
||||||
e.Run(t, "neo-go", "contract", "deploy",
|
e.Run(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", validatorWallet, "--address", validatorAddr,
|
"--wallet", wallet, "--address", address,
|
||||||
"--in", nefName, "--manifest", manifestName)
|
"--in", nefName, "--manifest", manifestName)
|
||||||
e.checkTxPersisted(t, "Sent invocation transaction ")
|
e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||||
line, err := e.Out.ReadString('\n')
|
line, err := e.Out.ReadString('\n')
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
line = strings.TrimSpace(strings.TrimPrefix(line, "Contract: "))
|
||||||
hVerify, err := util.Uint160DecodeStringLE(line)
|
h, err := util.Uint160DecodeStringLE(line)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return hVerify
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestComlileAndInvokeFunction(t *testing.T) {
|
func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -9,9 +10,19 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||||
"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/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// nftOwnerAddr is the owner of NFT-ND HASHY token (../examples/nft-nd/nft.go)
|
||||||
|
nftOwnerAddr = "NX1yL5wDx3inK2qUVLRVaqCLUxYnAbv85S"
|
||||||
|
nftOwnerWallet = "../examples/my_wallet.json"
|
||||||
|
nftOwnerPass = "qwerty"
|
||||||
|
)
|
||||||
|
|
||||||
func TestNEP11Import(t *testing.T) {
|
func TestNEP11Import(t *testing.T) {
|
||||||
e := newExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
@ -73,3 +84,127 @@ func TestNEP11Import(t *testing.T) {
|
||||||
require.Equal(t, err, io.EOF)
|
require.Equal(t, err, io.EOF)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNEP11_BalanceOf_Transfer(t *testing.T) {
|
||||||
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
tmpDir, err := ioutil.TempDir(os.TempDir(), "neogo.test.nftwallet*")
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
os.RemoveAll(tmpDir)
|
||||||
|
})
|
||||||
|
|
||||||
|
// copy wallet to temp dir in order not to overwrite the original file
|
||||||
|
bytesRead, err := ioutil.ReadFile(nftOwnerWallet)
|
||||||
|
require.NoError(t, err)
|
||||||
|
wall := path.Join(tmpDir, "my_wallet.json")
|
||||||
|
err = ioutil.WriteFile(wall, bytesRead, 0755)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// transfer funds to contract owner
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet,
|
||||||
|
"--to", nftOwnerAddr,
|
||||||
|
"--token", "GAS",
|
||||||
|
"--amount", "10000",
|
||||||
|
"--from", validatorAddr)
|
||||||
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
// deploy NFT HASHY contract
|
||||||
|
h := deployNFTContract(t, e)
|
||||||
|
|
||||||
|
// mint 1 HASHY token by transferring 10 GAS to HASHY contract
|
||||||
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", wall,
|
||||||
|
"--to", h.StringLE(),
|
||||||
|
"--token", "GAS",
|
||||||
|
"--amount", "10",
|
||||||
|
"--from", nftOwnerAddr)
|
||||||
|
txMint, _ := e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
// get NFT ID from AER
|
||||||
|
aer, err := e.Chain.GetAppExecResults(txMint.Hash(), trigger.Application)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(aer))
|
||||||
|
require.Equal(t, 2, len(aer[0].Events))
|
||||||
|
hashyMintEvent := aer[0].Events[1]
|
||||||
|
require.Equal(t, "Transfer", hashyMintEvent.Name)
|
||||||
|
tokenID, err := hashyMintEvent.Item.Value().([]stackitem.Item)[3].TryBytes()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, tokenID)
|
||||||
|
|
||||||
|
// check the balance
|
||||||
|
cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
|
"--wallet", wall,
|
||||||
|
"--address", nftOwnerAddr}
|
||||||
|
checkBalanceResult := func(t *testing.T, acc string, amount string) {
|
||||||
|
e.checkNextLine(t, "^\\s*Account\\s+"+acc)
|
||||||
|
e.checkNextLine(t, "^\\s*HASHY:\\s+HASHY NFT \\("+h.StringLE()+"\\)")
|
||||||
|
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+amount+"$")
|
||||||
|
e.checkEOF(t)
|
||||||
|
}
|
||||||
|
// balance check: by symbol, token is not imported
|
||||||
|
e.RunWithError(t, append(cmdCheckBalance, "--token", "HASHY")...)
|
||||||
|
// balance check: by hash, ok
|
||||||
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
|
checkBalanceResult(t, nftOwnerAddr, "1")
|
||||||
|
|
||||||
|
// import token
|
||||||
|
e.Run(t, "neo-go", "wallet", "nep11", "import",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", wall,
|
||||||
|
"--token", h.StringLE())
|
||||||
|
|
||||||
|
// balance check: by symbol, ok
|
||||||
|
e.Run(t, append(cmdCheckBalance, "--token", "HASHY")...)
|
||||||
|
checkBalanceResult(t, nftOwnerAddr, "1")
|
||||||
|
|
||||||
|
// balance check: all accounts
|
||||||
|
e.Run(t, "neo-go", "wallet", "nep11", "balance",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", wall,
|
||||||
|
"--token", h.StringLE())
|
||||||
|
checkBalanceResult(t, nftOwnerAddr, "1")
|
||||||
|
|
||||||
|
// remove token from wallet
|
||||||
|
e.In.WriteString("y\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "nep11", "remove",
|
||||||
|
"--wallet", wall, "--token", h.StringLE())
|
||||||
|
|
||||||
|
cmdTransfer := []string{
|
||||||
|
"neo-go", "wallet", "nep11", "transfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
|
"--wallet", wall,
|
||||||
|
"--to", validatorAddr,
|
||||||
|
"--from", nftOwnerAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
// transfer: unimported token with symbol id specified
|
||||||
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
|
e.RunWithError(t, append(cmdTransfer,
|
||||||
|
"--token", "HASHY")...)
|
||||||
|
cmdTransfer = append(cmdTransfer, "--token", h.StringLE())
|
||||||
|
|
||||||
|
// transfer: no id specified
|
||||||
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
|
e.RunWithError(t, cmdTransfer...)
|
||||||
|
cmdTransfer = append(cmdTransfer, "--id", string(tokenID))
|
||||||
|
|
||||||
|
// transfer: good
|
||||||
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
|
e.Run(t, cmdTransfer...)
|
||||||
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
// check balance after transfer
|
||||||
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
|
checkBalanceResult(t, nftOwnerAddr, "0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func deployNFTContract(t *testing.T, e *executor) util.Uint160 {
|
||||||
|
return deployContract(t, e, "../examples/nft-nd/nft.go", "../examples/nft-nd/nft.yml", nftOwnerWallet, nftOwnerAddr, nftOwnerPass)
|
||||||
|
}
|
||||||
|
|
|
@ -7,9 +7,13 @@ 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/pkg/core/transaction"
|
||||||
"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/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
@ -24,6 +28,10 @@ func newNEP11Commands() []cli.Command {
|
||||||
copy(balanceFlags, baseBalanceFlags)
|
copy(balanceFlags, baseBalanceFlags)
|
||||||
balanceFlags = append(balanceFlags, tokenID)
|
balanceFlags = append(balanceFlags, tokenID)
|
||||||
balanceFlags = append(balanceFlags, options.RPC...)
|
balanceFlags = append(balanceFlags, options.RPC...)
|
||||||
|
transferFlags := make([]cli.Flag, len(baseTransferFlags))
|
||||||
|
copy(transferFlags, baseTransferFlags)
|
||||||
|
transferFlags = append(transferFlags, tokenID)
|
||||||
|
transferFlags = append(transferFlags, options.RPC...)
|
||||||
return []cli.Command{
|
return []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "balance",
|
Name: "balance",
|
||||||
|
@ -60,6 +68,21 @@ func newNEP11Commands() []cli.Command {
|
||||||
forceFlag,
|
forceFlag,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "transfer",
|
||||||
|
Usage: "transfer NEP11 tokens",
|
||||||
|
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
||||||
|
Action: transferNEP11,
|
||||||
|
Flags: transferFlags,
|
||||||
|
Description: `Transfers specified NEP11 token with optional cosigners list attached to
|
||||||
|
the transfer. Amount should be specified for divisible NEP11
|
||||||
|
tokens and omitted for non-divisible NEP11 tokens. See
|
||||||
|
'contract testinvokefunction' documentation for the details
|
||||||
|
about cosigners syntax. If no cosigners are given then the
|
||||||
|
sender with CalledByEntry scope will be used as the only
|
||||||
|
signer.
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,3 +182,42 @@ func getNEP11Balance(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transferNEP11(ctx *cli.Context) error {
|
||||||
|
return transferNEP(ctx, manifest.NEP11StandardName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func signAndSendNEP11Transfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, token, to util.Uint160, tokenID string, amount *big.Int, cosigners []client.SignerAccount) error {
|
||||||
|
gas := flags.Fixed8FromContext(ctx, "gas")
|
||||||
|
|
||||||
|
var (
|
||||||
|
tx *transaction.Transaction
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if amount != nil {
|
||||||
|
from, err := address.StringToUint160(acc.Address)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("bad account address: %w", err), 1)
|
||||||
|
}
|
||||||
|
tx, err = c.CreateNEP11TransferTx(acc, token, int64(gas), cosigners, from, to, amount, tokenID)
|
||||||
|
} else {
|
||||||
|
tx, err = c.CreateNEP11TransferTx(acc, token, int64(gas), cosigners, to, tokenID)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if outFile := ctx.String("out"); outFile != "" {
|
||||||
|
if err := paramcontext.InitAndSave(c.GetNetwork(), tx, acc, outFile); err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err := c.SignAndPushTx(tx, acc, cosigners)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ var (
|
||||||
Usage: "Token contract address or hash in LE",
|
Usage: "Token contract address or hash in LE",
|
||||||
},
|
},
|
||||||
}, options.RPC...)
|
}, options.RPC...)
|
||||||
transferFlags = append([]cli.Flag{
|
baseTransferFlags = []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
outFlag,
|
outFlag,
|
||||||
fromAddrFlag,
|
fromAddrFlag,
|
||||||
|
@ -54,7 +54,7 @@ var (
|
||||||
Name: "amount",
|
Name: "amount",
|
||||||
Usage: "Amount of asset to send",
|
Usage: "Amount of asset to send",
|
||||||
},
|
},
|
||||||
}, options.RPC...)
|
}
|
||||||
multiTransferFlags = append([]cli.Flag{
|
multiTransferFlags = append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
outFlag,
|
outFlag,
|
||||||
|
@ -67,6 +67,9 @@ func newNEP17Commands() []cli.Command {
|
||||||
balanceFlags := make([]cli.Flag, len(baseBalanceFlags))
|
balanceFlags := make([]cli.Flag, len(baseBalanceFlags))
|
||||||
copy(balanceFlags, baseBalanceFlags)
|
copy(balanceFlags, baseBalanceFlags)
|
||||||
balanceFlags = append(balanceFlags, options.RPC...)
|
balanceFlags = append(balanceFlags, options.RPC...)
|
||||||
|
transferFlags := make([]cli.Flag, len(baseTransferFlags))
|
||||||
|
copy(transferFlags, baseTransferFlags)
|
||||||
|
transferFlags = append(transferFlags, options.RPC...)
|
||||||
return []cli.Command{
|
return []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "balance",
|
Name: "balance",
|
||||||
|
@ -218,7 +221,9 @@ func getMatchingToken(ctx *cli.Context, w *wallet.Wallet, name string, standard
|
||||||
}, len(w.Extra.Tokens), name, standard)
|
}, len(w.Extra.Tokens), name, standard)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMatchingTokenRPC(ctx *cli.Context, c *client.Client, addr util.Uint160, name string) (*wallet.Token, error) {
|
func getMatchingTokenRPC(ctx *cli.Context, c *client.Client, addr util.Uint160, name string, standard string) (*wallet.Token, error) {
|
||||||
|
switch standard {
|
||||||
|
case manifest.NEP17StandardName:
|
||||||
bs, err := c.GetNEP17Balances(addr)
|
bs, err := c.GetNEP17Balances(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -227,7 +232,20 @@ func getMatchingTokenRPC(ctx *cli.Context, c *client.Client, addr util.Uint160,
|
||||||
t, _ := c.NEP17TokenInfo(bs.Balances[i].Asset)
|
t, _ := c.NEP17TokenInfo(bs.Balances[i].Asset)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
return getMatchingTokenAux(ctx, get, len(bs.Balances), name, manifest.NEP17StandardName)
|
return getMatchingTokenAux(ctx, get, len(bs.Balances), name, standard)
|
||||||
|
case manifest.NEP11StandardName:
|
||||||
|
tokenHash, err := flags.ParseAddress(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("valid token adress or hash in LE should be specified for %s RPC-node request: %s", standard, err.Error())
|
||||||
|
}
|
||||||
|
get := func(i int) *wallet.Token {
|
||||||
|
t, _ := c.NEP11TokenInfo(tokenHash)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
return getMatchingTokenAux(ctx, get, 1, name, standard)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported %s token", standard)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMatchingTokenAux(ctx *cli.Context, get func(i int) *wallet.Token, n int, name string, standard string) (*wallet.Token, error) {
|
func getMatchingTokenAux(ctx *cli.Context, get func(i int) *wallet.Token, n int, name string, standard string) (*wallet.Token, error) {
|
||||||
|
@ -423,7 +441,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
token, err = getMatchingToken(ctx, wall, ss[0], manifest.NEP17StandardName)
|
token, err = getMatchingToken(ctx, wall, ss[0], manifest.NEP17StandardName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.")
|
fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.")
|
||||||
token, err = getMatchingTokenRPC(ctx, c, from, ss[0])
|
token, err = getMatchingTokenRPC(ctx, c, from, ss[0], manifest.NEP17StandardName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -455,10 +473,14 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create NEP17 multitransfer transaction: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("failed to create NEP17 multitransfer transaction: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return signAndSendTransfer(ctx, c, acc, recipients, cosignersAccounts)
|
return signAndSendNEP17Transfer(ctx, c, acc, recipients, cosignersAccounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func transferNEP17(ctx *cli.Context) error {
|
func transferNEP17(ctx *cli.Context) error {
|
||||||
|
return transferNEP(ctx, manifest.NEP17StandardName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
wall, err := openWallet(ctx.String("wallet"))
|
wall, err := openWallet(ctx.String("wallet"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
|
@ -485,20 +507,15 @@ func transferNEP17(ctx *cli.Context) error {
|
||||||
|
|
||||||
toFlag := ctx.Generic("to").(*flags.Address)
|
toFlag := ctx.Generic("to").(*flags.Address)
|
||||||
to := toFlag.Uint160()
|
to := toFlag.Uint160()
|
||||||
token, err := getMatchingToken(ctx, wall, ctx.String("token"), manifest.NEP17StandardName)
|
token, err := getMatchingToken(ctx, wall, ctx.String("token"), standard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.")
|
fmt.Fprintln(ctx.App.ErrWriter, "Can't find matching token in the wallet. Querying RPC-node for balances.")
|
||||||
token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token"))
|
token, err = getMatchingTokenRPC(ctx, c, from, ctx.String("token"), standard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("failed to get matching token: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("failed to get matching token: %w", err), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
amount, err := fixedn.FromString(ctx.String("amount"), int(token.Decimals))
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
|
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
|
||||||
if extErr != nil {
|
if extErr != nil {
|
||||||
return extErr
|
return extErr
|
||||||
|
@ -513,15 +530,38 @@ func transferNEP17(ctx *cli.Context) error {
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create NEP17 transfer transaction: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("failed to create NEP17 transfer transaction: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return signAndSendTransfer(ctx, c, acc, []client.TransferTarget{{
|
amountArg := ctx.String("amount")
|
||||||
|
switch standard {
|
||||||
|
case manifest.NEP17StandardName:
|
||||||
|
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
||||||
|
}
|
||||||
|
return signAndSendNEP17Transfer(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)
|
}}, cosignersAccounts)
|
||||||
|
case manifest.NEP11StandardName:
|
||||||
|
tokenID := ctx.String("id")
|
||||||
|
if tokenID == "" {
|
||||||
|
return cli.NewExitError(errors.New("token ID should be specified"), 1)
|
||||||
|
}
|
||||||
|
if amountArg == "" {
|
||||||
|
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, nil, cosignersAccounts)
|
||||||
|
}
|
||||||
|
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
||||||
|
}
|
||||||
|
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, amount, cosignersAccounts)
|
||||||
|
default:
|
||||||
|
return cli.NewExitError(fmt.Errorf("unsupported token standard %s", standard), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func signAndSendTransfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, recipients []client.TransferTarget, cosigners []client.SignerAccount) error {
|
func signAndSendNEP17Transfer(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, cosigners)
|
tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients, cosigners)
|
||||||
|
|
Loading…
Reference in a new issue