mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 09:29:38 +00:00
Merge pull request #3235 from nspcc-dev/actor_refactor
cli: move actor handling
This commit is contained in:
commit
6f3a219d67
9 changed files with 191 additions and 226 deletions
|
@ -11,18 +11,25 @@ import (
|
|||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"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/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/urfave/cli"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// DefaultTimeout is the default timeout used for RPC requests.
|
||||
|
@ -97,6 +104,8 @@ var Debug = cli.BoolFlag{
|
|||
|
||||
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
|
||||
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
|
||||
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
|
||||
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
|
||||
|
||||
// GetNetwork examines Context's flags and returns the appropriate network. It
|
||||
// defaults to PrivNet if no flags are given.
|
||||
|
@ -279,3 +288,108 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
|
|||
log, err := cc.Build()
|
||||
return log, &cc.Level, _winfileSinkCloser, err
|
||||
}
|
||||
|
||||
// GetRPCWithActor returns an RPC client instance and Actor instance for the given context.
|
||||
func GetRPCWithActor(gctx context.Context, ctx *cli.Context, signers []actor.SignerAccount) (*rpcclient.Client, *actor.Actor, cli.ExitCoder) {
|
||||
c, err := GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
a, actorErr := actor.New(c, signers)
|
||||
if actorErr != nil {
|
||||
c.Close()
|
||||
return nil, nil, cli.NewExitError(fmt.Errorf("failed to create Actor: %w", actorErr), 1)
|
||||
}
|
||||
return c, a, nil
|
||||
}
|
||||
|
||||
// GetAccFromContext returns account and wallet from context. If address is not set, default address is used.
|
||||
func GetAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
|
||||
var addr util.Uint160
|
||||
|
||||
wPath := ctx.String("wallet")
|
||||
walletConfigPath := ctx.String("wallet-config")
|
||||
if len(wPath) != 0 && len(walletConfigPath) != 0 {
|
||||
return nil, nil, errConflictingWalletFlags
|
||||
}
|
||||
if len(wPath) == 0 && len(walletConfigPath) == 0 {
|
||||
return nil, nil, errNoWallet
|
||||
}
|
||||
var pass *string
|
||||
if len(walletConfigPath) != 0 {
|
||||
cfg, err := ReadWalletConfig(walletConfigPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
wPath = cfg.Path
|
||||
pass = &cfg.Password
|
||||
}
|
||||
|
||||
wall, err := wallet.NewWalletFromFile(wPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||
if addrFlag.IsSet {
|
||||
addr = addrFlag.Uint160()
|
||||
} else {
|
||||
addr = wall.GetChangeAddress()
|
||||
if addr.Equals(util.Uint160{}) {
|
||||
return nil, wall, errors.New("can't get default address")
|
||||
}
|
||||
}
|
||||
|
||||
acc, err := GetUnlockedAccount(wall, addr, pass)
|
||||
return acc, wall, err
|
||||
}
|
||||
|
||||
// GetUnlockedAccount returns account from wallet, address and uses pass to unlock specified account if given.
|
||||
// If the password is not given, then it is requested from user.
|
||||
func GetUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
|
||||
acc := wall.GetAccount(addr)
|
||||
if acc == nil {
|
||||
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
||||
}
|
||||
|
||||
if acc.CanSign() || acc.EncryptedWIF == "" {
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
if pass == nil {
|
||||
rawPass, err := input.ReadPassword(
|
||||
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error reading password: %w", err)
|
||||
}
|
||||
trimmed := strings.TrimRight(string(rawPass), "\n")
|
||||
pass = &trimmed
|
||||
}
|
||||
err := acc.Decrypt(*pass, wall.Scrypt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// ReadWalletConfig reads wallet config from the given path.
|
||||
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
|
||||
file, err := os.Open(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
configData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read wallet config: %w", err)
|
||||
}
|
||||
|
||||
cfg := &config.Wallet{}
|
||||
|
||||
err = yaml.Unmarshal(configData, &cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
|
@ -37,7 +38,7 @@ func manifestAddGroup(ctx *cli.Context) error {
|
|||
|
||||
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
||||
|
||||
gAcc, w, err := GetAccFromContext(ctx)
|
||||
gAcc, w, err := options.GetAccFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
||||
}
|
||||
|
|
|
@ -11,14 +11,11 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
|
||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"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/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
|
@ -39,16 +36,14 @@ import (
|
|||
const addressFlagName = "address, a"
|
||||
|
||||
var (
|
||||
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
|
||||
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
|
||||
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
|
||||
errNoMethod = errors.New("no method specified for function invocation command")
|
||||
errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
|
||||
errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
|
||||
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
||||
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
||||
errFileExist = errors.New("A file with given smart-contract name already exists")
|
||||
addressFlag = flags.AddressFlag{
|
||||
errNoInput = errors.New("no input file was found, specify an input file with the '--in or -i' flag")
|
||||
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
|
||||
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
|
||||
errNoMethod = errors.New("no method specified for function invocation command")
|
||||
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
||||
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
||||
errFileExist = errors.New("A file with given smart-contract name already exists")
|
||||
addressFlag = flags.AddressFlag{
|
||||
Name: addressFlagName,
|
||||
Usage: "address to use as transaction signee (and gas source)",
|
||||
}
|
||||
|
@ -570,7 +565,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
|||
w *wallet.Wallet
|
||||
)
|
||||
if signAndPush {
|
||||
acc, w, err = GetAccFromContext(ctx)
|
||||
acc, w, err = options.GetAccFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -597,19 +592,14 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
|||
}
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if signAndPush {
|
||||
act, err = actor.New(c, signersAccounts)
|
||||
_, act, err = options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
||||
return err
|
||||
}
|
||||
inv = &act.Invoker
|
||||
} else {
|
||||
inv, err = options.GetInvoker(c, ctx, cosigners)
|
||||
_, inv, err = options.GetRPCWithInvoker(gctx, ctx, cosigners)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -746,71 +736,6 @@ func inspect(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetAccFromContext returns account and wallet from context. If address is not set, default address is used.
|
||||
func GetAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
|
||||
var addr util.Uint160
|
||||
|
||||
wPath := ctx.String("wallet")
|
||||
walletConfigPath := ctx.String("wallet-config")
|
||||
if len(wPath) != 0 && len(walletConfigPath) != 0 {
|
||||
return nil, nil, errConflictingWalletFlags
|
||||
}
|
||||
if len(wPath) == 0 && len(walletConfigPath) == 0 {
|
||||
return nil, nil, errNoWallet
|
||||
}
|
||||
var pass *string
|
||||
if len(walletConfigPath) != 0 {
|
||||
cfg, err := cliwallet.ReadWalletConfig(walletConfigPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
wPath = cfg.Path
|
||||
pass = &cfg.Password
|
||||
}
|
||||
|
||||
wall, err := wallet.NewWalletFromFile(wPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||
if addrFlag.IsSet {
|
||||
addr = addrFlag.Uint160()
|
||||
} else {
|
||||
addr = wall.GetChangeAddress()
|
||||
}
|
||||
|
||||
acc, err := GetUnlockedAccount(wall, addr, pass)
|
||||
return acc, wall, err
|
||||
}
|
||||
|
||||
// GetUnlockedAccount returns account from wallet, address and uses pass to unlock specified account if given.
|
||||
// If the password is not given, then it is requested from user.
|
||||
func GetUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
|
||||
acc := wall.GetAccount(addr)
|
||||
if acc == nil {
|
||||
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
||||
}
|
||||
|
||||
if acc.CanSign() {
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
if pass == nil {
|
||||
rawPass, err := input.ReadPassword(
|
||||
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error reading password: %w", err)
|
||||
}
|
||||
trimmed := strings.TrimRight(string(rawPass), "\n")
|
||||
pass = &trimmed
|
||||
}
|
||||
err := acc.Decrypt(*pass, wall.Scrypt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// contractDeploy deploys contract.
|
||||
func contractDeploy(ctx *cli.Context) error {
|
||||
nefFile, f, err := readNEFFile(ctx.String("in"))
|
||||
|
@ -836,7 +761,7 @@ func contractDeploy(ctx *cli.Context) error {
|
|||
appCallParams = append(appCallParams, data[0])
|
||||
}
|
||||
|
||||
acc, w, err := GetAccFromContext(ctx)
|
||||
acc, w, err := options.GetAccFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
|
@ -31,30 +31,30 @@ func cancelTx(ctx *cli.Context) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
acc, w, err := options.GetAccFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to create RPC client: %w", err), 1)
|
||||
return cli.NewExitError(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1)
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
signers, err := cmdargs.GetSignersAccounts(acc, w, nil, transaction.CalledByEntry)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
}
|
||||
c, a, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
|
||||
if exitErr != nil {
|
||||
return exitErr
|
||||
}
|
||||
|
||||
mainTx, _ := c.GetRawTransactionVerbose(txHash)
|
||||
if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) {
|
||||
return cli.NewExitError(fmt.Errorf("transaction %s is already accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1)
|
||||
}
|
||||
acc, w, err := smartcontract.GetAccFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1)
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
if mainTx != nil && !mainTx.HasSigner(acc.ScriptHash()) {
|
||||
return cli.NewExitError(fmt.Errorf("account %s is not a signer of the conflicting transaction", acc.Address), 1)
|
||||
}
|
||||
|
||||
a, err := actor.NewSimple(c, acc)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to create Actor: %w", err), 1)
|
||||
}
|
||||
|
||||
resHash, _, err := a.SendTunedRun([]byte{byte(opcode.RET)}, []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: txHash}}}, func(r *result.Invoke, t *transaction.Transaction) error {
|
||||
err := actor.DefaultCheckerModifier(r, t)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
|
@ -46,7 +47,7 @@ func newWalletV2FromFile(path string, configPath string) (*walletV2, *string, er
|
|||
}
|
||||
var pass *string
|
||||
if len(configPath) != 0 {
|
||||
cfg, err := ReadWalletConfig(configPath)
|
||||
cfg, err := options.ReadWalletConfig(configPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
@ -21,11 +21,6 @@ func signStoredTransaction(ctx *cli.Context) error {
|
|||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
wall, pass, err := readWallet(ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
defer wall.Close()
|
||||
|
||||
pc, err := paramcontext.Read(ctx.String("in"))
|
||||
if err != nil {
|
||||
|
@ -35,9 +30,7 @@ func signStoredTransaction(ctx *cli.Context) error {
|
|||
if !addrFlag.IsSet {
|
||||
return cli.NewExitError("address was not provided", 1)
|
||||
}
|
||||
|
||||
var ch = addrFlag.Uint160()
|
||||
acc, err := getDecryptedAccount(wall, ch, pass)
|
||||
acc, _, err := options.GetAccFromContext(ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -47,20 +40,13 @@ func signStoredTransaction(ctx *cli.Context) error {
|
|||
return cli.NewExitError("verifiable item is not a transaction", 1)
|
||||
}
|
||||
|
||||
signerFound := false
|
||||
for i := range tx.Signers {
|
||||
if tx.Signers[i].Account == ch {
|
||||
signerFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !signerFound {
|
||||
if !tx.HasSigner(acc.ScriptHash()) {
|
||||
return cli.NewExitError("tx signers don't contain provided account", 1)
|
||||
}
|
||||
|
||||
if acc.CanSign() {
|
||||
sign := acc.SignHashable(pc.Network, pc.Verifiable)
|
||||
if err := pc.AddSignature(ch, acc.Contract, acc.PublicKey(), sign); err != nil {
|
||||
if err := pc.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
|
||||
}
|
||||
} else if rpcNode == "" {
|
||||
|
|
|
@ -522,7 +522,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
acc, err := getDecryptedAccount(wall, from, pass)
|
||||
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -530,25 +530,36 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
if ctx.NArg() == 0 {
|
||||
return cli.NewExitError("empty recipients list", 1)
|
||||
}
|
||||
var (
|
||||
recipients []transferTarget
|
||||
cosignersOffset = ctx.NArg()
|
||||
cosignersSepPos = ctx.NArg() // `--` position.
|
||||
)
|
||||
cache := make(map[string]*wallet.Token)
|
||||
for i := 0; i < ctx.NArg(); i++ {
|
||||
arg := ctx.Args().Get(i)
|
||||
if arg == cmdargs.CosignersSeparator {
|
||||
cosignersOffset = i + 1
|
||||
cosignersSepPos = i
|
||||
break
|
||||
}
|
||||
}
|
||||
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersSepPos+1)
|
||||
if extErr != nil {
|
||||
return extErr
|
||||
}
|
||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
}
|
||||
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||
if exitErr != nil {
|
||||
return exitErr
|
||||
}
|
||||
|
||||
cache := make(map[string]*wallet.Token)
|
||||
for i := 0; i < cosignersSepPos; i++ {
|
||||
arg := ctx.Args().Get(i)
|
||||
ss := strings.SplitN(arg, ":", 3)
|
||||
if len(ss) != 3 {
|
||||
return cli.NewExitError("send format must be '<token>:<addr>:<amount>", 1)
|
||||
|
@ -580,19 +591,6 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
|||
})
|
||||
}
|
||||
|
||||
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
|
||||
if extErr != nil {
|
||||
return extErr
|
||||
}
|
||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
}
|
||||
act, err := actor.New(c, signersAccounts)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
||||
}
|
||||
|
||||
tx, err := makeMultiTransferNEP17(act, recipients)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
|
||||
|
@ -618,7 +616,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
acc, err := getDecryptedAccount(wall, from, pass)
|
||||
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -626,9 +624,22 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
|
||||
if extErr != nil {
|
||||
return extErr
|
||||
}
|
||||
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
|
||||
if extErr != nil {
|
||||
return extErr
|
||||
}
|
||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
}
|
||||
|
||||
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||
if exitErr != nil {
|
||||
return exitErr
|
||||
}
|
||||
|
||||
toFlag := ctx.Generic("to").(*flags.Address)
|
||||
|
@ -644,24 +655,6 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
|||
}
|
||||
}
|
||||
|
||||
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
|
||||
if extErr != nil {
|
||||
return extErr
|
||||
}
|
||||
|
||||
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
|
||||
if extErr != nil {
|
||||
return extErr
|
||||
}
|
||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
}
|
||||
act, err := actor.New(c, signersAccounts)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
||||
}
|
||||
|
||||
amountArg := ctx.String("amount")
|
||||
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
||||
// It's OK for NEP-11 transfer to not have amount set.
|
||||
|
|
|
@ -5,13 +5,10 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
|
@ -111,7 +108,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
|||
return cli.NewExitError("address was not provided", 1)
|
||||
}
|
||||
addr := addrFlag.Uint160()
|
||||
acc, err := getDecryptedAccount(wall, addr, pass)
|
||||
acc, err := options.GetUnlockedAccount(wall, addr, pass)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -119,13 +116,13 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
signers, err := cmdargs.GetSignersAccounts(acc, wall, nil, transaction.CalledByEntry)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
}
|
||||
act, err := actor.NewSimple(c, acc)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("RPC actor issue: %w", err), 1)
|
||||
_, act, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
|
||||
if exitErr != nil {
|
||||
return exitErr
|
||||
}
|
||||
|
||||
contract := neo.New(act)
|
||||
|
@ -153,32 +150,3 @@ func handleVote(ctx *cli.Context) error {
|
|||
return contract.VoteUnsigned(addr, pub)
|
||||
})
|
||||
}
|
||||
|
||||
// getDecryptedAccount tries to get and unlock the specified account if it has a
|
||||
// key inside (otherwise it's returned as is, without an ability to sign). If
|
||||
// password is nil, it will be requested via terminal.
|
||||
func getDecryptedAccount(wall *wallet.Wallet, addr util.Uint160, password *string) (*wallet.Account, error) {
|
||||
acc := wall.GetAccount(addr)
|
||||
if acc == nil {
|
||||
return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr))
|
||||
}
|
||||
|
||||
// No private key available, nothing to decrypt, but it's still a useful account for many purposes.
|
||||
if acc.EncryptedWIF == "" {
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
if password == nil {
|
||||
pass, err := input.ReadPassword(EnterPasswordPrompt)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading password", err)
|
||||
return nil, err
|
||||
}
|
||||
password = &pass
|
||||
}
|
||||
err := acc.Decrypt(*password, wall.Scrypt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return acc, nil
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
|
@ -26,7 +25,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/urfave/cli"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -822,7 +820,7 @@ func createWallet(ctx *cli.Context) error {
|
|||
}
|
||||
var pass *string
|
||||
if len(configPath) != 0 {
|
||||
cfg, err := ReadWalletConfig(configPath)
|
||||
cfg, err := options.ReadWalletConfig(configPath)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -946,7 +944,7 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
|
|||
}
|
||||
var pass *string
|
||||
if len(configPath) != 0 {
|
||||
cfg, err := ReadWalletConfig(configPath)
|
||||
cfg, err := options.ReadWalletConfig(configPath)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -956,27 +954,6 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
|
|||
return path, pass, nil
|
||||
}
|
||||
|
||||
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
|
||||
file, err := os.Open(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
configData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read wallet config: %w", err)
|
||||
}
|
||||
|
||||
cfg := &config.Wallet{}
|
||||
|
||||
err = yaml.Unmarshal(configData, &cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func newAccountFromWIF(w io.Writer, wif string, scrypt keys.ScryptParams, label *string, pass *string) (*wallet.Account, error) {
|
||||
var (
|
||||
phrase, name string
|
||||
|
|
Loading…
Reference in a new issue