Summary
CALLCODE currently charges MegaETH new-account storage gas using the stack to address, which is the code-source address.
For CALLCODE, execution happens in the caller's account context, so new-account metering should be based on the caller/storage context rather than the raw code-source address.
Affected area
crates/mega-evm/src/evm/instructions.rs
Details
storage_gas_ext::wrap_call_with_storage_gas! currently reads the call target from stack position 1 and uses it for both account inspection and storage-gas charging:
let to = context.interpreter.stack.inspect::<1>().unwrap().into_address();
let to_account = context.host.inspect_account_delegated(mega_spec, to)?;
...
context.host.new_account_storage_gas(to)
That is correct for CALL, but not for CALLCODE.
For CALLCODE, the stack to address only selects the code to execute. The storage/account context remains the caller/current frame address. Charging new-account storage gas against the code-source address can charge when the wrong account is empty, or miss charging when the caller/storage account is the relevant account.
Impact
MegaETH storage-gas accounting for value-transferring CALLCODE can be wrong.
This is especially relevant around account-creation metering and EIP-7702 delegated-account emptiness checks.
Suggested remediation
Split the storage-gas wrapper behavior for CALL and CALLCODE.
For CALL:
- keep using the stack to address as the account being value-transferred to.
For CALLCODE:
- use the current execution/storage account, i.e. context.interpreter.input.target_address(), for emptiness checks and new_account_storage_gas(...).
- keep using the stack to address only as the code-source address for the actual CALLCODE instruction.
Add regression tests showing that a value-transferring CALLCODE meters new-account storage gas based on the caller/storage context, not the code-source address.
Please verify whether this behavior needs to be gated to the current unstable spec according to AGENTS.md.
Summary
CALLCODEcurrently charges MegaETH new-account storage gas using the stacktoaddress, which is the code-source address.For
CALLCODE, execution happens in the caller's account context, so new-account metering should be based on the caller/storage context rather than the raw code-source address.Affected area
crates/mega-evm/src/evm/instructions.rsDetails
storage_gas_ext::wrap_call_with_storage_gas!currently reads the call target from stack position 1 and uses it for both account inspection and storage-gas charging:That is correct for CALL, but not for CALLCODE.
For CALLCODE, the stack to address only selects the code to execute. The storage/account context remains the caller/current frame address. Charging new-account storage gas against the code-source address can charge when the wrong account is empty, or miss charging when the caller/storage account is the relevant account.
Impact
MegaETH storage-gas accounting for value-transferring CALLCODE can be wrong.
This is especially relevant around account-creation metering and EIP-7702 delegated-account emptiness checks.
Suggested remediation
Split the storage-gas wrapper behavior for CALL and CALLCODE.
For CALL:
For CALLCODE:
Add regression tests showing that a value-transferring CALLCODE meters new-account storage gas based on the caller/storage context, not the code-source address.
Please verify whether this behavior needs to be gated to the current unstable spec according to AGENTS.md.