Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

# Changelog

## Unreleased

* (evm) [#725](https://github.com/crypto-org-chain/ethermint/pull/725) feat(RPC): add authorizationList from eth_getTransactionByHash response for EIP-7702 transactions

## [v0.22.0] - 2025-08-12

* (geth) [#665](https://github.com/crypto-org-chain/ethermint/pull/665) Update go-ethereum version to [`v1.15.11`](https://github.com/ethereum/go-ethereum/releases/tag/v1.15.11).
Expand Down
113 changes: 113 additions & 0 deletions rpc/backend/tx_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import (
dbm "github.com/cosmos/cosmos-db"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/evmos/ethermint/indexer"
"github.com/evmos/ethermint/rpc/backend/mocks"
rpctypes "github.com/evmos/ethermint/rpc/types"
ethermint "github.com/evmos/ethermint/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/holiman/uint256"
"google.golang.org/grpc/metadata"
)

Expand Down Expand Up @@ -648,3 +650,114 @@ func (suite *BackendTestSuite) TestGetGasUsed() {
})
}
}

func (suite *BackendTestSuite) TestGetTransactionByHash_SetCodeTxType() {
msgSetCodeTx := suite.buildSetCodeTx()
txBz := suite.signAndEncodeEthTx(msgSetCodeTx)
txHash := msgSetCodeTx.Hash()
block := &types.Block{Header: types.Header{Height: 1, ChainID: "test"}, Data: types.Data{Txs: []types.Tx{txBz}}}
responseDeliver := []*abci.ExecTxResult{
{
Code: 0,
Events: []abci.Event{
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
{Key: "ethereumTxHash", Value: txHash.Hex()},
{Key: "txIndex", Value: "0"},
{Key: "amount", Value: "0"},
{Key: "txGasUsed", Value: "100000"},
{Key: "txHash", Value: ""},
{Key: "recipient", Value: "0x742d35cc6561c9d8f6b1b8e6e2c8b9f8f4a1e2d3"},
}},
},
},
}

expectedRPCTx, _ := rpctypes.NewRPCTransaction(msgSetCodeTx, common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID)

testCases := []struct {
name string
registerMock func()
expPass bool
}{
{
"pass - SetCodeTx transaction found and returned",
func() {
client := suite.backend.clientCtx.Client.(*mocks.Client)
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBlock(client, 1, txBz)
RegisterBlockResults(client, 1)
RegisterBaseFee(queryClient, sdkmath.NewInt(1))
},
true,
},
}

for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest()
tc.registerMock()

db := dbm.NewMemDB()
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
err := suite.backend.indexer.IndexBlock(block, responseDeliver)
suite.Require().NoError(err)

rpcTx, err := suite.backend.GetTransactionByHash(txHash)

if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(rpcTx)

suite.Require().Equal(hexutil.Uint64(ethtypes.SetCodeTxType), rpcTx.Type)

suite.Require().NotNil(rpcTx.GasFeeCap, "GasFeeCap should be set")
suite.Require().NotNil(rpcTx.GasTipCap, "GasTipCap should be set")
suite.Require().NotNil(rpcTx.ChainID, "ChainID should be set")
suite.Require().NotNil(rpcTx.Accesses, "AccessList should be set")
suite.Require().NotNil(rpcTx.AuthorizationList, "AuthorizationList should be set")

suite.Require().Equal(expectedRPCTx.Type, rpcTx.Type)
suite.Require().Equal(expectedRPCTx.From, rpcTx.From)
suite.Require().Equal(expectedRPCTx.Hash, rpcTx.Hash)
} else {
suite.Require().Error(err)
}
})
}
}

func (suite *BackendTestSuite) buildSetCodeTx() *evmtypes.MsgEthereumTx {
auth := ethtypes.SetCodeAuthorization{
ChainID: *uint256.MustFromBig(suite.backend.chainID),
Address: common.HexToAddress("0x4Cd241E8d1510e30b2076397afc7508Ae59C66c9"),
Nonce: 1,
V: uint8(27),
R: *uint256.NewInt(1),
S: *uint256.NewInt(1),
}

setCodeTx := &ethtypes.SetCodeTx{
ChainID: uint256.MustFromBig(suite.backend.chainID),
Nonce: 0,
GasTipCap: uint256.NewInt(10000),
GasFeeCap: uint256.NewInt(1000000000000),
Gas: 100000,
To: common.HexToAddress("0x742d35cc6561c9d8f6b1b8e6e2c8b9f8f4a1e2d3"),
Value: uint256.NewInt(0),
Data: []byte{},
AccessList: ethtypes.AccessList{},
AuthList: []ethtypes.SetCodeAuthorization{auth},
V: uint256.NewInt(1),
R: uint256.NewInt(1),
S: uint256.NewInt(1),
}

ethTx := ethtypes.NewTx(setCodeTx)
msgEthereumTx := &evmtypes.MsgEthereumTx{}
err := msgEthereumTx.FromSignedEthereumTx(ethTx, ethtypes.LatestSignerForChainID(suite.backend.chainID))
suite.Require().NoError(err)

msgEthereumTx.From = suite.signerAddress

return msgEthereumTx
}
40 changes: 21 additions & 19 deletions rpc/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,27 @@ type StorageResult struct {

// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
type RPCTransaction struct {
BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"`
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
Value *hexutil.Big `json:"value"`
Type hexutil.Uint64 `json:"type"`
Accesses *ethtypes.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"`
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
Value *hexutil.Big `json:"value"`
Type hexutil.Uint64 `json:"type"`
Accesses *ethtypes.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
AuthorizationList []ethtypes.SetCodeAuthorization `json:"authorizationList,omitempty"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
}

// StateOverride is the collection of overridden accounts.
Expand Down
19 changes: 18 additions & 1 deletion rpc/types/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,25 +240,42 @@ func NewRPCTransaction(
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
result.TransactionIndex = (*hexutil.Uint64)(&index)
}
yparity := hexutil.Uint64(v.Sign()) //#nosec G115
switch tx.Type() {
case ethtypes.AccessListTxType:
al := tx.AccessList()
result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId())
result.YParity = &yparity
case ethtypes.DynamicFeeTxType:
al := tx.AccessList()
result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId())
result.YParity = &yparity
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
// if the transaction has been mined, compute the effective gas price
if baseFee != nil && blockHash != (common.Hash{}) {
// price = min(tip, gasFeeCap - baseFee) + baseFee
// price = min(tip + baseFee, gasFeeCap)
price := ethermint.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap())
result.GasPrice = (*hexutil.Big)(price)
} else {
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
}
case ethtypes.SetCodeTxType:
al := tx.AccessList()
result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId())
result.YParity = &yparity
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
if baseFee != nil && blockHash != (common.Hash{}) {
price := ethermint.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap())
result.GasPrice = (*hexutil.Big)(price)
} else {
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
}
result.AuthorizationList = tx.SetCodeAuthorizations()
}
return result, nil
}
Expand Down
Loading
Loading