From 8f785fb9230fb553f511b9749bb1c95abf235016 Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:39:43 +0200 Subject: [PATCH 1/7] Add EIP: IS_CONTRACT instruction --- EIPS/eip-is-contract.md | 106 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 EIPS/eip-is-contract.md diff --git a/EIPS/eip-is-contract.md b/EIPS/eip-is-contract.md new file mode 100644 index 0000000000000..f6e357f2602e4 --- /dev/null +++ b/EIPS/eip-is-contract.md @@ -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: +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: + +- `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. + +## 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: + +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: + +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. + +### "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). From 17ac984108e555b6930c7081359442cbe8cdb2b7 Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:10:50 +0200 Subject: [PATCH 2/7] Apply suggestions and EIP number Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com> --- EIPS/eip-is-contract.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EIPS/eip-is-contract.md b/EIPS/eip-is-contract.md index f6e357f2602e4..aa18368f24edc 100644 --- a/EIPS/eip-is-contract.md +++ b/EIPS/eip-is-contract.md @@ -1,4 +1,5 @@ --- +eip: 7761 title: IS_CONTRACT instruction description: Introduce IS_CONTRACT instruction author: Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon) @@ -12,7 +13,7 @@ requires: 3540, 7692 ## Abstract -Allow EOF contracts to discriminate between EOA (Externally Owned Accounts) and smart contract accounts by introducing an `IS_CONTRACT` instruction. +Allow EOF contracts to discriminate between EOA (Externally Owned Accounts) and contracts (including smart contract accounts) by introducing an `IS_CONTRACT` instruction. ## Motivation From 24dc0b2a2798afb4429e727f98e039b75191d9c2 Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:29:32 +0200 Subject: [PATCH 3/7] Add discussion link and reference ERCs --- EIPS/{eip-is-contract.md => eip-7761.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename EIPS/{eip-is-contract.md => eip-7761.md} (95%) diff --git a/EIPS/eip-is-contract.md b/EIPS/eip-7761.md similarity index 95% rename from EIPS/eip-is-contract.md rename to EIPS/eip-7761.md index aa18368f24edc..6167ce138f7a1 100644 --- a/EIPS/eip-is-contract.md +++ b/EIPS/eip-7761.md @@ -3,7 +3,7 @@ eip: 7761 title: IS_CONTRACT instruction description: Introduce IS_CONTRACT instruction author: Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon) -discussions-to: +discussions-to: https://ethereum-magicians.org/t/eip-7761-is-contract-instruction/20936 status: Draft type: Standards Track category: Core @@ -17,7 +17,7 @@ Allow EOF contracts to discriminate between EOA (Externally Owned Accounts) and ## 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: +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](./eip-721.md) and [ERC-1155](./eip-1155.md) standard contracts to be implemented, as they rely on discovering whether a token's `safeTransfer` call target was an EOA or a smart contract: - `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) From 2be26b3496b568d602ac6aba85211a02f84594c0 Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:55:57 +0200 Subject: [PATCH 4/7] Fix and tidy EOA vs contract account nomenclature --- EIPS/eip-7761.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/EIPS/eip-7761.md b/EIPS/eip-7761.md index 6167ce138f7a1..be5eedb6bef98 100644 --- a/EIPS/eip-7761.md +++ b/EIPS/eip-7761.md @@ -13,14 +13,14 @@ requires: 3540, 7692 ## Abstract -Allow EOF contracts to discriminate between EOA (Externally Owned Accounts) and contracts (including smart contract accounts) by introducing an `IS_CONTRACT` instruction. +Allow EOF contracts to discriminate between EOAs (Externally Owned Accounts) and 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](./eip-721.md) and [ERC-1155](./eip-1155.md) standard contracts to be implemented, as they rely on discovering whether a token's `safeTransfer` call target was an EOA or a smart contract: +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](./eip-721.md) and [ERC-1155](./eip-1155.md) standard contracts to be implemented, as they rely on discovering whether a token's `safeTransfer` call target was an EOA or a contract account: -- `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) +- `safeTransfers` to EOAs succeed +- `safeTransfers` to contract accounts 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. @@ -48,7 +48,7 @@ EOF code which contains this instruction before `FORK_BLKNUM` is considered inva - 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.code` contains an [EIP-7702](./eip-7702.md) delegation, the result of `IS_CONTRACT` should follow the delegation and return a result according to 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`. @@ -84,7 +84,7 @@ 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. +After [EIP-7702](./eip-7702.md) is activated, the discrimination between EOAs and contract accounts using `EXTCODESIZE` (or `IS_CONTRACT`) has an edge case: Whenever an EOA sets its code to a contract account 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 From 4a5bdf3f8f788364d582ce3572a1f7b37acfa11c Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Tue, 3 Sep 2024 08:52:25 +0200 Subject: [PATCH 5/7] Rename to ISCONTRACT --- EIPS/eip-7761.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/EIPS/eip-7761.md b/EIPS/eip-7761.md index be5eedb6bef98..22d52c85e650a 100644 --- a/EIPS/eip-7761.md +++ b/EIPS/eip-7761.md @@ -1,7 +1,7 @@ --- eip: 7761 -title: IS_CONTRACT instruction -description: Introduce IS_CONTRACT instruction +title: ISCONTRACT instruction +description: Introduce ISCONTRACT instruction author: Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon) discussions-to: https://ethereum-magicians.org/t/eip-7761-is-contract-instruction/20936 status: Draft @@ -13,7 +13,7 @@ requires: 3540, 7692 ## Abstract -Allow EOF contracts to discriminate between EOAs (Externally Owned Accounts) and contract accounts by introducing an `IS_CONTRACT` instruction. +Allow EOF contracts to discriminate between EOAs (Externally Owned Accounts) and contract accounts by introducing an `ISCONTRACT` instruction. ## Motivation @@ -22,7 +22,7 @@ EOFv1 as scoped in [EIP-7692](./eip-7692.md) removes code introspection capabili - `safeTransfers` to EOAs succeed - `safeTransfers` to contract accounts 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. +`ISCONTRACT` is aimed to fill this gap and bring back the possibility to easily implement ERC-721 and ERC-1155 standard contracts in EOF. ## Specification @@ -34,13 +34,13 @@ EOFv1 as scoped in [EIP-7692](./eip-7692.md) removes code introspection capabili | `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`) +We introduce a new EOFv1 instruction on the block number `FORK_BLKNUM`: `ISCONTRACT` (`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` +#### `ISCONTRACT` - deduct `GAS_WARM_ACCESS` gas - pop 1 argument `target_address` from the stack @@ -48,7 +48,7 @@ EOF code which contains this instruction before `FORK_BLKNUM` is considered inva - 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 to 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.code` contains an [EIP-7702](./eip-7702.md) delegation, the result of `ISCONTRACT` should follow the delegation and return a result according to 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`. @@ -64,15 +64,15 @@ There have been other solutions proposed to alleviate the problems related to la 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. +`ISCONTRACT` 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` +### Reuse the `0x3b` (`EXTCODESIZE`) opcode for `ISCONTRACT` -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. +A new opcode is prefered by a general policy to not reuse opcodes. Also `ISCONTRACT` 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: +Removing code introspection is one of the tenets of EOF and `ISCONTRACT` would be an exception from the principle. Without `ISCONTRACT`, ERC-721 and ERC-1155 standard implementations have to resort to either: 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 @@ -84,19 +84,19 @@ 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 contract accounts using `EXTCODESIZE` (or `IS_CONTRACT`) has an edge case: Whenever an EOA sets its code to a contract account 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. +After [EIP-7702](./eip-7702.md) is activated, the discrimination between EOAs and contract accounts using `EXTCODESIZE` (or `ISCONTRACT`) has an edge case: Whenever an EOA sets its code to a contract account 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. +One potential solution to this would be to have a generalized `CONTRACT_KIND` instruction instead of `ISCONTRACT` 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. +`ISCONTRACT` 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 From 4cae577b1257a3c1a7d91fa18744418974805664 Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Wed, 4 Sep 2024 07:49:43 +0200 Subject: [PATCH 6/7] Apply suggestions from review --- EIPS/eip-7761.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-7761.md b/EIPS/eip-7761.md index 22d52c85e650a..ecd40558d67aa 100644 --- a/EIPS/eip-7761.md +++ b/EIPS/eip-7761.md @@ -1,7 +1,7 @@ --- eip: 7761 title: ISCONTRACT instruction -description: Introduce ISCONTRACT instruction +description: Introduce ISCONTRACT instruction to replace the EXTCODESIZE > 0 check in EOF author: Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon) discussions-to: https://ethereum-magicians.org/t/eip-7761-is-contract-instruction/20936 status: Draft @@ -80,11 +80,11 @@ Removing code introspection is one of the tenets of EOF and `ISCONTRACT` would b ### "Endgame Account Abstraction" issues -TBD - can someone verbalize it? - +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 contract accounts using `EXTCODESIZE` (or `ISCONTRACT`) has an edge case: Whenever an EOA sets its code to a contract account 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. +After [EIP-7702](./eip-7702.md) is activated, the discrimination between EOAs and contract accounts using `EXTCODESIZE` (or `ISCONTRACT`) has an edge case: Whenever an EOA sets its code to a contract account 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 @@ -100,7 +100,7 @@ This problem is potentially solvable on the application layer (proxy upgrade wou ## Security Considerations -TBA +Needs discussion ## Copyright From 762a6eb77859a278b85493ead38cdc71c7a0262b Mon Sep 17 00:00:00 2001 From: pdobacz <5735525+pdobacz@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:25:56 +0200 Subject: [PATCH 7/7] Rename to HASCODE --- EIPS/eip-7761.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/EIPS/eip-7761.md b/EIPS/eip-7761.md index ecd40558d67aa..d42f574a7ee55 100644 --- a/EIPS/eip-7761.md +++ b/EIPS/eip-7761.md @@ -1,7 +1,7 @@ --- eip: 7761 -title: ISCONTRACT instruction -description: Introduce ISCONTRACT instruction to replace the EXTCODESIZE > 0 check in EOF +title: HASCODE instruction +description: Introduce HASCODE instruction to replace the EXTCODESIZE > 0 check in EOF author: Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon) discussions-to: https://ethereum-magicians.org/t/eip-7761-is-contract-instruction/20936 status: Draft @@ -13,7 +13,7 @@ requires: 3540, 7692 ## Abstract -Allow EOF contracts to discriminate between EOAs (Externally Owned Accounts) and contract accounts by introducing an `ISCONTRACT` instruction. +Allow EOF contracts to discriminate between EOAs (Externally Owned Accounts) and contract accounts by introducing an `HASCODE` instruction. ## Motivation @@ -22,7 +22,7 @@ EOFv1 as scoped in [EIP-7692](./eip-7692.md) removes code introspection capabili - `safeTransfers` to EOAs succeed - `safeTransfers` to contract accounts 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) -`ISCONTRACT` is aimed to fill this gap and bring back the possibility to easily implement ERC-721 and ERC-1155 standard contracts in EOF. +`HASCODE` is aimed to fill this gap and bring back the possibility to easily implement ERC-721 and ERC-1155 standard contracts in EOF. ## Specification @@ -34,13 +34,13 @@ EOFv1 as scoped in [EIP-7692](./eip-7692.md) removes code introspection capabili | `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`: `ISCONTRACT` (`0xe9`) +We introduce a new EOFv1 instruction on the block number `FORK_BLKNUM`: `HASCODE` (`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 -#### `ISCONTRACT` +#### `HASCODE` - deduct `GAS_WARM_ACCESS` gas - pop 1 argument `target_address` from the stack @@ -48,7 +48,7 @@ EOF code which contains this instruction before `FORK_BLKNUM` is considered inva - 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 `ISCONTRACT` should follow the delegation and return a result according to 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.code` contains an [EIP-7702](./eip-7702.md) delegation, the result of `HASCODE` should follow the delegation and return a result according to 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`. @@ -64,15 +64,15 @@ There have been other solutions proposed to alleviate the problems related to la 4. `EXT*CALL` setting a new `callstatus` register (+ a new `CALLSTATUS` instruction) 5. Reenable `EXTCODESIZE` in EOF, keeping its behavior same as in legacy -`ISCONTRACT` has been chosen as the most elegant and minimal solution satisfying the requirements at hand and still able to be introduced in EOFv1. +`HASCODE` 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 `ISCONTRACT` +### Reuse the `0x3b` (`EXTCODESIZE`) opcode for `HASCODE` -A new opcode is prefered by a general policy to not reuse opcodes. Also `ISCONTRACT` can be rolled out in legacy EVM if desired. +A new opcode is prefered by a general policy to not reuse opcodes. Also `HASCODE` can be rolled out in legacy EVM if desired. ### Keep code introspection banned -Removing code introspection is one of the tenets of EOF and `ISCONTRACT` would be an exception from the principle. Without `ISCONTRACT`, ERC-721 and ERC-1155 standard implementations have to resort to either: +Removing code introspection is one of the tenets of EOF and `HASCODE` would be an exception from the principle. Without `HASCODE`, ERC-721 and ERC-1155 standard implementations have to resort to either: 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 @@ -84,19 +84,19 @@ 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 contract accounts using `EXTCODESIZE` (or `ISCONTRACT`) has an edge case: Whenever an EOA sets its code to a contract account 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. +After [EIP-7702](./eip-7702.md) is activated, the discrimination between EOAs and contract accounts using `EXTCODESIZE` (or `HASCODE`) has an edge case: Whenever an EOA sets its code to a contract account 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 `ISCONTRACT` 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. +One potential solution to this would be to have a generalized `CONTRACT_KIND` instruction instead of `HASCODE` 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 -`ISCONTRACT` 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. +`HASCODE` 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