soliditytrufflenfterc721

ERC4907 compile issue in "function _beforeTokenTransfer"


I am working on an NFT Marketplace creation task with Truffle. For that, I am using an ERC4907 smart contract and trying to compile it. Following is my ERC4907 code.

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

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "./IERC4907.sol";

contract ERC4907 is ERC721URIStorage, IERC4907 {
  struct UserInfo {
    address user; // address of user role
    uint64 expires; // unix timestamp, user expires
  }

  mapping(uint256 => UserInfo) internal _users;

  constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) {}

  /// @notice set the user and expires of a NFT
  /// @dev The zero address indicates there is no user
  /// Throws if `tokenId` is not valid NFT
  /// @param user  The new user of the NFT
  /// @param expires  UNIX timestamp, The new user could use the NFT before expires
  function setUser(
    uint256 tokenId,
    address user,
    uint64 expires
  ) public virtual override {
    require(
      _isApprovedOrOwner(msg.sender, tokenId),
      "ERC721: transfer caller is not owner nor approved"
    );
    UserInfo storage info = _users[tokenId];
    info.user = user;
    info.expires = expires;
    emit UpdateUser(tokenId, user, expires);
  }

  /// @notice Get the user address of an NFT
  /// @dev The zero address indicates that there is no user or the user is expired
  /// @param tokenId The NFT to get the user address for
  /// @return The user address for this NFT
  function userOf(uint256 tokenId)
    public
    view
    virtual
    override
    returns (address)
  {
    if (uint256(_users[tokenId].expires) >= block.timestamp) {
      return _users[tokenId].user;
    } else {
      return address(0);
    }
  }

  /// @notice Get the user expires of an NFT
  /// @dev The zero value indicates that there is no user
  /// @param tokenId The NFT to get the user expires for
  /// @return The user expires for this NFT
  function userExpires(uint256 tokenId)
    public
    view
    virtual
    override
    returns (uint256)
  {
      return _users[tokenId].expires;
  }

  /// @dev See {IERC165-supportsInterface}.
  function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override
    returns (bool)
  {
    return
      interfaceId == type(IERC4907).interfaceId ||
      super.supportsInterface(interfaceId);
  }

  function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId
  ) internal virtual override {
    super._beforeTokenTransfer(from, to, tokenId);

    if (from != to && _users[tokenId].user != address(0)) {
      delete _users[tokenId];
      emit UpdateUser(tokenId, address(0), 0);
    }
  }
}

I am getting the following error when trying to compile it. Error is on the "_beforeTokenTransfer" function.

CompileError: TypeError: Wrong argument count for function call: 3 arguments given but expected 4.
  --> project:/contracts/ERC4907.sol:87:5:
   |
87 |     super._beforeTokenTransfer(from, to, tokenId);
   |    

I am using following versions

I have checked with the reference implementation on https://eips.ethereum.org/EIPS/eip-4907 . But it is still the same code.

Can someone please show me what I have mistaken here? Thank You


EDIT

As answered by @Muhammad Hassan, it was identified that there was a breaking change in the _beforeTokenTransfer function on ERC721 very recently(2022-11-08). Please refer the changelog via the following link. https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7c5f6bc2c8743d83443fa46395d75f2f3f99054a/CHANGELOG.md#breaking-changes

Adding the additional argument "uint256 batchSize" resolved the compilation issue. Thank you.


Solution

  • Erc4907 is an extention of Erc721 which you may already know. so when calling super._beforeTokenTransfer() you are actually tapping ERC721's function. If you go to ERC721 you can see that indeed it takes 4 arguments for

    function _beforeTokenTransfer(
            address from,
            address to,
            uint256, /* firstTokenId */
            uint256 batchSize
        ) internal virtual {}
    

    You can visit the oz erc721 github page for more. The argument you are missing is uint256 batchSize.