Giter Site home page Giter Site logo

operator-filter-registry's Introduction

operator-filter-registry's People

Contributors

abarbatei avatar adjisb avatar balajmarius avatar dependabot[bot] avatar dievardump avatar emo-eth avatar felipelincoln avatar fulldecent avatar iainnash avatar irreverent-eth avatar neutiyoo avatar onionpeel avatar operatorfilterer avatar ryanio avatar sambarnes avatar slokh avatar web3jt avatar willpapper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

operator-filter-registry's Issues

Wrong default address for looksrare

The example used in documentation blocked listing on x2y2 but not looksrare on ethereum mainnet. I thought the correct address might be 0xf42aa99F011A1fA7CDA90E5E98b277E306BcA83e (this is the contract you setApprovalForAll on looksrare listings) not 0x59728544b08ab483533076417fbbb2fd0b17ce3a which is listed in the documentation, though when I ran UpdateOperator, it still didn't block looksrare.

Marketplaces can be designed to easily bypass this filter

This filter is only able to filter out specific operator addresses and codehashes, both of which can be made dynamic for (future) marketplaces. For example, a marketplace can be designed that deploys an operator contract for each user, or even for each order, with a slightly different codehash via a pseudo-random salt in creation code. It would be infeasible for this registry to denylist every dynamically created operator contract (with intentionally different codehashes), rendering it useless in the long run (likely only a couple of months).

Also, I want to note that I very much appreciate the open and honest conversations on this topic from you all ❤️

The check on from and msg.sender should be outside the codesize check

if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
// Allow spending tokens from addresses with balance
// Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
// from an EOA.
if (from == msg.sender) {
_;
return;
}
if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), msg.sender)) {
revert OperatorNotAllowed(msg.sender);
}
}
_;

The cost of comparing from and msg.sender is way less than the cost to go check the code size of an external address.

For the sake of not wasting gas on direct transfers (and imo a better flow) this code could be rewritten into

        if (from != msg.sender) {
          // Check registry code length to facilitate testing in environments without a deployed registry.
          if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
              if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), msg.sender)) {
                  revert OperatorNotAllowed(msg.sender);
              }
          }
        }
        _;

this would also allow to put the checking snippet in its own internal

function _checkOperatorFilter(address operator) internal virtual {
  if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
      if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) {
          revert OperatorNotAllowed(operator);
      }
  }
}

and have a cleaner code reuse

    modifier onlyAllowedOperator(address from) virtual {
       if (from != msg.sender) {
         _checkOperatorFilter(msg.sender);
       }
        _;
    }

    modifier onlyAllowedOperatorApproval(address operator) virtual {
        _checkOperatorFilter(operator);
        _;
    }
    
    function _checkOperatorFilter(address operator) internal virtual {
      // Check registry code length to facilitate testing in environments without a deployed registry.
      if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
          if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) {
              revert OperatorNotAllowed(operator);
          }
      }
    }
}

This would also allow to facilitate overrides from implementers, for example to add a switchs to enable/disable the OperatorFilter when all this drama of not wanting to respect creator fees/royalties will stop
Adding ~150gas at execution, but makes it hell of easier to override

Contracts on Goerli are incorrectly failing validation

Screenshot from 2022-11-11 00-21-46

Hey Deploy the contract on Goerli network.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {DefaultOperatorFilterer} from "./DefaultOperatorFilterer.sol";

contract NFTee is ERC721, DefaultOperatorFilterer, Ownable {


    constructor() ERC721("Example", "EXAMPLE") {
        _mint("YOUR_TREASURY_ADDRESS",1);
    }

    function transferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) {
        super.transferFrom(from, to, tokenId);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, tokenId);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
        public
        override
        onlyAllowedOperator(from)
    {
        super.safeTransferFrom(from, to, tokenId, data);
    }

    function tokenURI(uint256) public pure override returns (string memory) {
        return "";
    }
}

ERC721A not compatible

Hi,
your package is not working with erc721A because the transfers functions and setApproval are payable.
please update your package to allow erc721A as well.
thanks

Add SudoSwap Pair Factory Address

For people implementing these filters on approvals rather than directly on transfers, they should block the sudoswap PairFactory contract (0xb16c1342E617A5B6E4b631EB114483FDB289c0A4) in addition to the PairRouter. Might as well add this to the list you have going, as it's just one additional address

Unnecessary OperatorFilterer1155

I don't think it's necessary to have a separate filterer class for 1155. I presume the goal of OperatorFilterer1155.sol was to demonstrate what a 1155 filterer would look like, but the current example doesn't showcase anything different than the 721 filterer. Looping multiple times here without using the ids parameter seems unnecessary: https://github.com/ProjectOpenSea/operator-filter-registry/blob/main/src/example/OperatorFilterer1155.sol#L42. Additionally, the id parameter here is unused: https://github.com/ProjectOpenSea/operator-filter-registry/blob/main/src/example/OperatorFilterer1155.sol#L29.

I'm also trying to think of a scenario in which a certain 1155 id would need to be blocked, but another wouldn't be.

How to register to a different subscriber

According to the code, the subscribe method pushes an address onto the subscription stack (

function subscribe(address registrant, address newSubscription) external onlyAddressOrOwner(registrant) {
). If I wanted to subscribe to a different "operator filterer" instead of the default (0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6), how would I go about doing this? From what I gathered it should be implemented something like this:

import "https://github.com/ProjectOpenSea/operator-filter-registry/blob/main/src/OperatorFilterer.sol";
import "https://github.com/ProjectOpenSea/operator-filter-registry/blob/main/src/RevokableOperatorFilterer.sol";


contract ExampleNFT is ERC721, ERC721Enumerable, RevokableOperatorFilterer {


    address public currentOperatorFiltererSubscriber = address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);

    constructor() ERC721("ExampleNFT", "EXAMPLE") OperatorFilterer(currentOperatorFiltererSubscriber, true){}

    function setOperatorFiltererSubscriber(address _subscription) public onlyOwner {
        OPERATOR_FILTER_REGISTRY.unregister(address(this));
        OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), _subscription);
        currentOperatorFiltererSubscriber = _subscription;
    }


    /**
     * Overrides
     */

    function setApprovalForAll(address operator, bool approved) public override(IERC721, ERC721) onlyAllowedOperatorApproval(operator) {
        super.setApprovalForAll(operator, approved);
    }

    function approve(address operator, uint256 tokenId) public override(IERC721, ERC721) onlyAllowedOperatorApproval(operator) {
        super.approve(operator, tokenId);
    }

    function transferFrom(address from, address to, uint256 tokenId) public override(IERC721, ERC721) onlyAllowedOperator(from) {
        super.transferFrom(from, to, tokenId);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId) public override(IERC721, ERC721) onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, tokenId);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
        public
        override(IERC721, ERC721)
        onlyAllowedOperator(from)
    {
        super.safeTransferFrom(from, to, tokenId, data);
    }

    function owner() public view virtual override (Ownable, RevokableOperatorFilterer) returns (address) {
        return Ownable.owner();
    }

}

Separation of concerns for the OpenSea creator fees enforcement opt-in, and blacklisting other exchange contracts.

The Current Policy of Registry Use

Hello OpenSea, thank you for sharing the contracts. They are another interesting contribution to the NFT space and another learning opportunity. This issue concerns this part of the README.

Contract owners may implement their own filtering outside of this registry, or they may use this registry to curate their own lists of filtered operators. However, there are certain contracts that are filtered by the default subscription, and must be filtered in order to be eligible for creator fee enforcement on OpenSea.

The example in this repository has an NFT implementing a blacklist of transfers from the default OpenSea registry.

modifier onlyAllowedOperator() virtual {
// Check registry code length to facilitate testing in environments without a deployed registry.
if (address(operatorFilterRegistry).code.length > 0) {
if (!operatorFilterRegistry.isOperatorAllowed(address(this), msg.sender)) {
revert OperatorNotAllowed(msg.sender);
}
}
_;
}

The default OpenSea registry includes the following exchanges.

Name Address Network
Blur.io ExecutionDelegate 0x00000000000111AbE46ff893f3B2fdF1F759a8A8 Ethereum Mainnet
LooksRareExchange 0x59728544b08ab483533076417fbbb2fd0b17ce3a Ethereum Mainnet
X2Y2 ERC721Delegate 0xf849de01b080adc3a814fabe1e2087475cf2e354 Ethereum Mainnet
SudoSwap LSSVMPairRouter 0x2b2e8cda09bba9660dca5cb6233787738ad68329 Ethereum Mainnet

The Problem

As an NFT creator, I receive significant volume on my collections from several of these blacklisted exchanges. While these exchanges support optional creator fees, many of my community members still choose to pay creator fees. Ultimately it is their choice and I would like to respect that.

As an NFT creator, I also appreciate all the support OpenSea can give me. I would like for my NFT to ideally balance both my own expectations of profit from secondary sales and the experiences of my community on their platform of choice.

When my community chooses to use OpenSea as their trading platform, I would like to opt in to enforcing creator fees. I do not, however, want to negatively impact the experience of my community members who choose to use any other exchange and therefore do not want to blacklist the use of those exchanges. In short, I find the present situation as it stands right now ideal and would prefer a way to maintain that situation for my NFTs and my community.

I understand the business rationale behind combining these use cases, but as a creator would prefer if OpenSea gave me the option to opt in to enforced creator fees without also requiring that I blacklist any other exchanges.

How does function subscribe work?

First, i want to thank to OpenSea about enforce creator fees. I have some problems with the function subscribe:

    /**
     * @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);
    }

According to the function comments, if the registrant calls this function to subscribe a new subscription. Is that means the _filteredOperators[registrant] should contains _filteredOperators[newSubscription], but there is no copy code. And there is function copyEntriesOf, why not copy the entries of new subscription into registrant's filtered operators when call subscribe?

ERC1155 Clone + DefaultOperatorFilterUpgradeable

Hi OpenSea team! We're deploying a system that uses a factory contract to deploy ERC1155 clones. Our implementation contract inherits DefaultOperatorFilterUpgradeable and supports EIP-2981.

Our verification fork tests pass, creator fees are enforced in the OpenSea testnet UI, and the mainnet contracts look like they are correctly registered with the operator filter, but we are still seeing optional creator fees on mainnet OpenSea. Implementation contract bytecode is the same on Goerli and mainnet. Any idea what might be going on? We were surprised by this in production, since fork tests and testnet deployments both looked OK.

Here's an example deployment tx from mainnet for one of the clone contracts.

Multichain support / deploys

Currently Operator Filter Registry is just deployed on Ethereum and Goerli at 0x000000000000aaeb6d7670e522a718067333cd4e.

We could deploy our own registries in different networks, but it makes sense to have one unique registry address (0x000000000000aaeb6d7670e522a718067333cd4e) deployed across different blockchains.

It would be great to have full support (including filtered addresses) on the networks you already support: Arbitrum, Avalanche, Klaytn, Optimism, Polygon, Solana.
But at least and empty deployment on EVM Blockchains would ease things for multichain projects like ours, where we can share code across different blockchains and not having to think about different addresses on different blockchains and keeping our own registries.

We've implement it from the very first day at https://nfts2me.com/ (https://twitter.com/nfts2me/status/1589215568942747648) as we think this is a great option for creators, but support for other blockchain is really a need!

Creator fees not enforced on OpenSea - ERC1155

Hello!

I've read through most of the existing issues, but can't quite figure out why my contract is being shown as optional for creator fees...

Chain: Polygon Testnet (Mumbai)
Token Type: ERC1155

Here's my Smart Contract code:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "operator-filter-registry/src/DefaultOperatorFilterer.sol";

contract Clones is ERC1155, ERC2981, DefaultOperatorFilterer, Ownable {
    // Contract name
    string public name;
     // Contract symbol
    string public symbol;

    constructor(
        string memory _name,
        string memory _symbol,
        string memory someUri
        ) ERC1155("someBaseUri") {
        name = _name;
        symbol = _symbol;
        _setURI(someUri);
        
        _setDefaultRoyalty(owner(), 500);
    }

    function airdropClone(uint256 tokenId, address to) public onlyOwner {
        _mint(to, tokenId, 1, "");
    }

    function setDefaultRoyalty(address receiver, uint96 feeNumerator) public onlyOwner {
        _setDefaultRoyalty(receiver, feeNumerator);
    }

    /// @dev Set royalty fee for specific token
    /// @param _tokenId The tokenId where to add the royalty
    /// @param _receiver The royalty receiver
    /// @param _feeNumerator the fee for specific tokenId
    function setTokenRoyalty(
        uint256 _tokenId,
        address _receiver,
        uint96 _feeNumerator
    ) public onlyOwner {
        _setTokenRoyalty(_tokenId, _receiver, _feeNumerator);
    }

    /// @dev Allow owner to delete the default royalty for all collection
    function deleteDefaultRoyalty() external onlyOwner {
        _deleteDefaultRoyalty();
    }

    /// @dev Reset specific royalty
    /// @param tokenId The token id where to reset the royalty
    function resetTokenRoyalty(uint256 tokenId) external onlyOwner {
        _resetTokenRoyalty(tokenId);
    }

    //=======================================================================
    // [public/override/onlyAllowedOperatorApproval] for OperatorFilter
    //=======================================================================
    function setApprovalForAll(address operator, bool approved) public override onlyAllowedOperatorApproval(operator) { super.setApprovalForAll(operator, approved); }
    function safeTransferFrom(address from, address to, uint256 tokenId, uint256 amount, bytes memory data) public override onlyAllowedOperator(from) { super.safeTransferFrom(from, to, tokenId, amount, data); }
    function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) public virtual override onlyAllowedOperator(from) { super.safeBatchTransferFrom(from, to, ids, amounts, data); }

    //=======================================================================
    // [public/override] 
    //=======================================================================
    function supportsInterface(bytes4 interfaceId) public view override( ERC1155, ERC2981 ) returns (bool) {
        return super.supportsInterface(interfaceId);
    }
}

Editing the contract on OpenSea shows the following:
Screen Shot 2023-01-25 at 6 54 29 PM

I've seen some other people saying that they had to hit a refresh button, but I don't have access to a refresh button to run the check again. I've also minted a few NFTs from the contract, as it says in the documentation that the enforcement check is run whenever the first NFT is minted.

Any ideas as to why this isn't being enforced?

Thanks,

Matt

Add specific reasoning for filter list inclusion

It would be helpful to add the specific justification for inclusion of each marketplace contract on the table.

For example from what I can see LooksRare support via ERC2981, why are they on the list of excluded contracts?

ERC 721 with OperatorFilterer not defaultOperatorFilterer

Has anyone deployed a NFT smart contract with OperatorFilterer to set up the allowed Operators to make token transfers yet?
Please let us know the contract address.
Or if someone could provide an example code it would be a tremendous help.
Thank you

msg.sender breaks meta transactions in operator-filter registry

Summary:
The use of msg.sender in the operator-filter registry makes it impossible to inherit from these classes and override msg.sender. This can be a problem in contexts where the sender may be different than anticipated, such as with EIP-725X.

As a solution, it is recommended to follow the example of OpenZeppelin's contracts and use _msgSender() instead. This will make it easier to consume the operator-filter registry without having to fork the code.

Reference: https://forum.openzeppelin.com/t/why-use-msgsender-rather-than-msg-sender/4370

Default example doesn't work without working tokenURI

After trying to get royalty fees working on görli, I realized that a valid tokenURI is required to get the controls for creator fees working.

The examples here return a blank tokenURI and it could be replaced with an example token such as https://www.721.so/api/example/metadata/1.

ERC1155 cannot buy on Opensea (Testnet Goerli)

I have a simple ERC1155 contract that extends DefaultOperatorFilterer.

It also define the contract URI function.

I can deploy and mint correctly.

I can sell it on opensea, but when I try to buy on testnet i recieve this message 'Execution reverted. Please reach out to the collection owner to troubleshoot.'.

Do I need to configure something more to work correctly?

Creator fee information not being ingested from `contractURI` method

I am trying to deploy a contract with the creator earnings embedded into the contractURI function. I have implemented the DefaultOperatorFilter properly. The contractURI address is reachable as OpenSea is picking up the collection name and description and everything but not the seller_fee_basis_points and fee_recepient. It was working perfectly before Nov 8, but after implementing the DefaultOperatorFilter it is not working anymore. What could be the issue?

Here is a contract I have deployed to goerli and the creator earning informations are not being picked up.

https://goerli.etherscan.io/address/0x16e8255c88d0e24d99b5503467e03db9db722a63#code

Backwards compatibility

Hey there, I think that backwards compatibility could be achieved with an intermediate contract. This is a quick and dirty proof of concept:

contract ERC721OperatorFiltererAdapter is DefaultOperatorFilterer, Ownable {
  address public target;

  constructor(address _target) {
    target = _target;
  }

  function transferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator onlyApprovedOperator {
      IERC721(target).transferFrom(from, to, tokenId);
  }

  function safeTransferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator onlyApprovedOperator {
      IERC721(target).safeTransferFrom(from, to, tokenId);
  }

  function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
      public
      override
      onlyAllowedOperator
      onlyApprovedOperator
  {
      IERC721(target).safeTransferFrom(from, to, tokenId, data);
  }

  mapping(address => bool) private _operatorApprovals;
  function setApprovalForAll(address operator, bool approved) public virtual override onlyOwner {
    _operatorApprovals[operator] = approved;
  }

  modifier onlyApprovedOperator {
    require(true == _operatorApprovals[msg.sender]);
    _;
  }
}

Update Goerli filtered operators to match testnet addresses

On Goerli It looks like the OS curated filter are the operator addresses for the filtered mainnet operator contracts:

[
    0x00000000000111AbE46ff893f3B2fdF1F759a8A8, 
    0x59728544B08AB483533076417FbBB2fD0B17CE3a, 
    0xFED24eC7E22f573c2e08AEF55aA6797Ca2b3A051, 
    0x2B2e8cDA09bBA9660dCA5cB6233787738Ad68329, 
    0xf42aa99F011A1fA7CDA90E5E98b277E306BcA83e
]

However, at least for LooksRare their Transfer Manager on Goerli is deployed too: 0xf8c81f3ae82b6efc9154c69e3db57fd4da57ab6e

The testnet subscription should probably match their corresponding filtered testnet operators for full E2E testing.

After setting the creator fees, it failed to sell NFT on Opensea.

I have followed the ReadMe and added the required methods. This is the verified contract: https://goerli.etherscan.io/address/0x714965eAA0A9c44Fb741aEB690a565471Ba637a0#code

And I have added the contract address as the creator fees receiver in the settings.
image

But when I try to list an item for sale, below error happened:

RRNLRequestError: Relay request for `useHandleBlockchainActionsCreateOrderMutation` failed by the following reasons:

1. [500] [500] Error occurred while processing your request. Please try again later.

Error id: a505e5cba87d419885e84678461b6885

Error id: a505e5cba87d419885e84678461b6885
   
                       ^^^

This is my NFT collection on Opensea: https://testnets.opensea.io/collection/kits-og1sesicwa

X2Y2 ENFORCEMENT BROKEN

You forced us to implement this last minute, and yet people can buy our NFTs with 0% fees on X2Y2.

We almost rescheduled the mint, because without [operator-filter-registry](https://github.com/ProjectOpenSea/operator-filter-registry), OpenSea won't enforce creator fees after January 2. So we were kinda forced to implement this, otherwise no one will pay fees.

Then as it turned out, it meant nothing, people can still buy/sell on X2Y2 with 0% creator fees. When I think it can't be worse, OpenSea proves there is always worse, and you charge you a ridiculous 2.5% fee for providing this unacceptable infrastructure. And if I want access to the API, fill a fckn google form and pray...

Get errors when adding ERC721EnumerableUpgradeable in the Example Contract

I am using the example upgradeable contact, and modify some code to add the ERC721EnumerableUpgradeable, like as blow:
abstract contract ExampleERC721Upgradeable is ERC721Upgradeable, DefaultOperatorFiltererUpgradeable, OwnableUpgradeable, ERC721EnumerableUpgradeable
and I override the functions of ERC721EnumerableUpgradeable accordingly. Then I will get the error message:
Screen Shot 2022-12-07 at 15 03 06

The detail error message is :

`TypeError: Function needs to specify overridden contracts "ERC721Upgradeable" and "IERC721Upgradeable".
--> contracts/TEST.sol:50:72:
|
50 | function setApprovalForAll(address operator, bool approved) public override onlyAllowedOperatorApproval {
| ^^^^^^^^
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol:20:1:
|
20 | contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol:11:1:
|
11 | interface IERC721Upgradeable is IERC165Upgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).

TypeError: Function needs to specify overridden contracts "ERC721Upgradeable" and "IERC721Upgradeable".
--> contracts/TEST.sol:54:64:
|
54 | function approve(address operator, uint256 tokenId) public override onlyAllowedOperatorApproval(operator) {
| ^^^^^^^^
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol:20:1:
|
20 | contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol:11:1:
|
11 | interface IERC721Upgradeable is IERC165Upgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).

TypeError: Function needs to specify overridden contracts "ERC721Upgradeable" and "IERC721Upgradeable".
--> contracts/TEST.sol:58:77:
|
58 | function transferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) {
| ^^^^^^^^
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol:20:1:
|
20 | contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol:11:1:
|
11 | interface IERC721Upgradeable is IERC165Upgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).

TypeError: Function needs to specify overridden contracts "ERC721Upgradeable" and "IERC721Upgradeable".
--> contracts/TEST.sol:62:81:
|
62 | function safeTransferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) {
| ^^^^^^^^
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol:20:1:
|
20 | contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol:11:1:
|
11 | interface IERC721Upgradeable is IERC165Upgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).

TypeError: Function needs to specify overridden contracts "ERC721Upgradeable" and "IERC721Upgradeable".
--> contracts/TEST.sol:68:9:
|
68 | override
| ^^^^^^^^
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol:20:1:
|
20 | contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).
Note: This contract:
--> @openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol:11:1:
|
11 | interface IERC721Upgradeable is IERC165Upgradeable {
| ^ (Relevant source part starts here and spans across multiple lines).

TypeError: Wrong argument count for modifier invocation: 0 arguments given but expected 1.
--> contracts/TEST.sol:50:81:
|
50 | function setApprovalForAll(address operator, bool approved) public override onlyAllowedOperatorApproval {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
`

Could somebody help me fix this? thx in advance!

restrict via _beforeTokenTransfer?

The example implementations for ERC721 and ERC1155 are restricting safeTransferFrom and safeBatchTransferFrom like this:

    function safeTransferFrom(address from, address to, uint256 tokenId, uint256 amount, bytes memory data)
        public
        override
        onlyAllowedOperator(from)
    {
        super.safeTransferFrom(from, to, tokenId, amount, data);
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override onlyAllowedOperator(from) {
        super.safeBatchTransferFrom(from, to, ids, amounts, data);
    }

is there a reason to not restrict via _beforeTokenTransfer?

    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint[] memory ids,
        uint[] memory amounts,
        bytes memory data
    ) internal virtual override onlyAllowedOperator(from) {
        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
    }

Update Operator not working?

According to the Default operator registry code, the current owner of the smart contract or the smart contract itself can send request to update operators as shown in code below:

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)) } } } } _; }

The Ownable(addr) checks for the current owner, however, when I call the updateOperator with me being the owner, it throws an error. Am I missing something?

Blur bypasses Operator Filter Registry?

After taking a look at this tweet:
https://twitter.com/pandajackson42/status/1620081518575235073
It seems they did with their own conduit, and the seem to be honouring Royalties.

But, what stops Blur from not honoring Royalties? Using their own conduit allows them to remove or introduce any arbitrary fees as long as the user list the NFT under their conduit.

But, on the other hand a new conduit is a new contract that could be blocked, right? Will you? Or being royalties complain on this conduit is enough to follow the rules as long as they honour royalties?

EDIT: I've done some more research and realized that they actually are using OpenSea's conduit. Then, there's no way to forbid it, right?

Blocking token owners

The current implementation of the operator filtering logic allows token owners (also real users) to be blocked indefinitely from moving their tokens. See also #4 for a failing test.

Was this intentional? If so, what was the reasoning for it?
Even though it is the contract owners decision in the end to leave this in, I think this should not be allowed in the reference implementation.

add .prettierrc or linter

Please add a prettierrc or a linter or any conf you want so IDEs can follow the maintainers configuration

Operator Filter Registry Initializer Not Working When Upgrading

How can I upgrade my NFT smart contract to implement Operator Filter Registry? I know there's they release an upgradeable OFR, but it requires to be initialized. I'm just wondering how are you going to initialize it when you already deployed the smart contract and you're just upgrading it?

Upgrade contract is not working

I upgraded my ERC1155 contract yesterday but OpenSea still say "This collection is not eligible for creator fees" in the collection edit page.

I followed the example : https://github.com/ProjectOpenSea/operator-filter-registry/blob/main/src/example/upgradeable/ExampleERC1155Upgradeable.sol and added the following methods into my old contract

function setApprovalForAll(address operator, bool approved) public override onlyAllowedOperatorApproval(operator) {
super.setApprovalForAll(operator, approved);
}

function safeTransferFrom(address from, address to, uint256 tokenId, uint256 amount, bytes memory data)
    public
    override
    onlyAllowedOperator(from)
{
    super.safeTransferFrom(from, to, tokenId, amount, data);
}

function safeBatchTransferFrom(
    address from,
    address to,
    uint256[] memory ids,
    uint256[] memory amounts,
    bytes memory data
) public virtual override onlyAllowedOperator(from) {
    super.safeBatchTransferFrom(from, to, ids, amounts, data);
}

After upgrading my old contract on Ethereum Mainnet, nothing changed in my collection editing page, it still say "This collection is not eligible for creator fees".

Should OperatorFilterRegistry address be updatable to de-risk potential code errors?

Since the OperatorFilterRegistry is a new and un-audited contract, there is no guarantee there won't be any bugs and/or vulnerabilities discovered in future.

Because of that, hardcoding the address to this contract seems risky:

    IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY =
        IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);

To de-risk this should the address be updatable via a setOperatorFilterRegistry method?

"Creator earnings" of ERC1155 can be edited.

Hello to the OpenSea development team.

we have incorporated the DefaultOperatorFilterer into ERC1155 and deployed it to Goerli network.
we verified the sales on OpenSea's test net and was able to edit "Creatoer earnings".
screen shot 2023-01-12 16 06 01

Below is the verification code.
https://goerli.etherscan.io/address/0x3aa59d510abed17216c4c7da676862d8381e634b#code

Below is the OpenSea(testet) collection page.
https://testnets.opensea.io/ja/collection/unidentified-contract-baemdyveyr

Below is the transaction that was sold and successfully traded with the commission edited to 0%.
https://goerli.etherscan.io/tx/0xfd13270c2977b588b8256d6f719e4124b73a1d729b9bc1d3b10944c21331bd76

How can we disable the "creator earnings" edit when ERC1155 is offered for sale?
(When we tried with ERC721, the "Creatoer fearnigs" edits were disabled as expected.)

Thank you in advance for your help.

Not working on 1155 on goerli testnet

Hey! I made a simple 1155 erc contract but it seems like creator fee are not available , obv with the DefaultOperatorFilterer.
Here my contract ( i'm gonna strip some functions here)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

import "./DefaultOperatorFilterer.sol";


interface IERC2981Royalties {
    function royaltyInfo(uint256 _tokenId, uint256 _value)
        external
        view
        returns (address _receiver, uint256 _royaltyAmount);
}
abstract contract ERC2981Base is ERC165, IERC2981Royalties {
    struct RoyaltyInfo {
        address recipient;
        uint24 amount;
    }

    /// @inheritdoc ERC165
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override
        returns (bool)
    {
        return
            interfaceId == type(IERC2981Royalties).interfaceId ||
            super.supportsInterface(interfaceId);
    }
}
/// @custom:security-contact [email protected]
contract DversoTickets is ERC1155, Ownable, ERC1155Supply , Pausable, ERC1155Burnable , ERC2981Base , DefaultOperatorFilterer {

    using ECDSA for bytes32;

    mapping(uint256 => bool) public tokenEnabled;
    mapping(uint256 => bool) public tokenWhitelist;
    mapping(uint256 => uint256) public maxTokenPW;
    mapping(uint256 => uint256) public costs;
    mapping(uint256 => uint256) public tokenSupplies;
    mapping(uint256 => mapping(address => uint256)) private mintedBalances;
    mapping(uint256 => string) public cids;
    RoyaltyInfo private _royalties;

    constructor() ERC1155("") {
        _setRoyalties(0x5211063C82D0CD0aB516a063206D50AA919eac75 , 200);

        setTokenIndex(  1, //token Id
                        1, //max per wallet
                        1000, // supply
                        true, // whitelist verification enabled
                        true, // token enabled
                        "", //cid
                        0 ether); // cost
    }

    function setTokenIndex(uint256 tokenId,uint256 maxPerWallet,uint256 supply,bool whitelist,bool _enabled,string memory cid,uint256 cost) public onlyOwner {
        maxTokenPW[tokenId] = maxPerWallet;
        tokenEnabled[tokenId] = _enabled;
        tokenWhitelist[tokenId] = whitelist;
        tokenSupplies[tokenId] = supply;
        cids[tokenId] = cid;
        costs[tokenId] = cost;
    }

    function contractURI() public pure returns (string memory) {
        return "https://example.com/contract.json";
    }

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }


    function _baseURI(uint256 tokenId) internal view virtual returns (string memory) {
        return string(abi.encodePacked("ipfs://", cids[tokenId]));
    }

    function mintedBalanceOf(address account, uint256 id) public view returns (uint256) {
        require(account != address(0), "ERC1155: balance query for the zero address");
        return mintedBalances[id][account];
    }
    
    function mint(bytes calldata signature, uint256 id, bytes memory data) public payable
    {
        require(tokenSupplies[id] > 0, "Token is not mintable");
        require(tokenEnabled[id], "Token is not mintable");
        require(mintedBalanceOf(msg.sender,id) < maxTokenPW[id], "Reached max mint for token");
        require(totalSupply(id) < tokenSupplies[id], "Reached max supply");
        require(msg.value >= costs[id], "Value should not be lower than than cost");

        mintedBalances[id][msg.sender] += 1;
        _mint(msg.sender, id, 1, data);
    }
    
    function mintOwner(address account,uint256 id, uint256 amount, bytes memory data)
        public
        onlyOwner
    {
        require(totalSupply(id) + (amount - 1) < tokenSupplies[id], "Reached max supply");
        require(tokenEnabled[id], "Token is not mintable");

        _mint(account, id, amount, data);
    }
    
    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        public
        onlyOwner
    {
        
        for (uint256 i = 0; i < ids.length; i++) {
            require(totalSupply(ids[i]) + (amounts[i] - 1) < tokenSupplies[ids[i]], "Reached max supply");
            require(tokenEnabled[ids[i]], "Token is not mintable");
        }

        _mintBatch(to, ids, amounts, data);
    }

    function setApprovalForAll(address operator, bool approved) public override onlyAllowedOperatorApproval(operator) {
        super.setApprovalForAll(operator, approved);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, uint256 amount, bytes memory data)
        public
        override
        onlyAllowedOperator(from)
    {
        super.safeTransferFrom(from, to, tokenId, amount, data);
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override onlyAllowedOperator(from) {
        super.safeBatchTransferFrom(from, to, ids, amounts, data);
    }
    
    // The following functions are overrides required by Solidity.

    function _beforeTokenTransfer(address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        internal
        whenNotPaused
        override(ERC1155, ERC1155Supply)
    {
        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
    }

    function uri(uint _id) public override view returns (string memory) {
        return string(abi.encodePacked(
            _baseURI(_id), "/", Strings.toString(_id),".json"
        ));
    }

    function _setRoyalties(address recipient, uint256 value) internal {
        require(value <= 10000, 'ERC2981Royalties: Too high');
        _royalties = RoyaltyInfo(recipient, uint24(value));
    }


    function royaltyInfo(uint256, uint256 value)
        external
        view
        override
        returns (address receiver, uint256 royaltyAmount)
    {
        RoyaltyInfo memory royalties = _royalties;
        receiver = royalties.recipient;
        royaltyAmount = (value * royalties.amount) / 10000;
    }
    
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC2981Base) returns (bool) {
        return super.supportsInterface(interfaceId);
    }
}

Please update OpenZeppelin imports

Currently contracts are imporing from 'openzeppelin-contracts' instead of '@openzeppelin/contracts' which breaks smart contract verification as hardhat verification task can't find 'openzeppelin-contracts'

How to treat about owner() ?

When I try to inherit , below message pop-up.
Shoud I just delete "function owner()" at UpdatableOperatorFiltere.sol ?

Note: Definition in "Ownable":
--> @openzeppelin/contracts/access/Ownable.sol:43:5:
|
43 | function owner() public view virtual returns (address) {
| ^ (Relevant source part starts here and spans across multiple lines).
Note: Definition in "UpdatableOperatorFilterer":
--> contracts/RevokableOperatorFilterRegistry/UpdatableOperatorFilterer.sol:72:5:
|
72 | function owner() public view virtual returns (address);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Still showing contract is not eligible for Creator Fee

This is my contract address: 0x1b63Be0847C57f72cc8e093C99628D625C1F4baA on goerli network.
I checked [0x000000000000AAeB6D7670E522A718067333cd4E] and found my contract was registered the filter.
But the creator fee is still not eligible.
what's going on next?

After setting proxy contract "erc-1967 UUPSUpgradeable", the opensea royalties enforcement does not work!

I have implemented openSea royalty reforcement and normally it enforces royalties on opensea but now i'm using "erc1967 proxy UUPSUpgradeable" and then using proxy I mint nfts and when I check in openSea it doesnot enforces royalty. What is issue there I don't understand.Need help.
the proxy is calling transfer function when selling on opensea and as well as it identifies onlyAllowedOperator modifier but still I don't understand why it does not enforce royalties

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.