diff --git a/common/types.go b/common/types.go index fdb25f1b34..28e3fff6b6 100644 --- a/common/types.go +++ b/common/types.go @@ -39,6 +39,8 @@ const ( HashLength = 32 // AddressLength is the expected length of the address AddressLength = 20 + // Magic number to identify ETH transfers in logs (EIP-7708) + MagicTransferLog = 0xef ) var ( diff --git a/core/vm/evm.go b/core/vm/evm.go index 616668d565..41c8808666 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -509,6 +509,22 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } evm.Context.Transfer(evm.StateDB, caller.Address(), address, value) + // Emit log for ETH transfer (EIP-7708) + if evm.chainRules.IsEIP7708 && !value.IsZero() { + data := value.Bytes32() + topics := []common.Hash{ + common.BytesToHash([]byte{common.MagicTransferLog}), + common.BytesToHash(caller.Address().Bytes()), + common.BytesToHash(address.Bytes())} + + evm.StateDB.AddLog(&types.Log{ + Address: caller.Address(), + Topics: topics, + Data: data[:], + BlockNumber: evm.Context.BlockNumber.Uint64(), + }) + } + // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(address), value, gas) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 35d6393fba..a340cc5d23 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -762,6 +762,22 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt } ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, &value) + // Emit log for ETH transfer (EIP-7708) + if interpreter.evm.chainRules.IsEIP7708 && !value.IsZero() && err != nil { + data := value.Bytes32() + topics := []common.Hash{ + common.BytesToHash([]byte{common.MagicTransferLog}), + common.BytesToHash(scope.Contract.Address().Bytes()), + addr.Bytes32()} + + interpreter.evm.StateDB.AddLog(&types.Log{ + Address: scope.Contract.Address(), + Topics: topics, + Data: data[:], + BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(), + }) + } + if err != nil { temp.Clear() } else { @@ -908,6 +924,21 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) } } + // Emit log for ETH transfer (EIP-7708) + if interpreter.evm.chainRules.IsEIP7708 && !balance.IsZero() { + data := balance.Bytes32() + topics := []common.Hash{ + common.BytesToHash([]byte{common.MagicTransferLog}), + common.BytesToHash(scope.Contract.Address().Bytes()), + beneficiary.Bytes32()} + + interpreter.evm.StateDB.AddLog(&types.Log{ + Address: scope.Contract.Address(), + Topics: topics, + Data: data[:], + BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(), + }) + } return nil, errStopToken } diff --git a/params/config.go b/params/config.go index 9ecf465bb6..6c949366df 100644 --- a/params/config.go +++ b/params/config.go @@ -561,6 +561,11 @@ func (c *ChainConfig) IsEIP4762(num *big.Int, time uint64) bool { return c.IsVerkle(num, time) } +// IsCCv1 returns whether CCv1 has been activated at given block. +func (c *ChainConfig) IsCCv1(num *big.Int, time uint64) bool { + return true +} + // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { @@ -894,6 +899,7 @@ type Rules struct { IsBerlin, IsLondon bool IsMerge, IsShanghai, IsCancun, IsPrague bool IsVerkle bool + IsEIP7708 bool } // Rules ensures c's ChainID is not nil. @@ -924,5 +930,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules IsPrague: isMerge && c.IsPrague(num, timestamp), IsVerkle: isVerkle, IsEIP4762: isVerkle, + IsEIP7708: c.IsCCv1(num, timestamp), } }