---
eip: 7069
title: Revamped CALL instructions
description: Introduce EXTCALL, EXTDELEGATECALL and EXTSTATICCALL with simplified semantics
author: Alex Beregszaszi (@axic), Paweł Bylica (@chfast), Danno Ferrin (@shemnon), Andrei Maiboroda (@gumb0), Charles Cooper (@charles-cooper)
discussions-to: https://ethereum-magicians.org/t/eip-revamped-call-instructions/14432
status: Stagnant
type: Standards Track
category: Core
created: 2023-05-05
requires: 150, 211, 214, 2929, 3540
---

## Abstract

Introduce three new call instructions, `EXTCALL`, `EXTDELEGATECALL` and `EXTSTATICCALL`, with simplified semantics. Introduce another instruction, `RETURNDATALOAD` for loading a word from return data into stack. Modify the behavior of `RETURNDATACOPY` instruction executed within EOF formatted code (as defined by [EIP-3540](./eip-3540.md)). The existing `*CALL` instructions are rejected by EOF validation.

The new instructions do not allow specifying a gas limit, but rather rely on the "63/64th rule" ([EIP-150](./eip-150.md)) to limit gas. An important improvement is the rules around the "stipend" are simplified, and callers do not need to perform special calculation whether the value is sent or not. 

Furthermore, the obsolete functionality of specifying output buffer address is removed in favor of using `RETURNDATACOPY` instead. For cases which would previously `*CALL` output into a buffer and then `MLOAD` from the buffer, `RETURNDATALOAD` is provided instead.

Lastly, instead of returning a boolean for execution status, an extensible list of status codes is returned: `0` for success, `1` for revert, `2` for failure.

## Motivation

Observability of gas has been a problem for very long. The system of gas has been (and likely must be) flexible in adapting to changes to both how Ethereum is used as well as changes in underlying hardware.

Unfortunately, in many cases compromises or workarounds had to be made to avoid affecting call instructions negatively, mostly due to the complex semantics and expectations of them.

This change removes gas observability from the new instructions and opens the door for new classes of contracts that are not affected by repricings. Furthermore, the legacy call instructions are rejected within EOF contracts, making sure they are mostly unaffected by changes in gas fees. Because these operations are required for removing gas observability they are required for EOF in lieu of the existing legacy instructions.

It is important to note that starting Solidity 0.4.21, the compiler already passes all remaining gas to calls (using `call(gas(), ...`), unless the developer uses the explicit override (`{gas: ...}`) in the language. This suggests most contracts don't rely on controlling gas.

Besides the above, this change introduces a convenience feature of returning more detailed status codes: `success (0)`, `revert (1)`, `failure (2)`. This moves from the boolean option to codes, which are extensible in the future.

Lastly, the introduction of the `RETURNDATA*` instructions ([EIP-211](./eip-211.md)) has obsoleted the output parameters of calls, in a large number of cases rendering them unused. Using the output buffers have caused "bugs" in the past: in the case of [ERC-20](./eip-20.md), conflicting implementations caused a lot of trouble, where some would return something, while others would not. With relying on `RETURNDATA*` instructions this is implicitly clarified. This proposal also adds the "missing" `RETURNDATALOAD` instruction to round out returndata buffer access instructions.

## Specification

| Name | Value | Comment |
|------|-------|---------|
| WARM_STORAGE_READ_COST | 100 | From [EIP-2929](./eip-2929.md) |
| COLD_ACCOUNT_ACCESS | 2600 | From [EIP-2929](./eip-2929.md) |
| CALL_VALUE_COST | 9000 | |
| ACCOUNT_CREATION_COST | 25000 | |
| MIN_RETAINED_GAS | 5000 | |
| MIN_CALLEE_GAS | 2300 | |

We introduce four new instructions:

- `EXTCALL` (`0xf8`) with arguments `(target_address, input_offset, input_size, value)` 
- `EXTDELEGATECALL` (`0xf9`) with arguments `(target_address, input_offset, input_size)`
- `EXTSTATICCALL` (`0xfb`) with arguments `(target_address, input_offset, input_size)`
- `RETURNDATALOAD` (`0xf7`) with argument `offset`

These four new instructions are undefined in legacy code and only available in EOF code.

Execution semantics of `EXT*CALL`:

1. Charge `WARM_STORAGE_READ_COST` gas.
2. Pop required arguments from stack, halt with exceptional failure on stack underflow.
    - **NOTE**: When implemented in EOF, stack underflow check is done during stack validation and runtime check is omitted.
3. If `value` is non-zero (only `EXTCALL`):
    - Halt with exceptional failure if the current frame is in `static-mode`.
    - Charge `CALL_VALUE_COST` gas.
4. If `target_address` has any of the high 12 bytes set to a non-zero value (i.e. it does not contain a 20-byte address) then halt with an exceptional failure. 
5. Perform (and charge for) memory expansion using `[input_offset, input_size]`.
6. If `target_address` is not in the `warm_account_list`, charge `COLD_ACCOUNT_ACCESS - WARM_STORAGE_READ_COST` gas.
7. If `target_address` is not in the state and the call configuration would result in account creation, charge `ACCOUNT_CREATION_COST` gas.
    - The only such case in this EIP is if `value` is non-zero (only `EXTCALL`).
8. Calculate the gas available to callee as caller's remaining gas reduced by `max(floor(gas/64), MIN_RETAINED_GAS)`.
9. Clear the returndata buffer.
10. Fail with status code `1` returned on stack if any of the following is true (only gas charged until this point is consumed):
    - Gas available to callee at this point is less than `MIN_CALLEE_GAS`.
    - Balance of the current account is less than `value` (only `EXTCALL`).
    - Current call stack depth equals `1024`.
    - (only `EXTDELEGATECALL`) `target_address` account in the state doesn't have EOF code to execute (in particular, [EIP-7702](./eip-7702.md) delegations should be resolved, as if `EXTCALL` was used)
11. Perform the call with the available gas and configuration.
12. Push a status code on the stack:
    - `0` if the call was successful.
    - `1` if the call has reverted (also can be pushed earlier in a light failure scenario described in step 10).
    - `2` if the call has failed (in case of general OOG failure or any scenario where all gas passed to the callee is burnt in case of an error).
13. Gas not used by the callee is returned to the caller.

Execution semantics of `RETURNDATALOAD`:

1. Charge `3` gas
2. Pop 1 item from the stack, to be referred to as `offset`
3. Push 1 item onto the stack, the 32-byte word read from the returndata buffer starting at `offset`.
4. If `offset + 32 > len(returndata buffer)`, the result is zero-padded.

Execution semantics of `RETURNDATACOPY` in EOF formatted code ([EIP-3540](./eip-3540.md)) is modified as follows:

1. Assume the 3 arguments popped from stack are `destOffset`, `offset` and `size`. _(no change)_
2. Performs memory expansion to `destOffset + size` and deducts memory expansion cost. _(no change)_
3. If `offset + size > len(returndata buffer)` **do not** halt with exceptional failure, but instead set the `offset + size - len(returndata buffer)` memory bytes after the copied ones to zero.
4. Gas charged for memory copying remains `3 * num_words(size)`, regardless of the number of bytes actually copied or set to zero.
    
Execution of `RETURNDATACOPY` which is not in EOF formatted code (i.e. is in legacy code) is not changed.

## Rationale

### Removing gas selectability

One major change from the original `CALL` series of instructions is that the caller has no control over the amount of gas passed in as part of the call. The number of cases where such a feature is essential are probably better served by direct protocol integration.

Removing gas selectability also introduces a valuable property that future revisions to the gas schedule will benefit from: you can always overcome Out of Gas (OOG) errors by sending more gas as part of the transaction (subject to the block gas limit). Previously when raising storage costs ([EIP-1884](./eip-1884.md)) some contracts that sent only a limited amount of gas to their calls were broken by the new costing.

Hence some contracts had a gas ceiling they were sending to their next call, permanently limiting the amount of gas they could spend. No amount of extra gas could fix the issue as the call would limit the amount sent.  The notion of a stipend floor is retained in this spec. This floor can be changed independent of the smart contracts and still preserve the feature that OOG halts can be fixed by sending more gas as part of the transaction.

### Stipend and 63/64th rule

The purpose of the stipend is to have enough gas to emit logs (i.e. perform non-state-changing operations) when a "contract wallet" is called. The stipend is only added when the `CALL` instruction is used and the value is non-zero.

The 63/64th rule has multiple purposes:

a. to limit call depth,
b. to ensure the caller has gas left to make state changes after a callee returns.

Additionally, there is a call depth counter, and calls fail if the depth would exceed 1024.

Before the 63/64th rule was introduced, it was required to calculate available gas semi-accurately on caller side. Solidity has a complicated ruleset where it tries to estimate how much it will cost on the caller side to perform the call itself, in order to set a reasonable gas value.

We have changed the ruleset:

The 63/64th rule is still applied, but
    - At least `MIN_RETAINED_GAS` gas is retained prior to executing the callee,
    - At least `MIN_CALLEE_GAS` gas is available to the callee.

The `MIN_CALLEE_GAS` rule is a replacement for stipend: it simplifies the reasoning about the gas costs and is applied uniformly for all introduced `EXT*CALL` instructions.
The following table visualizes the differences (note the discrepancy between _caller required gas_ and _caller cost_ for `CALL`).

|                 | Caller required gas | Caller cost (burned gas) | Caller min retained gas | Callee min gas |   
|-----------------|---------------------|--------------------------|-------------------------|----------------|
| CALL V=0        | 100                 | 100                      | 0                       | 0              |
| CALL V≠0        | 100+9000            | 100+6700                 | 0                       | 2300           |
| DELEGATECALL    | 100                 | 100                      | 0                       | 0              |
| STATICCALL      | 100                 | 100                      | 0                       | 0              |
| EXTCALL V=0     | 100                 | 100                      | 5000                    | 2300           |
| EXTCALL V≠0     | 100+9000            | 100+9000                 | 5000                    | 2300           |
| EXTDELEGATECALL | 100                 | 100                      | 5000                    | 2300           |
| EXTSTATICCALL   | 100                 | 100                      | 5000                    | 2300           |

- **Caller required gas**: the minimum amount of gas a caller is required to have to execute a call instruction, lower value causes caller's OOG,
- **Caller cost (burned gas)**: the amount of gas deducted from the caller to execute the instruction, this amount is not available to the callee,
- **Caller min retained gas**: the minimum amount of gas the caller is guaranteed to have after the call, if this cannot be guaranteed the call fails without even reaching the callee,
- **Callee min gas**: the minimum gas limit for the callee's execution.

Removing the call stack depth check was initially considered, but this would be incompatible with the original `*CALL` instructions, as well as `CREATE*` instructions, which can be intertwined with the new `EXT*CALL` instructions in the call stack. As such, keeping the call stack depth check involves no change affecting legacy code.

Also, we find the simple (as opposed to the complex 63/64th rule) hard cap reassuring, that the call stack depth is limited, in case the gas rules can be bypassed. Lastly, the amount of gas to reach depth of 1024 is huge, but not absurdly huge, and we want to avoid constraining ourselves by dependency of this check on current gas limits.

### Output buffers

The functionality of specifying output buffer address is removed, because it is added complexity and in a large number of cases implementers prefer to use `RETURNDATACOPY` instead. Even if they rely on the output buffer (like in the case of Vyper), they would still check the length with `RETURNDATASIZE`. In Solidity one exception is the case when the expected return size is known (i.e. non-dynamic return values), in this case Solidity still uses the output buffer. For these cases, `RETURNDATALOAD` is introduced, which simplifies the workflow of copying returndata into a (known) output buffer and using `MLOAD` from there; instead, `RETURNDATALOAD` can be used directly.

### Status codes

Current call instructions return a boolean value to signal success: 0 means failure, 1 means success. The Solidity compiler assumed this value is a boolean and thus uses the value as branch condition to status (`if iszero(status) { /* failure */ }`). This prevents us from introducing new status codes without breaking existing contracts. At the time of the design of [EIP-211](./eip-211.md) the idea of return a specific code for revert was discussed, but ultimately abandoned for the above reason.

We change the value from boolean to a status code, where `0` signals success and thus it will be possible to introduce more non-success codes in the future, if desired.

Status code `1` is used for both reverts coming from the callee frame and light failures encountered (see step 10. of Execution Semantics) in the execution of the instructions. The reason for combining them is keeping the semantics similar to the original CALLs - both scenarios preserve unused gas and continue being indistinguishable to the caller.

Status code `2` signals an exceptional failure in the callee execution, meaning an error occurred that consumed all remaining gas in the callee frame.

### Parameter order

The order of parameters has been changed to move the `value` field to be the last. This allows the instructions to have identical encoding with the exception of the last parameter, and simplifies EVM and compiler implementations slightly.

### Opcode encoding

Instead of introducing three new `EXT*CALL` opcodes we have discussed a version with an immediate configuration byte (flags). There are two main disadvantages to this:

1. Some combination of flags may not be useful/be invalid, and this increases the testing/implementation surface.
2. The instruction could take variable number of stack items (i.e. `value` for `EXTCALL`) would be a brand new concept no other instruction has.

It is also useful to have these as new opcodes instead of modifying the existing CALL series inside of EOF. This creates an "escape hatch" in case gas observability needs to be restored to EOF contracts. This is done by adding the GAS and original CALL series opcodes to the valid EOF opcode list.

### `CALLCODE`

Since `CALLCODE` is deprecated, we do not introduce a counterpart here.

### Halting when `target_address` is not a 20-byte ethereum addresses  

When existing `CALL` series operations encounter an address that does not fit into 20 bytes the current behavior is to mask the address so that it fits into 20 bytes, ignoring all high bytes. For the `EXT*CALL` operations a halt was chosen over treating the contract as empty for two reasons. First, it handles the case of sending value to an address that doesn't exist without having to create a special case. Second, it keeps the `warm_access_list` from needing to track anything that is not a 20-byte ethereum address.

Smart contract developers should not rely on the operation reverting when such addresses are passed in. When a suitable proposal for the use of Address Space Extension is adopted it is expected that the `EXT*CALL` series of operations will adopt those changes.

### New instructions undefined in legacy (this EIP is part of EOF only)

Initially an alternative scenario was considered to introduce these new instructions separately in the legacy EVM first to limit the scope of EOF change, but it was decided to include it as a part of the EOF upgrade and keep them undefined in the legacy EVM.

### `RETURNDATALOAD` and `RETURNDATACOPY` padding behavior

This EIP initially proposed keeping the halt-on-OOB behavior of legacy `RETURNDATACOPY`. This makes compilers optimizations harder, because unnecessary `RETURNDATA*` instructions cannot be optimized out without change to code semantics.

It could be that only `RETURNDATALOAD` is given the padding behavior, but that would make it confusingly inconsistent with the closely related `RETURNDATACOPY` instruction.

There also was the alternative to have `RETURNDATACOPY2` introduced with the padding behavior, available in EOF only, at the same time banning `RETURNDATACOPY` in EOF. This has been rejected in order to avoid multiplying opcodes, and also as suboptimal from the point of view of compiler implementation.

### EOF1 contracts can `EXTDELEGATECALL` only EOF1 contracts

Legacy contracts can selfdestruct in three different ways (directly through `SELFDESTRUCT`, indirectly through `CALLCODE` and indirectly through `DELEGATECALL`). [EIP-3670](./eip-3670.md) disables the first two possibilities, however the third possibility remains. Allowing EOF1 contracts to `EXTDELEGATECALL` only other EOF1 contracts allows the following strong statement: EOF1 contract can never be destructed. Attacks based on `SELFDESTRUCT` completely disappear for EOF1 contracts. These include destructed library contracts (e.g. Parity Multisig).

## Backwards Compatibility

No existing instructions are changed and so we do not think any backwards compatibility issues can occur.

## Security Considerations

It is expected that the attack surface will not grow. All of these operations can be modeled by existing operations with fixed gas (all available) and output range (zero length at zero memory).

When implemented in EOF (where the GAS opcode and the original CALL operations are removed) existing out of gas attacks will be slightly more difficult, but not entirely prevented. Transactions can still pass in arbitrary gas values and clever contract construction can still result in specific gas values being passed to specific calls. It is expected the same surface will remain in EOF, but the ease of exploitation will be reduced.

The legacy `*CALL` instructions allow to pass gas available for the callee. This ability is used to prevent reentrancy attack but in case of potential future gas repricing proposal this pattern does not give this guarantee any longer. Protecting against reentrancy should be resolved by using `TSTORE/TLOAD` instructions introduced in [EIP-1153](./eip-1153.md) or other solutions which do not rely on current gas schedule.       

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
