Ripped about cmd logic to make middleware modular

This commit is contained in:
Ethan Frey
2017-07-18 20:12:51 +02:00
parent 5b70b207ef
commit 7b0934bf9f
12 changed files with 435 additions and 263 deletions
+53 -163
View File
@@ -6,10 +6,8 @@ import (
"strings"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/spf13/pflag"
"github.com/tendermint/light-client/commands"
txcmd "github.com/tendermint/light-client/commands/txs"
cmn "github.com/tendermint/tmlibs/common"
@@ -17,85 +15,44 @@ import (
"github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/modules/base"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/modules/fee"
"github.com/tendermint/basecoin/modules/nonce"
)
//-------------------------
// SendTx
// SendTxCmd is CLI command to send tokens between basecoin accounts
var SendTxCmd = &cobra.Command{
Use: "send",
Short: "send tokens from one account to another",
RunE: commands.RequireInit(doSendTx),
}
//nolint
const (
FlagTo = "to"
FlagAmount = "amount"
FlagFee = "fee"
FlagGas = "gas"
FlagExpires = "expires"
FlagSequence = "sequence"
var (
// Middleware must be set in main.go to defined the wrappers we should apply
Middleware Wrapper
)
func init() {
flags := SendTxCmd.Flags()
flags.String(FlagTo, "", "Destination address for the bits")
flags.String(FlagAmount, "", "Coins to send in the format <amt><coin>,<amt><coin>...")
flags.String(FlagFee, "0mycoin", "Coins for the transaction fee of the format <amt><coin>")
flags.Uint64(FlagGas, 0, "Amount of gas for this transaction")
flags.Uint64(FlagExpires, 0, "Block height at which this tx expires")
flags.Int(FlagSequence, -1, "Sequence number for this transaction")
// Wrapper defines the information needed for each middleware package that
// wraps the data. They should read all configuration out of bounds via viper.
type Wrapper interface {
Wrap(basecoin.Tx) (basecoin.Tx, error)
Register(*pflag.FlagSet)
}
// doSendTx is an example of how to make a tx
func doSendTx(cmd *cobra.Command, args []string) error {
// load data from json or flags
var tx basecoin.Tx
found, err := txcmd.LoadJSON(&tx)
if err != nil {
return err
}
if !found {
tx, err = readSendTxFlags()
}
if err != nil {
return err
}
// Wrappers combines a list of wrapper middlewares.
// The first one is the inner-most layer, eg. Fee, Nonce, Chain, Auth
type Wrappers []Wrapper
// TODO: make this more flexible for middleware
tx, err = WrapFeeTx(tx)
if err != nil {
return err
}
tx, err = WrapNonceTx(tx)
if err != nil {
return err
}
tx, err = WrapChainTx(tx)
if err != nil {
return err
}
var _ Wrapper = Wrappers{}
// Note: this is single sig (no multi sig yet)
stx := auth.NewSig(tx)
// Sign if needed and post. This it the work-horse
bres, err := txcmd.SignAndPostTx(stx)
if err != nil {
return err
}
if err = ValidateResult(bres); err != nil {
return err
// Wrap applies the wrappers to the passed in tx in order,
// aborting on the first error
func (ws Wrappers) Wrap(tx basecoin.Tx) (basecoin.Tx, error) {
var err error
for _, w := range ws {
tx, err = w.Wrap(tx)
if err != nil {
break
}
}
return tx, err
}
// Output result
return txcmd.OutputTx(bres)
// Register adds any needed flags to the command
func (ws Wrappers) Register(fs *pflag.FlagSet) {
for _, w := range ws {
w.Register(fs)
}
}
// ValidateResult returns an appropriate error if the server rejected the
@@ -110,44 +67,34 @@ func ValidateResult(res *ctypes.ResultBroadcastTxCommit) error {
return nil
}
// WrapNonceTx grabs the sequence number from the flag and wraps
// the tx with this nonce. Grabs the permission from the signer,
// as we still only support single sig on the cli
func WrapNonceTx(tx basecoin.Tx) (res basecoin.Tx, err error) {
//add the nonce tx layer to the tx
seq := viper.GetInt(FlagSequence)
if seq < 0 {
return res, fmt.Errorf("sequence must be greater than 0")
}
signers := []basecoin.Actor{GetSignerAct()}
res = nonce.NewTx(uint32(seq), signers, tx)
return
}
// ParseAddress parses an address of form:
// [<chain>:][<app>:]<hex address>
// into a basecoin.Actor.
// If app is not specified or "", then assume auth.NameSigs
func ParseAddress(input string) (res basecoin.Actor, err error) {
chain, app := "", auth.NameSigs
spl := strings.SplitN(input, ":", 3)
// WrapFeeTx checks for FlagFee and if present wraps the tx with a
// FeeTx of the given amount, paid by the signer
func WrapFeeTx(tx basecoin.Tx) (res basecoin.Tx, err error) {
//parse the fee and amounts into coin types
toll, err := coin.ParseCoin(viper.GetString(FlagFee))
if len(spl) == 3 {
chain = spl[0]
spl = spl[1:]
}
if len(spl) == 2 {
if spl[0] != "" {
app = spl[0]
}
spl = spl[1:]
}
addr, err := hex.DecodeString(cmn.StripHex(spl[0]))
if err != nil {
return res, err
return res, errors.Errorf("Address is invalid hex: %v\n", err)
}
// if no fee, do nothing, otherwise wrap it
if toll.IsZero() {
return tx, nil
res = basecoin.Actor{
ChainID: chain,
App: app,
Address: addr,
}
res = fee.NewFee(tx, toll, GetSignerAct())
return
}
// WrapChainTx will wrap the tx with a ChainTx from the standard flags
func WrapChainTx(tx basecoin.Tx) (res basecoin.Tx, err error) {
expires := viper.GetInt64(FlagExpires)
chain := commands.GetChainID()
if chain == "" {
return res, errors.New("No chain-id provided")
}
res = base.NewChainTx(chain, uint64(expires), tx)
return
}
@@ -161,60 +108,3 @@ func GetSignerAct() (res basecoin.Actor) {
}
return res
}
func readSendTxFlags() (tx basecoin.Tx, err error) {
// parse to address
chain, to, err := parseChainAddress(viper.GetString(FlagTo))
if err != nil {
return tx, err
}
toAddr := auth.SigPerm(to)
toAddr.ChainID = chain
amountCoins, err := coin.ParseCoins(viper.GetString(FlagAmount))
if err != nil {
return tx, err
}
// craft the inputs and outputs
ins := []coin.TxInput{{
Address: GetSignerAct(),
Coins: amountCoins,
}}
outs := []coin.TxOutput{{
Address: toAddr,
Coins: amountCoins,
}}
return coin.NewSendTx(ins, outs), nil
}
func parseChainAddress(toFlag string) (string, []byte, error) {
var toHex string
var chainPrefix string
spl := strings.Split(toFlag, "/")
switch len(spl) {
case 1:
toHex = spl[0]
case 2:
chainPrefix = spl[0]
toHex = spl[1]
default:
return "", nil, errors.Errorf("To address has too many slashes")
}
// convert destination address to bytes
to, err := hex.DecodeString(cmn.StripHex(toHex))
if err != nil {
return "", nil, errors.Errorf("To address is invalid hex: %v\n", err)
}
return chainPrefix, to, nil
}
/** TODO copied from basecoin cli - put in common somewhere? **/
// ParseHexFlag parses a flag string to byte array
func ParseHexFlag(flag string) ([]byte, error) {
return hex.DecodeString(cmn.StripHex(viper.GetString(flag)))
}
+1 -67
View File
@@ -1,78 +1,12 @@
package commands
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin"
wire "github.com/tendermint/go-wire"
lc "github.com/tendermint/light-client"
lcmd "github.com/tendermint/light-client/commands"
proofcmd "github.com/tendermint/light-client/commands/proofs"
"github.com/tendermint/light-client/proofs"
"github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/modules/nonce"
"github.com/tendermint/basecoin/stack"
"github.com/tendermint/basecoin"
)
// AccountQueryCmd - command to query an account
var AccountQueryCmd = &cobra.Command{
Use: "account [address]",
Short: "Get details of an account, with proof",
RunE: lcmd.RequireInit(doAccountQuery),
}
func doAccountQuery(cmd *cobra.Command, args []string) error {
addr, err := proofcmd.ParseHexKey(args, "address")
if err != nil {
return err
}
key := stack.PrefixedKey(coin.NameCoin, auth.SigPerm(addr).Bytes())
acc := coin.Account{}
proof, err := proofcmd.GetAndParseAppProof(key, &acc)
if lc.IsNoDataErr(err) {
return errors.Errorf("Account bytes are empty for address %X ", addr)
} else if err != nil {
return err
}
return proofcmd.OutputProof(acc, proof.BlockHeight())
}
// NonceQueryCmd - command to query an nonce account
var NonceQueryCmd = &cobra.Command{
Use: "nonce [address]",
Short: "Get details of a nonce sequence number, with proof",
RunE: lcmd.RequireInit(doNonceQuery),
}
func doNonceQuery(cmd *cobra.Command, args []string) error {
addr, err := proofcmd.ParseHexKey(args, "address")
if err != nil {
return err
}
act := []basecoin.Actor{basecoin.NewActor(
auth.NameSigs,
addr,
)}
key := stack.PrefixedKey(nonce.NameNonce, nonce.GetSeqKey(act))
var seq uint32
proof, err := proofcmd.GetAndParseAppProof(key, &seq)
if lc.IsNoDataErr(err) {
return errors.Errorf("Sequence is empty for address %X ", addr)
} else if err != nil {
return err
}
return proofcmd.OutputProof(seq, proof.BlockHeight())
}
// BaseTxPresenter this decodes all basecoin tx
type BaseTxPresenter struct {
proofs.RawPresenter // this handles MakeKey as hex bytes
+29 -5
View File
@@ -1,10 +1,12 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/tendermint/abci/version"
keycmd "github.com/tendermint/go-crypto/cmd"
"github.com/tendermint/light-client/commands"
"github.com/tendermint/light-client/commands/proofs"
@@ -15,7 +17,11 @@ import (
"github.com/tendermint/tmlibs/cli"
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
coincmd "github.com/tendermint/basecoin/cmd/basecoin/commands"
authcmd "github.com/tendermint/basecoin/modules/auth/commands"
basecmd "github.com/tendermint/basecoin/modules/base/commands"
coincmd "github.com/tendermint/basecoin/modules/coin/commands"
feecmd "github.com/tendermint/basecoin/modules/fee/commands"
noncecmd "github.com/tendermint/basecoin/modules/nonce/commands"
)
// BaseCli - main basecoin client command
@@ -30,6 +36,15 @@ tmcli to work for any custom abci app.
`,
}
// VersionCmd - command to show the application version
var VersionCmd = &cobra.Command{
Use: "version",
Short: "Show version info",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(version.Version)
},
}
func main() {
commands.AddBasicFlags(BaseCli)
@@ -38,15 +53,24 @@ func main() {
// These are default parsers, but optional in your app (you can remove key)
proofs.TxCmd,
proofs.KeyCmd,
bcmd.AccountQueryCmd,
bcmd.NonceQueryCmd,
coincmd.AccountQueryCmd,
noncecmd.NonceQueryCmd,
)
// set up the middleware
bcmd.Middleware = bcmd.Wrappers{
feecmd.FeeWrapper{},
noncecmd.NonceWrapper{},
basecmd.ChainWrapper{},
authcmd.SigWrapper{},
}
bcmd.Middleware.Register(txs.RootCmd.PersistentFlags())
// you will always want this for the base send command
proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{})
txs.RootCmd.AddCommand(
// This is the default transaction, optional in your app
bcmd.SendTxCmd,
coincmd.SendTxCmd,
)
// Set up the various commands to use
@@ -59,7 +83,7 @@ func main() {
proofs.RootCmd,
txs.RootCmd,
proxy.RootCmd,
coincmd.VersionCmd,
VersionCmd,
bcmd.AutoCompleteCmd,
)
@@ -9,7 +9,6 @@ import (
"github.com/tendermint/basecoin"
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
"github.com/tendermint/basecoin/docs/guide/counter/plugins/counter"
"github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/modules/coin"
)
@@ -34,45 +33,23 @@ func init() {
fs := CounterTxCmd.Flags()
fs.String(FlagCountFee, "", "Coins to send in the format <amt><coin>,<amt><coin>...")
fs.Bool(FlagValid, false, "Is count valid?")
fs.String(bcmd.FlagFee, "0mycoin", "Coins for the transaction fee of the format <amt><coin>")
fs.Int(bcmd.FlagSequence, -1, "Sequence number for this transaction")
}
// TODO: counterTx is very similar to the sendtx one,
// maybe we can pull out some common patterns?
func counterTx(cmd *cobra.Command, args []string) error {
// load data from json or flags
var tx basecoin.Tx
found, err := txcmd.LoadJSON(&tx)
if err != nil {
return err
}
if !found {
tx, err = readCounterTxFlags()
}
tx, err := readCounterTxFlags()
if err != nil {
return err
}
// TODO: make this more flexible for middleware
tx, err = bcmd.WrapFeeTx(tx)
tx, err = bcmd.Middleware.Wrap(tx)
if err != nil {
return err
}
tx, err = bcmd.WrapNonceTx(tx)
if err != nil {
return err
}
tx, err = bcmd.WrapChainTx(tx)
if err != nil {
return err
}
stx := auth.NewSig(tx)
// Sign if needed and post. This it the work-horse
bres, err := txcmd.SignAndPostTx(stx)
bres, err := txcmd.SignAndPostTx(tx.Unwrap())
if err != nil {
return err
}
+17 -2
View File
@@ -15,6 +15,11 @@ import (
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
bcount "github.com/tendermint/basecoin/docs/guide/counter/cmd/countercli/commands"
authcmd "github.com/tendermint/basecoin/modules/auth/commands"
basecmd "github.com/tendermint/basecoin/modules/base/commands"
coincmd "github.com/tendermint/basecoin/modules/coin/commands"
feecmd "github.com/tendermint/basecoin/modules/fee/commands"
noncecmd "github.com/tendermint/basecoin/modules/nonce/commands"
)
// BaseCli represents the base command when called without any subcommands
@@ -37,17 +42,27 @@ func main() {
// These are default parsers, optional in your app
proofs.TxCmd,
proofs.KeyCmd,
bcmd.AccountQueryCmd,
coincmd.AccountQueryCmd,
noncecmd.NonceQueryCmd,
// XXX IMPORTANT: here is how you add custom query commands in your app
bcount.CounterQueryCmd,
)
// set up the middleware
bcmd.Middleware = bcmd.Wrappers{
feecmd.FeeWrapper{},
noncecmd.NonceWrapper{},
basecmd.ChainWrapper{},
authcmd.SigWrapper{},
}
bcmd.Middleware.Register(txs.RootCmd.PersistentFlags())
// Prepare transactions
proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{})
txs.RootCmd.AddCommand(
// This is the default transaction, optional in your app
bcmd.SendTxCmd,
coincmd.SendTxCmd,
// XXX IMPORTANT: here is how you add custom tx construction for your app
bcount.CounterTxCmd,
+35
View File
@@ -0,0 +1,35 @@
package commands
import (
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/tendermint/basecoin"
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
"github.com/tendermint/basecoin/modules/auth"
)
//nolint
const (
FlagMulti = "multi"
)
// SigWrapper wraps a tx with a signature layer to hold pubkey sigs
type SigWrapper struct{}
var _ bcmd.Wrapper = SigWrapper{}
// Wrap will wrap the tx with OneSig or MultiSig depending on flags
func (SigWrapper) Wrap(tx basecoin.Tx) (res basecoin.Tx, err error) {
if !viper.GetBool(FlagMulti) {
res = auth.NewSig(tx).Wrap()
} else {
res = auth.NewMulti(tx).Wrap()
}
return
}
// Register adds the sequence flags to the cli
func (SigWrapper) Register(fs *pflag.FlagSet) {
fs.Bool(FlagMulti, false, "Prepare the tx for multisig")
}
+40
View File
@@ -0,0 +1,40 @@
package commands
import (
"errors"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/tendermint/light-client/commands"
"github.com/tendermint/basecoin"
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
"github.com/tendermint/basecoin/modules/base"
)
//nolint
const (
FlagExpires = "expires"
)
// ChainWrapper wraps a tx with an chain info and optional expiration
type ChainWrapper struct{}
var _ bcmd.Wrapper = ChainWrapper{}
// Wrap will wrap the tx with a ChainTx from the standard flags
func (ChainWrapper) Wrap(tx basecoin.Tx) (res basecoin.Tx, err error) {
expires := viper.GetInt64(FlagExpires)
chain := commands.GetChainID()
if chain == "" {
return res, errors.New("No chain-id provided")
}
res = base.NewChainTx(chain, uint64(expires), tx)
return
}
// Register adds the sequence flags to the cli
func (ChainWrapper) Register(fs *pflag.FlagSet) {
fs.Uint64(FlagExpires, 0, "Block height at which this tx expires")
}
+39
View File
@@ -0,0 +1,39 @@
package commands
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
lc "github.com/tendermint/light-client"
lcmd "github.com/tendermint/light-client/commands"
proofcmd "github.com/tendermint/light-client/commands/proofs"
"github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/stack"
)
// AccountQueryCmd - command to query an account
var AccountQueryCmd = &cobra.Command{
Use: "account [address]",
Short: "Get details of an account, with proof",
RunE: lcmd.RequireInit(doAccountQuery),
}
func doAccountQuery(cmd *cobra.Command, args []string) error {
addr, err := proofcmd.ParseHexKey(args, "address")
if err != nil {
return err
}
key := stack.PrefixedKey(coin.NameCoin, auth.SigPerm(addr).Bytes())
acc := coin.Account{}
proof, err := proofcmd.GetAndParseAppProof(key, &acc)
if lc.IsNoDataErr(err) {
return errors.Errorf("Account bytes are empty for address %X ", addr)
} else if err != nil {
return err
}
return proofcmd.OutputProof(acc, proof.BlockHeight())
}
+89
View File
@@ -0,0 +1,89 @@
package commands
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/light-client/commands"
txcmd "github.com/tendermint/light-client/commands/txs"
"github.com/tendermint/basecoin"
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
"github.com/tendermint/basecoin/modules/coin"
)
// SendTxCmd is CLI command to send tokens between basecoin accounts
var SendTxCmd = &cobra.Command{
Use: "send",
Short: "send tokens from one account to another",
RunE: commands.RequireInit(doSendTx),
}
//nolint
const (
FlagTo = "to"
FlagAmount = "amount"
)
func init() {
flags := SendTxCmd.Flags()
flags.String(FlagTo, "", "Destination address for the bits")
flags.String(FlagAmount, "", "Coins to send in the format <amt><coin>,<amt><coin>...")
}
// doSendTx is an example of how to make a tx
func doSendTx(cmd *cobra.Command, args []string) error {
// load data from json or flags
// var tx basecoin.Tx
// found, err := txcmd.LoadJSON(&tx)
// if err != nil {
// return err
// }
tx, err := readSendTxFlags()
if err != nil {
return err
}
tx, err = bcmd.Middleware.Wrap(tx)
if err != nil {
return err
}
// Sign if needed and post. This it the work-horse
bres, err := txcmd.SignAndPostTx(tx.Unwrap())
if err != nil {
return err
}
if err = bcmd.ValidateResult(bres); err != nil {
return err
}
// Output result
return txcmd.OutputTx(bres)
}
func readSendTxFlags() (tx basecoin.Tx, err error) {
// parse to address
toAddr, err := bcmd.ParseAddress(viper.GetString(FlagTo))
if err != nil {
return tx, err
}
amountCoins, err := coin.ParseCoins(viper.GetString(FlagAmount))
if err != nil {
return tx, err
}
// craft the inputs and outputs
ins := []coin.TxInput{{
Address: bcmd.GetSignerAct(),
Coins: amountCoins,
}}
outs := []coin.TxOutput{{
Address: toAddr,
Coins: amountCoins,
}}
return coin.NewSendTx(ins, outs), nil
}
+42
View File
@@ -0,0 +1,42 @@
package commands
import (
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/tendermint/basecoin"
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
"github.com/tendermint/basecoin/modules/coin"
"github.com/tendermint/basecoin/modules/fee"
)
//nolint
const (
FlagFee = "fee"
)
// FeeWrapper wraps a tx with an optional fee payment
type FeeWrapper struct{}
var _ bcmd.Wrapper = FeeWrapper{}
// Wrap checks for FlagFee and if present wraps the tx with a
// FeeTx of the given amount, paid by the signer
func (FeeWrapper) Wrap(tx basecoin.Tx) (res basecoin.Tx, err error) {
//parse the fee and amounts into coin types
toll, err := coin.ParseCoin(viper.GetString(FlagFee))
if err != nil {
return res, err
}
// if no fee, do nothing, otherwise wrap it
if toll.IsZero() {
return tx, nil
}
res = fee.NewFee(tx, toll, bcmd.GetSignerAct())
return
}
// Register adds the sequence flags to the cli
func (FeeWrapper) Register(fs *pflag.FlagSet) {
fs.String(FlagFee, "0mycoin", "Coins for the transaction fee of the format <amt><coin>")
}
+46
View File
@@ -0,0 +1,46 @@
package commands
import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
lc "github.com/tendermint/light-client"
lcmd "github.com/tendermint/light-client/commands"
proofcmd "github.com/tendermint/light-client/commands/proofs"
"github.com/tendermint/basecoin"
"github.com/tendermint/basecoin/modules/auth"
"github.com/tendermint/basecoin/modules/nonce"
"github.com/tendermint/basecoin/stack"
)
// NonceQueryCmd - command to query an nonce account
var NonceQueryCmd = &cobra.Command{
Use: "nonce [address]",
Short: "Get details of a nonce sequence number, with proof",
RunE: lcmd.RequireInit(doNonceQuery),
}
func doNonceQuery(cmd *cobra.Command, args []string) error {
addr, err := proofcmd.ParseHexKey(args, "address")
if err != nil {
return err
}
act := []basecoin.Actor{basecoin.NewActor(
auth.NameSigs,
addr,
)}
key := stack.PrefixedKey(nonce.NameNonce, nonce.GetSeqKey(act))
var seq uint32
proof, err := proofcmd.GetAndParseAppProof(key, &seq)
if lc.IsNoDataErr(err) {
return errors.Errorf("Sequence is empty for address %X ", addr)
} else if err != nil {
return err
}
return proofcmd.OutputProof(seq, proof.BlockHeight())
}
+41
View File
@@ -0,0 +1,41 @@
package commands
import (
"fmt"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/tendermint/basecoin"
bcmd "github.com/tendermint/basecoin/cmd/basecli/commands"
"github.com/tendermint/basecoin/modules/nonce"
)
// nolint
const (
FlagSequence = "sequence"
)
// NonceWrapper wraps a tx with a nonce
type NonceWrapper struct{}
var _ bcmd.Wrapper = NonceWrapper{}
// Wrap grabs the sequence number from the flag and wraps
// the tx with this nonce. Grabs the permission from the signer,
// as we still only support single sig on the cli
func (NonceWrapper) Wrap(tx basecoin.Tx) (res basecoin.Tx, err error) {
//add the nonce tx layer to the tx
seq := viper.GetInt(FlagSequence)
if seq < 0 {
return res, fmt.Errorf("sequence must be greater than 0")
}
signers := []basecoin.Actor{bcmd.GetSignerAct()}
res = nonce.NewTx(uint32(seq), signers, tx)
return
}
// Register adds the sequence flags to the cli
func (NonceWrapper) Register(fs *pflag.FlagSet) {
fs.Int(FlagSequence, -1, "Sequence number for this transaction")
}