diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index b26a9bdd45..45226a4a45 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -73,6 +73,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // custom tx codec func MakeTxCodec() *wire.Codec { cdc := wire.NewCodec() + cdc.RegisterInterface((*sdk.Msg)(nil), nil) crypto.RegisterWire(cdc) // Register crypto.[PubKey,PrivKey,Signature] types. bank.RegisterWire(cdc) // Register bank.[SendMsg,IssueMsg] types. return cdc diff --git a/examples/basecoin/cmd/basecli/commands.go b/examples/basecoin/cmd/basecli/account.go similarity index 81% rename from examples/basecoin/cmd/basecli/commands.go rename to examples/basecoin/cmd/basecli/account.go index a1c2dd5d82..26c8329044 100644 --- a/examples/basecoin/cmd/basecli/commands.go +++ b/examples/basecoin/cmd/basecli/account.go @@ -17,24 +17,6 @@ import ( "github.com/cosmos/cosmos-sdk/examples/basecoin/types" ) -const ( - flagTo = "to" - flagAmount = "amount" - flagFee = "fee" -) - -func postSendCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "send", - Short: "Create and sign a send tx", - RunE: todoNotImplemented, - } - cmd.Flags().String(flagTo, "", "Address to send coins") - cmd.Flags().String(flagAmount, "", "Amount of coins to send") - cmd.Flags().String(flagFee, "", "Fee to pay along with transaction") - return cmd -} - func getAccountCmd() *cobra.Command { cmd := &cobra.Command{ Use: "account
", diff --git a/examples/basecoin/cmd/basecli/sendtx.go b/examples/basecoin/cmd/basecli/sendtx.go new file mode 100644 index 0000000000..add8c27ebc --- /dev/null +++ b/examples/basecoin/cmd/basecli/sendtx.go @@ -0,0 +1,150 @@ +package main + +import ( + "encoding/hex" + "fmt" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/examples/basecoin/app" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" + crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/tmlibs/cli" +) + +const ( + flagTo = "to" + flagAmount = "amount" + flagFee = "fee" + flagSequence = "seq" +) + +func postSendCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "send", + Short: "Create and sign a send tx", + RunE: sendTx, + } + cmd.Flags().String(flagTo, "", "Address to send coins") + cmd.Flags().String(flagAmount, "", "Amount of coins to send") + cmd.Flags().String(flagFee, "", "Fee to pay along with transaction") + cmd.Flags().Int64(flagSequence, 0, "Sequence number to sign the tx") + return cmd +} + +func sendTx(cmd *cobra.Command, args []string) error { + txBytes, err := buildTx() + if err != nil { + return err + } + + uri := viper.GetString(flagNode) + if uri == "" { + return errors.New("Must define which node to query with --node") + } + node := client.GetNode(uri) + + result, err := node.BroadcastTxCommit(txBytes) + if err != nil { + return err + } + + if result.CheckTx.Code != uint32(0) { + return errors.Errorf("CheckTx failed: (%d) %s", + result.CheckTx.Code, + result.CheckTx.Log) + } + if result.DeliverTx.Code != uint32(0) { + return errors.Errorf("CheckTx failed: (%d) %s", + result.DeliverTx.Code, + result.DeliverTx.Log) + } + + fmt.Printf("Result: %#v\n", result) + + // // parse out the value + // acct := new(types.AppAccount) + // cdc := app.MakeTxCodec() + // err = cdc.UnmarshalBinary(resp.Value, acct) + // if err != nil { + // return err + // } + + // // TODO: better + // // fmt.Printf("Account: %#v\n", acct) + // output, err := json.MarshalIndent(acct, "", " ") + // // output, err := json.MarshalIndent(acct.BaseAccount.Coins, "", " ") + // if err != nil { + // return err + // } + // fmt.Println(string(output)) + return nil +} + +func buildTx() ([]byte, error) { + rootDir := viper.GetString(cli.HomeFlag) + keybase, err := client.GetKeyBase(rootDir) + if err != nil { + return nil, err + } + + name := viper.GetString(flagName) + info, err := keybase.Get(name) + if err != nil { + return nil, errors.WithMessage(err, "No key for name") + } + from := info.PubKey.Address() + + msg, err := buildMsg(from) + if err != nil { + return nil, err + } + + // sign and build + bz := msg.GetSignBytes() + passphrase := "1234567890" // XXX: adults only + sig, pubkey, err := keybase.Sign(name, passphrase, bz) + if err != nil { + return nil, err + } + sigs := []sdk.StdSignature{{ + PubKey: pubkey, + Signature: sig, + Sequence: viper.GetInt64(flagSequence), + }} + + // marshal bytes + tx := sdk.NewStdTx(msg, sigs) + cdc := app.MakeTxCodec() + txBytes, err := cdc.MarshalBinary(tx) + if err != nil { + return nil, err + } + return txBytes, nil +} + +func buildMsg(from crypto.Address) (sdk.Msg, error) { + // parse coins + amount := viper.GetString(flagAmount) + coins, err := sdk.ParseCoins(amount) + if err != nil { + return nil, err + } + + // parse destination address + dest := viper.GetString(flagTo) + bz, err := hex.DecodeString(dest) + if err != nil { + return nil, err + } + to := crypto.Address(bz) + + input := bank.NewInput(from, coins) + output := bank.NewOutput(to, coins) + msg := bank.NewSendMsg([]bank.Input{input}, []bank.Output{output}) + return msg, nil +}