diff --git a/cli/cmdargs/parser.go b/cli/cmdargs/parser.go index 1e449f5e3..2661d5831 100644 --- a/cli/cmdargs/parser.go +++ b/cli/cmdargs/parser.go @@ -9,7 +9,7 @@ import ( "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" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/urfave/cli" @@ -197,17 +197,32 @@ func ParseParams(args []string, calledFromMain bool) (int, []smartcontract.Param // GetSignersAccounts returns the list of signers combined with the corresponding // accounts from the provided wallet. -func GetSignersAccounts(wall *wallet.Wallet, signers []transaction.Signer) ([]rpcclient.SignerAccount, error) { - signersAccounts := make([]rpcclient.SignerAccount, len(signers)) - for i := range signers { - signerAcc := wall.GetAccount(signers[i].Account) +func GetSignersAccounts(senderAcc *wallet.Account, wall *wallet.Wallet, signers []transaction.Signer, accScope transaction.WitnessScope) ([]actor.SignerAccount, error) { + signersAccounts := make([]actor.SignerAccount, 0, len(signers)+1) + sender, err := address.StringToUint160(senderAcc.Address) + if err != nil { + return nil, err + } + signersAccounts = append(signersAccounts, actor.SignerAccount{ + Signer: transaction.Signer{ + Account: sender, + Scopes: accScope, + }, + Account: senderAcc, + }) + for i, s := range signers { + if s.Account == sender { + signersAccounts[0].Signer = s + continue + } + signerAcc := wall.GetAccount(s.Account) if signerAcc == nil { - return nil, fmt.Errorf("no account was found in the wallet for signer #%d (%s)", i, address.Uint160ToString(signers[i].Account)) + return nil, fmt.Errorf("no account was found in the wallet for signer #%d (%s)", i, address.Uint160ToString(s.Account)) } - signersAccounts[i] = rpcclient.SignerAccount{ - Signer: signers[i], + signersAccounts = append(signersAccounts, actor.SignerAccount{ + Signer: s, Account: signerAcc, - } + }) } return signersAccounts, nil } diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index c7530b541..e260306aa 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -22,7 +22,6 @@ import ( "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/neorpc/result" - "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/management" "github.com/nspcc-dev/neo-go/pkg/smartcontract" @@ -659,25 +658,22 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error { func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, script util.Uint160, operation string, params []smartcontract.Parameter, cosigners []transaction.Signer) (util.Uint160, error) { var ( - err error - gas, sysgas fixedn.Fixed8 - cosignersAccounts []rpcclient.SignerAccount - resp *result.Invoke - sender util.Uint160 - signAndPush = acc != nil - act *actor.Actor + err error + gas, sysgas fixedn.Fixed8 + signersAccounts []actor.SignerAccount + resp *result.Invoke + sender util.Uint160 + signAndPush = acc != nil + act *actor.Actor ) if signAndPush { gas = flags.Fixed8FromContext(ctx, "gas") sysgas = flags.Fixed8FromContext(ctx, "sysgas") - sender, err = address.StringToUint160(acc.Address) + signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None) if err != nil { - return sender, err - } - cosignersAccounts, err = cmdargs.GetSignersAccounts(wall, cosigners) - if err != nil { - return sender, cli.NewExitError(fmt.Errorf("failed to calculate network fee: %w", err), 1) + return sender, cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1) } + sender = signersAccounts[0].Signer.Account } gctx, cancel := options.GetTimeoutContext(ctx) defer cancel() @@ -687,26 +683,7 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, return sender, err } if signAndPush { - // This will eventually be handled in cmdargs.GetSignersAccounts. - asa := make([]actor.SignerAccount, 0, len(cosigners)+1) - asa = append(asa, actor.SignerAccount{ - Signer: transaction.Signer{ - Account: sender, - Scopes: transaction.None, - }, - Account: acc, - }) - for _, c := range cosignersAccounts { - if c.Signer.Account == sender { - asa[0].Signer = c.Signer - continue - } - asa = append(asa, actor.SignerAccount{ - Signer: c.Signer, - Account: c.Account, - }) - } - act, err = actor.New(c, asa) + act, err = actor.New(c, signersAccounts) if err != nil { return sender, cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1) } diff --git a/cli/wallet/nep11.go b/cli/wallet/nep11.go index 3b81dfc39..d69c27ecd 100644 --- a/cli/wallet/nep11.go +++ b/cli/wallet/nep11.go @@ -16,7 +16,7 @@ import ( "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/fixedn" - "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/rpcclient/nep11" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" @@ -262,44 +262,31 @@ func transferNEP11(ctx *cli.Context) error { return transferNEP(ctx, manifest.NEP11StandardName) } -func signAndSendNEP11Transfer(ctx *cli.Context, c *rpcclient.Client, acc *wallet.Account, token, to util.Uint160, tokenID []byte, amount *big.Int, data interface{}, cosigners []rpcclient.SignerAccount) error { - gas := flags.Fixed8FromContext(ctx, "gas") - sysgas := flags.Fixed8FromContext(ctx, "sysgas") - +func signAndSendNEP11Transfer(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, token, to util.Uint160, tokenID []byte, amount *big.Int, data interface{}) error { var ( - tx *transaction.Transaction - err error + err error + gas = flags.Fixed8FromContext(ctx, "gas") + sysgas = flags.Fixed8FromContext(ctx, "sysgas") + tx *transaction.Transaction ) if amount != nil { - var from util.Uint160 - - 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, data) //nolint:staticcheck // SA1019: c.CreateNEP11TransferTx is deprecated + n11 := nep11.NewDivisible(act, token) + tx, err = n11.TransferDUnsigned(act.Sender(), to, amount, tokenID, data) } else { - tx, err = c.CreateNEP11TransferTx(acc, token, int64(gas), cosigners, to, tokenID, data) //nolint:staticcheck // SA1019: c.CreateNEP11TransferTx is deprecated + n11 := nep11.NewNonDivisible(act, token) + tx, err = n11.TransferUnsigned(to, tokenID, data) } if err != nil { return cli.NewExitError(err, 1) } tx.SystemFee += int64(sysgas) + tx.NetworkFee += int64(gas) if outFile := ctx.String("out"); outFile != "" { - ver, err := c.GetVersion() - if err != nil { - return cli.NewExitError(fmt.Errorf("RPC failure: %w", err), 1) - } + ver := act.GetVersion() // Make a long-lived transaction, it's to be signed manually. tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2 - m, err := c.GetNetwork() - if err != nil { - return cli.NewExitError(fmt.Errorf("failed to save tx: %w", err), 1) - } - if err := paramcontext.InitAndSave(m, tx, acc, outFile); err != nil { - return cli.NewExitError(err, 1) - } + err = paramcontext.InitAndSave(ver.Protocol.Network, tx, acc, outFile) } else { if !ctx.Bool("force") { err := input.ConfirmTx(ctx.App.Writer, tx) @@ -307,10 +294,10 @@ func signAndSendNEP11Transfer(ctx *cli.Context, c *rpcclient.Client, acc *wallet return cli.NewExitError(err, 1) } } - _, err := c.SignAndPushTx(tx, acc, cosigners) //nolint:staticcheck // SA1019: c.SignAndPushTx is deprecated - if err != nil { - return cli.NewExitError(err, 1) - } + _, _, err = act.SignAndSend(tx) + } + if err != nil { + return cli.NewExitError(err, 1) } fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE()) diff --git a/cli/wallet/nep17.go b/cli/wallet/nep17.go index 5adba25d0..b14d593a6 100644 --- a/cli/wallet/nep17.go +++ b/cli/wallet/nep17.go @@ -12,13 +12,16 @@ import ( "github.com/nspcc-dev/neo-go/cli/input" "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/fixedn" "github.com/nspcc-dev/neo-go/pkg/neorpc/result" "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/gas" "github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker" "github.com/nspcc-dev/neo-go/pkg/rpcclient/neo" + "github.com/nspcc-dev/neo-go/pkg/smartcontract" "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" @@ -546,12 +549,16 @@ func multiTransferNEP17(ctx *cli.Context) error { if extErr != nil { return extErr } - cosignersAccounts, err := cmdargs.GetSignersAccounts(wall, cosigners) + signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create NEP-17 multitransfer transaction: %w", err), 1) + 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) } - return signAndSendNEP17Transfer(ctx, c, acc, recipients, cosignersAccounts) + return signAndSendNEP17Transfer(ctx, act, acc, recipients) } func transferNEP17(ctx *cli.Context) error { @@ -604,9 +611,13 @@ func transferNEP(ctx *cli.Context, standard string) error { if extErr != nil { return extErr } - cosignersAccounts, err := cmdargs.GetSignersAccounts(wall, cosigners) + signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry) if err != nil { - return cli.NewExitError(fmt.Errorf("failed to create NEP-17 transfer transaction: %w", err), 1) + 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") @@ -616,12 +627,12 @@ func transferNEP(ctx *cli.Context, standard string) error { if err != nil { return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) } - return signAndSendNEP17Transfer(ctx, c, acc, []rpcclient.TransferTarget{{ + return signAndSendNEP17Transfer(ctx, act, acc, []rpcclient.TransferTarget{{ Token: token.Hash, Address: to, Amount: amount.Int64(), Data: data, - }}, cosignersAccounts) + }}) case manifest.NEP11StandardName: tokenID := ctx.String("id") if tokenID == "" { @@ -632,42 +643,43 @@ func transferNEP(ctx *cli.Context, standard string) error { return cli.NewExitError(fmt.Errorf("invalid token ID: %w", err), 1) } if amountArg == "" { - return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenIDBytes, nil, data, cosignersAccounts) + return signAndSendNEP11Transfer(ctx, act, acc, token.Hash, to, tokenIDBytes, nil, data) } 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, tokenIDBytes, amount, data, cosignersAccounts) + return signAndSendNEP11Transfer(ctx, act, acc, token.Hash, to, tokenIDBytes, amount, data) default: return cli.NewExitError(fmt.Errorf("unsupported token standard %s", standard), 1) } } -func signAndSendNEP17Transfer(ctx *cli.Context, c *rpcclient.Client, acc *wallet.Account, recipients []rpcclient.TransferTarget, cosigners []rpcclient.SignerAccount) error { +func signAndSendNEP17Transfer(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, recipients []rpcclient.TransferTarget) error { gas := flags.Fixed8FromContext(ctx, "gas") sysgas := flags.Fixed8FromContext(ctx, "sysgas") - tx, err := c.CreateNEP17MultiTransferTx(acc, int64(gas), recipients, cosigners) + scr := smartcontract.NewBuilder() + for i := range recipients { + scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(), + recipients[i].Address, recipients[i].Amount, recipients[i].Data) + } + script, err := scr.Script() + if err != nil { + return err + } + tx, err := act.MakeUnsignedRun(script, nil) if err != nil { return cli.NewExitError(err, 1) } tx.SystemFee += int64(sysgas) + tx.NetworkFee += int64(gas) if outFile := ctx.String("out"); outFile != "" { - ver, err := c.GetVersion() - if err != nil { - return cli.NewExitError(fmt.Errorf("RPC failure: %w", err), 1) - } + ver := act.GetVersion() // Make a long-lived transaction, it's to be signed manually. tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2 - m, err := c.GetNetwork() - if err != nil { - return cli.NewExitError(fmt.Errorf("failed to save tx: %w", err), 1) - } - if err := paramcontext.InitAndSave(m, tx, acc, outFile); err != nil { - return cli.NewExitError(err, 1) - } + err = paramcontext.InitAndSave(ver.Protocol.Network, tx, acc, outFile) } else { if !ctx.Bool("force") { err := input.ConfirmTx(ctx.App.Writer, tx) @@ -675,10 +687,10 @@ func signAndSendNEP17Transfer(ctx *cli.Context, c *rpcclient.Client, acc *wallet return cli.NewExitError(err, 1) } } - _, err := c.SignAndPushTx(tx, acc, cosigners) //nolint:staticcheck // SA1019: c.SignAndPushTx is deprecated - if err != nil { - return cli.NewExitError(err, 1) - } + _, _, err = act.SignAndSend(tx) + } + if err != nil { + return cli.NewExitError(err, 1) } fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())