Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
### BUG FIXES

- [\#869](https://github.com/cosmos/evm/pull/869) Fix erc20 IBC callbacks to check for native token transfer before parsing recipient.
- [\#860](https://github.com/cosmos/evm/pull/860) Fix EIP-712 signature verification to use configured EVM chain ID instead of parsing cosmos chain ID string and replace legacytx.StdSignBytes with the aminojson sign mode handler.
- [\#794](https://github.com/cosmos/evm/pull/794) Fix mempool.max-txs flag not using desired default of 0
- [\#748](https://github.com/cosmos/evm/pull/748) Fix DynamicFeeChecker in Cosmos ante handler to respect NoBaseFee feemarkets' parameter.
- [\#690](https://github.com/cosmos/evm/pull/690) Fix Ledger hardware wallet support for coin type 60.
Expand Down
53 changes: 38 additions & 15 deletions ante/cosmos/eip712.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cosmos

import (
"context"
"fmt"
"strconv"

ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
Expand All @@ -11,8 +11,12 @@ import (
anteinterfaces "github.com/cosmos/evm/ante/interfaces"
"github.com/cosmos/evm/crypto/ethsecp256k1"
"github.com/cosmos/evm/ethereum/eip712"
evmtypes "github.com/cosmos/evm/x/vm/types"

txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
errorsmod "cosmossdk.io/errors"
txsigning "cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/tx/signing/aminojson"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
Expand All @@ -21,7 +25,6 @@ import (
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)

Expand Down Expand Up @@ -136,6 +139,7 @@ func (svd LegacyEip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
ChainID: chainID,
AccountNumber: accNum,
Sequence: acc.GetSequence(),
Address: acc.GetAddress().String(),
}

if simulate {
Expand Down Expand Up @@ -177,22 +181,41 @@ func VerifySignature(
return errorsmod.Wrap(errortypes.ErrNoSignatures, "tx doesn't contain any msgs to verify signature")
}

txBytes := legacytx.StdSignBytes( //nolint:staticcheck // TODO: fix
signerData.ChainID,
signerData.AccountNumber,
signerData.Sequence,
tx.GetTimeoutHeight(),
legacytx.StdFee{
Amount: tx.GetFee(),
Gas: tx.GetGas(),
anyMsgs, err := eip712.ToAnyMsgs(msgs)
if err != nil {
return err
}
feeAmount := eip712.ToFeeAmount(tx.GetFee())
txData := txsigning.TxData{
Body: &txv1beta1.TxBody{
Messages: anyMsgs,
Memo: tx.GetMemo(),
TimeoutHeight: tx.GetTimeoutHeight(),
},
msgs, tx.GetMemo(),
)

signerChainID, err := strconv.ParseUint(signerData.ChainID, 10, 64)
AuthInfo: &txv1beta1.AuthInfo{
Fee: &txv1beta1.Fee{
Amount: feeAmount,
GasLimit: tx.GetGas(),
},
},
}
signModeHandler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
signer := txsigning.SignerData{
ChainID: signerData.ChainID,
AccountNumber: signerData.AccountNumber,
Sequence: signerData.Sequence,
Address: signerData.Address,
}
txBytes, err := signModeHandler.GetSignBytes(context.Background(), signer, txData)
if err != nil {
return errorsmod.Wrapf(err, "failed to parse chain-id: %s", signerData.ChainID)
return errorsmod.Wrap(err, "failed to get sign bytes using aminojson")
}

ethChainID := evmtypes.GetEthChainConfig().ChainID
if ethChainID == nil {
return errorsmod.Wrap(errortypes.ErrInvalidChainID, "eth chain ID not configured")
}
signerChainID := ethChainID.Uint64()

txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
if !ok {
Expand Down
54 changes: 40 additions & 14 deletions ethereum/eip712/encoding.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package eip712

import (
"context"
"errors"
"fmt"

apitypes "github.com/ethereum/go-ethereum/signer/core/apitypes"

txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
errorsmod "cosmossdk.io/errors"
txsigning "cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/tx/signing/aminojson"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
txTypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
Expand Down Expand Up @@ -159,22 +166,41 @@ func decodeProtobufSignDoc(signDocBytes []byte) (apitypes.TypedData, error) {
}

signerInfo := authInfo.SignerInfos[0]

stdFee := &legacytx.StdFee{
Amount: authInfo.Fee.Amount,
Gas: authInfo.Fee.GasLimit,
var pubKey cryptotypes.PubKey
err := protoCodec.UnpackAny(signerInfo.PublicKey, &pubKey)
if err != nil {
return apitypes.TypedData{}, errorsmod.Wrap(err, "failed to unpack signer public key")
}

// WrapTxToTypedData expects the payload as an Amino Sign Doc
signBytes := legacytx.StdSignBytes( //nolint:staticcheck // TODO: fix
signDoc.ChainId,
signDoc.AccountNumber,
signerInfo.Sequence,
body.TimeoutHeight,
*stdFee,
msgs,
body.Memo,
)
anyMsgs, err := ToAnyMsgs(msgs)
if err != nil {
return apitypes.TypedData{}, err
}
feeAmount := ToFeeAmount(authInfo.Fee.Amount)
txData := txsigning.TxData{
Body: &txv1beta1.TxBody{
Messages: anyMsgs,
Memo: body.Memo,
TimeoutHeight: body.TimeoutHeight,
},
AuthInfo: &txv1beta1.AuthInfo{
Fee: &txv1beta1.Fee{
Amount: feeAmount,
GasLimit: authInfo.Fee.GasLimit,
},
},
}
signModeHandler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
signer := txsigning.SignerData{
ChainID: signDoc.ChainId,
AccountNumber: signDoc.AccountNumber,
Sequence: signerInfo.Sequence,
Address: pubKey.Address().String(),
}
signBytes, err := signModeHandler.GetSignBytes(context.Background(), signer, txData)
if err != nil {
return apitypes.TypedData{}, errorsmod.Wrap(err, "failed to get sign bytes using aminojson")
}

typedData, err := WrapTxToTypedData(
eip155ChainID,
Expand Down
56 changes: 41 additions & 15 deletions ethereum/eip712/encoding_legacy.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package eip712

import (
"context"
"encoding/json"
"errors"
"fmt"

apitypes "github.com/ethereum/go-ethereum/signer/core/apitypes"

txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
errorsmod "cosmossdk.io/errors"
txsigning "cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/tx/signing/aminojson"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
txTypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
Expand Down Expand Up @@ -157,14 +164,12 @@ func legacyDecodeProtobufSignDoc(signDocBytes []byte, eip155ChainID uint64) (api

// Use first message for fee payer and type inference
msg := msgs[0]

signerInfo := authInfo.SignerInfos[0]

stdFee := &legacytx.StdFee{
Amount: authInfo.Fee.Amount,
Gas: authInfo.Fee.GasLimit,
var pubKey cryptotypes.PubKey
err := protoCodec.UnpackAny(signerInfo.PublicKey, &pubKey)
if err != nil {
return apitypes.TypedData{}, errorsmod.Wrap(err, "failed to unpack signer public key")
}

signers, _, err := protoCodec.GetMsgV1Signers(msg)
if err != nil {
return apitypes.TypedData{}, err
Expand All @@ -175,15 +180,36 @@ func legacyDecodeProtobufSignDoc(signDocBytes []byte, eip155ChainID uint64) (api
}

// WrapTxToTypedData expects the payload as an Amino Sign Doc
signBytes := legacytx.StdSignBytes( //nolint:staticcheck // TODO: fix
signDoc.ChainId,
signDoc.AccountNumber,
signerInfo.Sequence,
body.TimeoutHeight,
*stdFee,
msgs,
body.Memo,
)
anyMsgs, err := ToAnyMsgs(msgs)
if err != nil {
return apitypes.TypedData{}, err
}
feeAmount := ToFeeAmount(authInfo.Fee.Amount)
txData := txsigning.TxData{
Body: &txv1beta1.TxBody{
Messages: anyMsgs,
Memo: body.Memo,
TimeoutHeight: body.TimeoutHeight,
},
AuthInfo: &txv1beta1.AuthInfo{
Fee: &txv1beta1.Fee{
Amount: feeAmount,
GasLimit: authInfo.Fee.GasLimit,
},
},
}

signModeHandler := aminojson.NewSignModeHandler(aminojson.SignModeHandlerOptions{})
signer := txsigning.SignerData{
ChainID: signDoc.ChainId,
AccountNumber: signDoc.AccountNumber,
Sequence: signerInfo.Sequence,
Address: pubKey.Address().String(),
}
signBytes, err := signModeHandler.GetSignBytes(context.Background(), signer, txData)
if err != nil {
return apitypes.TypedData{}, errorsmod.Wrap(err, "failed to get sign bytes using aminojson")
}

typedData, err := LegacyWrapTxToTypedData(
protoCodec,
Expand Down
26 changes: 26 additions & 0 deletions ethereum/eip712/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ import (
"github.com/tidwall/gjson"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"google.golang.org/protobuf/types/known/anypb"

basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
errorsmod "cosmossdk.io/errors"

"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
)

Expand Down Expand Up @@ -387,3 +391,25 @@ func doRecover(err *error) {
*err = fmt.Errorf("%v", r)
}
}

// ToAnyMsgs helps to convert sdk.Msg slice to []*anypb.Any
func ToAnyMsgs(msgs []sdk.Msg) ([]*anypb.Any, error) {
anyMsgs := make([]*anypb.Any, len(msgs))
for i, msg := range msgs {
anyMsg, err := types.NewAnyWithValue(msg)
if err != nil {
return nil, errorsmod.Wrap(err, "failed to convert sdk.Msg to Any")
}
anyMsgs[i] = &anypb.Any{TypeUrl: anyMsg.TypeUrl, Value: anyMsg.Value}
}
return anyMsgs, nil
}

// ToFeeAmount helps to convert sdk.Coins to []*basev1beta1.Coin
func ToFeeAmount(coins sdk.Coins) []*basev1beta1.Coin {
feeAmount := make([]*basev1beta1.Coin, len(coins))
for i, coin := range coins {
feeAmount[i] = &basev1beta1.Coin{Denom: coin.Denom, Amount: coin.Amount.String()}
}
return feeAmount
}
Loading
Loading