DELEGATECALL
EIP-7 proposes the addition of a new opcode, DELEGATECALL, to the Ethereum Virtual Machine (EVM). This opcode is similar to CALLCODE but propagates the sender and value from the parent scope to the child scope. In other words, it allows a contract to delegate a call to another contract while maintaining the original sender and value. The DELEGATECALL opcode can be useful in various scenarios such as creating libraries that can be shared across multiple contracts or implementing complex contract interactions. It also helps reduce gas costs by avoiding unnecessary copying of data between contracts. The specification for DELEGATECALL includes details on gas costs, unused gas refunds, and limitations on depth limits. The activation block for this opcode was set at block 1,150,000 on the mainnet and block 494,000 on Morden. Overall, EIP-7 provides an important improvement to the Ethereum network by enabling more efficient and flexible contract interactions.
Video
Original
Hard Fork
Parameters
- Activation:
- Block >= 1,150,000 on Mainnet
- Block >= 494,000 on Morden
- Block >= 0 on future testnets
Overview
Add a new opcode, DELEGATECALL
at 0xf4
, which is similar in idea to CALLCODE
, except that it propagates the sender and value from the parent scope to the child scope, i.e. the call created has the same sender and value as the original call.
Specification
DELEGATECALL
: 0xf4
, takes 6 operands:
gas
: the amount of gas the code may use in order to execute;to
: the destination address whose code is to be executed;in_offset
: the offset into memory of the input;in_size
: the size of the input in bytes;out_offset
: the offset into memory of the output;out_size
: the size of the scratch pad for the output.
Notes on gas
- The basic stipend is not given;
gas
is the total amount the callee receives. - Like
CALLCODE
, account creation never happens, so the upfront gas cost is alwaysschedule.callGas
+gas
. - Unused gas is refunded as normal.
Notes on sender
CALLER
andVALUE
behave exactly in the callee's environment as they do in the caller's environment.
Other notes
- The depth limit of 1024 is still preserved as normal.
Rationale
Propagating the sender and value from the parent scope to the child scope makes it much easier for a contract to store another address as a mutable source of code and ''pass through'' calls to it, as the child code would execute in essentially the same environment (except for reduced gas and increased callstack depth) as the parent.
Use case 1: split code to get around 3m gas barrier
~calldatacopy(0, 0, ~calldatasize()) if ~calldataload(0) < 2**253: ~delegate_call(msg.gas - 10000, $ADDR1, 0, ~calldatasize(), ~calldatasize(), 10000) ~return(~calldatasize(), 10000) elif ~calldataload(0) < 2**253 * 2: ~delegate_call(msg.gas - 10000, $ADDR2, 0, ~calldatasize(), ~calldatasize(), 10000) ~return(~calldatasize(), 10000) ...
Use case 2: mutable address for storing the code of a contract:
if ~calldataload(0) / 2**224 == 0x12345678 and self.owner == msg.sender: self.delegate = ~calldataload(4) else: ~delegate_call(msg.gas - 10000, self.delegate, 0, ~calldatasize(), ~calldatasize(), 10000) ~return(~calldatasize(), 10000)
The child functions called by these methods can now freely reference msg.sender
and msg.value
.
Possible arguments against
- You can replicate this functionality by just sticking the sender into the first twenty bytes of the call data. However, this would mean that code would need to be specially compiled for delegated contracts, and would not be usable in delegated and raw contexts at the same time.
Not miss a beat of EIPs' update?
Subscribe EIPs Fun to receive the latest updates of EIPs Good for Buidlers to follow up.
View all