From 30ab758afb72461f31b71eebb17ef0f31bcc3fef Mon Sep 17 00:00:00 2001 From: Iain Nash Date: Thu, 14 Sep 2023 17:37:21 -0400 Subject: [PATCH] remove operator filterer registry from 721 (#150) --- DEPLOYING.md | 11 - script/Deploy.s.sol | 4 - script/TestUpgradeAndMint.s.sol | 2 - script/UpgradeERC721DropFactory.s.sol | 3 - src/DeploymentConfig.sol | 7 - src/ERC721Drop.sol | 79 --- src/filter/OwnedSubscriptionManager.sol | 14 - src/interfaces/IOperatorFilterRegistry.sol | 30 - test/ERC721Drop.t.sol | 265 +++------ test/ZoraNFTCreatorV1.t.sol | 1 - test/filter/OperatorFilterRegistry.sol | 530 ------------------ .../OperatorFilterRegistryErrorsAndEvents.sol | 30 - test/merkle/MerkleDrop.t.sol | 10 +- 13 files changed, 74 insertions(+), 912 deletions(-) delete mode 100644 src/filter/OwnedSubscriptionManager.sol delete mode 100644 src/interfaces/IOperatorFilterRegistry.sol delete mode 100644 test/filter/OperatorFilterRegistry.sol delete mode 100644 test/filter/OperatorFilterRegistryErrorsAndEvents.sol diff --git a/DEPLOYING.md b/DEPLOYING.md index 2a2760b..0b10b5e 100644 --- a/DEPLOYING.md +++ b/DEPLOYING.md @@ -7,17 +7,6 @@ Make sure required addresses / multisigs are setup for 1. funds recipient 2. contract factory upgrade owner address -Ensure that the default operator-filterer-registry deployment is on the current chain. - -If not, use the mainnet default filter address to re-deploy on the chain using ImmutableCreate2Factory (required also for seaport). - -To deploy ImmutableCreate2Factory, follow the steps in the seaport deploy scripts: https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md#setting-up-factory-on-a-new-chain - -example call: -cast send 0x0000000000FFe8B47B3e2130213B802212439497 'function safeCreate2(bytes32,bytes)' [...] --rpc-url $(rpc base) --interactive - -copied from the mainnet deploy txn: https://etherscan.io/tx/0x4c2038f55147cae309c2e597a5323b42b63fd556a15d2f1b5a799eee1b3ddf04 - ### 1. Setup `chainConfigs` file. Use `1.json` for reference. We are ordering keys alphabetically. diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index f6100fd..e361a60 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -8,7 +8,6 @@ import {ERC721Drop} from "../src/ERC721Drop.sol"; import {ERC721DropProxy} from "../src/ERC721DropProxy.sol"; import {ZoraNFTCreatorV1} from "../src/ZoraNFTCreatorV1.sol"; import {ZoraNFTCreatorProxy} from "../src/ZoraNFTCreatorProxy.sol"; -import {IOperatorFilterRegistry} from "../src/interfaces/IOperatorFilterRegistry.sol"; import {FactoryUpgradeGate} from "../src/FactoryUpgradeGate.sol"; import {DropMetadataRenderer} from "../src/metadata/DropMetadataRenderer.sol"; import {EditionMetadataRenderer} from "../src/metadata/EditionMetadataRenderer.sol"; @@ -25,8 +24,6 @@ contract Deploy is ZoraDropsDeployBase { console2.log("Factory Owner", chainConfig.factoryOwner); console2.log("Fee Recipient", chainConfig.mintFeeRecipient); console2.log("Fee Amount", chainConfig.mintFeeAmount); - console2.log("Filterer Registry", chainConfig.subscriptionMarketFilterAddress); - console2.log("Filterer Subscription", chainConfig.subscriptionMarketFilterOwner); console2.log("Setup contracts ---"); @@ -41,7 +38,6 @@ contract Deploy is ZoraDropsDeployBase { ERC721Drop dropImplementation = new ERC721Drop({ _zoraERC721TransferHelper: address(0x0), _factoryUpgradeGate: factoryUpgradeGate, - _marketFilterDAOAddress: address(chainConfig.subscriptionMarketFilterAddress), _mintFeeAmount: chainConfig.mintFeeAmount, _mintFeeRecipient: payable(chainConfig.mintFeeRecipient), _protocolRewards: address(chainConfig.protocolRewards) diff --git a/script/TestUpgradeAndMint.s.sol b/script/TestUpgradeAndMint.s.sol index 8000657..8a88016 100644 --- a/script/TestUpgradeAndMint.s.sol +++ b/script/TestUpgradeAndMint.s.sol @@ -11,8 +11,6 @@ import {ZoraNFTCreatorV1} from "../src/ZoraNFTCreatorV1.sol"; import {IERC721Drop} from "../src/interfaces/IERC721Drop.sol"; import {ZoraNFTCreatorProxy} from "../src/ZoraNFTCreatorProxy.sol"; -import {IOperatorFilterRegistry} from "../src/interfaces/IOperatorFilterRegistry.sol"; -import {OwnedSubscriptionManager} from "../src/filter/OwnedSubscriptionManager.sol"; import {FactoryUpgradeGate} from "../src/FactoryUpgradeGate.sol"; import {DropMetadataRenderer} from "../src/metadata/DropMetadataRenderer.sol"; import {EditionMetadataRenderer} from "../src/metadata/EditionMetadataRenderer.sol"; diff --git a/script/UpgradeERC721DropFactory.s.sol b/script/UpgradeERC721DropFactory.s.sol index ae8c36e..58c6bfa 100644 --- a/script/UpgradeERC721DropFactory.s.sol +++ b/script/UpgradeERC721DropFactory.s.sol @@ -9,8 +9,6 @@ import {ERC721Drop} from "../src/ERC721Drop.sol"; import {ERC721DropProxy} from "../src/ERC721DropProxy.sol"; import {ZoraNFTCreatorV1} from "../src/ZoraNFTCreatorV1.sol"; import {ZoraNFTCreatorProxy} from "../src/ZoraNFTCreatorProxy.sol"; -import {IOperatorFilterRegistry} from "../src/interfaces/IOperatorFilterRegistry.sol"; -import {OwnedSubscriptionManager} from "../src/filter/OwnedSubscriptionManager.sol"; import {FactoryUpgradeGate} from "../src/FactoryUpgradeGate.sol"; import {DropMetadataRenderer} from "../src/metadata/DropMetadataRenderer.sol"; import {EditionMetadataRenderer} from "../src/metadata/EditionMetadataRenderer.sol"; @@ -57,7 +55,6 @@ contract UpgradeERC721DropFactory is ZoraDropsDeployBase { ERC721Drop dropImplementation = new ERC721Drop({ _zoraERC721TransferHelper: chainConfig.zoraERC721TransferHelper, _factoryUpgradeGate: IFactoryUpgradeGate(deployment.factoryUpgradeGate), - _marketFilterDAOAddress: chainConfig.subscriptionMarketFilterAddress, _mintFeeAmount: chainConfig.mintFeeAmount, _mintFeeRecipient: payable(chainConfig.mintFeeRecipient), _protocolRewards: chainConfig.protocolRewards diff --git a/src/DeploymentConfig.sol b/src/DeploymentConfig.sol index 47246eb..cbf9a83 100644 --- a/src/DeploymentConfig.sol +++ b/src/DeploymentConfig.sol @@ -16,10 +16,6 @@ struct ChainConfig { uint256 mintFeeAmount; /// @notice Mint fee recipient user address mintFeeRecipient; - /// @notice Subscription address for operator-filterer-registry (opensea / cori) - address subscriptionMarketFilterAddress; - /// @notice Owner for subscription of operator-filterer-registry (opensea / cori) - address subscriptionMarketFilterOwner; /// @notice Auto-approved hyperstructure on mainnet for enabling ZORA v3 with less gas. Deprecated – safe to set to address(0x) address zoraERC721TransferHelper; /// @notice The Protocol Rewards contract @@ -65,8 +61,6 @@ abstract contract DeploymentConfig is StdChains, StdCheatsSafe, StdUtils, Script string constant FACTORY_UPGRADE_GATE_OWNER = "FACTORY_OWNER"; string constant MINT_FEE_AMOUNT = "MINT_FEE_AMOUNT"; string constant MINT_FEE_RECIPIENT = "MINT_FEE_RECIPIENT"; - string constant SUBSCRIPTION_MARKET_FILTER_ADDRESS = "SUBSCRIPTION_MARKET_FILTER_ADDRESS"; - string constant SUBSCRIPTION_MARKET_FILTER_OWNER = "SUBSCRIPTION_MARKET_FILTER_OWNER"; string constant ZORA_ERC721_TRANSFER_HELPER = "ZORA_ERC721_TRANSFER_HELPER"; string constant PROTOCOL_REWARDS = "PROTOCOL_REWARDS"; @@ -93,7 +87,6 @@ abstract contract DeploymentConfig is StdChains, StdCheatsSafe, StdUtils, Script chainConfig.factoryUpgradeGateOwner = json.readAddress(getKeyPrefix(FACTORY_UPGRADE_GATE_OWNER)); chainConfig.mintFeeAmount = json.readUint(getKeyPrefix(MINT_FEE_AMOUNT)); chainConfig.mintFeeRecipient = json.readAddress(getKeyPrefix(MINT_FEE_RECIPIENT)); - chainConfig.subscriptionMarketFilterAddress = json.readAddress(getKeyPrefix(SUBSCRIPTION_MARKET_FILTER_ADDRESS)); chainConfig.zoraERC721TransferHelper = json.readAddress(getKeyPrefix(ZORA_ERC721_TRANSFER_HELPER)); chainConfig.protocolRewards = json.readAddress(getKeyPrefix(PROTOCOL_REWARDS)); } diff --git a/src/ERC721Drop.sol b/src/ERC721Drop.sol index 5ab6d04..826fa2e 100644 --- a/src/ERC721Drop.sol +++ b/src/ERC721Drop.sol @@ -29,7 +29,6 @@ import {ERC721Rewards} from "@zoralabs/protocol-rewards/src/abstract/ERC721/ERC7 import {ERC721RewardsStorageV1} from "@zoralabs/protocol-rewards/src/abstract/ERC721/ERC721RewardsStorageV1.sol"; import {IMetadataRenderer} from "./interfaces/IMetadataRenderer.sol"; -import {IOperatorFilterRegistry} from "./interfaces/IOperatorFilterRegistry.sol"; import {IERC721Drop} from "./interfaces/IERC721Drop.sol"; import {IOwnable} from "./interfaces/IOwnable.sol"; import {IERC4906} from "./interfaces/IERC4906.sol"; @@ -97,12 +96,6 @@ contract ERC721Drop is // /// @notice Empty string for blank comments // string constant EMPTY_STRING = ""; - /// @notice Market filter DAO address for opensea filter registry - address public immutable marketFilterDAOAddress; - - IOperatorFilterRegistry immutable operatorFilterRegistry = - IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E); - /// @notice Only allow for users with admin access modifier onlyAdmin() { if (!hasRole(DEFAULT_ADMIN_ROLE, _msgSender())) { @@ -178,20 +171,17 @@ contract ERC721Drop is /// @dev Marked as an initializer to prevent storage being used of base implementation. Can only be init'd by a proxy. /// @param _zoraERC721TransferHelper Transfer helper /// @param _factoryUpgradeGate Factory upgrade gate address - /// @param _marketFilterDAOAddress Market filter DAO address /// @param _mintFeeAmount Mint fee amount in wei /// @param _mintFeeRecipient Mint fee recipient address constructor( address _zoraERC721TransferHelper, IFactoryUpgradeGate _factoryUpgradeGate, - address _marketFilterDAOAddress, uint256 _mintFeeAmount, address payable _mintFeeRecipient, address _protocolRewards ) initializer ERC721Rewards(_protocolRewards, _mintFeeRecipient) { zoraERC721TransferHelper = _zoraERC721TransferHelper; factoryUpgradeGate = _factoryUpgradeGate; - marketFilterDAOAddress = _marketFilterDAOAddress; ZORA_MINT_FEE = _mintFeeAmount; ZORA_MINT_FEE_RECIPIENT = _mintFeeRecipient; } @@ -759,75 +749,6 @@ contract ERC721Drop is return firstMintedTokenId; } - /** - *** ---------------------------------- *** - *** *** - *** ADMIN OPERATOR FILTERING *** - *** *** - *** ---------------------------------- *** - ***/ - - /// @notice Proxy to update market filter settings in the main registry contracts - /// @notice Requires admin permissions - /// @param args Calldata args to pass to the registry - function updateMarketFilterSettings(bytes calldata args) - external - onlyAdmin - returns (bytes memory) - { - (bool success, bytes memory ret) = address(operatorFilterRegistry).call( - args - ); - if (!success) { - revert RemoteOperatorFilterRegistryCallFailed(); - } - return ret; - } - - /// @notice Manage subscription to the DAO for marketplace filtering based off royalty payouts. - /// @param enable Enable filtering to non-royalty payout marketplaces - function manageMarketFilterDAOSubscription(bool enable) external onlyAdmin { - address self = address(this); - if (marketFilterDAOAddress == address(0x0)) { - revert MarketFilterDAOAddressNotSupportedForChain(); - } - if (!operatorFilterRegistry.isRegistered(self) && enable) { - operatorFilterRegistry.registerAndSubscribe( - self, - marketFilterDAOAddress - ); - } else if (enable) { - operatorFilterRegistry.subscribe(self, marketFilterDAOAddress); - } else { - operatorFilterRegistry.unsubscribe(self, false); - operatorFilterRegistry.unregister(self); - } - } - - /// @notice Hook to filter operators (no-op if no filters are registered) - /// @dev Part of ERC721A token hooks - /// @param from Transfer from user - function _beforeTokenTransfers( - address from, - address, - uint256, - uint256 - ) internal virtual override { - if ( - from != address(0) && // skip on mints - from != msg.sender // skip on transfers from sender - ) { - if ( - !operatorFilterRegistry.isOperatorAllowed( - address(this), - msg.sender - ) - ) { - revert OperatorNotAllowed(msg.sender); - } - } - } - /** *** ---------------------------------- *** *** *** diff --git a/src/filter/OwnedSubscriptionManager.sol b/src/filter/OwnedSubscriptionManager.sol deleted file mode 100644 index c69943c..0000000 --- a/src/filter/OwnedSubscriptionManager.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import {IOperatorFilterRegistry} from "../../src/interfaces/IOperatorFilterRegistry.sol"; -import {OwnableWithConfirmation} from "../../src/utils/OwnableWithConfirmation.sol"; - -contract OwnedSubscriptionManager is OwnableWithConfirmation { - IOperatorFilterRegistry immutable registry = - IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E); - - constructor(address _initialOwner) OwnableWithConfirmation(_initialOwner) { - registry.register(address(this)); - } -} diff --git a/src/interfaces/IOperatorFilterRegistry.sol b/src/interfaces/IOperatorFilterRegistry.sol deleted file mode 100644 index ff7b9b9..0000000 --- a/src/interfaces/IOperatorFilterRegistry.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -interface IOperatorFilterRegistry { - function isOperatorAllowed(address registrant, address operator) external view returns (bool); - function register(address registrant) external; - function registerAndSubscribe(address registrant, address subscription) external; - function registerAndCopyEntries(address registrant, address registrantToCopy) external; - function updateOperator(address registrant, address operator, bool filtered) external; - function updateOperators(address registrant, address[] calldata operators, bool filtered) external; - function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external; - function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external; - function subscribe(address registrant, address registrantToSubscribe) external; - function unsubscribe(address registrant, bool copyExistingEntries) external; - function subscriptionOf(address addr) external returns (address registrant); - function subscribers(address registrant) external returns (address[] memory); - function subscriberAt(address registrant, uint256 index) external returns (address); - function copyEntriesOf(address registrant, address registrantToCopy) external; - function isOperatorFiltered(address registrant, address operator) external returns (bool); - function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool); - function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool); - function filteredOperators(address addr) external returns (address[] memory); - function filteredCodeHashes(address addr) external returns (bytes32[] memory); - function filteredOperatorAt(address registrant, uint256 index) external returns (address); - function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32); - function isRegistered(address addr) external returns (bool); - function codeHashOf(address addr) external returns (bytes32); - - function unregister(address registrant) external; -} \ No newline at end of file diff --git a/test/ERC721Drop.t.sol b/test/ERC721Drop.t.sol index 62817ae..d57fd9b 100644 --- a/test/ERC721Drop.t.sol +++ b/test/ERC721Drop.t.sol @@ -10,14 +10,10 @@ import {RewardsSettings} from "@zoralabs/protocol-rewards/src/abstract/RewardSpl import {ERC721Drop} from "../src/ERC721Drop.sol"; import {DummyMetadataRenderer} from "./utils/DummyMetadataRenderer.sol"; import {MockUser} from "./utils/MockUser.sol"; -import {IOperatorFilterRegistry} from "../src/interfaces/IOperatorFilterRegistry.sol"; import {IMetadataRenderer} from "../src/interfaces/IMetadataRenderer.sol"; import {IERC721Drop} from "../src/interfaces/IERC721Drop.sol"; import {FactoryUpgradeGate} from "../src/FactoryUpgradeGate.sol"; import {ERC721DropProxy} from "../src/ERC721DropProxy.sol"; -import {OperatorFilterRegistry} from "./filter/OperatorFilterRegistry.sol"; -import {OperatorFilterRegistryErrorsAndEvents} from "./filter/OperatorFilterRegistryErrorsAndEvents.sol"; -import {OwnedSubscriptionManager} from "../src/filter/OwnedSubscriptionManager.sol"; contract ERC721DropTest is Test { /// @notice Event emitted when the funds are withdrawn from the minting contract @@ -26,21 +22,11 @@ contract ERC721DropTest is Test { /// @param amount amount that was withdrawn /// @param feeRecipient user getting withdraw fee (if any) /// @param feeAmount amount of the fee getting sent (if any) - event FundsWithdrawn( - address indexed withdrawnBy, - address indexed withdrawnTo, - uint256 amount, - address feeRecipient, - uint256 feeAmount - ); - - event Sale( - address indexed to, uint256 indexed purchaseQuantity, uint256 indexed pricePerToken, uint256 firstPurchasedTokenId - ); - - event MintComment( - address indexed sender, address indexed tokenContract, uint256 indexed tokenId, uint256 purchaseQuantity, string comment - ); + event FundsWithdrawn(address indexed withdrawnBy, address indexed withdrawnTo, uint256 amount, address feeRecipient, uint256 feeAmount); + + event Sale(address indexed to, uint256 indexed purchaseQuantity, uint256 indexed pricePerToken, uint256 firstPurchasedTokenId); + + event MintComment(address indexed sender, address indexed tokenContract, uint256 indexed tokenId, uint256 purchaseQuantity, string comment); address internal creator; address internal collector; @@ -59,7 +45,6 @@ contract ERC721DropTest is Test { address public constant UPGRADE_GATE_ADMIN_ADDRESS = address(0x942924224); address public constant mediaContract = address(0x123456); address public impl; - address public ownedSubscriptionManager; address payable public constant mintFeeRecipient = payable(address(0x11)); uint256 public constant mintFee = 777000000000000; // 0.000777 ETH uint256 public constant TOTAL_REWARD_PER_MINT = 0.000999 ether; @@ -119,35 +104,31 @@ contract ERC721DropTest is Test { vm.prank(DEFAULT_ZORA_DAO_ADDRESS); factoryUpgradeGate = new FactoryUpgradeGate(UPGRADE_GATE_ADMIN_ADDRESS); - vm.etch(address(0x000000000000AAeB6D7670E522A718067333cd4E), address(new OperatorFilterRegistry()).code); - ownedSubscriptionManager = address(new OwnedSubscriptionManager(address(0x123456))); vm.prank(DEFAULT_ZORA_DAO_ADDRESS); impl = address( - new ERC721Drop( - address(0x1234), - factoryUpgradeGate, - address(0x0), - mintFee, - mintFeeRecipient, - address(protocolRewards) - ) + new ERC721Drop({ + _zoraERC721TransferHelper: address(0x1234), + _factoryUpgradeGate: factoryUpgradeGate, + _mintFeeAmount: mintFee, + _mintFeeRecipient: mintFeeRecipient, + _protocolRewards: address(protocolRewards) + }) ); address payable newDrop = payable(address(new ERC721DropProxy(impl, ""))); zoraNFTBase = ERC721Drop(newDrop); } - modifier factoryWithSubscriptionAddress(address subscriptionAddress) { + modifier withFactory() { vm.prank(DEFAULT_ZORA_DAO_ADDRESS); impl = address( - new ERC721Drop( - address(0x1234), - factoryUpgradeGate, - address(subscriptionAddress), - mintFee, - mintFeeRecipient, - address(protocolRewards) - ) + new ERC721Drop({ + _zoraERC721TransferHelper: address(0x1234), + _factoryUpgradeGate: factoryUpgradeGate, + _mintFeeAmount: mintFee, + _mintFeeRecipient: mintFeeRecipient, + _protocolRewards: address(protocolRewards) + }) ); address payable newDrop = payable(address(new ERC721DropProxy(impl, ""))); zoraNFTBase = ERC721Drop(newDrop); @@ -158,8 +139,7 @@ contract ERC721DropTest is Test { function test_Init() public setupZoraNFTBase(10) { require(zoraNFTBase.owner() == DEFAULT_OWNER_ADDRESS, "Default owner set wrong"); - (IMetadataRenderer renderer, uint64 editionSize, uint16 royaltyBPS, address payable fundsRecipient) = - zoraNFTBase.config(); + (IMetadataRenderer renderer, uint64 editionSize, uint16 royaltyBPS, address payable fundsRecipient) = zoraNFTBase.config(); require(address(renderer) == address(dummyRenderer)); require(editionSize == 10, "EditionSize is wrong"); @@ -212,69 +192,9 @@ contract ERC721DropTest is Test { assertTrue(!zoraNFTBase.isAdmin(address(0))); } - function test_SubscriptionEnabled() - public - factoryWithSubscriptionAddress(ownedSubscriptionManager) - setupZoraNFTBase(10) - { - IOperatorFilterRegistry operatorFilterRegistry = - IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E); - vm.startPrank(address(0x123456)); - operatorFilterRegistry.updateOperator(ownedSubscriptionManager, address(0xcafeea3), true); - vm.stopPrank(); - vm.startPrank(DEFAULT_OWNER_ADDRESS); - zoraNFTBase.manageMarketFilterDAOSubscription(true); - zoraNFTBase.adminMint(DEFAULT_OWNER_ADDRESS, 10); - zoraNFTBase.setApprovalForAll(address(0xcafeea3), true); - vm.stopPrank(); - vm.prank(address(0xcafeea3)); - vm.expectRevert( - abi.encodeWithSelector(OperatorFilterRegistryErrorsAndEvents.AddressFiltered.selector, address(0xcafeea3)) - ); - zoraNFTBase.transferFrom(DEFAULT_OWNER_ADDRESS, address(0x123456), 1); - vm.prank(DEFAULT_OWNER_ADDRESS); - zoraNFTBase.manageMarketFilterDAOSubscription(false); - vm.prank(address(0xcafeea3)); - zoraNFTBase.transferFrom(DEFAULT_OWNER_ADDRESS, address(0x123456), 1); - } - - function test_OnlyAdminEnableSubscription() - public - factoryWithSubscriptionAddress(ownedSubscriptionManager) - setupZoraNFTBase(10) - { - vm.startPrank(address(0xcafecafe)); - vm.expectRevert(IERC721Drop.Access_OnlyAdmin.selector); - zoraNFTBase.manageMarketFilterDAOSubscription(true); - vm.stopPrank(); - } - - function test_ProxySubscriptionAccessOnlyAdmin() - public - factoryWithSubscriptionAddress(ownedSubscriptionManager) - setupZoraNFTBase(10) - { - bytes memory baseCall = abi.encodeWithSelector(IOperatorFilterRegistry.register.selector, address(zoraNFTBase)); - vm.startPrank(address(0xcafecafe)); - vm.expectRevert(IERC721Drop.Access_OnlyAdmin.selector); - zoraNFTBase.updateMarketFilterSettings(baseCall); - vm.stopPrank(); - } - - function test_ProxySubscriptionAccess() - public - factoryWithSubscriptionAddress(ownedSubscriptionManager) - setupZoraNFTBase(10) - { - vm.startPrank(address(DEFAULT_OWNER_ADDRESS)); - bytes memory baseCall = abi.encodeWithSelector(IOperatorFilterRegistry.register.selector, address(zoraNFTBase)); - zoraNFTBase.updateMarketFilterSettings(baseCall); - vm.stopPrank(); - } - function test_RoyaltyInfo() public setupZoraNFTBase(10) { // assert 800 royaltyAmount or 8% - ( , uint256 royaltyAmount) = zoraNFTBase.royaltyInfo(10, 1 ether); + (, uint256 royaltyAmount) = zoraNFTBase.royaltyInfo(10, 1 ether); assertEq(royaltyAmount, 0.08 ether); } @@ -282,7 +202,7 @@ contract ERC721DropTest is Test { vm.prank(DEFAULT_OWNER_ADDRESS); zoraNFTBase.setFundsRecipient(payable(address(0))); // assert 800 royaltyAmount or 8% - ( , uint256 royaltyAmount) = zoraNFTBase.royaltyInfo(10, 1 ether); + (, uint256 royaltyAmount) = zoraNFTBase.royaltyInfo(10, 1 ether); assertEq(royaltyAmount, 0 ether); } @@ -314,10 +234,7 @@ contract ERC721DropTest is Test { assertEq(mintFeeRecipient.balance, zoraFee); } - function test_PurchaseWithComment(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function test_PurchaseWithComment(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); vm.prank(DEFAULT_OWNER_ADDRESS); zoraNFTBase.setSaleConfiguration({ @@ -339,10 +256,7 @@ contract ERC721DropTest is Test { zoraNFTBase.purchaseWithComment{value: paymentAmount}(purchaseQuantity, "test comment"); } - function test_PurchaseWithRecipient(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function test_PurchaseWithRecipient(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); vm.prank(DEFAULT_OWNER_ADDRESS); zoraNFTBase.setSaleConfiguration({ @@ -365,15 +279,12 @@ contract ERC721DropTest is Test { vm.prank(minter); zoraNFTBase.purchaseWithRecipient{value: paymentAmount}(recipient, purchaseQuantity, ""); - for (uint256 i; i < purchaseQuantity;) { + for (uint256 i; i < purchaseQuantity; ) { assertEq(zoraNFTBase.ownerOf(++i), recipient); } } - function test_PurchaseWithRecipientAndComment(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function test_PurchaseWithRecipientAndComment(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); vm.prank(DEFAULT_OWNER_ADDRESS); zoraNFTBase.setSaleConfiguration({ @@ -400,10 +311,7 @@ contract ERC721DropTest is Test { zoraNFTBase.purchaseWithRecipient{value: paymentAmount}(recipient, purchaseQuantity, "test comment"); } - function testRevert_PurchaseWithInvalidRecipient(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function testRevert_PurchaseWithInvalidRecipient(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); vm.prank(DEFAULT_OWNER_ADDRESS); zoraNFTBase.setSaleConfiguration({ @@ -482,10 +390,7 @@ contract ERC721DropTest is Test { assertEq(protocolRewards.balanceOf(mintReferral), settings.mintReferralReward); } - function test_FreeMintRewardsWithCreateReferral(uint32 purchaseQuantity) - public - setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) - { + function test_FreeMintRewardsWithCreateReferral(uint32 purchaseQuantity) public setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) { vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); vm.prank(DEFAULT_OWNER_ADDRESS); @@ -512,10 +417,9 @@ contract ERC721DropTest is Test { assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); } - function test_FreeMintRewardsWithMintAndCreateReferrals(uint32 purchaseQuantity) - public - setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) - { + function test_FreeMintRewardsWithMintAndCreateReferrals( + uint32 purchaseQuantity + ) public setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) { vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); vm.prank(DEFAULT_OWNER_ADDRESS); @@ -543,10 +447,7 @@ contract ERC721DropTest is Test { assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); } - function testRevert_FreeMintRewardsInsufficientEth(uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function testRevert_FreeMintRewardsInsufficientEth(uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); vm.prank(DEFAULT_OWNER_ADDRESS); @@ -564,10 +465,7 @@ contract ERC721DropTest is Test { zoraNFTBase.mintWithRewards(collector, purchaseQuantity, "test comment", address(0)); } - function test_PaidMintRewards(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function test_PaidMintRewards(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(salePrice > 0); vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); @@ -597,10 +495,7 @@ contract ERC721DropTest is Test { assertEq(protocolRewards.balanceOf(mintFeeRecipient), settings.zoraReward + settings.mintReferralReward + settings.createReferralReward); } - function test_PaidMintRewardsWithMintReferral(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function test_PaidMintRewardsWithMintReferral(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(salePrice > 0); vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); @@ -630,10 +525,10 @@ contract ERC721DropTest is Test { assertEq(protocolRewards.balanceOf(mintReferral), settings.mintReferralReward); } - function test_PaidMintRewardsWithCreateReferral(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) - { + function test_PaidMintRewardsWithCreateReferral( + uint64 salePrice, + uint32 purchaseQuantity + ) public setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) { vm.assume(salePrice > 0); vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); @@ -664,10 +559,10 @@ contract ERC721DropTest is Test { assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); } - function test_PaidMintRewardsWithMintAndCreateReferrals(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) - { + function test_PaidMintRewardsWithMintAndCreateReferrals( + uint64 salePrice, + uint32 purchaseQuantity + ) public setupZoraNFTBaseWithCreateReferral(purchaseQuantity, createReferral) { vm.assume(salePrice > 0); vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); @@ -699,10 +594,7 @@ contract ERC721DropTest is Test { assertEq(protocolRewards.balanceOf(createReferral), settings.createReferralReward); } - function testRevert_PaidMintRewardsInsufficientEth(uint64 salePrice, uint32 purchaseQuantity) - public - setupZoraNFTBase(purchaseQuantity) - { + function testRevert_PaidMintRewardsInsufficientEth(uint64 salePrice, uint32 purchaseQuantity) public setupZoraNFTBase(purchaseQuantity) { vm.assume(salePrice > 0); vm.assume(purchaseQuantity < 100 && purchaseQuantity > 0); @@ -723,14 +615,13 @@ contract ERC721DropTest is Test { function test_UpgradeApproved() public setupZoraNFTBase(10) { address newImpl = address( - new ERC721Drop( - address(0x3333), - factoryUpgradeGate, - address(0x0), - mintFee, - mintFeeRecipient, - address(protocolRewards) - ) + new ERC721Drop({ + _zoraERC721TransferHelper: address(0x3333), + _factoryUpgradeGate: factoryUpgradeGate, + _mintFeeAmount: mintFee, + _mintFeeRecipient: mintFeeRecipient, + _protocolRewards: address(protocolRewards) + }) ); address[] memory lastImpls = new address[](1); @@ -742,16 +633,7 @@ contract ERC721DropTest is Test { } function test_UpgradeFailsNotApproved() public setupZoraNFTBase(10) { - address newImpl = address( - new ERC721Drop( - address(0x3333), - factoryUpgradeGate, - address(0x0), - mintFee, - mintFeeRecipient, - address(protocolRewards) - ) - ); + address newImpl = address(new ERC721Drop(address(0x3333), factoryUpgradeGate, mintFee, mintFeeRecipient, address(protocolRewards))); vm.prank(DEFAULT_OWNER_ADDRESS); vm.expectRevert(abi.encodeWithSelector(IERC721Drop.Admin_InvalidUpgradeAddress.selector, newImpl)); @@ -831,10 +713,7 @@ contract ERC721DropTest is Test { calls[1] = abi.encodeWithSelector(IERC721Drop.adminMint.selector, address(0x123), 3); vm.expectRevert( - abi.encodeWithSelector( - IERC721Drop.Access_MissingRoleOrAdmin.selector, - bytes32(0xf0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc9) - ) + abi.encodeWithSelector(IERC721Drop.Access_MissingRoleOrAdmin.selector, bytes32(0xf0887ba65ee2024ea881d91b74c2450ef19e1557f03bed3ea9f16b037cbe2dc9)) ); zoraNFTBase.multicall(calls); @@ -855,8 +734,9 @@ contract ERC721DropTest is Test { calls[2] = abi.encodeWithSelector(IERC721Drop.saleDetails.selector); bytes[] memory results = zoraNFTBase.multicall(calls); - (bool saleActive, bool presaleActive, uint256 publicSalePrice,,,,,,,,) = abi.decode( - results[2], (bool, bool, uint256, uint64, uint64, uint64, uint64, bytes32, uint256, uint256, uint256) + (bool saleActive, bool presaleActive, uint256 publicSalePrice, , , , , , , , ) = abi.decode( + results[2], + (bool, bool, uint256, uint64, uint64, uint64, uint64, bytes32, uint256, uint256, uint256) ); assertTrue(!saleActive); assertTrue(!presaleActive); @@ -870,9 +750,7 @@ contract ERC721DropTest is Test { function test_UpdatePriceMulticall() public setupZoraNFTBase(10) { vm.startPrank(DEFAULT_OWNER_ADDRESS); bytes[] memory calls = new bytes[](3); - calls[0] = abi.encodeWithSelector( - IERC721Drop.setSaleConfiguration.selector, 0.1 ether, 2, 0, type(uint64).max, 0, 0, bytes32(0) - ); + calls[0] = abi.encodeWithSelector(IERC721Drop.setSaleConfiguration.selector, 0.1 ether, 2, 0, type(uint64).max, 0, 0, bytes32(0)); calls[1] = abi.encodeWithSelector(IERC721Drop.adminMint.selector, address(0x123), 3); calls[2] = abi.encodeWithSelector(IERC721Drop.adminMint.selector, address(0x123), 3); bytes[] memory results = zoraNFTBase.multicall(calls); @@ -922,9 +800,7 @@ contract ERC721DropTest is Test { vm.prank(DEFAULT_OWNER_ADDRESS); vm.expectEmit(true, true, true, true); - emit FundsWithdrawn( - DEFAULT_OWNER_ADDRESS, DEFAULT_FUNDS_RECIPIENT_ADDRESS, leftoverFunds, payable(address(0)), 0 - ); + emit FundsWithdrawn(DEFAULT_OWNER_ADDRESS, DEFAULT_FUNDS_RECIPIENT_ADDRESS, leftoverFunds, payable(address(0)), 0); zoraNFTBase.withdraw(); assertEq(DEFAULT_FUNDS_RECIPIENT_ADDRESS.balance, amount); @@ -971,9 +847,7 @@ contract ERC721DropTest is Test { vm.deal(address(444), 1_000_000 ether); vm.prank(address(444)); vm.expectRevert(IERC721Drop.Purchase_TooManyForAddress.selector); - zoraNFTBase.purchase{value: (0.1 ether * (uint256(limit) + 1)) + (fee * (uint256(limit) + 1))}( - uint256(limit) + 1 - ); + zoraNFTBase.purchase{value: (0.1 ether * (uint256(limit) + 1)) + (fee * (uint256(limit) + 1))}(uint256(limit) + 1); assertEq(zoraNFTBase.saleDetails().totalMinted, limit); } @@ -990,7 +864,7 @@ contract ERC721DropTest is Test { presaleMerkleRoot: bytes32(0) }); - (,,,,, uint64 presaleEndLookup,) = zoraNFTBase.salesConfig(); + (, , , , , uint64 presaleEndLookup, ) = zoraNFTBase.salesConfig(); assertEq(presaleEndLookup, 100); address SALES_MANAGER_ADDR = address(0x11002); @@ -1008,7 +882,7 @@ contract ERC721DropTest is Test { presaleMerkleRoot: bytes32(0) }); - (,,,, uint64 presaleStartLookup2, uint64 presaleEndLookup2,) = zoraNFTBase.salesConfig(); + (, , , , uint64 presaleStartLookup2, uint64 presaleEndLookup2, ) = zoraNFTBase.salesConfig(); assertEq(presaleEndLookup2, 0); assertEq(presaleStartLookup2, 100); } @@ -1186,17 +1060,14 @@ contract ERC721DropTest is Test { function test_AdminMetadataRendererUpdateCall() public setupZoraNFTBase(10) { vm.startPrank(DEFAULT_OWNER_ADDRESS); assertEq(dummyRenderer.someState(), ""); - zoraNFTBase.callMetadataRenderer( - abi.encodeWithSelector(DummyMetadataRenderer.updateSomeState.selector, "new state", address(zoraNFTBase)) - ); + zoraNFTBase.callMetadataRenderer(abi.encodeWithSelector(DummyMetadataRenderer.updateSomeState.selector, "new state", address(zoraNFTBase))); assertEq(dummyRenderer.someState(), "new state"); } function test_NonAdminMetadataRendererUpdateCall() public setupZoraNFTBase(10) { vm.startPrank(address(0x99493)); assertEq(dummyRenderer.someState(), ""); - bytes memory targetCall = - abi.encodeWithSelector(DummyMetadataRenderer.updateSomeState.selector, "new state", address(zoraNFTBase)); + bytes memory targetCall = abi.encodeWithSelector(DummyMetadataRenderer.updateSomeState.selector, "new state", address(zoraNFTBase)); vm.expectRevert(IERC721Drop.Access_OnlyAdmin.selector); zoraNFTBase.callMetadataRenderer(targetCall); assertEq(dummyRenderer.someState(), ""); @@ -1208,14 +1079,8 @@ contract ERC721DropTest is Test { zoraNFTBase.updateRoyaltyMintSchedule(1); } - function test_SupplyRoyaltyPurchase(uint32 royaltyMintSchedule, uint32 editionSize, uint256 mintQuantity) - public - setupZoraNFTBase(editionSize) - { - vm.assume( - royaltyMintSchedule > 1 && royaltyMintSchedule <= editionSize && editionSize <= 100000 && mintQuantity > 0 - && mintQuantity <= editionSize - ); + function test_SupplyRoyaltyPurchase(uint32 royaltyMintSchedule, uint32 editionSize, uint256 mintQuantity) public setupZoraNFTBase(editionSize) { + vm.assume(royaltyMintSchedule > 1 && royaltyMintSchedule <= editionSize && editionSize <= 100000 && mintQuantity > 0 && mintQuantity <= editionSize); uint256 totalRoyaltyMintsForSale = editionSize / royaltyMintSchedule; vm.assume(mintQuantity <= editionSize - totalRoyaltyMintsForSale); diff --git a/test/ZoraNFTCreatorV1.t.sol b/test/ZoraNFTCreatorV1.t.sol index 281be1d..93afc25 100644 --- a/test/ZoraNFTCreatorV1.t.sol +++ b/test/ZoraNFTCreatorV1.t.sol @@ -36,7 +36,6 @@ contract ZoraNFTCreatorV1Test is Test { dropImpl = new ERC721Drop( address(1234), FactoryUpgradeGate(address(0)), - address(0), mintFee, mintFeeRecipient, address(protocolRewards) diff --git a/test/filter/OperatorFilterRegistry.sol b/test/filter/OperatorFilterRegistry.sol deleted file mode 100644 index 0693511..0000000 --- a/test/filter/OperatorFilterRegistry.sol +++ /dev/null @@ -1,530 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -import {IOperatorFilterRegistry} from "../../src/interfaces/IOperatorFilterRegistry.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {OperatorFilterRegistryErrorsAndEvents} from "./OperatorFilterRegistryErrorsAndEvents.sol"; - -/** - * @title OperatorFilterRegistry - * @notice Borrows heavily from the QQL BlacklistOperatorFilter contract: - * https://github.com/qql-art/contracts/blob/main/contracts/BlacklistOperatorFilter.sol - * @notice This contracts allows tokens or token owners to register specific addresses or codeHashes that may be - * * restricted according to the isOperatorAllowed function. - */ -contract OperatorFilterRegistry is IOperatorFilterRegistry, OperatorFilterRegistryErrorsAndEvents { - using EnumerableSet for EnumerableSet.AddressSet; - using EnumerableSet for EnumerableSet.Bytes32Set; - - /// @dev initialized accounts have a nonzero codehash (see https://eips.ethereum.org/EIPS/eip-1052) - /// Note that this will also be a smart contract's codehash when making calls from its constructor. - bytes32 constant EOA_CODEHASH = keccak256(""); - - mapping(address => EnumerableSet.AddressSet) private _filteredOperators; - mapping(address => EnumerableSet.Bytes32Set) private _filteredCodeHashes; - mapping(address => address) private _registrations; - mapping(address => EnumerableSet.AddressSet) private _subscribers; - - /** - * @notice restricts method caller to the address or EIP-173 "owner()" - */ - modifier onlyAddressOrOwner(address addr) { - if (msg.sender != addr) { - try Ownable(addr).owner() returns (address owner) { - if (msg.sender != owner) { - revert OnlyAddressOrOwner(); - } - } catch (bytes memory reason) { - if (reason.length == 0) { - revert NotOwnable(); - } else { - /// @solidity memory-safe-assembly - assembly { - revert(add(32, reason), mload(reason)) - } - } - } - } - _; - } - - /** - * @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns - * true if supplied registrant address is not registered. - */ - function isOperatorAllowed(address registrant, address operator) external view returns (bool) { - address registration = _registrations[registrant]; - if (registration != address(0)) { - EnumerableSet.AddressSet storage filteredOperatorsRef; - EnumerableSet.Bytes32Set storage filteredCodeHashesRef; - - filteredOperatorsRef = _filteredOperators[registration]; - filteredCodeHashesRef = _filteredCodeHashes[registration]; - - if (filteredOperatorsRef.contains(operator)) { - revert AddressFiltered(operator); - } - if (operator.code.length > 0) { - bytes32 codeHash = operator.codehash; - if (filteredCodeHashesRef.contains(codeHash)) { - revert CodeHashFiltered(operator, codeHash); - } - } - } - return true; - } - - ////////////////// - // AUTH METHODS // - ////////////////// - - /** - * @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner. - */ - function register(address registrant) external onlyAddressOrOwner(registrant) { - if (_registrations[registrant] != address(0)) { - revert AlreadyRegistered(); - } - _registrations[registrant] = registrant; - emit RegistrationUpdated(registrant, true); - } - - /** - * @notice Unregisters an address with the registry and removes its subscription. May be called by address itself or by EIP-173 owner. - * Note that this does not remove any filtered addresses or codeHashes. - * Also note that any subscriptions to this registrant will still be active and follow the existing filtered addresses and codehashes. - */ - function unregister(address registrant) external onlyAddressOrOwner(registrant) { - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration != registrant) { - _subscribers[registration].remove(registrant); - emit SubscriptionUpdated(registrant, registration, false); - } - _registrations[registrant] = address(0); - emit RegistrationUpdated(registrant, false); - } - - /** - * @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes. - */ - function registerAndSubscribe(address registrant, address subscription) external onlyAddressOrOwner(registrant) { - address registration = _registrations[registrant]; - if (registration != address(0)) { - revert AlreadyRegistered(); - } - if (registrant == subscription) { - revert CannotSubscribeToSelf(); - } - address subscriptionRegistration = _registrations[subscription]; - if (subscriptionRegistration == address(0)) { - revert NotRegistered(subscription); - } - if (subscriptionRegistration != subscription) { - revert CannotSubscribeToRegistrantWithSubscription(subscription); - } - - _registrations[registrant] = subscription; - _subscribers[subscription].add(registrant); - emit RegistrationUpdated(registrant, true); - emit SubscriptionUpdated(registrant, subscription, true); - } - - /** - * @notice Registers an address with the registry and copies the filtered operators and codeHashes from another - * address without subscribing. - */ - function registerAndCopyEntries(address registrant, address registrantToCopy) - external - onlyAddressOrOwner(registrant) - { - if (registrantToCopy == registrant) { - revert CannotCopyFromSelf(); - } - address registration = _registrations[registrant]; - if (registration != address(0)) { - revert AlreadyRegistered(); - } - address registrantRegistration = _registrations[registrantToCopy]; - if (registrantRegistration == address(0)) { - revert NotRegistered(registrantToCopy); - } - _registrations[registrant] = registrant; - emit RegistrationUpdated(registrant, true); - _copyEntries(registrant, registrantToCopy); - } - - /** - * @notice Update an operator address for a registered address - when filtered is true, the operator is filtered. - */ - function updateOperator(address registrant, address operator, bool filtered) - external - onlyAddressOrOwner(registrant) - { - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration != registrant) { - revert CannotUpdateWhileSubscribed(registration); - } - EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrant]; - - if (!filtered) { - bool removed = filteredOperatorsRef.remove(operator); - if (!removed) { - revert AddressNotFiltered(operator); - } - } else { - bool added = filteredOperatorsRef.add(operator); - if (!added) { - revert AddressAlreadyFiltered(operator); - } - } - emit OperatorUpdated(registrant, operator, filtered); - } - - /** - * @notice Update a codeHash for a registered address - when filtered is true, the codeHash is filtered. - */ - function updateCodeHash(address registrant, bytes32 codeHash, bool filtered) - external - onlyAddressOrOwner(registrant) - { - if (codeHash == EOA_CODEHASH) { - revert CannotFilterEOAs(); - } - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration != registrant) { - revert CannotUpdateWhileSubscribed(registration); - } - EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrant]; - - if (!filtered) { - bool removed = filteredCodeHashesRef.remove(codeHash); - if (!removed) { - revert CodeHashNotFiltered(codeHash); - } - } else { - bool added = filteredCodeHashesRef.add(codeHash); - if (!added) { - revert CodeHashAlreadyFiltered(codeHash); - } - } - emit CodeHashUpdated(registrant, codeHash, filtered); - } - - /** - * @notice Update multiple operators for a registered address - when filtered is true, the operators will be filtered. Reverts on duplicates. - */ - function updateOperators(address registrant, address[] calldata operators, bool filtered) - external - onlyAddressOrOwner(registrant) - { - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration != registrant) { - revert CannotUpdateWhileSubscribed(registration); - } - EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrant]; - uint256 operatorsLength = operators.length; - unchecked { - if (!filtered) { - for (uint256 i = 0; i < operatorsLength; ++i) { - address operator = operators[i]; - bool removed = filteredOperatorsRef.remove(operator); - if (!removed) { - revert AddressNotFiltered(operator); - } - } - } else { - for (uint256 i = 0; i < operatorsLength; ++i) { - address operator = operators[i]; - bool added = filteredOperatorsRef.add(operator); - if (!added) { - revert AddressAlreadyFiltered(operator); - } - } - } - } - emit OperatorsUpdated(registrant, operators, filtered); - } - - /** - * @notice Update multiple codeHashes for a registered address - when filtered is true, the codeHashes will be filtered. Reverts on duplicates. - */ - function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) - external - onlyAddressOrOwner(registrant) - { - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration != registrant) { - revert CannotUpdateWhileSubscribed(registration); - } - EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrant]; - uint256 codeHashesLength = codeHashes.length; - unchecked { - if (!filtered) { - for (uint256 i = 0; i < codeHashesLength; ++i) { - bytes32 codeHash = codeHashes[i]; - bool removed = filteredCodeHashesRef.remove(codeHash); - if (!removed) { - revert CodeHashNotFiltered(codeHash); - } - } - } else { - for (uint256 i = 0; i < codeHashesLength; ++i) { - bytes32 codeHash = codeHashes[i]; - if (codeHash == EOA_CODEHASH) { - revert CannotFilterEOAs(); - } - bool added = filteredCodeHashesRef.add(codeHash); - if (!added) { - revert CodeHashAlreadyFiltered(codeHash); - } - } - } - } - emit CodeHashesUpdated(registrant, codeHashes, filtered); - } - - /** - * @notice Subscribe an address to another registrant's filtered operators and codeHashes. Will remove previous - * subscription if present. - * Note that accounts with subscriptions may go on to subscribe to other accounts - in this case, - * subscriptions will not be forwarded. Instead the former subscription's existing entries will still be - * used. - */ - function subscribe(address registrant, address newSubscription) external onlyAddressOrOwner(registrant) { - if (registrant == newSubscription) { - revert CannotSubscribeToSelf(); - } - if (newSubscription == address(0)) { - revert CannotSubscribeToZeroAddress(); - } - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration == newSubscription) { - revert AlreadySubscribed(newSubscription); - } - address newSubscriptionRegistration = _registrations[newSubscription]; - if (newSubscriptionRegistration == address(0)) { - revert NotRegistered(newSubscription); - } - if (newSubscriptionRegistration != newSubscription) { - revert CannotSubscribeToRegistrantWithSubscription(newSubscription); - } - - if (registration != registrant) { - _subscribers[registration].remove(registrant); - emit SubscriptionUpdated(registrant, registration, false); - } - _registrations[registrant] = newSubscription; - _subscribers[newSubscription].add(registrant); - emit SubscriptionUpdated(registrant, newSubscription, true); - } - - /** - * @notice Unsubscribe an address from its current subscribed registrant, and optionally copy its filtered operators and codeHashes. - */ - function unsubscribe(address registrant, bool copyExistingEntries) external onlyAddressOrOwner(registrant) { - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration == registrant) { - revert NotSubscribed(); - } - _subscribers[registration].remove(registrant); - _registrations[registrant] = registrant; - emit SubscriptionUpdated(registrant, registration, false); - if (copyExistingEntries) { - _copyEntries(registrant, registration); - } - } - - /** - * @notice Copy filtered operators and codeHashes from a different registrantToCopy to addr. - */ - function copyEntriesOf(address registrant, address registrantToCopy) external onlyAddressOrOwner(registrant) { - if (registrant == registrantToCopy) { - revert CannotCopyFromSelf(); - } - address registration = _registrations[registrant]; - if (registration == address(0)) { - revert NotRegistered(registrant); - } - if (registration != registrant) { - revert CannotUpdateWhileSubscribed(registration); - } - address registrantRegistration = _registrations[registrantToCopy]; - if (registrantRegistration == address(0)) { - revert NotRegistered(registrantToCopy); - } - _copyEntries(registrant, registrantToCopy); - } - - /// @dev helper to copy entries from registrantToCopy to registrant and emit events - function _copyEntries(address registrant, address registrantToCopy) private { - EnumerableSet.AddressSet storage filteredOperatorsRef = _filteredOperators[registrantToCopy]; - EnumerableSet.Bytes32Set storage filteredCodeHashesRef = _filteredCodeHashes[registrantToCopy]; - uint256 filteredOperatorsLength = filteredOperatorsRef.length(); - uint256 filteredCodeHashesLength = filteredCodeHashesRef.length(); - unchecked { - for (uint256 i = 0; i < filteredOperatorsLength; ++i) { - address operator = filteredOperatorsRef.at(i); - bool added = _filteredOperators[registrant].add(operator); - if (added) { - emit OperatorUpdated(registrant, operator, true); - } - } - for (uint256 i = 0; i < filteredCodeHashesLength; ++i) { - bytes32 codehash = filteredCodeHashesRef.at(i); - bool added = _filteredCodeHashes[registrant].add(codehash); - if (added) { - emit CodeHashUpdated(registrant, codehash, true); - } - } - } - } - - ////////////////// - // VIEW METHODS // - ////////////////// - - /** - * @notice Get the subscription address of a given registrant, if any. - */ - function subscriptionOf(address registrant) external view returns (address subscription) { - subscription = _registrations[registrant]; - if (subscription == address(0)) { - revert NotRegistered(registrant); - } else if (subscription == registrant) { - subscription = address(0); - } - } - - /** - * @notice Get the set of addresses subscribed to a given registrant. - * Note that order is not guaranteed as updates are made. - */ - function subscribers(address registrant) external view returns (address[] memory) { - return _subscribers[registrant].values(); - } - - /** - * @notice Get the subscriber at a given index in the set of addresses subscribed to a given registrant. - * Note that order is not guaranteed as updates are made. - */ - function subscriberAt(address registrant, uint256 index) external view returns (address) { - return _subscribers[registrant].at(index); - } - - /** - * @notice Returns true if operator is filtered by a given address or its subscription. - */ - function isOperatorFiltered(address registrant, address operator) external view returns (bool) { - address registration = _registrations[registrant]; - if (registration != registrant) { - return _filteredOperators[registration].contains(operator); - } - return _filteredOperators[registrant].contains(operator); - } - - /** - * @notice Returns true if a codeHash is filtered by a given address or its subscription. - */ - function isCodeHashFiltered(address registrant, bytes32 codeHash) external view returns (bool) { - address registration = _registrations[registrant]; - if (registration != registrant) { - return _filteredCodeHashes[registration].contains(codeHash); - } - return _filteredCodeHashes[registrant].contains(codeHash); - } - - /** - * @notice Returns true if the hash of an address's code is filtered by a given address or its subscription. - */ - function isCodeHashOfFiltered(address registrant, address operatorWithCode) external view returns (bool) { - bytes32 codeHash = operatorWithCode.codehash; - address registration = _registrations[registrant]; - if (registration != registrant) { - return _filteredCodeHashes[registration].contains(codeHash); - } - return _filteredCodeHashes[registrant].contains(codeHash); - } - - /** - * @notice Returns true if an address has registered - */ - function isRegistered(address registrant) external view returns (bool) { - return _registrations[registrant] != address(0); - } - - /** - * @notice Returns a list of filtered operators for a given address or its subscription. - */ - function filteredOperators(address registrant) external view returns (address[] memory) { - address registration = _registrations[registrant]; - if (registration != registrant) { - return _filteredOperators[registration].values(); - } - return _filteredOperators[registrant].values(); - } - - /** - * @notice Returns the set of filtered codeHashes for a given address or its subscription. - * Note that order is not guaranteed as updates are made. - */ - function filteredCodeHashes(address registrant) external view returns (bytes32[] memory) { - address registration = _registrations[registrant]; - if (registration != registrant) { - return _filteredCodeHashes[registration].values(); - } - return _filteredCodeHashes[registrant].values(); - } - - /** - * @notice Returns the filtered operator at the given index of the set of filtered operators for a given address or - * its subscription. - * Note that order is not guaranteed as updates are made. - */ - function filteredOperatorAt(address registrant, uint256 index) external view returns (address) { - address registration = _registrations[registrant]; - if (registration != registrant) { - return _filteredOperators[registration].at(index); - } - return _filteredOperators[registrant].at(index); - } - - /** - * @notice Returns the filtered codeHash at the given index of the list of filtered codeHashes for a given address or - * its subscription. - * Note that order is not guaranteed as updates are made. - */ - function filteredCodeHashAt(address registrant, uint256 index) external view returns (bytes32) { - address registration = _registrations[registrant]; - if (registration != registrant) { - return _filteredCodeHashes[registration].at(index); - } - return _filteredCodeHashes[registrant].at(index); - } - - /// @dev Convenience method to compute the code hash of an arbitrary contract - function codeHashOf(address a) external view returns (bytes32) { - return a.codehash; - } -} diff --git a/test/filter/OperatorFilterRegistryErrorsAndEvents.sol b/test/filter/OperatorFilterRegistryErrorsAndEvents.sol deleted file mode 100644 index 03af044..0000000 --- a/test/filter/OperatorFilterRegistryErrorsAndEvents.sol +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.10; - -contract OperatorFilterRegistryErrorsAndEvents { - error CannotFilterEOAs(); - error AddressAlreadyFiltered(address operator); - error AddressNotFiltered(address operator); - error CodeHashAlreadyFiltered(bytes32 codeHash); - error CodeHashNotFiltered(bytes32 codeHash); - error OnlyAddressOrOwner(); - error NotRegistered(address registrant); - error AlreadyRegistered(); - error AlreadySubscribed(address subscription); - error NotSubscribed(); - error CannotUpdateWhileSubscribed(address subscription); - error CannotSubscribeToSelf(); - error CannotSubscribeToZeroAddress(); - error NotOwnable(); - error AddressFiltered(address filtered); - error CodeHashFiltered(address account, bytes32 codeHash); - error CannotSubscribeToRegistrantWithSubscription(address registrant); - error CannotCopyFromSelf(); - - event RegistrationUpdated(address indexed registrant, bool indexed registered); - event OperatorUpdated(address indexed registrant, address indexed operator, bool indexed filtered); - event OperatorsUpdated(address indexed registrant, address[] operators, bool indexed filtered); - event CodeHashUpdated(address indexed registrant, bytes32 indexed codeHash, bool indexed filtered); - event CodeHashesUpdated(address indexed registrant, bytes32[] codeHashes, bool indexed filtered); - event SubscriptionUpdated(address indexed registrant, address indexed subscription, bool indexed subscribed); -} diff --git a/test/merkle/MerkleDrop.t.sol b/test/merkle/MerkleDrop.t.sol index 9cd2bde..73a3b0f 100644 --- a/test/merkle/MerkleDrop.t.sol +++ b/test/merkle/MerkleDrop.t.sol @@ -46,7 +46,15 @@ contract ZoraNFTBaseTest is Test { protocolRewards = new ProtocolRewards(); vm.prank(DEFAULT_ZORA_DAO_ADDRESS); - address impl = address(new ERC721Drop(address(1234), FactoryUpgradeGate(address(0)), address(0), mintFee, mintFeeRecipient, address(protocolRewards))); + address impl = address( + new ERC721Drop( + address(1234), + FactoryUpgradeGate(address(0)), + mintFee, + mintFeeRecipient, + address(protocolRewards) + ) + ); address payable newDrop = payable(address(new ERC721DropProxy(impl, ""))); zoraNFTBase = ERC721Drop(newDrop); merkleData = new MerkleData();