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
10 changes: 7 additions & 3 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1911,12 +1911,16 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE
vmError = execResult.Err.Error()
}

// Create core.Message from ethTx for WriteReceipt
// WriteReceipt needs msg for GasPrice, To, From, Data, Nonce fields
// Create core.Message from ethTx for WriteReceipt.
// GasPrice must be the EIP-1559 effective gas price (min(baseFee+tip,
// maxFee)) — that's what the chain actually charges (see line 1866)
// and what the receipt's EffectiveGasPrice field needs to report.
// ethTx.GasPrice() returns GasFeeCap for dynamic-fee txs, which puts
// the wrong value on the receipt and breaks EIP-1559 clients.
evmMsg := &core.Message{
Nonce: ethTx.Nonce(),
GasLimit: ethTx.Gas(),
GasPrice: ethTx.GasPrice(),
GasPrice: effectiveGasPrice,
GasFeeCap: ethTx.GasFeeCap(),
GasTipCap: ethTx.GasTipCap(),
To: ethTx.To(),
Expand Down
49 changes: 49 additions & 0 deletions giga/deps/xevm/keeper/receipt_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package keeper_test

import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
testkeeper "github.com/sei-protocol/sei-chain/giga/deps/testutil/keeper"
"github.com/sei-protocol/sei-chain/giga/deps/xevm/state"
"github.com/sei-protocol/sei-chain/giga/deps/xevm/types"
sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -39,3 +42,49 @@ func TestDeleteTransientReceipt(t *testing.T) {
require.Nil(t, receipt)
require.Equal(t, "receipt not found", err.Error())
}

// TestWriteReceiptStoresMsgGasPriceAsEffectiveGasPrice documents the contract
// between WriteReceipt and its caller for EIP-1559 dynamic-fee txs:
// receipt.EffectiveGasPrice is taken from msg.GasPrice verbatim, so the caller
// is responsible for setting msg.GasPrice = min(baseFee + tipCap, feeCap)
// (the actual effective gas price the chain charged).
//
// The bug this guards against: passing ethTx.GasPrice() into msg for a
// dynamic-fee tx returns GasFeeCap (i.e., maxFee) — the receipt would then
// report maxFee even when the tx actually paid baseFee+tip < maxFee, breaking
// EIP-1559 RPC semantics for clients (e.g. ethers, hardhat-ethers).
func TestWriteReceiptStoresMsgGasPriceAsEffectiveGasPrice(t *testing.T) {
k, ctx := testkeeper.MockEVMKeeper(t)
stateDB := state.NewDBImpl(ctx, k, false)
txHash := common.HexToHash("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef")

// Scenario: tip=1gwei, maxFee=10gwei, baseFee=1gwei →
// effectiveGasPrice = baseFee + tip = 2gwei (additive branch).
const (
effectiveGasPrice uint64 = 2_000_000_000 // 2 gwei
feeCap uint64 = 10_000_000_000 // 10 gwei
tipCap uint64 = 1_000_000_000 // 1 gwei
gasUsed uint64 = 21_000
)

msg := &core.Message{
Nonce: 0,
GasLimit: gasUsed,
GasPrice: new(big.Int).SetUint64(effectiveGasPrice),
GasFeeCap: new(big.Int).SetUint64(feeCap),
GasTipCap: new(big.Int).SetUint64(tipCap),
To: nil,
Value: big.NewInt(0),
From: common.HexToAddress("0x000000000000000000000000000000000000beef"),
}

r, err := k.WriteReceipt(ctx, stateDB, msg, uint32(ethtypes.DynamicFeeTxType), txHash, gasUsed, "")
require.NoError(t, err)
require.NotNil(t, r)
require.Equal(t, effectiveGasPrice, r.EffectiveGasPrice,
"receipt.EffectiveGasPrice must equal msg.GasPrice; if the caller passes "+
"ethTx.GasPrice() for a dynamic-fee tx, the receipt would wrongly report GasFeeCap (%d) "+
"instead of the EIP-1559 effective gas price (%d)", feeCap, effectiveGasPrice)
require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), r.Status)
require.Equal(t, gasUsed, r.GasUsed)
}
Loading