Last active
May 22, 2024 03:08
-
-
Save ipekt/ec9b6cfca9935e1c3bf12377770e2a6a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // SPDX-License-Identifier: UNLICENSED | |
| pragma solidity 0.8.20; | |
| import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; | |
| import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | |
| import {OperatorAllowlistEnforced} from "./OperatorAllowlistEnforced.sol"; | |
| contract ClashOfCats is ERC721Upgradeable, OperatorAllowlistEnforced { | |
| function initialize() public initializer { | |
| __ERC721_init("ClashOfCats", "CATs"); | |
| // Testnet address | |
| _setOperatorAllowlistRegistry( | |
| address(0x6b969FD89dE634d8DE3271EbE97734FEFfcd58eE) | |
| ); | |
| } | |
| function approve( | |
| address to, | |
| uint256 tokenId | |
| ) public virtual override(ERC721Upgradeable) validateApproval(to) { | |
| super.approve(to, tokenId); | |
| } | |
| function setApprovalForAll( | |
| address operator, | |
| bool approved | |
| ) public virtual override(ERC721Upgradeable) validateApproval(operator) { | |
| super.setApprovalForAll(operator, approved); | |
| } | |
| function _safeTransfer( | |
| address from, | |
| address to, | |
| uint256 tokenId, | |
| bytes memory _data | |
| ) internal virtual override(ERC721Upgradeable) validateTransfer(from, to) { | |
| super._safeTransfer(from, to, tokenId, _data); | |
| } | |
| // Not required, example function | |
| function safeTransfer( | |
| address from, | |
| address to, | |
| uint256 tokenId, | |
| bytes memory _data | |
| ) public { | |
| _safeTransfer(from, to, tokenId, _data); | |
| } | |
| function transferFrom( | |
| address from, | |
| address to, | |
| uint256 tokenId | |
| ) public virtual override(ERC721Upgradeable) validateTransfer(from, to) { | |
| super.transferFrom(from, to, tokenId); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright Immutable Pty Ltd 2018 - 2023 | |
| // SPDX-License-Identifier: Apache 2.0 | |
| pragma solidity 0.8.20; | |
| /** | |
| * @notice Required interface of an OperatorAllowlist compliant contract | |
| */ | |
| interface IOperatorAllowlist { | |
| /** | |
| * @notice Returns true if an address is Allowlisted false otherwise | |
| * @param target the address to be checked against the Allowlist | |
| */ | |
| function isAllowlisted(address target) external view returns (bool); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copy of these files: | |
| // - https://github.com/immutable/contracts/blob/main/contracts/allowlist/OperatorAllowlistEnforced.sol | |
| // - https://github.com/immutable/contracts/blob/main/contracts/errors/Errors.sol#L33-L51 | |
| // - only solidity version is updated to 0.8.20 | |
| // Copyright Immutable Pty Ltd 2018 - 2023 | |
| // SPDX-License-Identifier: Apache 2.0 | |
| // slither-disable-start calls-loop | |
| pragma solidity 0.8.20; | |
| // Allowlist Registry | |
| import {IOperatorAllowlist} from "./IOperatorAllowlist.sol"; | |
| // Interface | |
| import {IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; | |
| // Errors | |
| interface OperatorAllowlistEnforcementErrors { | |
| /// @dev Error thrown when the operatorAllowlist address does not implement the IOperatorAllowlist interface | |
| error AllowlistDoesNotImplementIOperatorAllowlist(); | |
| /// @dev Error thrown when calling address is not OperatorAllowlist | |
| error CallerNotInAllowlist(address caller); | |
| /// @dev Error thrown when 'from' address is not OperatorAllowlist | |
| error TransferFromNotInAllowlist(address from); | |
| /// @dev Error thrown when 'to' address is not OperatorAllowlist | |
| error TransferToNotInAllowlist(address to); | |
| /// @dev Error thrown when approve target is not OperatorAllowlist | |
| error ApproveTargetNotInAllowlist(address target); | |
| /// @dev Error thrown when approve target is not OperatorAllowlist | |
| error ApproverNotInAllowlist(address approver); | |
| } | |
| /* | |
| OperatorAllowlistEnforced is an abstract contract that token contracts can inherit in order to set the | |
| address of the OperatorAllowlist registry that it will interface with, so that the token contract may | |
| enable the restriction of approvals and transfers to allowlisted users. | |
| OperatorAllowlistEnforced is not designed to be upgradeable or extended. | |
| */ | |
| abstract contract OperatorAllowlistEnforced is OperatorAllowlistEnforcementErrors { | |
| /// ===== State Variables ===== | |
| /// @notice Interface that implements the `IOperatorAllowlist` interface | |
| IOperatorAllowlist public operatorAllowlist; | |
| /// ===== Events ===== | |
| /// @notice Emitted whenever the transfer Allowlist registry is updated | |
| event OperatorAllowlistRegistryUpdated(address oldRegistry, address newRegistry); | |
| /// ===== Modifiers ===== | |
| /** | |
| * @notice Internal function to validate an approval, according to whether the target is an EOA or Allowlisted | |
| * @param targetApproval the address of the approval target to be validated | |
| */ | |
| modifier validateApproval(address targetApproval) { | |
| // Check for: | |
| // 1. approver is an EOA. Contract constructor is handled as transfers 'from' are blocked | |
| // 2. approver is address or bytecode is allowlisted | |
| if (msg.sender.code.length != 0 && !operatorAllowlist.isAllowlisted(msg.sender)) { | |
| revert ApproverNotInAllowlist(msg.sender); | |
| } | |
| // Check for: | |
| // 1. approval target is an EOA | |
| // 2. approval target address is Allowlisted or target address bytecode is Allowlisted | |
| if (targetApproval.code.length != 0 && !operatorAllowlist.isAllowlisted(targetApproval)) { | |
| revert ApproveTargetNotInAllowlist(targetApproval); | |
| } | |
| _; | |
| } | |
| /** | |
| * @notice Internal function to validate a transfer, according to whether the calling address, | |
| * from address and to address is an EOA or Allowlisted | |
| * @param from the address of the from target to be validated | |
| * @param to the address of the to target to be validated | |
| */ | |
| modifier validateTransfer(address from, address to) { | |
| // Check for: | |
| // 1. caller is an EOA | |
| // 2. caller is Allowlisted or is the calling address bytecode is Allowlisted | |
| if ( | |
| msg.sender != tx.origin && // solhint-disable-line avoid-tx-origin | |
| !operatorAllowlist.isAllowlisted(msg.sender) | |
| ) { | |
| revert CallerNotInAllowlist(msg.sender); | |
| } | |
| // Check for: | |
| // 1. from is an EOA | |
| // 2. from is Allowlisted or from address bytecode is Allowlisted | |
| if (from.code.length != 0 && !operatorAllowlist.isAllowlisted(from)) { | |
| revert TransferFromNotInAllowlist(from); | |
| } | |
| // Check for: | |
| // 1. to is an EOA | |
| // 2. to is Allowlisted or to address bytecode is Allowlisted | |
| if (to.code.length != 0 && !operatorAllowlist.isAllowlisted(to)) { | |
| revert TransferToNotInAllowlist(to); | |
| } | |
| _; | |
| } | |
| /// ===== External functions ===== | |
| /** | |
| * @notice Internal function to set the operator allowlist the calling contract will interface with | |
| * @param _operatorAllowlist the address of the Allowlist registry | |
| */ | |
| function _setOperatorAllowlistRegistry(address _operatorAllowlist) internal { | |
| if (!IERC165(_operatorAllowlist).supportsInterface(type(IOperatorAllowlist).interfaceId)) { | |
| revert AllowlistDoesNotImplementIOperatorAllowlist(); | |
| } | |
| emit OperatorAllowlistRegistryUpdated(address(operatorAllowlist), _operatorAllowlist); | |
| operatorAllowlist = IOperatorAllowlist(_operatorAllowlist); | |
| } | |
| } | |
| // slither-disable-end calls-loop |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment