|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +pragma solidity >0.6.0 <0.8.0; |
| 3 | + |
| 4 | +/* Library Imports */ |
| 5 | +import { EnumerableSet } from "../../../../vendor/OpenZeppelin/openzeppelin-contracts/contracts/utils/EnumerableSet.sol"; |
| 6 | + |
| 7 | +/* Contract Imports */ |
| 8 | +import { Initializable } from "../../../../vendor/OpenZeppelin/openzeppelin-contracts-upgradeable/contracts/proxy/Initializable.sol"; |
| 9 | +import { OwnableUpgradeable } from "../../../../vendor/OpenZeppelin/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; |
| 10 | + |
| 11 | +/** |
| 12 | + * @dev Abstract helper contract used to keep track of OVM EOA contract set (OVM specific) |
| 13 | + * |
| 14 | + * The OVM implements a basic form of account abstraction. In effect, this means |
| 15 | + * that the only type of account is a smart contract (no EOAs), and all user wallets |
| 16 | + * are in fact smart contract wallets. So to check for EOA, we need to actually check if |
| 17 | + * the sender is an OVM_ProxyEOA contract, which gets deployed by the ovmCREATEEOA opcode. |
| 18 | + * |
| 19 | + * As the OVM_ProxyEOA.sol contract source could potentially change in the future (i.e., due to a fork), |
| 20 | + * here we actually track a set of possible EOA proxy contracts. |
| 21 | + */ |
| 22 | +abstract contract OVM_EOACodeHashSet is /* Initializable, */ OwnableUpgradeable { |
| 23 | + // Add the EnumerableSet library |
| 24 | + using EnumerableSet for EnumerableSet.Bytes32Set; |
| 25 | + |
| 26 | + // Declare a Bytes32Set of code hashes |
| 27 | + EnumerableSet.Bytes32Set private s_codeHasheSet; |
| 28 | + |
| 29 | + // Declare the genesis OVM_ProxyEOA.sol EXTCODEHASH |
| 30 | + bytes32 constant OVM_EOA_CODE_HASH_V0 = 0x93bb081a7dd92bde63b4d0aa9b8612352b2ec585176a80efc0a2a277ecfc010e; |
| 31 | + bytes32 constant OVM_EOA_CODE_HASH_V1 = 0x8b4ea2cb36c232a7bab9d385b7054ff04752ec4c0fad5dc2ed4b1c18d982154c; |
| 32 | + bytes32 constant OVM_EOA_CODE_HASH_V2 = 0xb6268ee2707994607682cc0e3b288cdd71acc63df8de0e6baa39a31a2b91d0ad; |
| 33 | + bytes32 constant OVM_EOA_CODE_HASH_V3 = 0x93fae832274ff6aa942fa0c287fc0d8fe180f26b36c92e83d9be7e39309d3464; |
| 34 | + // Optimism v0.3.0-rc |
| 35 | + bytes32 constant OVM_EOA_CODE_HASH_V4 = 0xef2ab076db773ffc554c9f287134123439a5228e92f5b3194a28fec0a0afafe3; |
| 36 | + |
| 37 | + function __OVM_EOACodeHashSet_init() |
| 38 | + internal |
| 39 | + initializer() |
| 40 | + { |
| 41 | + __Context_init_unchained(); |
| 42 | + __Ownable_init_unchained(); |
| 43 | + __OVM_EOACodeHashSet_init_unchained(); |
| 44 | + } |
| 45 | + |
| 46 | + /// @notice Adds genesis OVM_ProxyEOA.sol EXTCODEHASH to the default set. |
| 47 | + function __OVM_EOACodeHashSet_init_unchained() |
| 48 | + internal |
| 49 | + initializer() |
| 50 | + { |
| 51 | + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V0); |
| 52 | + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V1); |
| 53 | + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V2); |
| 54 | + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V3); |
| 55 | + s_codeHasheSet.add(OVM_EOA_CODE_HASH_V4); |
| 56 | + } |
| 57 | + |
| 58 | + /// @notice Reverts if called by anyone other than whitelisted EOA contracts. |
| 59 | + modifier onlyEOAContract() { |
| 60 | + require(_isEOAContract(msg.sender), "Only callable by whitelisted EOA"); |
| 61 | + _; |
| 62 | + } |
| 63 | + |
| 64 | + /** |
| 65 | + * @dev Returns true if the EOA contract code hash value is in the set. O(1). |
| 66 | + * |
| 67 | + * @param value EOA contract code hash to check |
| 68 | + */ |
| 69 | + function containsEOACodeHash( |
| 70 | + bytes32 value |
| 71 | + ) |
| 72 | + public |
| 73 | + view |
| 74 | + returns (bool) |
| 75 | + { |
| 76 | + return s_codeHasheSet.contains(value); |
| 77 | + } |
| 78 | + |
| 79 | + /** |
| 80 | + * @dev Adds a EOA contract code hash value to the set. O(1). |
| 81 | + * |
| 82 | + * Returns true if the value was added to the set, that is if it was not already present. |
| 83 | + * @param value EOA contract code hash to add |
| 84 | + */ |
| 85 | + function addEOACodeHash( |
| 86 | + bytes32 value |
| 87 | + ) |
| 88 | + public |
| 89 | + onlyOwner() |
| 90 | + returns (bool) |
| 91 | + { |
| 92 | + return s_codeHasheSet.add(value); |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * @dev Removes a EOA contract code hash value from the set. O(1). |
| 97 | + * |
| 98 | + * Returns true if the value was removed from the set, that is if it was present. |
| 99 | + * @param value EOA contract code hash to remove |
| 100 | + */ |
| 101 | + function removeEOACodeHash( |
| 102 | + bytes32 value |
| 103 | + ) |
| 104 | + public |
| 105 | + onlyOwner() |
| 106 | + returns (bool) |
| 107 | + { |
| 108 | + return s_codeHasheSet.remove(value); |
| 109 | + } |
| 110 | + |
| 111 | + /** |
| 112 | + * @dev Returns true if `account` is a whitelisted EOA contract. |
| 113 | + * @param account Address to check |
| 114 | + */ |
| 115 | + function _isEOAContract( |
| 116 | + address account |
| 117 | + ) |
| 118 | + internal |
| 119 | + view |
| 120 | + returns (bool) |
| 121 | + { |
| 122 | + bytes32 codehash; |
| 123 | + // solhint-disable-next-line no-inline-assembly |
| 124 | + assembly { codehash := extcodehash(account) } |
| 125 | + return s_codeHasheSet.contains(codehash); |
| 126 | + } |
| 127 | +} |
0 commit comments