diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index 4232c616eb7..fcaf04f2afb 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -114,9 +114,6 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er */ function approve(address to, uint256 tokenId) public virtual { address owner = ownerOf(tokenId); - if (to == owner) { - revert ERC721InvalidOperator(owner); - } if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender())) { revert ERC721InvalidApprover(_msgSender()); @@ -131,7 +128,7 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er function getApproved(uint256 tokenId) public view virtual returns (address) { _requireMinted(tokenId); - return _tokenApprovals[tokenId]; + return _getApproved(tokenId); } /** @@ -220,16 +217,22 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er return _ownerOf(tokenId) != address(0); } + /** + * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. + */ + function _getApproved(uint256 tokenId) internal view virtual returns (address) { + return _tokenApprovals[tokenId]; + } + /** * @dev Returns whether `spender` is allowed to manage `tokenId`. - * - * Requirements: - * - * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { - address owner = ownerOf(tokenId); - return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); + address owner = _ownerOf(tokenId); + return (owner != address(0) && + (spender == owner || + isApprovedForAll(owner, spender) || + (_getApproved(tokenId) == spender && spender != address(0)))); } /** @@ -386,8 +389,12 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { + address owner = ownerOf(tokenId); + if (to == owner || to == address(0)) { + revert ERC721InvalidOperator(to); + } _tokenApprovals[tokenId] = to; - emit Approval(ownerOf(tokenId), to, tokenId); + emit Approval(owner, to, tokenId); } /** @@ -396,8 +403,8 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er * Emits an {ApprovalForAll} event. */ function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { - if (owner == operator) { - revert ERC721InvalidOperator(owner); + if (operator == owner || operator == address(0)) { + revert ERC721InvalidOperator(operator); } _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved);