198 lines
5.9 KiB
Go
198 lines
5.9 KiB
Go
package wallet
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/tutus-one/tutus-chain/cli/cmdargs"
|
|
"github.com/tutus-one/tutus-chain/cli/flags"
|
|
"github.com/tutus-one/tutus-chain/cli/options"
|
|
"github.com/tutus-one/tutus-chain/cli/txctx"
|
|
"github.com/tutus-one/tutus-chain/pkg/core/native/nativehashes"
|
|
"github.com/tutus-one/tutus-chain/pkg/core/transaction"
|
|
"github.com/tutus-one/tutus-chain/pkg/crypto/keys"
|
|
"github.com/tutus-one/tutus-chain/pkg/rpcclient/gas"
|
|
"github.com/tutus-one/tutus-chain/pkg/rpcclient/neo"
|
|
"github.com/tutus-one/tutus-chain/pkg/rpcclient/nep17"
|
|
"github.com/tutus-one/tutus-chain/pkg/util"
|
|
"github.com/tutus-one/tutus-chain/pkg/wallet"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
func newValidatorCommands() []*cli.Command {
|
|
return []*cli.Command{
|
|
{
|
|
Name: "register",
|
|
Usage: "Register as a new candidate",
|
|
UsageText: "register -w <path> -r <rpc> [-s timeout] -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
|
Action: handleRegister,
|
|
Flags: append([]cli.Flag{
|
|
walletPathFlag,
|
|
walletConfigFlag,
|
|
txctx.GasFlag,
|
|
txctx.SysGasFlag,
|
|
txctx.OutFlag,
|
|
txctx.ForceFlag,
|
|
txctx.AwaitFlag,
|
|
&flags.AddressFlag{
|
|
Name: "address",
|
|
Aliases: []string{"a"},
|
|
Required: true,
|
|
Usage: "Address to register",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "useRegisterCall",
|
|
Usage: "Use a call to registerCandidate method instead of NEP-17 GAS transfer",
|
|
},
|
|
}, options.RPC...),
|
|
},
|
|
{
|
|
Name: "unregister",
|
|
Usage: "Unregister self as a candidate",
|
|
UsageText: "unregister -w <path> -r <rpc> [-s timeout] -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
|
Action: handleUnregister,
|
|
Flags: append([]cli.Flag{
|
|
walletPathFlag,
|
|
walletConfigFlag,
|
|
txctx.GasFlag,
|
|
txctx.SysGasFlag,
|
|
txctx.OutFlag,
|
|
txctx.ForceFlag,
|
|
txctx.AwaitFlag,
|
|
&flags.AddressFlag{
|
|
Name: "address",
|
|
Required: true,
|
|
Aliases: []string{"a"},
|
|
Usage: "Address to unregister",
|
|
},
|
|
}, options.RPC...),
|
|
},
|
|
{
|
|
Name: "vote",
|
|
Usage: "Vote for a validator",
|
|
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force] [--await]",
|
|
Description: `Votes for a validator by calling "vote" method of a NEO native
|
|
contract. Do not provide candidate argument to perform unvoting. If --await flag is
|
|
included, the command waits for the transaction to be included in a block before exiting.
|
|
`,
|
|
Action: handleVote,
|
|
Flags: append([]cli.Flag{
|
|
walletPathFlag,
|
|
walletConfigFlag,
|
|
txctx.GasFlag,
|
|
txctx.SysGasFlag,
|
|
txctx.OutFlag,
|
|
txctx.ForceFlag,
|
|
txctx.AwaitFlag,
|
|
&flags.AddressFlag{
|
|
Name: "address",
|
|
Required: true,
|
|
Aliases: []string{"a"},
|
|
Usage: "Address to vote from",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "candidate",
|
|
Aliases: []string{"c"},
|
|
Usage: "Public key of candidate to vote for",
|
|
},
|
|
}, options.RPC...),
|
|
},
|
|
}
|
|
}
|
|
|
|
func handleRegister(ctx *cli.Context) error {
|
|
if ctx.Bool("useRegisterCall") {
|
|
return handleNeoAction(ctx, func(contract *neo.Contract, _ util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
|
return contract.RegisterCandidateUnsigned(acc.PublicKey())
|
|
})
|
|
}
|
|
return handleGasAction(ctx, func(nc *neo.Contract, gasT *nep17.Token, _ util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
|
regPrice, err := nc.GetRegisterPrice()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return gasT.TransferUnsigned(
|
|
acc.ScriptHash(),
|
|
nativehashes.NeoToken,
|
|
big.NewInt(regPrice),
|
|
acc.PublicKey().Bytes(),
|
|
)
|
|
})
|
|
}
|
|
|
|
func handleUnregister(ctx *cli.Context) error {
|
|
return handleNeoAction(ctx, func(contract *neo.Contract, _ util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
|
return contract.UnregisterCandidateUnsigned(acc.PublicKey())
|
|
})
|
|
}
|
|
|
|
func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *wallet.Account) (*transaction.Transaction, error)) error {
|
|
return handleTokenAction(ctx, func(nc *neo.Contract, _ *nep17.Token, addr util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
|
return mkTx(nc, addr, acc)
|
|
}, transaction.CalledByEntry)
|
|
}
|
|
|
|
func handleGasAction(ctx *cli.Context, mkTx func(*neo.Contract, *nep17.Token, util.Uint160, *wallet.Account) (*transaction.Transaction, error)) error {
|
|
return handleTokenAction(ctx, mkTx, transaction.Global)
|
|
}
|
|
|
|
func handleTokenAction(
|
|
ctx *cli.Context,
|
|
mkTx func(nc *neo.Contract, gasT *nep17.Token, addr util.Uint160, acc *wallet.Account) (*transaction.Transaction, error),
|
|
scope transaction.WitnessScope,
|
|
) error {
|
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
|
return err
|
|
}
|
|
wall, pass, err := readWallet(ctx)
|
|
if err != nil {
|
|
return cli.Exit(err, 1)
|
|
}
|
|
defer wall.Close()
|
|
|
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
|
addr := addrFlag.Uint160()
|
|
acc, err := options.GetUnlockedAccount(wall, addr, pass)
|
|
if err != nil {
|
|
return cli.Exit(err, 1)
|
|
}
|
|
|
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
|
defer cancel()
|
|
|
|
signers, err := cmdargs.GetSignersAccounts(acc, wall, nil, scope)
|
|
if err != nil {
|
|
return cli.Exit(fmt.Errorf("invalid signers: %w", err), 1)
|
|
}
|
|
_, act, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
|
|
if exitErr != nil {
|
|
return exitErr
|
|
}
|
|
|
|
neoT := neo.New(act)
|
|
gasT := gas.New(act)
|
|
tx, err := mkTx(neoT, gasT, addr, acc)
|
|
if err != nil {
|
|
return cli.Exit(err, 1)
|
|
}
|
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
|
}
|
|
|
|
func handleVote(ctx *cli.Context) error {
|
|
return handleNeoAction(ctx, func(contract *neo.Contract, addr util.Uint160, acc *wallet.Account) (*transaction.Transaction, error) {
|
|
var (
|
|
err error
|
|
pub *keys.PublicKey
|
|
)
|
|
pubStr := ctx.String("candidate")
|
|
if pubStr != "" {
|
|
pub, err = keys.NewPublicKeyFromString(pubStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid public key: '%s'", pubStr)
|
|
}
|
|
}
|
|
|
|
return contract.VoteUnsigned(addr, pub)
|
|
})
|
|
}
|