EIP-7 Adding the DELEGATECALL Instruction (DELEGATECALL)
Final · EVM & execution · EIP status Final · created 2015-11-15
Adds a new instruction, DELEGATECALL (0xf4), to the EVM. It executes another contract's code while preserving the original call's sender and value information.
Why it is needed
There was already a way for a contract to borrow another contract's code. The CALLCODE instruction lets you run code located at another address on top of your own storage. The problem with this is that the sender and value information ends up reflecting the intermediate contract rather than the original user. As a result, the borrowed code has no way to know who the original user was. Avoiding this requires a workaround of embedding the sender address in the first 20 bytes of the call data, which means the code must be compiled separately for delegation and the same code cannot be used for both delegate calls and normal calls at once. DELEGATECALL passes the sender and value from the parent call straight through to the child call, letting a contract execute code at another address almost as if it were running in its own environment.
What changes
Today
- Borrowing and executing code from another address changes the sender and value information to reflect the intermediate contract
- For the borrowed code to know the original user, it needs a workaround of embedding the address in the call data plus dedicated compilation
- Code built this way becomes delegate-call-only and cannot also be used for normal calls
After EIP-7
- Even when executing code at another address, the sender (CALLER) and value (VALUE) remain exactly as in the original call
- A contract can be structured to treat another address as a code store and pass calls straight through
- Designing the address holding the code to be replaceable lets you swap out a contract's operating code
Who is affected
- Smart contract developers: When splitting code across multiple addresses or building a structure where the code address can change, calls can be passed through without losing sender and value information.
- Client teams: The EVM must implement the 0xf4 instruction and its gas rules (no basic stipend, no account creation).
- Users: This is not a feature you use directly, but when interacting with a contract that uses this instruction, your own address and the value you send are passed through unchanged all the way to the delegated code.
In depth
Instruction and Operands
DELEGATECALL is a new opcode assigned to 0xf4 that takes six operands from the stack: gas (the gas available to the child code), to (the destination address holding the code to execute), in_offset (the memory offset where the input begins), in_size (the input size in bytes), out_offset (the memory offset to write the output to), and out_size (the size of the output scratch pad). The code is fetched from the to address, but the execution context (storage, etc.) belongs to the caller.
Gas Rules
Unlike CALL, it provides no basic stipend. The gas passed as an operand is all the callee receives. As with CALLCODE, no account creation occurs, so the upfront gas cost is always fixed at schedule.callGas + gas. Unused gas is refunded as usual.
Sender/Value Propagation and Depth Limit
In the callee's environment, CALLER and VALUE behave exactly as they did in the caller's environment. In other words, the parent call's sender and value propagate unchanged into the child call. The call depth limit of 1024 remains unchanged, so DELEGATECALL also increases the call stack depth by 1.
Difference from CALLCODE and Design Intent
The concept itself is similar to CALLCODE, but it differs in that it propagates sender and value from the parent scope to the child scope. This makes it much easier for a contract to treat another, replaceable address as a code store and pass calls straight through. Aside from reduced gas and an increased call stack depth, the child code runs in an environment essentially identical to the parent's, so it can freely reference msg.sender and msg.value.
Two Usage Examples from the Original Text
The first is splitting code to avoid the 3 million gas barrier. Depending on the value range in the call data, the delegate_call branches to several addresses such as ADDR1 and ADDR2, letting large code be split across multiple contracts while still behaving as one. The second is a contract whose code address can be changed. When the owner calls with a specific function selector (0x12345678), self.delegate is updated; all other calls are forwarded to the code at the self.delegate address.
Counterarguments and Responses
One counterargument is that the same functionality could be mimicked by putting the sender address in the first 20 bytes of the call data. The original text responds that this approach requires compiling the delegate contract's code separately, and the same code cannot be used in both delegate and normal contexts at once.
Activation and Status
Activated by the Homestead hard fork. It applies from block 1,150,000 on mainnet, from block 494,000 on the Morden testnet, and from block 0 on subsequent testnets. Its status is Final, a finalized specification.