Created
January 8, 2021 04:59
-
-
Save arlenner/d48a9b863f71bf792388d9dbcaf94f5d to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=undefined&optimize=undefined&runs=undefined&gist=
This file contains hidden or 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.6.2; | |
/** | |
* @dev Utility library of inline functions on addresses. | |
* @notice Based on: | |
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol | |
* Requires EIP-1052. | |
*/ | |
library AddressUtils | |
{ | |
/** | |
* @dev Returns whether the target address is a contract. | |
* @param _addr Address to check. | |
* @return addressCheck True if _addr is a contract, false if not. | |
*/ | |
function isContract( | |
address _addr | |
) | |
internal | |
view | |
returns (bool addressCheck) | |
{ | |
// This method relies in extcodesize, which returns 0 for contracts in | |
// construction, since the code is only stored at the end of the | |
// constructor execution. | |
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts | |
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned | |
// for accounts without code, i.e. `keccak256('')` | |
bytes32 codehash; | |
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; | |
assembly { codehash := extcodehash(_addr) } // solhint-disable-line | |
addressCheck = (codehash != 0x0 && codehash != accountHash); | |
} | |
} |
This file contains hidden or 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.4.25; | |
library ConvertLib{ | |
function convert(uint amount,uint conversionRate) public pure returns (uint convertedAmount) | |
{ | |
return amount * conversionRate; | |
} | |
} |
This file contains hidden or 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.4.0; | |
interface ERC165 { | |
/// @notice Query if a contract implements an interface | |
/// @param interfaceID The interface identifier, as specified in ERC-165 | |
/// @dev Interface identification is specified in ERC-165. This function | |
/// uses less than 30,000 gas. | |
/// @return `true` if the contract implements `interfaceID` and | |
/// `interfaceID` is not 0xffffffff, `false` otherwise | |
function supportsInterface(bytes4 interfaceID) external view returns (bool); | |
} |
This file contains hidden or 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.4.20; | |
/// @title ERC-721 Non-Fungible Token Standard | |
/// @dev See https://eips.ethereum.org/EIPS/eip-721 | |
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. | |
interface ERC721 /* is ERC165 */ { | |
// /// @dev This emits when ownership of any NFT changes by any mechanism. | |
// /// This event emits when NFTs are created (`from` == 0) and destroyed | |
// /// (`to` == 0). Exception: during contract creation, any number of NFTs | |
// /// may be created and assigned without emitting Transfer. At the time of | |
// /// any transfer, the approved address for that NFT (if any) is reset to none. | |
// event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); | |
// /// @dev This emits when the approved address for an NFT is changed or | |
// /// reaffirmed. The zero address indicates there is no approved address. | |
// /// When a Transfer event emits, this also indicates that the approved | |
// /// address for that NFT (if any) is reset to none. | |
// event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); | |
// /// @dev This emits when an operator is enabled or disabled for an owner. | |
// /// The operator can manage all NFTs of the owner. | |
// event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); | |
/// @notice Count all NFTs assigned to an owner | |
/// @dev NFTs assigned to the zero address are considered invalid, and this | |
/// function throws for queries about the zero address. | |
/// @param _owner An address for whom to query the balance | |
/// @return The number of NFTs owned by `_owner`, possibly zero | |
function balanceOf(address _owner) external view returns (uint256); | |
/// @notice Find the owner of an NFT | |
/// @dev NFTs assigned to zero address are considered invalid, and queries | |
/// about them do throw. | |
/// @param _tokenId The identifier for an NFT | |
/// @return The address of the owner of the NFT | |
function ownerOf(uint256 _tokenId) external view returns (address); | |
/// @notice Transfers the ownership of an NFT from one address to another address | |
/// @dev Throws unless `msg.sender` is the current owner, an authorized | |
/// operator, or the approved address for this NFT. Throws if `_from` is | |
/// not the current owner. Throws if `_to` is the zero address. Throws if | |
/// `_tokenId` is not a valid NFT. When transfer is complete, this function | |
/// checks if `_to` is a smart contract (code size > 0). If so, it calls | |
/// `onERC721Received` on `_to` and throws if the return value is not | |
/// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. | |
/// @param _from The current owner of the NFT | |
/// @param _to The new owner | |
/// @param _tokenId The NFT to transfer | |
/// @param data Additional data with no specified format, sent in call to `_to` | |
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; | |
/// @notice Transfers the ownership of an NFT from one address to another address | |
/// @dev This works identically to the other function with an extra data parameter, | |
/// except this function just sets data to "". | |
/// @param _from The current owner of the NFT | |
/// @param _to The new owner | |
/// @param _tokenId The NFT to transfer | |
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; | |
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE | |
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE | |
/// THEY MAY BE PERMANENTLY LOST | |
/// @dev Throws unless `msg.sender` is the current owner, an authorized | |
/// operator, or the approved address for this NFT. Throws if `_from` is | |
/// not the current owner. Throws if `_to` is the zero address. Throws if | |
/// `_tokenId` is not a valid NFT. | |
/// @param _from The current owner of the NFT | |
/// @param _to The new owner | |
/// @param _tokenId The NFT to transfer | |
function transferFrom(address _from, address _to, uint256 _tokenId) external payable; | |
/// @notice Change or reaffirm the approved address for an NFT | |
/// @dev The zero address indicates there is no approved address. | |
/// Throws unless `msg.sender` is the current NFT owner, or an authorized | |
/// operator of the current owner. | |
/// @param _approved The new approved NFT controller | |
/// @param _tokenId The NFT to approve | |
function approve(address _approved, uint256 _tokenId) external payable; | |
/// @notice Enable or disable approval for a third party ("operator") to manage | |
/// all of `msg.sender`'s assets | |
/// @dev Emits the ApprovalForAll event. The contract MUST allow | |
/// multiple operators per owner. | |
/// @param _operator Address to add to the set of authorized operators | |
/// @param _approved True if the operator is approved, false to revoke approval | |
function setApprovalForAll(address _operator, bool _approved) external; | |
/// @notice Get the approved address for a single NFT | |
/// @dev Throws if `_tokenId` is not a valid NFT. | |
/// @param _tokenId The NFT to find the approved address for | |
/// @return The approved address for this NFT, or the zero address if there is none | |
function getApproved(uint256 _tokenId) external view returns (address); | |
/// @notice Query if an address is an authorized operator for another address | |
/// @param _owner The address that owns the NFTs | |
/// @param _operator The address that acts on behalf of the owner | |
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise | |
function isApprovedForAll(address _owner, address _operator) external view returns (bool); | |
} | |
This file contains hidden or 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.4.0; | |
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension | |
/// @dev See https://eips.ethereum.org/EIPS/eip-721 | |
/// Note: the ERC-165 identifier for this interface is 0x780e9d63. | |
interface ERC721Enumerable /* is ERC721 */ { | |
/// @notice Count NFTs tracked by this contract | |
/// @return A count of valid NFTs tracked by this contract, where each one of | |
/// them has an assigned and queryable owner not equal to the zero address | |
function totalSupply() external view returns (uint256); | |
/// @notice Enumerate valid NFTs | |
/// @dev Throws if `_index` >= `totalSupply()`. | |
/// @param _index A counter less than `totalSupply()` | |
/// @return The token identifier for the `_index`th NFT, | |
/// (sort order not specified) | |
function tokenByIndex(uint256 _index) external view returns (uint256); | |
/// @notice Enumerate NFTs assigned to an owner | |
/// @dev Throws if `_index` >= `balanceOf(_owner)` or if | |
/// `_owner` is the zero address, representing invalid NFTs. | |
/// @param _owner An address where we are interested in NFTs owned by them | |
/// @param _index A counter less than `balanceOf(_owner)` | |
/// @return The token identifier for the `_index`th NFT assigned to `_owner`, | |
/// (sort order not specified) | |
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); | |
} |
This file contains hidden or 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.4.0; | |
/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension | |
/// @dev See https://eips.ethereum.org/EIPS/eip-721 | |
/// Note: the ERC-165 identifier for this interface is 0x5b5e139f. | |
interface ERC721Metadata /* is ERC721 */ { | |
/// @notice A descriptive name for a collection of NFTs in this contract | |
function name() external view returns (string memory _name); | |
/// @notice An abbreviated name for NFTs in this contract | |
function symbol() external view returns (string memory _symbol); | |
/// @notice A distinct Uniform Resource Identifier (URI) for a given asset. | |
/// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC | |
/// 3986. The URI may point to a JSON file that conforms to the "ERC721 | |
/// Metadata JSON Schema". | |
function tokenURI(uint256 _tokenId) external view returns (string memory); | |
} |
This file contains hidden or 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.6.2; | |
/** | |
* @dev ERC-721 interface for accepting safe transfers. | |
* See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md. | |
*/ | |
interface ERC721TokenReceiver | |
{ | |
/** | |
* @dev Handle the receipt of a NFT. The ERC721 smart contract calls this function on the | |
* recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return | |
* of other than the magic value MUST result in the transaction being reverted. | |
* Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` unless throwing. | |
* @notice The contract address is always the message sender. A wallet/broker/auction application | |
* MUST implement the wallet interface if it will accept safe transfers. | |
* @param _operator The address which called `safeTransferFrom` function. | |
* @param _from The address which previously owned the token. | |
* @param _tokenId The NFT identifier which is being transferred. | |
* @param _data Additional data with no specified format. | |
* @return Returns `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. | |
*/ | |
function onERC721Received( | |
address _operator, | |
address _from, | |
uint256 _tokenId, | |
bytes calldata _data | |
) | |
external | |
returns(bytes4); | |
} |
This file contains hidden or 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.6.2; | |
import "./ERC721.sol"; | |
import "./ERC721TokenReceiver.sol"; | |
import "./SafeMath.sol"; | |
import "./SupportsInterface.sol"; | |
import "./AddressUtils.sol"; | |
/** | |
* @dev Implementation of ERC-721 non-fungible token standard. | |
*/ | |
contract NFToken is | |
ERC721, | |
SupportsInterface | |
{ | |
using SafeMath for uint256; | |
using AddressUtils for address; | |
// | |
// List of revert message codes. Implementing dApp should handle showing the correct message. | |
// Based on 0xcert framework error codes. | |
// | |
string constant ZERO_ADDRESS = "003001"; | |
string constant NOT_VALID_NFT = "003002"; | |
string constant NOT_OWNER_OR_OPERATOR = "003003"; | |
string constant NOT_OWNER_APPROWED_OR_OPERATOR = "003004"; | |
string constant NOT_ABLE_TO_RECEIVE_NFT = "003005"; | |
string constant NFT_ALREADY_EXISTS = "003006"; | |
string constant NOT_OWNER = "003007"; | |
string constant IS_OWNER = "003008"; | |
/** | |
* @dev Magic value of a smart contract that can recieve NFT. | |
* Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")). | |
*/ | |
bytes4 internal constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02; | |
/** | |
* @dev A mapping from NFT ID to the address that owns it. | |
*/ | |
mapping (uint256 => address) internal idToOwner; | |
/** | |
* @dev Mapping from NFT ID to approved address. | |
*/ | |
mapping (uint256 => address) internal idToApproval; | |
/** | |
* @dev Mapping from owner address to count of his tokens. | |
*/ | |
mapping (address => uint256) private ownerToNFTokenCount; | |
/** | |
* @dev Mapping from owner address to mapping of operator addresses. | |
*/ | |
mapping (address => mapping (address => bool)) internal ownerToOperators; | |
/** | |
* @dev Emits when ownership of any NFT changes by any mechanism. This event emits when NFTs are | |
* created (`from` == 0) and destroyed (`to` == 0). Exception: during contract creation, any | |
* number of NFTs may be created and assigned without emitting Transfer. At the time of any | |
* transfer, the approved address for that NFT (if any) is reset to none. | |
* @param _from Sender of NFT (if address is zero address it indicates token creation). | |
* @param _to Receiver of NFT (if address is zero address it indicates token destruction). | |
* @param _tokenId The NFT that got transfered. | |
*/ | |
event Transfer( | |
address indexed _from, | |
address indexed _to, | |
uint256 indexed _tokenId | |
); | |
/** | |
* @dev This emits when the approved address for an NFT is changed or reaffirmed. The zero | |
* address indicates there is no approved address. When a Transfer event emits, this also | |
* indicates that the approved address for that NFT (if any) is reset to none. | |
* @param _owner Owner of NFT. | |
* @param _approved Address that we are approving. | |
* @param _tokenId NFT which we are approving. | |
*/ | |
event Approval( | |
address indexed _owner, | |
address indexed _approved, | |
uint256 indexed _tokenId | |
); | |
/** | |
* @dev This emits when an operator is enabled or disabled for an owner. The operator can manage | |
* all NFTs of the owner. | |
* @param _owner Owner of NFT. | |
* @param _operator Address to which we are setting operator rights. | |
* @param _approved Status of operator rights(true if operator rights are given and false if | |
* revoked). | |
*/ | |
event ApprovalForAll( | |
address indexed _owner, | |
address indexed _operator, | |
bool _approved | |
); | |
/** | |
* @dev Guarantees that the msg.sender is an owner or operator of the given NFT. | |
* @param _tokenId ID of the NFT to validate. | |
*/ | |
modifier canOperate( | |
uint256 _tokenId | |
) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require(tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender], NOT_OWNER_OR_OPERATOR); | |
_; | |
} | |
/** | |
* @dev Guarantees that the msg.sender is allowed to transfer NFT. | |
* @param _tokenId ID of the NFT to transfer. | |
*/ | |
modifier canTransfer( | |
uint256 _tokenId | |
) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require( | |
tokenOwner == msg.sender | |
|| idToApproval[_tokenId] == msg.sender | |
|| ownerToOperators[tokenOwner][msg.sender], | |
NOT_OWNER_APPROWED_OR_OPERATOR | |
); | |
_; | |
} | |
/** | |
* @dev Guarantees that _tokenId is a valid Token. | |
* @param _tokenId ID of the NFT to validate. | |
*/ | |
modifier validNFToken( | |
uint256 _tokenId | |
) | |
{ | |
require(idToOwner[_tokenId] != address(0), NOT_VALID_NFT); | |
_; | |
} | |
/** | |
* @dev Contract constructor. | |
*/ | |
constructor() | |
{ | |
supportedInterfaces[0x80ac58cd] = true; // ERC721 | |
} | |
/** | |
* @dev Transfers the ownership of an NFT from one address to another address. This function can | |
* be changed to payable. | |
* @notice Throws unless `msg.sender` is the current owner, an authorized operator, or the | |
* approved address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is | |
* the zero address. Throws if `_tokenId` is not a valid NFT. When transfer is complete, this | |
* function checks if `_to` is a smart contract (code size > 0). If so, it calls | |
* `onERC721Received` on `_to` and throws if the return value is not | |
* `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
* @param _data Additional data with no specified format, sent in call to `_to`. | |
*/ | |
function safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId, | |
bytes calldata _data | |
) | |
external | |
override | |
payable | |
{ | |
_safeTransferFrom(_from, _to, _tokenId, _data); | |
} | |
/** | |
* @dev Transfers the ownership of an NFT from one address to another address. This function can | |
* be changed to payable. | |
* @notice This works identically to the other function with an extra data parameter, except this | |
* function just sets data to "" | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
*/ | |
function safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId | |
) | |
external | |
override | |
payable | |
{ | |
_safeTransferFrom(_from, _to, _tokenId, ""); | |
} | |
/** | |
* @dev Throws unless `msg.sender` is the current owner, an authorized operator, or the approved | |
* address for this NFT. Throws if `_from` is not the current owner. Throws if `_to` is the zero | |
* address. Throws if `_tokenId` is not a valid NFT. This function can be changed to payable. | |
* @notice The caller is responsible to confirm that `_to` is capable of receiving NFTs or else | |
* they maybe be permanently lost. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
*/ | |
function transferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId | |
) | |
external | |
override | |
payable | |
canTransfer(_tokenId) | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require(tokenOwner == _from, NOT_OWNER); | |
require(_to != address(0), ZERO_ADDRESS); | |
_transfer(_to, _tokenId); | |
} | |
/** | |
* @dev Set or reaffirm the approved address for an NFT. This function can be changed to payable. | |
* @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is | |
* the current NFT owner, or an authorized operator of the current owner. | |
* @param _approved Address to be approved for the given NFT ID. | |
* @param _tokenId ID of the token to be approved. | |
*/ | |
function approve( | |
address _approved, | |
uint256 _tokenId | |
) | |
external | |
override | |
payable | |
canOperate(_tokenId) | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require(_approved != tokenOwner, IS_OWNER); | |
idToApproval[_tokenId] = _approved; | |
emit Approval(tokenOwner, _approved, _tokenId); | |
} | |
/** | |
* @dev Enables or disables approval for a third party ("operator") to manage all of | |
* `msg.sender`'s assets. It also emits the ApprovalForAll event. | |
* @notice This works even if sender doesn't own any tokens at the time. | |
* @param _operator Address to add to the set of authorized operators. | |
* @param _approved True if the operators is approved, false to revoke approval. | |
*/ | |
function setApprovalForAll( | |
address _operator, | |
bool _approved | |
) | |
external | |
override | |
{ | |
ownerToOperators[msg.sender][_operator] = _approved; | |
emit ApprovalForAll(msg.sender, _operator, _approved); | |
} | |
/** | |
* @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are | |
* considered invalid, and this function throws for queries about the zero address. | |
* @param _owner Address for whom to query the balance. | |
* @return Balance of _owner. | |
*/ | |
function balanceOf( | |
address _owner | |
) | |
external | |
override | |
view | |
returns (uint256) | |
{ | |
require(_owner != address(0), ZERO_ADDRESS); | |
return _getOwnerNFTCount(_owner); | |
} | |
/** | |
* @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered | |
* invalid, and queries about them do throw. | |
* @param _tokenId The identifier for an NFT. | |
* @return _owner Address of _tokenId owner. | |
*/ | |
function ownerOf( | |
uint256 _tokenId | |
) | |
external | |
override | |
view | |
returns (address _owner) | |
{ | |
_owner = idToOwner[_tokenId]; | |
require(_owner != address(0), NOT_VALID_NFT); | |
} | |
/** | |
* @dev Get the approved address for a single NFT. | |
* @notice Throws if `_tokenId` is not a valid NFT. | |
* @param _tokenId ID of the NFT to query the approval of. | |
* @return Address that _tokenId is approved for. | |
*/ | |
function getApproved( | |
uint256 _tokenId | |
) | |
external | |
override | |
view | |
validNFToken(_tokenId) | |
returns (address) | |
{ | |
return idToApproval[_tokenId]; | |
} | |
/** | |
* @dev Checks if `_operator` is an approved operator for `_owner`. | |
* @param _owner The address that owns the NFTs. | |
* @param _operator The address that acts on behalf of the owner. | |
* @return True if approved for all, false otherwise. | |
*/ | |
function isApprovedForAll( | |
address _owner, | |
address _operator | |
) | |
external | |
override | |
view | |
returns (bool) | |
{ | |
return ownerToOperators[_owner][_operator]; | |
} | |
/** | |
* @dev Actually preforms the transfer. | |
* @notice Does NO checks. | |
* @param _to Address of a new owner. | |
* @param _tokenId The NFT that is being transferred. | |
*/ | |
function _transfer( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
{ | |
address from = idToOwner[_tokenId]; | |
_clearApproval(_tokenId); | |
_removeNFToken(from, _tokenId); | |
_addNFToken(_to, _tokenId); | |
emit Transfer(from, _to, _tokenId); | |
} | |
/** | |
* @dev Mints a new NFT. | |
* @notice This is an internal function which should be called from user-implemented external | |
* mint function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. | |
* @param _to The address that will own the minted NFT. | |
* @param _tokenId of the NFT to be minted by the msg.sender. | |
*/ | |
function _mint( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
{ | |
require(_to != address(0), ZERO_ADDRESS); | |
require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS); | |
_addNFToken(_to, _tokenId); | |
emit Transfer(address(0), _to, _tokenId); | |
} | |
/** | |
* @dev Burns a NFT. | |
* @notice This is an internal function which should be called from user-implemented external burn | |
* function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. Also, note that this burn implementation allows the minter to re-mint a burned | |
* NFT. | |
* @param _tokenId ID of the NFT to be burned. | |
*/ | |
function _burn( | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
_clearApproval(_tokenId); | |
_removeNFToken(tokenOwner, _tokenId); | |
emit Transfer(tokenOwner, address(0), _tokenId); | |
} | |
/** | |
* @dev Removes a NFT from owner. | |
* @notice Use and override this function with caution. Wrong usage can have serious consequences. | |
* @param _from Address from wich we want to remove the NFT. | |
* @param _tokenId Which NFT we want to remove. | |
*/ | |
function _removeNFToken( | |
address _from, | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
{ | |
require(idToOwner[_tokenId] == _from, NOT_OWNER); | |
ownerToNFTokenCount[_from] = ownerToNFTokenCount[_from] - 1; | |
delete idToOwner[_tokenId]; | |
} | |
/** | |
* @dev Assignes a new NFT to owner. | |
* @notice Use and override this function with caution. Wrong usage can have serious consequences. | |
* @param _to Address to wich we want to add the NFT. | |
* @param _tokenId Which NFT we want to add. | |
*/ | |
function _addNFToken( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
virtual | |
{ | |
require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS); | |
idToOwner[_tokenId] = _to; | |
ownerToNFTokenCount[_to] = ownerToNFTokenCount[_to].add(1); | |
} | |
/** | |
* @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable | |
* extension to remove double storage (gas optimization) of owner nft count. | |
* @param _owner Address for whom to query the count. | |
* @return Number of _owner NFTs. | |
*/ | |
function _getOwnerNFTCount( | |
address _owner | |
) | |
internal | |
virtual | |
view | |
returns (uint256) | |
{ | |
return ownerToNFTokenCount[_owner]; | |
} | |
/** | |
* @dev Actually perform the safeTransferFrom. | |
* @param _from The current owner of the NFT. | |
* @param _to The new owner. | |
* @param _tokenId The NFT to transfer. | |
* @param _data Additional data with no specified format, sent in call to `_to`. | |
*/ | |
function _safeTransferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId, | |
bytes memory _data | |
) | |
private | |
canTransfer(_tokenId) | |
validNFToken(_tokenId) | |
{ | |
address tokenOwner = idToOwner[_tokenId]; | |
require(tokenOwner == _from, NOT_OWNER); | |
require(_to != address(0), ZERO_ADDRESS); | |
_transfer(_to, _tokenId); | |
if (_to.isContract()) | |
{ | |
bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data); | |
require(retval == MAGIC_ON_ERC721_RECEIVED, NOT_ABLE_TO_RECEIVE_NFT); | |
} | |
} | |
/** | |
* @dev Clears the current approval of a given NFT ID. | |
* @param _tokenId ID of the NFT to be transferred. | |
*/ | |
function _clearApproval( | |
uint256 _tokenId | |
) | |
private | |
{ | |
if (idToApproval[_tokenId] != address(0)) | |
{ | |
delete idToApproval[_tokenId]; | |
} | |
} | |
} |
This file contains hidden or 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.6.2; | |
import "./NFToken.sol"; | |
import "./ERC721Enumerable.sol"; | |
/** | |
* @dev Optional enumeration implementation for ERC-721 non-fungible token standard. | |
*/ | |
contract NFTokenEnumerable is | |
NFToken, | |
ERC721Enumerable | |
{ | |
/** | |
* List of revert message codes. Implementing dApp should handle showing the correct message. | |
* Based on 0xcert framework error codes. | |
*/ | |
string constant INVALID_INDEX = "005007"; | |
/** | |
* @dev Array of all NFT IDs. | |
*/ | |
uint256[] internal tokens; | |
/** | |
* @dev Mapping from token ID to its index in global tokens array. | |
*/ | |
mapping(uint256 => uint256) internal idToIndex; | |
/** | |
* @dev Mapping from owner to list of owned NFT IDs. | |
*/ | |
mapping(address => uint256[]) internal ownerToIds; | |
/** | |
* @dev Mapping from NFT ID to its index in the owner tokens list. | |
*/ | |
mapping(uint256 => uint256) internal idToOwnerIndex; | |
/** | |
* @dev Contract constructor. | |
*/ | |
constructor() | |
public | |
{ | |
supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable | |
} | |
/** | |
* @dev Returns the count of all existing NFTokens. | |
* @return Total supply of NFTs. | |
*/ | |
function totalSupply() | |
external | |
override | |
view | |
returns (uint256) | |
{ | |
return tokens.length; | |
} | |
/** | |
* @dev Returns NFT ID by its index. | |
* @param _index A counter less than `totalSupply()`. | |
* @return Token id. | |
*/ | |
function tokenByIndex( | |
uint256 _index | |
) | |
external | |
override | |
view | |
returns (uint256) | |
{ | |
require(_index < tokens.length, INVALID_INDEX); | |
return tokens[_index]; | |
} | |
/** | |
* @dev returns the n-th NFT ID from a list of owner's tokens. | |
* @param _owner Token owner's address. | |
* @param _index Index number representing n-th token in owner's list of tokens. | |
* @return Token id. | |
*/ | |
function tokenOfOwnerByIndex( | |
address _owner, | |
uint256 _index | |
) | |
external | |
override | |
view | |
returns (uint256) | |
{ | |
require(_index < ownerToIds[_owner].length, INVALID_INDEX); | |
return ownerToIds[_owner][_index]; | |
} | |
/** | |
* @dev Mints a new NFT. | |
* @notice This is an internal function which should be called from user-implemented external | |
* mint function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. | |
* @param _to The address that will own the minted NFT. | |
* @param _tokenId of the NFT to be minted by the msg.sender. | |
*/ | |
function _mint( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
override | |
virtual | |
{ | |
super._mint(_to, _tokenId); | |
tokens.push(_tokenId); | |
idToIndex[_tokenId] = tokens.length - 1; | |
} | |
/** | |
* @dev Burns a NFT. | |
* @notice This is an internal function which should be called from user-implemented external | |
* burn function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. Also, note that this burn implementation allows the minter to re-mint a burned | |
* NFT. | |
* @param _tokenId ID of the NFT to be burned. | |
*/ | |
function _burn( | |
uint256 _tokenId | |
) | |
internal | |
override | |
virtual | |
{ | |
super._burn(_tokenId); | |
uint256 tokenIndex = idToIndex[_tokenId]; | |
uint256 lastTokenIndex = tokens.length - 1; | |
uint256 lastToken = tokens[lastTokenIndex]; | |
tokens[tokenIndex] = lastToken; | |
tokens.pop(); | |
// This wastes gas if you are burning the last token but saves a little gas if you are not. | |
idToIndex[lastToken] = tokenIndex; | |
idToIndex[_tokenId] = 0; | |
} | |
/** | |
* @dev Removes a NFT from an address. | |
* @notice Use and override this function with caution. Wrong usage can have serious consequences. | |
* @param _from Address from wich we want to remove the NFT. | |
* @param _tokenId Which NFT we want to remove. | |
*/ | |
function _removeNFToken( | |
address _from, | |
uint256 _tokenId | |
) | |
internal | |
override | |
virtual | |
{ | |
require(idToOwner[_tokenId] == _from, NOT_OWNER); | |
delete idToOwner[_tokenId]; | |
uint256 tokenToRemoveIndex = idToOwnerIndex[_tokenId]; | |
uint256 lastTokenIndex = ownerToIds[_from].length - 1; | |
if (lastTokenIndex != tokenToRemoveIndex) | |
{ | |
uint256 lastToken = ownerToIds[_from][lastTokenIndex]; | |
ownerToIds[_from][tokenToRemoveIndex] = lastToken; | |
idToOwnerIndex[lastToken] = tokenToRemoveIndex; | |
} | |
ownerToIds[_from].pop(); | |
} | |
/** | |
* @dev Assignes a new NFT to an address. | |
* @notice Use and override this function with caution. Wrong usage can have serious consequences. | |
* @param _to Address to wich we want to add the NFT. | |
* @param _tokenId Which NFT we want to add. | |
*/ | |
function _addNFToken( | |
address _to, | |
uint256 _tokenId | |
) | |
internal | |
override | |
virtual | |
{ | |
require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS); | |
idToOwner[_tokenId] = _to; | |
ownerToIds[_to].push(_tokenId); | |
idToOwnerIndex[_tokenId] = ownerToIds[_to].length - 1; | |
} | |
/** | |
* @dev Helper function that gets NFT count of owner. This is needed for overriding in enumerable | |
* extension to remove double storage(gas optimization) of owner nft count. | |
* @param _owner Address for whom to query the count. | |
* @return Number of _owner NFTs. | |
*/ | |
function _getOwnerNFTCount( | |
address _owner | |
) | |
internal | |
override | |
virtual | |
view | |
returns (uint256) | |
{ | |
return ownerToIds[_owner].length; | |
} | |
} |
This file contains hidden or 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.6.2; | |
import "./NFToken.sol"; | |
import "./ERC721Metadata.sol"; | |
/** | |
* @dev Optional metadata implementation for ERC-721 non-fungible token standard. | |
*/ | |
contract NFTokenMetadata is | |
NFToken, | |
ERC721Metadata | |
{ | |
/** | |
* @dev A descriptive name for a collection of NFTs. | |
*/ | |
string internal nftName; | |
/** | |
* @dev An abbreviated name for NFTokens. | |
*/ | |
string internal nftSymbol; | |
/** | |
* @dev Mapping from NFT ID to metadata uri. | |
*/ | |
mapping (uint256 => string) internal idToUri; | |
/** | |
* @dev Contract constructor. | |
* @notice When implementing this contract don't forget to set nftName and nftSymbol. | |
*/ | |
constructor() | |
public | |
{ | |
supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata | |
} | |
/** | |
* @dev Returns a descriptive name for a collection of NFTokens. | |
* @return _name Representing name. | |
*/ | |
function name() | |
external | |
override | |
view | |
returns (string memory _name) | |
{ | |
_name = nftName; | |
} | |
/** | |
* @dev Returns an abbreviated name for NFTokens. | |
* @return _symbol Representing symbol. | |
*/ | |
function symbol() | |
external | |
override | |
view | |
returns (string memory _symbol) | |
{ | |
_symbol = nftSymbol; | |
} | |
/** | |
* @dev A distinct URI (RFC 3986) for a given NFT. | |
* @param _tokenId Id for which we want uri. | |
* @return URI of _tokenId. | |
*/ | |
function tokenURI( | |
uint256 _tokenId | |
) | |
external | |
override | |
view | |
validNFToken(_tokenId) | |
returns (string memory) | |
{ | |
return idToUri[_tokenId]; | |
} | |
/** | |
* @dev Burns a NFT. | |
* @notice This is an internal function which should be called from user-implemented external | |
* burn function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. Also, note that this burn implementation allows the minter to re-mint a burned | |
* NFT. | |
* @param _tokenId ID of the NFT to be burned. | |
*/ | |
function _burn( | |
uint256 _tokenId | |
) | |
internal | |
override | |
virtual | |
{ | |
super._burn(_tokenId); | |
if (bytes(idToUri[_tokenId]).length != 0) | |
{ | |
delete idToUri[_tokenId]; | |
} | |
} | |
/** | |
* @dev Set a distinct URI (RFC 3986) for a given NFT ID. | |
* @notice This is an internal function which should be called from user-implemented external | |
* function. Its purpose is to show and properly initialize data structures when using this | |
* implementation. | |
* @param _tokenId Id for which we want URI. | |
* @param _uri String representing RFC 3986 URI. | |
*/ | |
function _setTokenUri( | |
uint256 _tokenId, | |
string memory _uri | |
) | |
internal | |
validNFToken(_tokenId) | |
{ | |
idToUri[_tokenId] = _uri; | |
} | |
} |
This file contains hidden or 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.6.2; | |
/** | |
* @dev Math operations with safety checks that throw on error. This contract is based on the | |
* source code at: | |
* https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol. | |
*/ | |
library SafeMath | |
{ | |
// | |
// List of revert message codes. Implementing dApp should handle showing the correct message. | |
// Based on 0xcert framework error codes. | |
// | |
string constant OVERFLOW = "008001"; | |
string constant SUBTRAHEND_GREATER_THEN_MINUEND = "008002"; | |
string constant DIVISION_BY_ZERO = "008003"; | |
/** | |
* @dev Multiplies two numbers, reverts on overflow. | |
* @param _factor1 Factor number. | |
* @param _factor2 Factor number. | |
* @return product The product of the two factors. | |
*/ | |
function mul( | |
uint256 _factor1, | |
uint256 _factor2 | |
) | |
internal | |
pure | |
returns (uint256 product) | |
{ | |
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the | |
// benefit is lost if 'b' is also tested. | |
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 | |
if (_factor1 == 0) | |
{ | |
return 0; | |
} | |
product = _factor1 * _factor2; | |
require(product / _factor1 == _factor2, OVERFLOW); | |
} | |
/** | |
* @dev Integer division of two numbers, truncating the quotient, reverts on division by zero. | |
* @param _dividend Dividend number. | |
* @param _divisor Divisor number. | |
* @return quotient The quotient. | |
*/ | |
function div( | |
uint256 _dividend, | |
uint256 _divisor | |
) | |
internal | |
pure | |
returns (uint256 quotient) | |
{ | |
// Solidity automatically asserts when dividing by 0, using all gas. | |
require(_divisor > 0, DIVISION_BY_ZERO); | |
quotient = _dividend / _divisor; | |
// assert(_dividend == _divisor * quotient + _dividend % _divisor); // There is no case in which this doesn't hold. | |
} | |
/** | |
* @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). | |
* @param _minuend Minuend number. | |
* @param _subtrahend Subtrahend number. | |
* @return difference Difference. | |
*/ | |
function sub( | |
uint256 _minuend, | |
uint256 _subtrahend | |
) | |
internal | |
pure | |
returns (uint256 difference) | |
{ | |
require(_subtrahend <= _minuend, SUBTRAHEND_GREATER_THEN_MINUEND); | |
difference = _minuend - _subtrahend; | |
} | |
/** | |
* @dev Adds two numbers, reverts on overflow. | |
* @param _addend1 Number. | |
* @param _addend2 Number. | |
* @return sum Sum. | |
*/ | |
function add( | |
uint256 _addend1, | |
uint256 _addend2 | |
) | |
internal | |
pure | |
returns (uint256 sum) | |
{ | |
sum = _addend1 + _addend2; | |
require(sum >= _addend1, OVERFLOW); | |
} | |
/** | |
* @dev Divides two numbers and returns the remainder (unsigned integer modulo), reverts when | |
* dividing by zero. | |
* @param _dividend Number. | |
* @param _divisor Number. | |
* @return remainder Remainder. | |
*/ | |
function mod( | |
uint256 _dividend, | |
uint256 _divisor | |
) | |
internal | |
pure | |
returns (uint256 remainder) | |
{ | |
require(_divisor != 0, DIVISION_BY_ZERO); | |
remainder = _dividend % _divisor; | |
} | |
} |
This file contains hidden or 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.6.2; | |
import "./ERC165.sol"; | |
/** | |
* @dev Implementation of standard for detect smart contract interfaces. | |
*/ | |
contract SupportsInterface is ERC165 { | |
/** | |
* @dev Mapping of supported intefraces. | |
* *notice You must not set element 0xffffffff to true. | |
*/ | |
mapping(bytes4 => bool) internal supportedInterfaces; | |
/** | |
* @dev Contract constructor. | |
*/ | |
constructor() { | |
supportedInterfaces[0x01ffc9a7] = true; // ERC165 | |
} | |
/** | |
* @dev Function to check which interfaces are suported by this contract. | |
* @param _interfaceID Id of the interface. | |
* @return True if _interfaceID is supported, false otherwise. | |
*/ | |
function supportsInterface(bytes4 _interfaceID) | |
external | |
override | |
view | |
returns (bool) | |
{ | |
return supportedInterfaces[_interfaceID]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment