diff --git a/contracts/token/ERC721/ERC721BasicToken.sol b/contracts/token/ERC721/ERC721BasicToken.sol index b3506218a9c..f2acdbfef8d 100644 --- a/contracts/token/ERC721/ERC721BasicToken.sol +++ b/contracts/token/ERC721/ERC721BasicToken.sol @@ -161,13 +161,25 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic { ) public { - require(isApprovedOrOwner(msg.sender, _tokenId)); - require(_from != address(0)); + address owner = ownerOf(_tokenId); + require(_from == owner); require(_to != address(0)); - clearApproval(_from, _tokenId); - removeTokenFrom(_from, _tokenId); - addTokenTo(_to, _tokenId); + address spender = msg.sender; + require( + spender == owner || + isApprovedForAll(owner, spender) || + getApproved(_tokenId) == spender + ); + + if (tokenApprovals[_tokenId] != address(0)) { + tokenApprovals[_tokenId] = address(0); + emit Approval(owner, address(0), _tokenId); + } + + tokenOwner[_tokenId] = _to; + ownedTokensCount[_from] = ownedTokensCount[_from].sub(1); + ownedTokensCount[_to] = ownedTokensCount[_to].add(1); emit Transfer(_from, _to, _tokenId); } diff --git a/contracts/token/ERC721/ERC721Token.sol b/contracts/token/ERC721/ERC721Token.sol index 4cc0edf3a86..3a55bc142ba 100644 --- a/contracts/token/ERC721/ERC721Token.sol +++ b/contracts/token/ERC721/ERC721Token.sol @@ -106,6 +106,41 @@ contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 { return ownedTokens[_owner][_index]; } + /** + * @dev Transfers the ownership of a given token ID to another address + * Usage of this method is discouraged, use `safeTransferFrom` whenever possible + * Requires the msg sender to be the owner, approved, or operator + * @param _from current owner of the token + * @param _to address to receive the ownership of the given token ID + * @param _tokenId uint256 ID of the token to be transferred + */ + function transferFrom( + address _from, + address _to, + uint256 _tokenId + ) + public + { + super.transferFrom(_from, _to, _tokenId); + + uint256 tokenIndex = ownedTokensIndex[_tokenId]; + uint256 lastTokenIndex = ownedTokens[_from].length.sub(1); + uint256 lastToken = ownedTokens[_from][lastTokenIndex]; + + ownedTokens[_from][tokenIndex] = lastToken; + ownedTokens[_from][lastTokenIndex] = 0; + // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to + // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping + // the lastToken to the first position, and then dropping the element placed in the last position of the list + + ownedTokens[_from].length--; + ownedTokensIndex[_tokenId] = 0; + ownedTokensIndex[lastToken] = tokenIndex; + + uint256 length = ownedTokens[_to].length; + ownedTokens[_to].push(_tokenId); + ownedTokensIndex[_tokenId] = length; + } /** * @dev Gets the total amount of tokens stored by the contract * @return uint256 representing the total amount of tokens