Created
September 3, 2018 15:16
-
-
Save ghiliweld/8eeadc00a97b9aa133ec12656351b0b8 to your computer and use it in GitHub Desktop.
NFTs owned by ENS names
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; | |
interface ENS { | |
// Logged when the owner of a node assigns a new owner to a subnode. | |
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); | |
// Logged when the owner of a node transfers ownership to a new account. | |
event Transfer(bytes32 indexed node, address owner); | |
// Logged when the resolver for a node changes. | |
event NewResolver(bytes32 indexed node, address resolver); | |
// Logged when the TTL of a node changes | |
event NewTTL(bytes32 indexed node, uint64 ttl); | |
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public; | |
function setResolver(bytes32 node, address resolver) public; | |
function setOwner(bytes32 node, address owner) public; | |
function setTTL(bytes32 node, uint64 ttl) public; | |
function owner(bytes32 node) public view returns (address); | |
function resolver(bytes32 node) public view returns (address); | |
function ttl(bytes32 node) public view returns (uint64); | |
} | |
contract ERCOver9000 { | |
using SafeMath for uint256; | |
using Address for address; | |
ENS ens = ENS(0xENSaDdREsS0000000); | |
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` | |
// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` | |
bytes4 private constant ERCOver9000_RECEIVED = 0x150b7a02; | |
// Mapping from token ID to owning ENS name | |
mapping (uint256 => bytes32) internal tokenOwner; | |
// Mapping from token ID to approved name | |
mapping (uint256 => bytes32) internal tokenApprovals; | |
// Mapping from owner to number of owned token | |
mapping (bytes32 => uint256) internal ownedTokensCount; | |
// Mapping from owner to operator approvals | |
mapping (bytes32 => mapping (bytes32 => bool)) internal operatorApprovals; | |
function ERCOver9000() public { | |
// register the supported interfaces to conform to ERC721 via ERC165 | |
_registerInterface(InterfaceId_ERC721); | |
} | |
/** | |
* @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(bytes32 _owner) public view returns (uint256) { | |
require(ens.owner(_owner) != address(0)); | |
return ownedTokensCount[_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 (bytes32) { | |
bytes32 owner = tokenOwner[_tokenId]; | |
require(ens.owner(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(bytes32 _to, uint256 _tokenId) public { | |
bytes32 owner = ownerOf(_tokenId); | |
require(_to != owner); | |
require(msg.sender == ens.owner(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 | |
* @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 (bytes32) { | |
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(bytes32 _from, bytes32 _to, bool _approved) public { | |
require(msg.sender == ens.owner(_from)); | |
require(ens.owner(_to) != msg.sender); | |
operatorApprovals[_from][_to] = _approved; | |
emit ApprovalForAll(msg.sender, _to, _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( | |
bytes32 _owner, | |
bytes32 _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( | |
bytes32 _from, | |
bytes32 _to, | |
uint256 _tokenId | |
) | |
public | |
{ | |
require(isApprovedOrOwner(msg.sender, _tokenId)); | |
require(ens.owner(_to) != address(0)); | |
clearApproval(_from, _tokenId); | |
removeTokenFrom(_from, _tokenId); | |
addTokenTo(_to, _tokenId); | |
emit Transfer(_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( | |
bytes32 _from, | |
bytes32 _to, | |
uint256 _tokenId | |
) | |
public | |
{ | |
// solium-disable-next-line arg-overflow | |
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( | |
bytes32 _from, | |
bytes32 _to, | |
uint256 _tokenId, | |
bytes _data | |
) | |
public | |
{ | |
transferFrom(_from, _to, _tokenId); | |
// solium-disable-next-line arg-overflow | |
require(checkAndCallSafeTransfer(_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) { | |
bytes32 owner = tokenOwner[_tokenId]; | |
return ens.owner(owner) != address(0); // TODO: What is zero value of bytes32? | |
} | |
/** | |
* @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( | |
bytes32 _spender, | |
uint256 _tokenId | |
) | |
internal | |
view | |
returns (bool) | |
{ | |
bytes32 owner = ownerOf(_tokenId); | |
// Disable solium check because of | |
// https://github.com/duaraghav8/Solium/issues/175 | |
// solium-disable-next-line operator-whitespace | |
return ( | |
_spender == owner || | |
getApproved(_tokenId) == _spender || | |
isApprovedForAll(owner, _spender) | |
); | |
} | |
/** | |
* @dev Internal function to mint a new token | |
* Reverts if the given token ID already exists | |
* @param _to The address that will own the minted token | |
* @param _tokenId uint256 ID of the token to be minted by the msg.sender | |
*/ | |
function _mint(bytes32 _to, uint256 _tokenId) internal { | |
require(_to != address(0)); | |
addTokenTo(_to, _tokenId); | |
emit Transfer(address(0), _to, _tokenId); | |
} | |
/** | |
* @dev Internal function to burn a specific token | |
* Reverts if the token does not exist | |
* @param _tokenId uint256 ID of the token being burned by the msg.sender | |
*/ | |
function _burn(bytes32 _owner, uint256 _tokenId) internal { | |
clearApproval(_owner, _tokenId); | |
removeTokenFrom(_owner, _tokenId); | |
emit Transfer(_owner, address(0), _tokenId); | |
} | |
/** | |
* @dev Internal function to clear current approval of a given token ID | |
* Reverts if the given address is not indeed the owner of the token | |
* @param _owner owner of the token | |
* @param _tokenId uint256 ID of the token to be transferred | |
*/ | |
function clearApproval(bytes32 _owner, uint256 _tokenId) internal { | |
require(ownerOf(_tokenId) == _owner); | |
if (tokenApprovals[_tokenId] != address(0)) { | |
tokenApprovals[_tokenId] = address(0); | |
} | |
} | |
/** | |
* @dev Internal function to add a token ID to the list of a given address | |
* @param _to address representing the new owner of the given token ID | |
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address | |
*/ | |
function addTokenTo(bytes32 _to, uint256 _tokenId) internal { | |
require(tokenOwner[_tokenId] == 0); // TODO: What is zero value of bytes32? | |
tokenOwner[_tokenId] = _to; | |
ownedTokensCount[_to] = ownedTokensCount[_to].add(1); | |
} | |
/** | |
* @dev Internal function to remove a token ID from the list of a given address | |
* @param _from address representing the previous owner of the given token ID | |
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address | |
*/ | |
function removeTokenFrom(bytes32 _from, uint256 _tokenId) internal { | |
require(ownerOf(_tokenId) == _from); | |
ownedTokensCount[_from] = ownedTokensCount[_from].sub(1); | |
tokenOwner[_tokenId] = 0; // TODO: What is zero value of bytes32? | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment