/**
* CALLCODE opcode (0xf2) - DEPRECATED
* Execute code in current context
*/
export function callcode(frame: FrameType): EvmError | null {
// Pop 7 arguments (same as CALL)
const gas = popStack(frame);
const address = popStack(frame);
const value = popStack(frame);
const inOffset = popStack(frame);
const inLength = popStack(frame);
const outOffset = popStack(frame);
const outLength = popStack(frame);
// Calculate gas cost
let gasCost = 700n; // Base (Tangerine Whistle+)
// Value transfer (even though to self)
if (value > 0n) {
gasCost += 9000n;
// No new account cost - value sent to self
}
// Cold access cost (Berlin+)
const accessCost = getAccessCost(address);
gasCost += accessCost;
// Memory expansion
const inEnd = inLength > 0 ? inOffset + inLength : 0;
const outEnd = outLength > 0 ? outOffset + outLength : 0;
const maxEnd = Math.max(inEnd, outEnd);
if (maxEnd > 0) {
gasCost += memoryExpansionCost(frame, maxEnd);
updateMemorySize(frame, maxEnd);
}
// Calculate forwarded gas (63/64 rule)
const afterCharge = frame.gasRemaining - gasCost;
const maxForward = afterCharge - afterCharge / 64n;
const forwardedGas = min(gas, maxForward);
// Charge total cost
consumeGas(frame, gasCost + forwardedGas);
// Read calldata
const calldata = readMemory(frame, inOffset, inLength);
// Execute in caller context with target's code
const result = executeCallCode({
codeAddress: address, // Code to execute
storageAddress: frame.address, // Storage to modify
sender: frame.address, // msg.sender = caller
value: value, // msg.value = specified
data: calldata,
gas: forwardedGas
});
// Refund unused gas
frame.gasRemaining += result.gasLeft;
// Copy returndata
const copySize = min(outLength, result.returnData.length);
writeMemory(frame, outOffset, result.returnData.slice(0, copySize));
// Set return_data buffer
frame.returnData = result.returnData;
// Push success flag
pushStack(frame, result.success ? 1n : 0n);
frame.pc += 1;
return null;
}