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
Truffle v5.6.8 (core: 5.6.8)
Ganache v7.5.0
Solidity v0.5.16 (solc-js)
Node v16.17.1
Web3.js v1.7.4
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.
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
.