Created
January 9, 2019 23:51
-
-
Save yuyasugano/65d98a54063241da7c53c19d3c8b49f8 to your computer and use it in GitHub Desktop.
Cow ownership smart contract
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
pragma solidity ^0.4.23; | |
import "./CowBreeding.sol"; | |
import "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol"; | |
/** | |
* @title ERC721 compatible Cow Standard Basic Implementation | |
* @dev Implements Cow transfer with inherited OpenZeppelin ERC721 | |
*/ | |
contract CowOwnership is CowBreeding, ERC721 { | |
using SafeMath for uint256; | |
using Address for address; | |
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` | |
// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` | |
bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; | |
// Mapping from token ID to approved address | |
mapping (uint256 => address) private _tokenApprovals; | |
// Mapping from owner to operator approvals | |
mapping (address => mapping (address => bool)) private _operatorApprovals; | |
/** | |
* @dev Gets the balance of the specified address | |
* @param owner address to query the balance of | |
* @return uint256 representing the amount owned by the passed address | |
*/ | |
function balanceOf(address _owner) public view returns (uint256 _balance) { | |
require(_owner != address(0)); | |
return ownerCowCount[_owner]; | |
} | |
/** | |
* @dev Gets the owner of the specified token ID | |
* @param tokenId uint256 ID of the token to query the owner of | |
* @return owner address currently marked as the owner of the given token ID | |
*/ | |
function ownerOf(uint256 _tokenId) public view returns (address _owner) { | |
address owner = cowToOwner[_tokenId]; | |
require(owner != address(0)); | |
return owner; | |
} | |
/** | |
* @dev Approves another address to transfer the given token ID | |
* The zero address indicates there is no approved address. | |
* There can only be one approved address per token at a given time. | |
* Can only be called by the token owner or an approved operator. | |
* @param to address to be approved for the given token ID | |
* @param tokenId uint256 ID of the token to be approved | |
*/ | |
function approve(address _to, uint256 _tokenId) public { | |
address owner = ownerOf(_tokenId); | |
require(_to != owner); | |
require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); | |
_tokenApprovals[_tokenId] = _to; | |
emit Approval(owner, _to, _tokenId); | |
} | |
/** | |
* @dev Gets the approved address for a token ID, or zero if no address set | |
* Reverts if the token ID does not exist. | |
* @param tokenId uint256 ID of the token to query the approval of | |
* @return address currently approved for the given token ID | |
*/ | |
function getApproved(uint256 _tokenId) public view returns (address operator) { | |
require(_exists(_tokenId)); | |
return _tokenApprovals[_tokenId]; | |
} | |
/** | |
* @dev Sets or unsets the approval of a given operator | |
* An operator is allowed to transfer all tokens of the sender on their behalf | |
* @param to operator address to set the approval | |
* @param approved representing the status of the approval to be set | |
*/ | |
function setApprovalForAll(address _operator, bool _approved) public { | |
require(_operator != msg.sender); | |
_operatorApprovals[msg.sender][_operator] = _approved; | |
emit ApprovalForAll(msg.sender, _operator, _approved); | |
} | |
/** | |
* @dev Tells whether an operator is approved by a given owner | |
* @param owner owner address which you want to query the approval of | |
* @param operator operator address which you want to query the approval of | |
* @return bool whether the given operator is approved by the given owner | |
*/ | |
function isApprovedForAll(address _owner, address _operator) public view returns (bool) { | |
return _operatorApprovals[_owner][_operator]; | |
} | |
/** | |
* @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 { | |
require(_isApprovedOrOwner(msg.sender, _tokenId)); | |
_transferFrom(_from, _to, _tokenId); | |
} | |
/** | |
* @dev Safely transfers the ownership of a given token ID to another address | |
* If the target address is a contract, it must implement `onERC721Received`, | |
* which is called upon a safe transfer, and return the magic value | |
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, | |
* the transfer is reverted. | |
* | |
* 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 safeTransferFrom(address _from, address _to, uint256 _tokenId) public { | |
safeTransferFrom(_from, _to, _tokenId, ""); | |
} | |
/** | |
* @dev Safely transfers the ownership of a given token ID to another address | |
* If the target address is a contract, it must implement `onERC721Received`, | |
* which is called upon a safe transfer, and return the magic value | |
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, | |
* the transfer is reverted. | |
* 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 | |
* @param _data bytes data to send along with a safe transfer check | |
*/ | |
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) public { | |
transferFrom(_from, _to, _tokenId); | |
require(_checkOnERC721Received(_from, _to, _tokenId, _data)); | |
} | |
/** | |
* @dev Returns whether the specified token exists | |
* @param tokenId uint256 ID of the token to query the existence of | |
* @return whether the token exists | |
*/ | |
function _exists(uint256 _tokenId) internal view returns (bool) { | |
address owner = cowToOwner[_tokenId]; | |
return owner != address(0); | |
} | |
/** | |
* @dev Returns whether the given spender can transfer a given token ID | |
* @param spender address of the spender to query | |
* @param tokenId uint256 ID of the token to be transferred | |
* @return bool whether the msg.sender is approved for the given token ID, | |
* is an operator of the owner, or is the owner of the token | |
*/ | |
function _isApprovedOrOwner(address _spender, uint256 _tokenId) internal view returns (bool) { | |
address owner = ownerOf(_tokenId); | |
return (_spender == owner || getApproved(_tokenId) == _spender || isApprovedForAll(owner, _spender)); | |
} | |
/** | |
* @dev Internal function to transfer ownership of a given token ID to another address. | |
* As opposed to transferFrom, this imposes no restrictions on msg.sender. | |
* @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) internal { | |
require(ownerOf(_tokenId) ==_from); | |
require(_to != address(0)); | |
_clearApproval(_tokenId); | |
ownerCowCount[_from] = ownerCowCount[_from].sub(1); | |
ownerCowCount[_to] = ownerCowCount[_to].add(1); | |
cowToOwner[_tokenId] = _to; | |
emit Transfer(_from, _to, _tokenId); | |
} | |
/** | |
* @dev Private function to clear current approval of a given token ID | |
* @param tokenId uint256 ID of the token to be transferred | |
*/ | |
function _clearApproval(uint256 _tokenId) private { | |
if (_tokenApprovals[_tokenId] != address(0)) { | |
_tokenApprovals[_tokenId] = address(0); | |
} | |
} | |
/** | |
* @dev Internal function to invoke `onERC721Received` on a target address | |
* The call is not executed if the target address is not a contract | |
* @param from address representing the previous owner of the given token ID | |
* @param to target address that will receive the tokens | |
* @param tokenId uint256 ID of the token to be transferred | |
* @param _data bytes optional data to send along with the call | |
* @return whether the call correctly returned the expected magic value | |
*/ | |
function _checkOnERC721Received(address _from, address _to, uint256 _tokenID, bytes _data) internal returns (bool) { | |
if (!_to.isContract()) { | |
return true; | |
} | |
bytes4 retval = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data); | |
return (retval == _ERC721_RECEIVED); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment