Ripped about cmd logic to make middleware modular
This commit is contained in:
+53
-163
@@ -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,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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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>")
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
Reference in New Issue
Block a user