-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
--- | ||
title: IS_CONTRACT instruction | ||
description: Introduce IS_CONTRACT instruction | ||
author: Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon) | ||
discussions-to: <URL> | ||
status: Draft | ||
type: Standards Track | ||
category: Core | ||
created: 2024-09-01 | ||
requires: 3540, 7692 | ||
--- | ||
|
||
## Abstract | ||
|
||
Allow EOF contracts to discriminate between EOA (Externally Owned Accounts) and smart contract accounts by introducing an `IS_CONTRACT` instruction. | ||
|
||
## Motivation | ||
|
||
EOFv1 as scoped in [EIP-7692](./eip-7692.md) removes code introspection capabilities from the EVM, including the `EXTCODESIZE` instruction. This makes it hard for ERC-721 and ERC-1155 standard contracts to be implemented, as they rely on discovering whether a token's `safeTransfer` call target was an EOA or a smart contract: | ||
Check failure on line 19 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 19 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 19 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 19 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
|
||
|
||
- `safeTransfers` to EOA succeed | ||
- `safeTransfers` to smart contracts call an `onERC721Received` (`onERC1155Received`) on them and expect to get a special magic return value, otherwise the transfer reverts (on the assumption that such a receipient may not be able to interact with the token) | ||
|
||
`IS_CONTRACT` is aimed to fill this gap and bring back the possibility to easily implement ERC-721 and ERC-1155 standard contracts in EOF. | ||
Check failure on line 24 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 24 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 24 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 24 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
|
||
|
||
## Specification | ||
|
||
### Parameters | ||
|
||
| Constant | Value | | ||
| - | - | | ||
| `FORK_BLKNUM` | tbd | | ||
| `GAS_COLD_ACCOUNT_ACCESS` | Defined as `2600` in the [Ethereum Execution Layer Specs](https://github.com/ethereum/execution-specs/blob/fcd12750edd4443a91f138728689a1d0a503a7c1/src/ethereum/cancun/vm/gas.py#L64) | | ||
| `GAS_WARM_ACCESS` | Defined as `100` in the [Ethereum Execution Layer Specs](https://github.com/ethereum/execution-specs/blob/fcd12750edd4443a91f138728689a1d0a503a7c1/src/ethereum/cancun/vm/gas.py#L65) | | ||
|
||
We introduce a new EOFv1 instruction on the block number `FORK_BLKNUM`: `IS_CONTRACT` (`0xe9`) | ||
|
||
EOF code which contains this instruction before `FORK_BLKNUM` is considered invalid. Beginning with block `FORK_BLKNUM` `0xe9` is added to the set of valid EOFv1 instructions. | ||
|
||
### Execution Semantics | ||
|
||
#### `IS_CONTRACT` | ||
|
||
- deduct `GAS_WARM_ACCESS` gas | ||
- pop 1 argument `target_address` from the stack | ||
- 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 | ||
- deduct `GAS_COLD_ACCOUNT_ACCESS - GAS_WARM_ACCESS` if `target_address` is not in `accessed_addresses` and add `target_address` to `accessed_addresses` | ||
- push `1` onto the stack if `target_address.code` is not empty, `0` otherwise | ||
|
||
If `target_address.code` contains an [EIP-7702](./eip-7702.md) delegation, the result of `IS_CONTRACT` should follow the delegation and return a result according the delegation designator account. Additional gas costs and rules concering `accessed_addresses` apply as specified in EIP-7702 for code reading instructions like `EXTCODESIZE`. | ||
|
||
If `target_address` points to an account with a contract mid-creation, it behaves aligned with similar instructions like `EXTCODESIZE` and returns `0`. | ||
|
||
## Rationale | ||
|
||
### Alternative solutions | ||
|
||
There have been other solutions proposed to alleviate the problems related to lack of code introspection required for ERC-721 and ERC-1155 standards: | ||
Check failure on line 58 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 58 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 58 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 58 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
|
||
|
||
1. Extra status code for `EXT*CALL` instruction - allowing to discriminate a result coming from calling an EOA | ||
2. Extra argument for `EXT*CALL` (a "fail if EOA" flag) | ||
3. Two return values from `EXT*CALL` (status code + whether it was EOA) | ||
4. `EXT*CALL` setting a new `callstatus` register (+ a new `CALLSTATUS` instruction) | ||
5. Reenable `EXTCODESIZE` in EOF, keeping its behavior same as in legacy | ||
|
||
`IS_CONTRACT` has been chosen as the most elegant and minimal solution satisfying the requirements at hand and still able to be introduced in EOFv1. | ||
|
||
### Reuse the `0x3b` (`EXTCODESIZE`) opcode for `IS_CONTRACT` | ||
|
||
A new opcode is prefered by a general policy to not reuse opcodes. Also `IS_CONTRACT` can be rolled out in legacy EVM if desired. | ||
|
||
### Keep code introspection banned | ||
|
||
Removing code introspection is one of the tenets of EOF and `IS_CONTRACT` would be an exception from the principle. Without `IS_CONTRACT`, ERC-721 and ERC-1155 standard implementations have to resort to either: | ||
Check failure on line 74 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 74 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 74 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 74 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
|
||
|
||
1. Leveraging a "booster contract" which would be legacy and would call `EXTCODESIZE` for them. This has been deemed inelegant and inconvenient from the point of view of library implementers, requiring them to hard code an address of such a contract (with the usual address-related problems arising on different EVM chains) | ||
2. Continuing to use legacy EVM themselves. This is sub-optimal, since EVM compilers are likely to at some point deprecate legacy EVM as compilation target | ||
3. Updating the standards to not rely on code introspection (`safeTransfer` safe guards) patterns, also unlikely to happen as ERC-721 and ERC-1155 are Final and adopted in practice. | ||
Check failure on line 78 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 78 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 78 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
Check failure on line 78 in EIPS/eip-is-contract.md GitHub Actions / EIP Walidatorthe first match of the given pattern must be a link
|
||
|
||
### "Endgame Account Abstraction" issues | ||
|
||
TBD - can someone verbalize it? | ||
|
||
### Relation to [EIP-7702](./eip-7702.md) "Set EOA account code" | ||
|
||
After [EIP-7702](./eip-7702.md) is activated, the discrimination between EOAs and smart contracts using `EXTCODESIZE` (or `IS_CONTRACT`) has an edge case: Whenever an EOA sets its code to a smart contract which does not respond as expected to an `onERC721Received` (`onERC1155Received`) callback, transfers to it will revert, despite the recipient being able to interact with the token. This has been deemed unlikely to be a problem, as for the intended real-world uses of `EIP-7702`, those callbacks will be implemented by designator codes. | ||
|
||
### Including safe guarding against proxy bricking | ||
|
||
In parallel to the ERC-721 / ERC-1155 problem, another potential risk has been brought to attention. Since EOFv1 prohibits `EXTDELEGATECALL` targetting legacy contracts, there exists a scenario where an EOF proxy contract accidentally upgrades its implementation to a legacy EVM one. Since reverting this or upgrading again (using current proxy standards) requires the implementation contract to be called, it would effectively render the contract unusable. | ||
|
||
One potential solution to this would be to have a generalized `CONTRACT_KIND` instruction instead of `IS_CONTRACT` which would further discriminate the account into legacy or EOFv1 with a `0` / `1` / `2` return value, thereby providing means for an additional safeguard against such a scenario. | ||
|
||
This problem is potentially solvable on the application layer (proxy upgrade would include a direct check of the implementation contract being `EXTDELEGATECALL`-able) or even by re-enabling `EXTDELEGATECALL` to a legacy target in a future EVM upgrade. | ||
|
||
## Backwards Compatibility | ||
|
||
`IS_CONTRACT` at `0xe9` can be introduced in a backwards compatible manner into EOFv1 (no bump to version), because `0xe9` has been rejected by EOF validation before `FORK_BLKNUM` and there are no EOF contracts on-chain with a `0xe9` which would have their behavior altered. | ||
|
||
## Security Considerations | ||
|
||
TBA | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |