Created
July 15, 2023 20:29
-
-
Save lukasz-glen/c1768ecb0d5138f10d52a07c23e16140 to your computer and use it in GitHub Desktop.
A demonstration of approvals with expiration date for ERC721 NFTs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | |
/** | |
* @author lukasz-glen | |
* @dev This is not production ready implementation. | |
* Just a demonstration of the idea of approvals with expiration date. | |
* Block numbers could be used as well. | |
* The same can be applied to signle approvals, token id based approvals, and others. | |
* The point is that bool requires 1 storage slot anyway, so it is the same cost if we put there more information. | |
* Approval-for-all functions from ERC721 are overriden in order to comply with ERC721 standard and approvals with expiration date. | |
*/ | |
contract TimeLimitedApprove is ERC721 { | |
event ApprovalForAll(address indexed owner, address indexed operator, uint256 timeLimit); | |
// Mapping from owner to operator approvals with time limits | |
mapping(address => mapping(address => uint256)) private __operatorApprovals; | |
constructor(string memory __name, string memory __symbol) ERC721(__name, __symbol) { } | |
/** | |
* @dev See {IERC721-setApprovalForAll}. | |
*/ | |
function setApprovalForAll(address operator, bool approved) public virtual override { | |
address owner = _msgSender(); | |
require(owner != operator, "ERC721: approve to caller"); | |
__operatorApprovals[owner][operator] = approved ? type(uint256).max : 0; | |
emit ApprovalForAll(owner, operator, approved); | |
} | |
/** | |
* @dev See {IERC721-isApprovedForAll}. | |
*/ | |
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { | |
return __operatorApprovals[owner][operator] == type(uint256).max; | |
} | |
function setApprovalForAll(address operator, uint256 timeLimit) public virtual { | |
address owner = _msgSender(); | |
require(owner != operator, "ERC721: approve to caller"); | |
if (__operatorApprovals[owner][operator] == type(uint256).max) { | |
emit ApprovalForAll(owner, operator, false); | |
} | |
__operatorApprovals[owner][operator] = timeLimit; | |
emit ApprovalForAll(owner, operator, timeLimit); | |
} | |
function getApprovedForAllTimeLimit(address owner, address operator) public view virtual returns (uint256) { | |
return __operatorApprovals[owner][operator]; | |
} | |
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual override returns (bool) { | |
address owner = ERC721.ownerOf(tokenId); | |
return (spender == owner || getApprovedForAllTimeLimit(owner, spender) >= block.timestamp || getApproved(tokenId) == spender); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment