Skip to content

Commit

Permalink
Merge pull request #11 from Kava-Labs/feat/eip712-msgs
Browse files Browse the repository at this point in the history
EIP712 Update to support multiple transactions
  • Loading branch information
DracoLi authored Jul 28, 2022
2 parents 29a0cb5 + 19ff370 commit 816c280
Show file tree
Hide file tree
Showing 15 changed files with 1,514 additions and 547 deletions.
35 changes: 35 additions & 0 deletions app/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@ func (suite AnteTestSuite) TestAnteHandler() {

suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt(10000000000))

// allow send & delegate msg via eip712
params := suite.app.EvmKeeper.GetParams(suite.ctx)
params.EIP712AllowedMsgs = []evmtypes.EIP712AllowedMsg{
{
MsgTypeUrl: "/cosmos.bank.v1beta1.MsgSend",
MsgValueTypeName: "MsgValueSend",
ValueTypes: []evmtypes.EIP712MsgAttrType{
{Name: "from_address", Type: "string"},
{Name: "to_address", Type: "string"},
{Name: "amount", Type: "Coin[]"},
},
},
{
MsgTypeUrl: "/cosmos.staking.v1beta1.MsgDelegate",
MsgValueTypeName: "MsgValueDelegate",
ValueTypes: []evmtypes.EIP712MsgAttrType{
{Name: "delegator_address", Type: "string"},
{Name: "validator_address", Type: "string"},
{Name: "amount", Type: "Coin"},
},
},
}
suite.app.EvmKeeper.SetParams(suite.ctx, params)

suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100))

testCases := []struct {
Expand Down Expand Up @@ -324,6 +348,17 @@ func (suite AnteTestSuite) TestAnteHandler() {
return txBuilder.GetTx()
}, false, false, true,
},
{
"success - DeliverTx EIP712 signed Cosmos Tx with multiple messages",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMultipleMsgs(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
func() sdk.Tx {
Expand Down
13 changes: 8 additions & 5 deletions app/ante/eip712.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ func init() {
type Eip712SigVerificationDecorator struct {
ak evmtypes.AccountKeeper
signModeHandler authsigning.SignModeHandler
evmKeeper EVMKeeper
}

// NewEip712SigVerificationDecorator creates a new Eip712SigVerificationDecorator
func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler) Eip712SigVerificationDecorator {
func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler, ek EVMKeeper) Eip712SigVerificationDecorator {
return Eip712SigVerificationDecorator{
ak: ak,
signModeHandler: signModeHandler,
evmKeeper: ek,
}
}

Expand Down Expand Up @@ -126,7 +128,8 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx,
return next(ctx, tx, simulate)
}

if err := VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx); err != nil {
evmParams := svd.evmKeeper.GetParams(ctx)
if err := VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx, evmParams); err != nil {
errMsg := fmt.Errorf("signature verification failed; please verify account number (%d) and chain-id (%s): %w", accNum, chainID, err)
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg.Error())
}
Expand All @@ -142,6 +145,7 @@ func VerifySignature(
sigData signing.SignatureData,
_ authsigning.SignModeHandler,
tx authsigning.Tx,
params evmtypes.Params,
) error {
switch data := sigData.(type) {
case *signing.SingleSignatureData:
Expand All @@ -162,7 +166,7 @@ func VerifySignature(
return sdkerrors.Wrap(sdkerrors.ErrNoSignatures, "tx doesn't contain any msgs to verify signature")
}

txBytes := legacytx.StdSignBytes(
txBytes := eip712.ConstructUntypedEIP712Data(
signerData.ChainID,
signerData.AccountNumber,
signerData.Sequence,
Expand All @@ -173,7 +177,6 @@ func VerifySignature(
},
msgs, tx.GetMemo(),
)

signerChainID, err := ethermint.ParseChainID(signerData.ChainID)
if err != nil {
return sdkerrors.Wrapf(err, "failed to parse chainID: %s", signerData.ChainID)
Expand Down Expand Up @@ -215,7 +218,7 @@ func VerifySignature(
FeePayer: feePayer,
}

typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
typedData, err := eip712.WrapTxToTypedData(extOpt.TypedDataChainID, msgs, txBytes, feeDelegation, params)
if err != nil {
return sdkerrors.Wrap(err, "failed to pack tx data in EIP712 object")
}
Expand Down
2 changes: 1 addition & 1 deletion app/ante/handler_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
ante.NewValidateSigCountDecorator(options.AccountKeeper),
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
// Note: signature verification uses EIP instead of the cosmos signature validator
NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler, options.EvmKeeper),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewAnteDecorator(options.IBCKeeper),
)
Expand Down
26 changes: 17 additions & 9 deletions app/ante/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"testing"
"time"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
types2 "github.com/cosmos/cosmos-sdk/x/bank/types"
types3 "github.com/cosmos/cosmos-sdk/x/staking/types"
Expand Down Expand Up @@ -216,19 +215,28 @@ func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress
// Build MsgSend
recipient := sdk.AccAddress(common.Address{}.Bytes())
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(1))))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend})
}

func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build MsgSend
valEthAddr := tests.GenerateAddress()
valAddr := sdk.ValAddress(valEthAddr.Bytes())
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend})
}

func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMultipleMsgs(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
valEthAddr := tests.GenerateAddress()
valAddr := sdk.ValAddress(valEthAddr.Bytes())
recipient := sdk.AccAddress(common.Address{}.Bytes())
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(1))))
msgDelegate := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend, msgDelegate, msgDelegate, msgSend})
}

func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msgs []sdk.Msg,
) client.TxBuilder {
var err error

Expand All @@ -240,14 +248,14 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
ethChainId := pc.Uint64()

// GenerateTypedData TypedData
var ethermintCodec codec.ProtoCodecMarshaler
fee := legacytx.NewStdFee(gas, gasAmount)
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()

data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "")
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{
data := eip712.ConstructUntypedEIP712Data(chainId, accNumber, nonce, 0, fee, msgs, "")
evmParams := suite.app.EvmKeeper.GetParams(suite.ctx)
typedData, err := eip712.WrapTxToTypedData(ethChainId, msgs, data, &eip712.FeeDelegationOptions{
FeePayer: from,
})
}, evmParams)
suite.Require().NoError(err)

sigHash, err := eip712.ComputeTypedDataHash(typedData)
Expand Down Expand Up @@ -288,7 +296,7 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
err = builder.SetSignatures(sigsV2)
suite.Require().NoError(err)

err = builder.SetMsgs(msg)
err = builder.SetMsgs(msgs...)
suite.Require().NoError(err)

return builder
Expand Down
2 changes: 1 addition & 1 deletion cmd/ethermintd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func main() {

rootCmd, _ := NewRootCmd()

if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil {
if err := svrcmd.Execute(rootCmd, EnvPrefix, app.DefaultNodeHome); err != nil {
switch e := err.(type) {
case server.ErrorCode:
os.Exit(e.Code)
Expand Down
54 changes: 54 additions & 0 deletions docs/api/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
- [ethermint/evm/v1/evm.proto](#ethermint/evm/v1/evm.proto)
- [AccessTuple](#ethermint.evm.v1.AccessTuple)
- [ChainConfig](#ethermint.evm.v1.ChainConfig)
- [EIP712AllowedMsg](#ethermint.evm.v1.EIP712AllowedMsg)
- [EIP712MsgAttrType](#ethermint.evm.v1.EIP712MsgAttrType)
- [EIP712NestedMsgType](#ethermint.evm.v1.EIP712NestedMsgType)
- [Log](#ethermint.evm.v1.Log)
- [Params](#ethermint.evm.v1.Params)
- [State](#ethermint.evm.v1.State)
Expand Down Expand Up @@ -187,6 +190,56 @@ instead of *big.Int.



<a name="ethermint.evm.v1.EIP712AllowedMsg"></a>

### EIP712AllowedMsg
EIP712AllowedMsg stores an allowed legacy msg and its eip712 type.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `msg_type_url` | [string](#string) | | msg's proto type name. ie "/cosmos.bank.v1beta1.MsgSend" |
| `msg_value_type_name` | [string](#string) | | name of the eip712 value type. ie "MsgValueSend" |
| `value_types` | [EIP712MsgAttrType](#ethermint.evm.v1.EIP712MsgAttrType) | repeated | types of the msg value |
| `nested_types` | [EIP712NestedMsgType](#ethermint.evm.v1.EIP712NestedMsgType) | repeated | nested types of the msg value |






<a name="ethermint.evm.v1.EIP712MsgAttrType"></a>

### EIP712MsgAttrType
EIP712MsgAttrType is the eip712 type of a single message attribute.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `name` | [string](#string) | | |
| `type` | [string](#string) | | |






<a name="ethermint.evm.v1.EIP712NestedMsgType"></a>

### EIP712NestedMsgType
EIP712MsgType is the eip712 type of a single message.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `name` | [string](#string) | | name of the nested type. ie "Fee", "Coin" |
| `attrs` | [EIP712MsgAttrType](#ethermint.evm.v1.EIP712MsgAttrType) | repeated | attrs of the nested type |






<a name="ethermint.evm.v1.Log"></a>

### Log
Expand Down Expand Up @@ -225,6 +278,7 @@ Params defines the EVM module parameters
| `enable_call` | [bool](#bool) | | enable call toggles state transitions that use the vm.Call function |
| `extra_eips` | [int64](#int64) | repeated | extra eips defines the additional EIPs for the vm.Config |
| `chain_config` | [ChainConfig](#ethermint.evm.v1.ChainConfig) | | chain config defines the EVM chain configuration parameters |
| `eip712_allowed_msgs` | [EIP712AllowedMsg](#ethermint.evm.v1.EIP712AllowedMsg) | repeated | list of allowed eip712 msgs and their types |



Expand Down
Loading

0 comments on commit 816c280

Please sign in to comment.