Skip to content

Instantly share code, notes, and snippets.

@shobhitic
Last active April 20, 2023 09:16
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save shobhitic/bd803916d148800b108cc1534ecb090c to your computer and use it in GitHub Desktop.
Save shobhitic/bd803916d148800b108cc1534ecb090c to your computer and use it in GitHub Desktop.
Rentable NFT with ERC 4907 on Ethereal, Polygon, and other EVM chains - https://youtu.be/t1ZB0-UwWB0
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "./IERC4907.sol";
contract ERC4907 is ERC721, 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 an 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 override virtual{
require(_isApprovedOrOwner(msg.sender, tokenId), "ERC4907: transfer caller is not owner nor approved");
UserInfo storage info = _users[tokenId];
// require(info.expires < block.timestamp, "Already rented to someone");
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 override virtual returns(address){
if (uint256(_users[tokenId].expires) >= block.timestamp) {
return _users[tokenId].user;
} else {
return ownerOf(tokenId);
}
}
/// @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 override virtual returns(uint256){
if (uint256(_users[tokenId].expires) >= block.timestamp) {
return _users[tokenId].expires;
} else {
return 115792089237316195423570985008687907853269984665640564039457584007913129639935;
}
}
/// @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);
}
}
function mint(uint256 tokenId) public {
// this is the mint function that you need to customize for yourself
_mint(msg.sender, tokenId);
}
function time() public view returns (uint256) {
return block.timestamp;
}
}
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
interface IERC4907 {
// Logged when the user of an NFT is changed or expires is changed
/// @notice Emitted when the `user` of an NFT or the `expires` of the `user` is changed
/// The zero address for user indicates that there is no user address
event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires);
/// @notice set the user and expires of an 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) external;
/// @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) external view returns(address);
/// @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) external view returns(uint256);
}
@lpurdy01
Copy link

There was recently a breaking update to _beforeTokenTransfer, so now it needs 4 variables to be overridden correctly. Have a look at this thread: trufflesuite/truffle#5715

@umarrazay
Copy link

There was recently a breaking update to _beforeTokenTransfer, so now it needs 4 variables to be overridden correctly. Have a look at this thread: trufflesuite/truffle#5715

yed you are right , it needs to be fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment