laconicd/x/evm/client/cli/tx.go
Austin Abell 6eef37b0c6
Finish and clean up module queries and txs (#152)
* Basic transactions set up (to be separated)

* Change transaction command to not include create operation (to include other command in next commit)

* set up create command and made minor changes

* wip implements module queries

* Added tests for query address decoding

* Added ambiguous encoding of to address in transaction and added tests

* Fix linting issue

* Move registering key types to application level to allow module usage to ignore

* Move genaccounts code to be reused

* Switches nonce increase to always happen in ante handler

* change SetNonce from keeper to point to actual nonce operation

* Remove no op nonce switch (not needed with clearing cache)

* Changes to update all accounts pre state transition and clear cache at end of block

* Update accounts before end of block commit (edge case where necessary)

* Fix nonce of sender going into evm in case it's checked, and let evm set contract starting nonce
2019-11-15 12:02:13 -05:00

159 lines
4.4 KiB
Go

package cli
import (
"fmt"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
emint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
)
// GetTxCmd defines the CLI commands regarding evm module transactions
func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
evmTxCmd := &cobra.Command{
Use: types.ModuleName,
Short: "EVM transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
evmTxCmd.AddCommand(client.PostCommands(
GetCmdGenTx(cdc),
GetCmdGenCreateTx(cdc),
)...)
return evmTxCmd
}
// GetCmdGenTx generates an Emint transaction (excludes create operations)
func GetCmdGenTx(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "send [to_address] [amount (in photons)] [<data>]",
Short: "send transaction to address (call operations included)",
Args: cobra.RangeArgs(2, 3),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
toAddr, err := cosmosAddressFromArg(args[0])
if err != nil {
return errors.Wrap(err, "must provide a valid Bech32 address for to_address")
}
// Ambiguously decode amount from any base
amount, err := strconv.ParseInt(args[1], 0, 64)
if err != nil {
return err
}
var data []byte
if len(args) > 2 {
payload := args[2]
if !strings.HasPrefix(payload, "0x") {
payload = "0x" + payload
}
data, err = hexutil.Decode(payload)
if err != nil {
fmt.Println(err)
}
}
from := cliCtx.GetFromAddress()
_, seq, err := authtypes.NewAccountRetriever(cliCtx).GetAccountNumberSequence(from)
if err != nil {
return errors.Wrap(err, "Could not retrieve account sequence")
}
// TODO: Potentially allow overriding of gas price and gas limit
msg := types.NewEmintMsg(seq, &toAddr, sdk.NewInt(amount), txBldr.Gas(),
sdk.NewInt(emint.DefaultGasPrice), data, from)
err = msg.ValidateBasic()
if err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
}
// GetCmdGenTx generates an Emint transaction (excludes create operations)
func GetCmdGenCreateTx(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "create [contract bytecode] [<amount (in photons)>]",
Short: "create contract through the evm using compiled bytecode",
Args: cobra.RangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
payload := args[0]
if !strings.HasPrefix(payload, "0x") {
payload = "0x" + payload
}
data, err := hexutil.Decode(payload)
if err != nil {
fmt.Println(err)
}
var amount int64
if len(args) > 1 {
// Ambiguously decode amount from any base
amount, err = strconv.ParseInt(args[1], 0, 64)
if err != nil {
return errors.Wrap(err, "invalid amount")
}
}
from := cliCtx.GetFromAddress()
_, seq, err := authtypes.NewAccountRetriever(cliCtx).GetAccountNumberSequence(from)
if err != nil {
return errors.Wrap(err, "Could not retrieve account sequence")
}
// TODO: Potentially allow overriding of gas price and gas limit
msg := types.NewEmintMsg(seq, nil, sdk.NewInt(amount), txBldr.Gas(),
sdk.NewInt(emint.DefaultGasPrice), data, from)
err = msg.ValidateBasic()
if err != nil {
return err
}
if err = utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}); err != nil {
return err
}
contractAddr := ethcrypto.CreateAddress(common.BytesToAddress(from.Bytes()), seq)
fmt.Printf(
"Contract will be deployed to: \nHex: %s\nCosmos Address: %s\n",
contractAddr.Hex(),
sdk.AccAddress(contractAddr.Bytes()),
)
return nil
},
}
}