Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Add EIP-712 encoding support type for any array #1430

Merged
merged 13 commits into from
Nov 16, 2022
13 changes: 12 additions & 1 deletion app/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,18 @@ func (suite AnteTestSuite) TestAnteHandler() {
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712MsgEditValidator(from, privKey, "ethermint_9000-1", gas, amount)
txBuilder := suite.CreateTestEIP712MsgSubmitEvidence(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
{
"success- DeliverTx EIP712 submit proposal v1",
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712SubmitProposalV1(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
}, false, false, true,
},
Expand Down
30 changes: 30 additions & 0 deletions app/ante/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
"github.com/cosmos/cosmos-sdk/x/feegrant"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
types5 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
"github.com/evmos/ethermint/app"
ante "github.com/evmos/ethermint/app/ante"
Expand Down Expand Up @@ -343,6 +344,35 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddres
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
}

func (suite *AnteTestSuite) CreateTestEIP712SubmitProposalV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build V1 proposal messages. Must all be same-type, since EIP-712
// does not support arrays of variable type.
recipient1 := sdk.AccAddress(common.Address{}.Bytes())
msgSend1 := types2.NewMsgSend(from, recipient1, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))

recipient2 := sdk.AccAddress(common.HexToAddress(
"0x4242424242424242424242424242424242424242",
).Bytes())
msgSend2 := types2.NewMsgSend(from, recipient2, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))

proposalMsgs := []sdk.Msg{
msgSend1,
msgSend2,
}

// Build V1 proposal
msgProposal, err := govtypes.NewMsgSubmitProposal(
proposalMsgs,
0a1c marked this conversation as resolved.
Show resolved Hide resolved
sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100))),
sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), from.Bytes()),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

"Metadata",
)

suite.Require().NoError(err)

return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgProposal)
}

// StdSignBytes returns the bytes to sign for a transaction.
func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequence uint64, timeout uint64, fee legacytx.StdFee, msgs []sdk.Msg, memo string, tip *txtypes.Tip) []byte {
msgsBytes := make([]json.RawMessage, 0, len(msgs))
Expand Down
79 changes: 60 additions & 19 deletions ethereum/eip712/eip712.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,32 +206,20 @@ func traverseFields(
}

for i := 0; i < n; i++ {
var field reflect.Value
var (
field reflect.Value
err error
)

if v.IsValid() {
field = v.Field(i)
}

fieldType := t.Field(i).Type
fieldName := jsonNameFromTag(t.Field(i).Tag)

if fieldType == cosmosAnyType {
any, ok := field.Interface().(*codectypes.Any)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrPackAny, "%T", field.Interface())
}

anyWrapper := &cosmosAnyWrapper{
Type: any.TypeUrl,
}

if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
return sdkerrors.Wrap(err, "failed to unpack Any in msg struct")
}

fieldType = reflect.TypeOf(anyWrapper)
field = reflect.ValueOf(anyWrapper)

// then continue as normal
if fieldType, field, err = unpackIfAny(cdc, fieldType, field, true); err != nil {
0a1c marked this conversation as resolved.
Show resolved Hide resolved
return err
}

// If its a nil pointer, do not include in types
Expand Down Expand Up @@ -273,6 +261,10 @@ func traverseFields(
fieldType = fieldType.Elem()
field = field.Index(0)
isCollection = true

if fieldType, field, err = unpackIfAny(cdc, fieldType, field, false); err != nil {
0a1c marked this conversation as resolved.
Show resolved Hide resolved
return err
}
}

for {
Expand Down Expand Up @@ -363,6 +355,55 @@ func jsonNameFromTag(tag reflect.StructTag) string {
return parts[0]
}

func unpackIfAny(
cdc codectypes.AnyUnpacker,
_fieldType reflect.Type,
_field reflect.Value,
0a1c marked this conversation as resolved.
Show resolved Hide resolved
assumeMsgStructure bool,
0a1c marked this conversation as resolved.
Show resolved Hide resolved
) (reflect.Type, reflect.Value, error) {
// Verify type is Any, else return as-is
if _fieldType != cosmosAnyType {
0a1c marked this conversation as resolved.
Show resolved Hide resolved
return _fieldType, _field, nil
}

// Unwrap as Any
any, ok := _field.Interface().(*codectypes.Any)
if !ok {
return nil, reflect.Value{}, sdkerrors.Wrapf(sdkerrors.ErrPackAny, "%T", _field.Interface())
}

var (
fieldType reflect.Type
field reflect.Value
)

if assumeMsgStructure {
// Unpack Any as Msg (for Amino messages)
anyWrapper := &cosmosAnyWrapper{
Type: any.TypeUrl,
}

if err := cdc.UnpackAny(any, &anyWrapper.Value); err != nil {
return nil, reflect.Value{}, sdkerrors.Wrap(err, "failed to unpack Any in msg struct")
}

fieldType = reflect.TypeOf(anyWrapper)
field = reflect.ValueOf(anyWrapper)
} else {
0a1c marked this conversation as resolved.
Show resolved Hide resolved
// Unpack using default (direct)
var anyUnwrapped interface{}

if err := cdc.UnpackAny(any, &anyUnwrapped); err != nil {
return nil, reflect.Value{}, sdkerrors.Wrap(err, "failed to unpack Any in msg struct")
}

fieldType = reflect.TypeOf(anyUnwrapped)
field = reflect.ValueOf(anyUnwrapped)
}

return fieldType, field, nil
}

// _.foo_bar.baz -> TypeFooBarBaz
//
// this is needed for Geth's own signing code which doesn't
Expand Down