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

Commit 382a6ae

Browse files
Migrate updated EIP-712 algorithm from Evmos (#1746)
* Migrate updated EIP-712 algorithm from Evmos * Update licenses for Ethermint * update gomod2nix and go mod tidy * Move ante test suite execution to ante_test --------- Co-authored-by: Freddy Caceres <facs95@gmail.com>
1 parent dfd99e0 commit 382a6ae

19 files changed

+2028
-1119
lines changed

app/ante/ante_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import (
55
"fmt"
66
"math/big"
77
"strings"
8+
"testing"
89
"time"
910

1011
sdkmath "cosmossdk.io/math"
1112
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
13+
"github.com/stretchr/testify/suite"
1214

1315
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
1416
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
@@ -34,6 +36,26 @@ import (
3436
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
3537
)
3638

39+
func TestAnteTestSuite(t *testing.T) {
40+
suite.Run(t, &AnteTestSuite{
41+
enableLondonHF: true,
42+
})
43+
44+
// Re-run the tests with EIP-712 Legacy encodings to ensure backwards compatibility.
45+
// LegacyEIP712Extension should not be run with current TypedData encodings, since they are not compatible.
46+
suite.Run(t, &AnteTestSuite{
47+
enableLondonHF: true,
48+
useLegacyEIP712Extension: true,
49+
useLegacyEIP712TypedData: true,
50+
})
51+
52+
suite.Run(t, &AnteTestSuite{
53+
enableLondonHF: true,
54+
useLegacyEIP712Extension: false,
55+
useLegacyEIP712TypedData: true,
56+
})
57+
}
58+
3759
func (suite AnteTestSuite) TestAnteHandler() {
3860
var acc authtypes.AccountI
3961
addr, privKey := tests.NewAddrKey()
@@ -387,7 +409,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
387409
from, grantee, &banktypes.SendAuthorization{SpendLimit: gasAmount}, &expiresAt,
388410
)
389411
suite.Require().NoError(err)
390-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, privKey, "ethermint_9000-1", gas, gasAmount, msg).GetTx()
412+
return suite.CreateTestEIP712SingleMessageTxBuilder(privKey, "ethermint_9000-1", gas, gasAmount, msg).GetTx()
391413
}, false, false, true,
392414
},
393415

app/ante/eip712.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ func VerifySignature(
266266
FeePayer: feePayer,
267267
}
268268

269-
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
269+
typedData, err := eip712.LegacyWrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
270270
if err != nil {
271271
return errorsmod.Wrap(err, "failed to create EIP-712 typed data from tx")
272272
}

app/ante/utils_test.go

Lines changed: 45 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"math"
77
"math/big"
8-
"testing"
98
"time"
109

1110
sdkmath "cosmossdk.io/math"
@@ -15,11 +14,9 @@ import (
1514
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
1615
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
1716
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
18-
"github.com/ethereum/go-ethereum/crypto"
19-
"github.com/ethereum/go-ethereum/signer/core/apitypes"
2017
"github.com/evmos/ethermint/ethereum/eip712"
2118
"github.com/evmos/ethermint/testutil"
22-
"github.com/evmos/ethermint/types"
19+
utiltx "github.com/evmos/ethermint/testutil/tx"
2320

2421
"github.com/ethereum/go-ethereum/common"
2522
ethtypes "github.com/ethereum/go-ethereum/core/types"
@@ -40,7 +37,6 @@ import (
4037
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
4138
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
4239
authz "github.com/cosmos/cosmos-sdk/x/authz"
43-
cryptocodec "github.com/evmos/ethermint/crypto/codec"
4440
"github.com/evmos/ethermint/crypto/ethsecp256k1"
4541

4642
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
@@ -63,15 +59,17 @@ import (
6359
type AnteTestSuite struct {
6460
suite.Suite
6561

66-
ctx sdk.Context
67-
app *app.EthermintApp
68-
clientCtx client.Context
69-
anteHandler sdk.AnteHandler
70-
priv cryptotypes.PrivKey
71-
ethSigner ethtypes.Signer
72-
enableFeemarket bool
73-
enableLondonHF bool
74-
evmParamsOption func(*evmtypes.Params)
62+
ctx sdk.Context
63+
app *app.EthermintApp
64+
clientCtx client.Context
65+
anteHandler sdk.AnteHandler
66+
priv cryptotypes.PrivKey
67+
ethSigner ethtypes.Signer
68+
enableFeemarket bool
69+
enableLondonHF bool
70+
evmParamsOption func(*evmtypes.Params)
71+
useLegacyEIP712Extension bool
72+
useLegacyEIP712TypedData bool
7573
}
7674

7775
const TestGasLimit uint64 = 100000
@@ -169,12 +167,6 @@ func (suite *AnteTestSuite) SetupTest() {
169167
suite.Require().NoError(err)
170168
}
171169

172-
func TestAnteTestSuite(t *testing.T) {
173-
suite.Run(t, &AnteTestSuite{
174-
enableLondonHF: true,
175-
})
176-
}
177-
178170
func (s *AnteTestSuite) BuildTestEthTx(
179171
from common.Address,
180172
to common.Address,
@@ -303,15 +295,15 @@ func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress
303295
// Build MsgSend
304296
recipient := sdk.AccAddress(common.Address{}.Bytes())
305297
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
306-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
298+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgSend)
307299
}
308300

309301
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
310302
// Build MsgSend
311303
valEthAddr := tests.GenerateAddress()
312304
valAddr := sdk.ValAddress(valEthAddr.Bytes())
313305
msgSend := stakingtypes.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
314-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
306+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgSend)
315307
}
316308

317309
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@@ -327,7 +319,7 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator(from sdk.AccAddre
327319
sdk.OneInt(),
328320
)
329321
suite.Require().NoError(err)
330-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
322+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgCreate)
331323
}
332324

333325
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator2(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@@ -344,15 +336,15 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator2(from sdk.AccAddr
344336
sdk.OneInt(),
345337
)
346338
suite.Require().NoError(err)
347-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
339+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgCreate)
348340
}
349341

350342
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposal(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, deposit sdk.Coins) client.TxBuilder {
351343
proposal, ok := govtypes.ContentFromProposalType("My proposal", "My description", govtypes.ProposalTypeText)
352344
suite.Require().True(ok)
353345
msgSubmit, err := govtypes.NewMsgSubmitProposal(proposal, deposit, from)
354346
suite.Require().NoError(err)
355-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgSubmit)
347+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgSubmit)
356348
}
357349

358350
func (suite *AnteTestSuite) CreateTestEIP712GrantAllowance(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@@ -366,7 +358,7 @@ func (suite *AnteTestSuite) CreateTestEIP712GrantAllowance(from sdk.AccAddress,
366358
grantedAddr := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, granted.Bytes())
367359
msgGrant, err := feegrant.NewMsgGrantAllowance(basic, from, grantedAddr.GetAddress())
368360
suite.Require().NoError(err)
369-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgGrant)
361+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgGrant)
370362
}
371363

372364
func (suite *AnteTestSuite) CreateTestEIP712MsgEditValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@@ -377,7 +369,7 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgEditValidator(from sdk.AccAddress
377369
nil,
378370
nil,
379371
)
380-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgEdit)
372+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgEdit)
381373
}
382374

383375
func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@@ -390,12 +382,12 @@ func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddres
390382
})
391383
suite.Require().NoError(err)
392384

393-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
385+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgEvidence)
394386
}
395387

396388
func (suite *AnteTestSuite) CreateTestEIP712MsgVoteV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
397389
msgVote := govtypesv1.NewMsgVote(from, 1, govtypesv1.VoteOption_VOTE_OPTION_YES, "")
398-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgVote)
390+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgVote)
399391
}
400392

401393
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposalV1(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
@@ -434,28 +426,28 @@ func (suite *AnteTestSuite) CreateTestEIP712SubmitProposalV1(from sdk.AccAddress
434426

435427
suite.Require().NoError(err)
436428

437-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, msgProposal)
429+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, msgProposal)
438430
}
439431

440432
func (suite *AnteTestSuite) CreateTestEIP712MsgExec(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
441433
recipient := sdk.AccAddress(common.Address{}.Bytes())
442434
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
443435
msgExec := authz.NewMsgExec(from, []sdk.Msg{msgSend})
444-
return suite.CreateTestEIP712SingleMessageTxBuilder(from, priv, chainId, gas, gasAmount, &msgExec)
436+
return suite.CreateTestEIP712SingleMessageTxBuilder(priv, chainId, gas, gasAmount, &msgExec)
445437
}
446438

447439
func (suite *AnteTestSuite) CreateTestEIP712MultipleMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
448440
recipient := sdk.AccAddress(common.Address{}.Bytes())
449441
msgSend := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
450-
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend, msgSend, msgSend})
442+
return suite.CreateTestEIP712CosmosTxBuilder(priv, chainId, gas, gasAmount, []sdk.Msg{msgSend, msgSend, msgSend})
451443
}
452444

453445
// Fails
454446
func (suite *AnteTestSuite) CreateTestEIP712MultipleSignerMsgs(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
455447
recipient := sdk.AccAddress(common.Address{}.Bytes())
456448
msgSend1 := banktypes.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
457449
msgSend2 := banktypes.NewMsgSend(recipient, from, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
458-
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msgSend1, msgSend2})
450+
return suite.CreateTestEIP712CosmosTxBuilder(priv, chainId, gas, gasAmount, []sdk.Msg{msgSend1, msgSend2})
459451
}
460452

461453
// StdSignBytes returns the bytes to sign for a transaction.
@@ -497,80 +489,35 @@ func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequenc
497489
}
498490

499491
func (suite *AnteTestSuite) CreateTestEIP712SingleMessageTxBuilder(
500-
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
492+
priv cryptotypes.PrivKey, chainID string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
501493
) client.TxBuilder {
502-
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, []sdk.Msg{msg})
494+
return suite.CreateTestEIP712CosmosTxBuilder(priv, chainID, gas, gasAmount, []sdk.Msg{msg})
503495
}
504496

505497
func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
506-
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msgs []sdk.Msg,
498+
priv cryptotypes.PrivKey, chainID string, gas uint64, gasAmount sdk.Coins, msgs []sdk.Msg,
507499
) client.TxBuilder {
508-
var err error
509-
510-
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, from)
511-
suite.Require().NoError(err)
512-
513-
pc, err := types.ParseChainID(chainId)
514-
suite.Require().NoError(err)
515-
ethChainId := pc.Uint64()
516-
517-
// GenerateTypedData TypedData
518-
var ethermintCodec codec.ProtoCodecMarshaler
519-
registry := codectypes.NewInterfaceRegistry()
520-
types.RegisterInterfaces(registry)
521-
ethermintCodec = codec.NewProtoCodec(registry)
522-
cryptocodec.RegisterInterfaces(registry)
523-
524-
fee := legacytx.NewStdFee(gas, gasAmount)
525-
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
526-
527-
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, msgs, "", nil)
528-
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msgs[0], data, &eip712.FeeDelegationOptions{
529-
FeePayer: from,
530-
})
531-
suite.Require().NoError(err)
532-
533-
sigHash, _, err := apitypes.TypedDataAndHash(typedData)
534-
suite.Require().NoError(err)
535-
536-
// Sign typedData
537-
keyringSigner := tests.NewSigner(priv)
538-
signature, pubKey, err := keyringSigner.SignByAddress(from, sigHash)
539-
suite.Require().NoError(err)
540-
signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
541-
542-
// Add ExtensionOptionsWeb3Tx extension
543-
var option *codectypes.Any
544-
option, err = codectypes.NewAnyWithValue(&types.ExtensionOptionsWeb3Tx{
545-
FeePayer: from.String(),
546-
TypedDataChainID: ethChainId,
547-
FeePayerSig: signature,
548-
})
549-
suite.Require().NoError(err)
550-
551-
suite.clientCtx.TxConfig.SignModeHandler()
552-
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
553-
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
554-
suite.Require().True(ok)
555-
556-
builder.SetExtensionOptions(option)
557-
builder.SetFeeAmount(gasAmount)
558-
builder.SetGasLimit(gas)
559-
560-
sigsV2 := signing.SignatureV2{
561-
PubKey: pubKey,
562-
Data: &signing.SingleSignatureData{
563-
SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
564-
},
565-
Sequence: nonce,
500+
config := suite.clientCtx.TxConfig
501+
cosmosTxArgs := utiltx.CosmosTxArgs{
502+
TxCfg: config,
503+
Priv: priv,
504+
ChainID: chainID,
505+
Gas: gas,
506+
Fees: gasAmount,
507+
Msgs: msgs,
566508
}
567509

568-
err = builder.SetSignatures(sigsV2)
569-
suite.Require().NoError(err)
510+
builder, err := utiltx.PrepareEIP712CosmosTx(
511+
suite.ctx,
512+
suite.app,
513+
utiltx.EIP712TxArgs{
514+
CosmosTxArgs: cosmosTxArgs,
515+
UseLegacyExtension: suite.useLegacyEIP712Extension,
516+
UseLegacyTypedData: suite.useLegacyEIP712TypedData,
517+
},
518+
)
570519

571-
err = builder.SetMsgs(msgs...)
572520
suite.Require().NoError(err)
573-
574521
return builder
575522
}
576523

crypto/ethsecp256k1/ethsecp256k1.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,17 @@ func (pubKey PubKey) verifySignatureAsEIP712(msg, sig []byte) bool {
236236
return false
237237
}
238238

239-
return pubKey.verifySignatureECDSA(eip712Bytes, sig)
239+
if pubKey.verifySignatureECDSA(eip712Bytes, sig) {
240+
return true
241+
}
242+
243+
// Try verifying the signature using the legacy EIP-712 encoding
244+
legacyEIP712Bytes, err := eip712.LegacyGetEIP712BytesForMsg(msg)
245+
if err != nil {
246+
return false
247+
}
248+
249+
return pubKey.verifySignatureECDSA(legacyEIP712Bytes, sig)
240250
}
241251

242252
// Perform standard ECDSA signature verification for the given raw bytes and signature.

ethereum/eip712/domain.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2023 Evmos Foundation
2+
// This file is part of Evmos' Ethermint library.
3+
//
4+
// The Ethermint library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The Ethermint library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the Ethermint library. If not, see https://github.com/evmos/ethermint/blob/main/LICENSE
16+
package eip712
17+
18+
import (
19+
"github.com/ethereum/go-ethereum/common/math"
20+
"github.com/ethereum/go-ethereum/signer/core/apitypes"
21+
)
22+
23+
// createEIP712Domain creates the typed data domain for the given chainID.
24+
func createEIP712Domain(chainID uint64) apitypes.TypedDataDomain {
25+
domain := apitypes.TypedDataDomain{
26+
Name: "Cosmos Web3",
27+
Version: "1.0.0",
28+
ChainId: math.NewHexOrDecimal256(int64(chainID)), // #nosec G701
29+
VerifyingContract: "cosmos",
30+
Salt: "0",
31+
}
32+
33+
return domain
34+
}

0 commit comments

Comments
 (0)