From 7958e26f20ea1abe2bf68fc7dac4251885a7335a Mon Sep 17 00:00:00 2001
From: Dreamer <dreamer.x.cn@gmail.com>
Date: Fri, 12 Jul 2024 10:57:18 +0800
Subject: [PATCH 1/2] add extensions logic

---
 x/evm/keeper/gas.go              |  7 ++++++-
 x/evm/keeper/keeper.go           | 12 +++++++++++-
 x/evm/keeper/state_transition.go |  7 +++----
 x/evm/types/extensions.go        | 28 ++++++++++++++++++++++++++++
 x/evm/types/msg.go               |  5 ++++-
 5 files changed, 52 insertions(+), 7 deletions(-)
 create mode 100644 x/evm/types/extensions.go

diff --git a/x/evm/keeper/gas.go b/x/evm/keeper/gas.go
index e6518cc83b..26b986abc2 100644
--- a/x/evm/keeper/gas.go
+++ b/x/evm/keeper/gas.go
@@ -18,6 +18,7 @@ package keeper
 import (
 	"math/big"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/params"
 
@@ -46,6 +47,10 @@ func (k *Keeper) GetEthIntrinsicGas(ctx sdk.Context, msg core.Message, cfg *para
 func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64, denom string) error {
 	// Return EVM tokens for remaining gas, exchanged at the original rate.
 	remaining := new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), msg.GasPrice())
+	feePayer := msg.From().Bytes()
+	if m,ok := msg.(types.Message); ok {
+		feePayer = common.HexToAddress(m.FeePayer).Bytes()
+	}
 
 	switch remaining.Sign() {
 	case -1:
@@ -57,7 +62,7 @@ func (k *Keeper) RefundGas(ctx sdk.Context, msg core.Message, leftoverGas uint64
 
 		// refund to sender from the fee collector module account, which is the escrow account in charge of collecting tx fees
 
-		err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins)
+		err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, feePayer, refundedCoins)
 		if err != nil {
 			err = errorsmod.Wrapf(errortypes.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error())
 			return errorsmod.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String())
diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go
index ac947247ac..e36f4c6ba9 100644
--- a/x/evm/keeper/keeper.go
+++ b/x/evm/keeper/keeper.go
@@ -1,4 +1,4 @@
-// Copyright 2021 Evmos Foundation
+// Package keeper Copyright 2021 Evmos Foundation
 // This file is part of Evmos' Ethermint library.
 //
 // The Ethermint library is free software: you can redistribute it and/or modify
@@ -78,6 +78,9 @@ type Keeper struct {
 	evmConstructor evm.Constructor
 	// Legacy subspace
 	ss paramstypes.Subspace
+
+	// options for the EVM
+	opts types.Options
 }
 
 // NewKeeper generates new evm module keeper
@@ -118,6 +121,7 @@ func NewKeeper(
 		evmConstructor:    evmConstructor,
 		tracer:            tracer,
 		ss:                ss,
+		opts:              types.DefaultOptions(),
 	}
 }
 
@@ -126,6 +130,12 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
 	return ctx.Logger().With("module", types.ModuleName)
 }
 
+// WithOptions sets the options to the keeper
+func (k *Keeper) WithOptions(opts types.Options) *Keeper{
+	k.opts = opts
+	return k
+}
+
 // WithChainID sets the chain id to the local variable in the keeper
 func (k *Keeper) WithChainID(ctx sdk.Context) {
 	chainID, err := ethermint.ParseChainID(ctx.ChainID())
diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go
index a13d2cfd43..db650ba9ee 100644
--- a/x/evm/keeper/state_transition.go
+++ b/x/evm/keeper/state_transition.go
@@ -1,4 +1,4 @@
-// Copyright 2021 Evmos Foundation
+// Package keeper Copyright 2021 Evmos Foundation
 // This file is part of Evmos' Ethermint library.
 //
 // The Ethermint library is free software: you can redistribute it and/or modify
@@ -44,7 +44,6 @@ import (
 // NOTE: the RANDOM opcode is currently not supported since it requires
 // RANDAO implementation. See https://github.com/evmos/ethermint/pull/1520#pullrequestreview-1200504697
 // for more information.
-
 func (k *Keeper) NewEVM(
 	ctx sdk.Context,
 	msg core.Message,
@@ -53,8 +52,8 @@ func (k *Keeper) NewEVM(
 	stateDB vm.StateDB,
 ) evm.EVM {
 	blockCtx := vm.BlockContext{
-		CanTransfer: core.CanTransfer,
-		Transfer:    core.Transfer,
+		CanTransfer: k.opts.CanTransfer,
+		Transfer:    k.opts.Transfer,
 		GetHash:     k.GetHashFn(ctx),
 		Coinbase:    cfg.CoinBase,
 		GasLimit:    ethermint.BlockGasLimit(ctx),
diff --git a/x/evm/types/extensions.go b/x/evm/types/extensions.go
new file mode 100644
index 0000000000..bce22ab5d8
--- /dev/null
+++ b/x/evm/types/extensions.go
@@ -0,0 +1,28 @@
+package types
+
+import (
+	"github.com/ethereum/go-ethereum/core"
+	"github.com/ethereum/go-ethereum/core/vm"
+)
+
+var _ core.Message = (*Message)(nil)
+
+// Options for the EVM module
+type Options struct {
+	CanTransfer vm.CanTransferFunc
+	Transfer    vm.TransferFunc
+}
+
+// DefaultOptions for the EVM module
+func DefaultOptions() Options {
+	return Options{
+		CanTransfer: core.CanTransfer,
+		Transfer:    core.Transfer,
+	}
+}
+
+// Message wrap the core.Message interface.
+type Message struct {
+	core.Message
+	FeePayer string
+}
\ No newline at end of file
diff --git a/x/evm/types/msg.go b/x/evm/types/msg.go
index fbe5623769..7e5d7e3349 100644
--- a/x/evm/types/msg.go
+++ b/x/evm/types/msg.go
@@ -376,7 +376,10 @@ func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer, baseFee *big.Int) (co
 		false,
 	)
 
-	return ethMsg, nil
+	return Message{
+		Message:  ethMsg,
+		FeePayer: msg.FeePayer,
+	}, nil
 }
 
 // GetSender extracts the sender address from the signature values using the latest signer for the given chainID.

From ee1c256ce2874ea564a9d1cb5f1a7c39f2294968 Mon Sep 17 00:00:00 2001
From: Dreamer <dreamer.x.cn@gmail.com>
Date: Fri, 12 Jul 2024 11:02:22 +0800
Subject: [PATCH 2/2] check feePayer

---
 x/evm/types/msg.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/x/evm/types/msg.go b/x/evm/types/msg.go
index 7e5d7e3349..1e6492335b 100644
--- a/x/evm/types/msg.go
+++ b/x/evm/types/msg.go
@@ -376,6 +376,10 @@ func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer, baseFee *big.Int) (co
 		false,
 	)
 
+	if msg.FeePayer == "" {
+		return ethMsg, nil
+	}
+
 	return Message{
 		Message:  ethMsg,
 		FeePayer: msg.FeePayer,