├── contracts ├── IERC721Receiver.sol ├── IKIP17.sol ├── IKIP17Enumerable.sol ├── IKIP17Full.sol ├── IKIP17Metadata.sol ├── IKIP17Receiver.sol ├── KIP17.sol ├── KIP17Burnable.sol ├── KIP17Enumerable.sol ├── KIP17Full.sol ├── KIP17Kbirdz.sol ├── KIP17KbirdzToken.sol ├── KIP17Metadata.sol ├── KIP17MetadataMintable.sol ├── KIP17Mintable.sol ├── KIP17Pausable.sol ├── KIP17Token.sol ├── MerkleProof.sol ├── drafts │ └── Counters.sol ├── introspection │ ├── IKIP13.sol │ ├── KIP13.sol │ └── KIP13Checker.sol ├── lifecycle │ └── Pausable.sol ├── math │ └── SafeMath.sol ├── ownership │ └── Ownable.sol ├── roles │ ├── MinterRole.sol │ ├── PauserRole.sol │ └── Roles.sol └── utils │ ├── Address.sol │ └── String.sol ├── flatten └── KIP17KbirdzTokenFlatten.sol ├── migrations └── 1_initial_migration.js ├── test └── .gitkeep └── truffle-config.js /contracts/IERC721Receiver.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @title ERC721 token receiver interface 5 | * @dev Interface for any contract that wants to support safeTransfers 6 | * from ERC721 asset contracts. 7 | */ 8 | contract IERC721Receiver { 9 | /** 10 | * @notice Handle the receipt of an NFT 11 | * @dev The ERC721 smart contract calls this function on the recipient 12 | * after a `safeTransfer`. This function MUST return the function selector, 13 | * otherwise the caller will revert the transaction. The selector to be 14 | * returned can be obtained as `this.onERC721Received.selector`. This 15 | * function MAY throw to revert and reject the transfer. 16 | * Note: the ERC721 contract address is always the message sender. 17 | * @param operator The address which called `safeTransferFrom` function 18 | * @param from The address which previously owned the token 19 | * @param tokenId The NFT identifier which is being transferred 20 | * @param data Additional data with no specified format 21 | * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 22 | */ 23 | function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) 24 | public returns (bytes4); 25 | } 26 | -------------------------------------------------------------------------------- /contracts/IKIP17.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./introspection/IKIP13.sol"; 4 | 5 | /** 6 | * @dev Required interface of an KIP17 compliant contract. 7 | */ 8 | contract IKIP17 is IKIP13 { 9 | event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 10 | event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); 11 | event ApprovalForAll(address indexed owner, address indexed operator, bool approved); 12 | 13 | /** 14 | * @dev Returns the number of NFTs in `owner`'s account. 15 | */ 16 | function balanceOf(address owner) public view returns (uint256 balance); 17 | 18 | /** 19 | * @dev Returns the owner of the NFT specified by `tokenId`. 20 | */ 21 | function ownerOf(uint256 tokenId) public view returns (address owner); 22 | 23 | /** 24 | * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to 25 | * another (`to`). 26 | * 27 | * Requirements: 28 | * - `from`, `to` cannot be zero. 29 | * - `tokenId` must be owned by `from`. 30 | * - If the caller is not `from`, it must be have been allowed to move this 31 | * NFT by either `approve` or `setApproveForAll`. 32 | */ 33 | function safeTransferFrom(address from, address to, uint256 tokenId) public; 34 | 35 | /** 36 | * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to 37 | * another (`to`). 38 | * 39 | * Requirements: 40 | * - If the caller is not `from`, it must be approved to move this NFT by 41 | * either `approve` or `setApproveForAll`. 42 | */ 43 | function transferFrom(address from, address to, uint256 tokenId) public; 44 | function approve(address to, uint256 tokenId) public; 45 | function getApproved(uint256 tokenId) public view returns (address operator); 46 | 47 | function setApprovalForAll(address operator, bool _approved) public; 48 | function isApprovedForAll(address owner, address operator) public view returns (bool); 49 | 50 | 51 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; 52 | } 53 | -------------------------------------------------------------------------------- /contracts/IKIP17Enumerable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IKIP17.sol"; 4 | 5 | /** 6 | * @title KIP-17 Non-Fungible Token Standard, optional enumeration extension 7 | * @dev See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 8 | */ 9 | contract IKIP17Enumerable is IKIP17 { 10 | function totalSupply() public view returns (uint256); 11 | function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId); 12 | 13 | function tokenByIndex(uint256 index) public view returns (uint256); 14 | } 15 | -------------------------------------------------------------------------------- /contracts/IKIP17Full.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IKIP17.sol"; 4 | import "./IKIP17Enumerable.sol"; 5 | import "./IKIP17Metadata.sol"; 6 | 7 | /** 8 | * @title KIP-17 Non-Fungible Token Standard, full implementation interface 9 | * @dev See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 10 | */ 11 | contract IKIP17Full is IKIP17, IKIP17Enumerable, IKIP17Metadata { 12 | // solhint-disable-previous-line no-empty-blocks 13 | } 14 | -------------------------------------------------------------------------------- /contracts/IKIP17Metadata.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IKIP17.sol"; 4 | 5 | /** 6 | * @title KIP-17 Non-Fungible Token Standard, optional metadata extension 7 | * @dev See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 8 | */ 9 | contract IKIP17Metadata is IKIP17 { 10 | function name() external view returns (string memory); 11 | function symbol() external view returns (string memory); 12 | function tokenURI(uint256 tokenId) external view returns (string memory); 13 | } 14 | -------------------------------------------------------------------------------- /contracts/IKIP17Receiver.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @title KIP17 token receiver interface 5 | * @dev Interface for any contract that wants to support safeTransfers 6 | * from KIP17 asset contracts. 7 | * @dev see http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 8 | */ 9 | contract IKIP17Receiver { 10 | /** 11 | * @notice Handle the receipt of an NFT 12 | * @dev The KIP17 smart contract calls this function on the recipient 13 | * after a `safeTransfer`. This function MUST return the function selector, 14 | * otherwise the caller will revert the transaction. The selector to be 15 | * returned can be obtained as `this.onKIP17Received.selector`. This 16 | * function MAY throw to revert and reject the transfer. 17 | * Note: the KIP17 contract address is always the message sender. 18 | * @param operator The address which called `safeTransferFrom` function 19 | * @param from The address which previously owned the token 20 | * @param tokenId The NFT identifier which is being transferred 21 | * @param data Additional data with no specified format 22 | * @return bytes4 `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))` 23 | */ 24 | function onKIP17Received(address operator, address from, uint256 tokenId, bytes memory data) 25 | public returns (bytes4); 26 | } 27 | -------------------------------------------------------------------------------- /contracts/KIP17.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IKIP17.sol"; 4 | import "./IERC721Receiver.sol"; 5 | import "./IKIP17Receiver.sol"; 6 | import "./math/SafeMath.sol"; 7 | import "./utils/Address.sol"; 8 | import "./drafts/Counters.sol"; 9 | import "./introspection/KIP13.sol"; 10 | 11 | /** 12 | * @title KIP17 Non-Fungible Token Standard basic implementation 13 | * @dev see http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 14 | */ 15 | contract KIP17 is KIP13, IKIP17 { 16 | using SafeMath for uint256; 17 | using Address for address; 18 | using Counters for Counters.Counter; 19 | 20 | // Equals to `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))` 21 | // which can be also obtained as `IKIP17Receiver(0).onKIP17Received.selector` 22 | bytes4 private constant _KIP17_RECEIVED = 0x6745782b; 23 | 24 | // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 25 | // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` 26 | bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; 27 | 28 | // Mapping from token ID to owner 29 | mapping (uint256 => address) private _tokenOwner; 30 | 31 | // Mapping from token ID to approved address 32 | mapping (uint256 => address) private _tokenApprovals; 33 | 34 | // Mapping from owner to number of owned token 35 | mapping (address => Counters.Counter) private _ownedTokensCount; 36 | 37 | // Mapping from owner to operator approvals 38 | mapping (address => mapping (address => bool)) private _operatorApprovals; 39 | 40 | /* 41 | * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 42 | * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e 43 | * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 44 | * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc 45 | * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 46 | * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c 47 | * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd 48 | * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e 49 | * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde 50 | * 51 | * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ 52 | * 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd 53 | */ 54 | bytes4 private constant _INTERFACE_ID_KIP17 = 0x80ac58cd; 55 | 56 | constructor () public { 57 | // register the supported interfaces to conform to KIP17 via KIP13 58 | _registerInterface(_INTERFACE_ID_KIP17); 59 | } 60 | 61 | /** 62 | * @dev Gets the balance of the specified address. 63 | * @param owner address to query the balance of 64 | * @return uint256 representing the amount owned by the passed address 65 | */ 66 | function balanceOf(address owner) public view returns (uint256) { 67 | require(owner != address(0), "KIP17: balance query for the zero address"); 68 | 69 | return _ownedTokensCount[owner].current(); 70 | } 71 | 72 | /** 73 | * @dev Gets the owner of the specified token ID. 74 | * @param tokenId uint256 ID of the token to query the owner of 75 | * @return address currently marked as the owner of the given token ID 76 | */ 77 | function ownerOf(uint256 tokenId) public view returns (address) { 78 | address owner = _tokenOwner[tokenId]; 79 | require(owner != address(0), "KIP17: owner query for nonexistent token"); 80 | 81 | return owner; 82 | } 83 | 84 | /** 85 | * @dev Approves another address to transfer the given token ID 86 | * The zero address indicates there is no approved address. 87 | * There can only be one approved address per token at a given time. 88 | * Can only be called by the token owner or an approved operator. 89 | * @param to address to be approved for the given token ID 90 | * @param tokenId uint256 ID of the token to be approved 91 | */ 92 | function approve(address to, uint256 tokenId) public { 93 | address owner = ownerOf(tokenId); 94 | require(to != owner, "KIP17: approval to current owner"); 95 | 96 | require(msg.sender == owner || isApprovedForAll(owner, msg.sender), 97 | "KIP17: approve caller is not owner nor approved for all" 98 | ); 99 | 100 | _tokenApprovals[tokenId] = to; 101 | emit Approval(owner, to, tokenId); 102 | } 103 | 104 | /** 105 | * @dev Gets the approved address for a token ID, or zero if no address set 106 | * Reverts if the token ID does not exist. 107 | * @param tokenId uint256 ID of the token to query the approval of 108 | * @return address currently approved for the given token ID 109 | */ 110 | function getApproved(uint256 tokenId) public view returns (address) { 111 | require(_exists(tokenId), "KIP17: approved query for nonexistent token"); 112 | 113 | return _tokenApprovals[tokenId]; 114 | } 115 | 116 | /** 117 | * @dev Sets or unsets the approval of a given operator 118 | * An operator is allowed to transfer all tokens of the sender on their behalf. 119 | * @param to operator address to set the approval 120 | * @param approved representing the status of the approval to be set 121 | */ 122 | function setApprovalForAll(address to, bool approved) public { 123 | require(to != msg.sender, "KIP17: approve to caller"); 124 | 125 | _operatorApprovals[msg.sender][to] = approved; 126 | emit ApprovalForAll(msg.sender, to, approved); 127 | } 128 | 129 | /** 130 | * @dev Tells whether an operator is approved by a given owner. 131 | * @param owner owner address which you want to query the approval of 132 | * @param operator operator address which you want to query the approval of 133 | * @return bool whether the given operator is approved by the given owner 134 | */ 135 | function isApprovedForAll(address owner, address operator) public view returns (bool) { 136 | return _operatorApprovals[owner][operator]; 137 | } 138 | 139 | /** 140 | * @dev Transfers the ownership of a given token ID to another address. 141 | * Usage of this method is discouraged, use `safeTransferFrom` whenever possible. 142 | * Requires the msg.sender to be the owner, approved, or operator. 143 | * @param from current owner of the token 144 | * @param to address to receive the ownership of the given token ID 145 | * @param tokenId uint256 ID of the token to be transferred 146 | */ 147 | function transferFrom(address from, address to, uint256 tokenId) public { 148 | //solhint-disable-next-line max-line-length 149 | require(_isApprovedOrOwner(msg.sender, tokenId), "KIP17: transfer caller is not owner nor approved"); 150 | 151 | _transferFrom(from, to, tokenId); 152 | } 153 | 154 | /** 155 | * @dev Safely transfers the ownership of a given token ID to another address 156 | * If the target address is a contract, it must implement `onKIP17Received`, 157 | * which is called upon a safe transfer, and return the magic value 158 | * `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))`; otherwise, 159 | * the transfer is reverted. 160 | * Requires the msg.sender to be the owner, approved, or operator 161 | * @param from current owner of the token 162 | * @param to address to receive the ownership of the given token ID 163 | * @param tokenId uint256 ID of the token to be transferred 164 | */ 165 | function safeTransferFrom(address from, address to, uint256 tokenId) public { 166 | safeTransferFrom(from, to, tokenId, ""); 167 | } 168 | 169 | /** 170 | * @dev Safely transfers the ownership of a given token ID to another address 171 | * If the target address is a contract, it must implement `onKIP17Received`, 172 | * which is called upon a safe transfer, and return the magic value 173 | * `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))`; otherwise, 174 | * the transfer is reverted. 175 | * Requires the msg.sender to be the owner, approved, or operator 176 | * @param from current owner of the token 177 | * @param to address to receive the ownership of the given token ID 178 | * @param tokenId uint256 ID of the token to be transferred 179 | * @param _data bytes data to send along with a safe transfer check 180 | */ 181 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { 182 | transferFrom(from, to, tokenId); 183 | require(_checkOnKIP17Received(from, to, tokenId, _data), "KIP17: transfer to non KIP17Receiver implementer"); 184 | } 185 | 186 | /** 187 | * @dev Returns whether the specified token exists. 188 | * @param tokenId uint256 ID of the token to query the existence of 189 | * @return bool whether the token exists 190 | */ 191 | function _exists(uint256 tokenId) internal view returns (bool) { 192 | address owner = _tokenOwner[tokenId]; 193 | return owner != address(0); 194 | } 195 | 196 | /** 197 | * @dev Returns whether the given spender can transfer a given token ID. 198 | * @param spender address of the spender to query 199 | * @param tokenId uint256 ID of the token to be transferred 200 | * @return bool whether the msg.sender is approved for the given token ID, 201 | * is an operator of the owner, or is the owner of the token 202 | */ 203 | function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { 204 | require(_exists(tokenId), "KIP17: operator query for nonexistent token"); 205 | address owner = ownerOf(tokenId); 206 | return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); 207 | } 208 | 209 | /** 210 | * @dev Internal function to mint a new token. 211 | * Reverts if the given token ID already exists. 212 | * @param to The address that will own the minted token 213 | * @param tokenId uint256 ID of the token to be minted 214 | */ 215 | function _mint(address to, uint256 tokenId) internal { 216 | require(to != address(0), "KIP17: mint to the zero address"); 217 | require(!_exists(tokenId), "KIP17: token already minted"); 218 | 219 | _tokenOwner[tokenId] = to; 220 | _ownedTokensCount[to].increment(); 221 | 222 | emit Transfer(address(0), to, tokenId); 223 | } 224 | 225 | /** 226 | * @dev Internal function to burn a specific token. 227 | * Reverts if the token does not exist. 228 | * Deprecated, use _burn(uint256) instead. 229 | * @param owner owner of the token to burn 230 | * @param tokenId uint256 ID of the token being burned 231 | */ 232 | function _burn(address owner, uint256 tokenId) internal { 233 | require(ownerOf(tokenId) == owner, "KIP17: burn of token that is not own"); 234 | 235 | _clearApproval(tokenId); 236 | 237 | _ownedTokensCount[owner].decrement(); 238 | _tokenOwner[tokenId] = address(0); 239 | 240 | emit Transfer(owner, address(0), tokenId); 241 | } 242 | 243 | /** 244 | * @dev Internal function to burn a specific token. 245 | * Reverts if the token does not exist. 246 | * @param tokenId uint256 ID of the token being burned 247 | */ 248 | function _burn(uint256 tokenId) internal { 249 | _burn(ownerOf(tokenId), tokenId); 250 | } 251 | 252 | /** 253 | * @dev Internal function to transfer ownership of a given token ID to another address. 254 | * As opposed to transferFrom, this imposes no restrictions on msg.sender. 255 | * @param from current owner of the token 256 | * @param to address to receive the ownership of the given token ID 257 | * @param tokenId uint256 ID of the token to be transferred 258 | */ 259 | function _transferFrom(address from, address to, uint256 tokenId) internal { 260 | require(ownerOf(tokenId) == from, "KIP17: transfer of token that is not own"); 261 | require(to != address(0), "KIP17: transfer to the zero address"); 262 | 263 | _clearApproval(tokenId); 264 | 265 | _ownedTokensCount[from].decrement(); 266 | _ownedTokensCount[to].increment(); 267 | 268 | _tokenOwner[tokenId] = to; 269 | 270 | emit Transfer(from, to, tokenId); 271 | } 272 | 273 | /** 274 | * @dev Internal function to invoke `onKIP17Received` on a target address. 275 | * The call is not executed if the target address is not a contract. 276 | * 277 | * This function is deprecated. 278 | * @param from address representing the previous owner of the given token ID 279 | * @param to target address that will receive the tokens 280 | * @param tokenId uint256 ID of the token to be transferred 281 | * @param _data bytes optional data to send along with the call 282 | * @return bool whether the call correctly returned the expected magic value 283 | */ 284 | function _checkOnKIP17Received(address from, address to, uint256 tokenId, bytes memory _data) 285 | internal returns (bool) 286 | { 287 | bool success; 288 | bytes memory returndata; 289 | 290 | if (!to.isContract()) { 291 | return true; 292 | } 293 | 294 | // Logic for compatibility with ERC721. 295 | (success, returndata) = to.call( 296 | abi.encodeWithSelector(_ERC721_RECEIVED, msg.sender, from, tokenId, _data) 297 | ); 298 | if (returndata.length != 0 && abi.decode(returndata, (bytes4)) == _ERC721_RECEIVED) { 299 | return true; 300 | } 301 | 302 | (success, returndata) = to.call( 303 | abi.encodeWithSelector(_KIP17_RECEIVED, msg.sender, from, tokenId, _data) 304 | ); 305 | if (returndata.length != 0 && abi.decode(returndata, (bytes4)) == _KIP17_RECEIVED) { 306 | return true; 307 | } 308 | 309 | return false; 310 | } 311 | 312 | /** 313 | * @dev Private function to clear current approval of a given token ID. 314 | * @param tokenId uint256 ID of the token to be transferred 315 | */ 316 | function _clearApproval(uint256 tokenId) private { 317 | if (_tokenApprovals[tokenId] != address(0)) { 318 | _tokenApprovals[tokenId] = address(0); 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /contracts/KIP17Burnable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17.sol"; 4 | import "./introspection/KIP13.sol"; 5 | 6 | /** 7 | * @title KIP17 Burnable Token 8 | * @dev KIP17 Token that can be irreversibly burned (destroyed). 9 | * See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 10 | */ 11 | contract KIP17Burnable is KIP13, KIP17 { 12 | /* 13 | * bytes4(keccak256('burn(uint256)')) == 0x42966c68 14 | * 15 | * => 0x42966c68 == 0x42966c68 16 | */ 17 | bytes4 private constant _INTERFACE_ID_KIP17_BURNABLE = 0x42966c68; 18 | 19 | /** 20 | * @dev Constructor function. 21 | */ 22 | constructor () public { 23 | // register the supported interface to conform to KIP17Burnable via KIP13 24 | _registerInterface(_INTERFACE_ID_KIP17_BURNABLE); 25 | } 26 | 27 | /** 28 | * @dev Burns a specific KIP17 token. 29 | * @param tokenId uint256 id of the KIP17 token to be burned. 30 | */ 31 | function burn(uint256 tokenId) public { 32 | //solhint-disable-next-line max-line-length 33 | require(_isApprovedOrOwner(msg.sender, tokenId), "KIP17Burnable: caller is not owner nor approved"); 34 | _burn(tokenId); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/KIP17Enumerable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IKIP17Enumerable.sol"; 4 | import "./KIP17.sol"; 5 | import "./introspection/KIP13.sol"; 6 | 7 | /** 8 | * @title KIP-17 Non-Fungible Token with optional enumeration extension logic 9 | * @dev See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 10 | */ 11 | contract KIP17Enumerable is KIP13, KIP17, IKIP17Enumerable { 12 | // Mapping from owner to list of owned token IDs 13 | mapping(address => uint256[]) private _ownedTokens; 14 | 15 | // Mapping from token ID to index of the owner tokens list 16 | mapping(uint256 => uint256) private _ownedTokensIndex; 17 | 18 | // Array with all token ids, used for enumeration 19 | uint256[] private _allTokens; 20 | 21 | // Mapping from token id to position in the allTokens array 22 | mapping(uint256 => uint256) private _allTokensIndex; 23 | 24 | /* 25 | * bytes4(keccak256('totalSupply()')) == 0x18160ddd 26 | * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 27 | * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 28 | * 29 | * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 30 | */ 31 | bytes4 private constant _INTERFACE_ID_KIP17_ENUMERABLE = 0x780e9d63; 32 | 33 | /** 34 | * @dev Constructor function. 35 | */ 36 | constructor () public { 37 | // register the supported interface to conform to KIP17Enumerable via KIP13 38 | _registerInterface(_INTERFACE_ID_KIP17_ENUMERABLE); 39 | } 40 | 41 | /** 42 | * @dev Gets the token ID at a given index of the tokens list of the requested owner. 43 | * @param owner address owning the tokens list to be accessed 44 | * @param index uint256 representing the index to be accessed of the requested tokens list 45 | * @return uint256 token ID at the given index of the tokens list owned by the requested address 46 | */ 47 | function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) { 48 | require(index < balanceOf(owner), "KIP17Enumerable: owner index out of bounds"); 49 | return _ownedTokens[owner][index]; 50 | } 51 | 52 | /** 53 | * @dev Gets the total amount of tokens stored by the contract. 54 | * @return uint256 representing the total amount of tokens 55 | */ 56 | function totalSupply() public view returns (uint256) { 57 | return _allTokens.length; 58 | } 59 | 60 | /** 61 | * @dev Gets the token ID at a given index of all the tokens in this contract 62 | * Reverts if the index is greater or equal to the total number of tokens. 63 | * @param index uint256 representing the index to be accessed of the tokens list 64 | * @return uint256 token ID at the given index of the tokens list 65 | */ 66 | function tokenByIndex(uint256 index) public view returns (uint256) { 67 | require(index < totalSupply(), "KIP17Enumerable: global index out of bounds"); 68 | return _allTokens[index]; 69 | } 70 | 71 | /** 72 | * @dev Internal function to transfer ownership of a given token ID to another address. 73 | * As opposed to transferFrom, this imposes no restrictions on msg.sender. 74 | * @param from current owner of the token 75 | * @param to address to receive the ownership of the given token ID 76 | * @param tokenId uint256 ID of the token to be transferred 77 | */ 78 | function _transferFrom(address from, address to, uint256 tokenId) internal { 79 | super._transferFrom(from, to, tokenId); 80 | 81 | _removeTokenFromOwnerEnumeration(from, tokenId); 82 | 83 | _addTokenToOwnerEnumeration(to, tokenId); 84 | } 85 | 86 | /** 87 | * @dev Internal function to mint a new token. 88 | * Reverts if the given token ID already exists. 89 | * @param to address the beneficiary that will own the minted token 90 | * @param tokenId uint256 ID of the token to be minted 91 | */ 92 | function _mint(address to, uint256 tokenId) internal { 93 | super._mint(to, tokenId); 94 | 95 | _addTokenToOwnerEnumeration(to, tokenId); 96 | 97 | _addTokenToAllTokensEnumeration(tokenId); 98 | } 99 | 100 | /** 101 | * @dev Internal function to burn a specific token. 102 | * Reverts if the token does not exist. 103 | * Deprecated, use _burn(uint256) instead. 104 | * @param owner owner of the token to burn 105 | * @param tokenId uint256 ID of the token being burned 106 | */ 107 | function _burn(address owner, uint256 tokenId) internal { 108 | super._burn(owner, tokenId); 109 | 110 | _removeTokenFromOwnerEnumeration(owner, tokenId); 111 | // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund 112 | _ownedTokensIndex[tokenId] = 0; 113 | 114 | _removeTokenFromAllTokensEnumeration(tokenId); 115 | } 116 | 117 | /** 118 | * @dev Gets the list of token IDs of the requested owner. 119 | * @param owner address owning the tokens 120 | * @return uint256[] List of token IDs owned by the requested address 121 | */ 122 | function _tokensOfOwner(address owner) internal view returns (uint256[] storage) { 123 | return _ownedTokens[owner]; 124 | } 125 | 126 | /** 127 | * @dev Private function to add a token to this extension's ownership-tracking data structures. 128 | * @param to address representing the new owner of the given token ID 129 | * @param tokenId uint256 ID of the token to be added to the tokens list of the given address 130 | */ 131 | function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { 132 | _ownedTokensIndex[tokenId] = _ownedTokens[to].length; 133 | _ownedTokens[to].push(tokenId); 134 | } 135 | 136 | /** 137 | * @dev Private function to add a token to this extension's token tracking data structures. 138 | * @param tokenId uint256 ID of the token to be added to the tokens list 139 | */ 140 | function _addTokenToAllTokensEnumeration(uint256 tokenId) private { 141 | _allTokensIndex[tokenId] = _allTokens.length; 142 | _allTokens.push(tokenId); 143 | } 144 | 145 | /** 146 | * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that 147 | * while the token is not assigned a new owner, the _ownedTokensIndex mapping is _not_ updated: this allows for 148 | * gas optimizations e.g. when performing a transfer operation (avoiding double writes). 149 | * This has O(1) time complexity, but alters the order of the _ownedTokens array. 150 | * @param from address representing the previous owner of the given token ID 151 | * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address 152 | */ 153 | function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { 154 | // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and 155 | // then delete the last slot (swap and pop). 156 | 157 | uint256 lastTokenIndex = _ownedTokens[from].length.sub(1); 158 | uint256 tokenIndex = _ownedTokensIndex[tokenId]; 159 | 160 | // When the token to delete is the last token, the swap operation is unnecessary 161 | if (tokenIndex != lastTokenIndex) { 162 | uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; 163 | 164 | _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token 165 | _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index 166 | } 167 | 168 | // This also deletes the contents at the last position of the array 169 | _ownedTokens[from].length--; 170 | 171 | // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by 172 | // lastTokenId, or just over the end of the array if the token was the last one). 173 | } 174 | 175 | /** 176 | * @dev Private function to remove a token from this extension's token tracking data structures. 177 | * This has O(1) time complexity, but alters the order of the _allTokens array. 178 | * @param tokenId uint256 ID of the token to be removed from the tokens list 179 | */ 180 | function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { 181 | // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and 182 | // then delete the last slot (swap and pop). 183 | 184 | uint256 lastTokenIndex = _allTokens.length.sub(1); 185 | uint256 tokenIndex = _allTokensIndex[tokenId]; 186 | 187 | // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so 188 | // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding 189 | // an 'if' statement (like in _removeTokenFromOwnerEnumeration) 190 | uint256 lastTokenId = _allTokens[lastTokenIndex]; 191 | 192 | _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token 193 | _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index 194 | 195 | // This also deletes the contents at the last position of the array 196 | _allTokens.length--; 197 | _allTokensIndex[tokenId] = 0; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /contracts/KIP17Full.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17.sol"; 4 | import "./KIP17Enumerable.sol"; 5 | import "./KIP17Metadata.sol"; 6 | import "./ownership/Ownable.sol"; 7 | import "./KIP17Kbirdz.sol"; 8 | 9 | /** 10 | * @title Full KIP-17 Token 11 | * This implementation includes all the required and some optional functionality of the KIP-17 standard 12 | * Moreover, it includes approve all functionality using operator terminology 13 | * @dev see http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 14 | */ 15 | contract KIP17Full is KIP17, KIP17Enumerable, KIP17Metadata, Ownable, KIP17Kbirdz { 16 | constructor (string memory name, string memory symbol) public KIP17Metadata(name, symbol) { 17 | // solhint-disable-previous-line no-empty-blocks 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/KIP17Kbirdz.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17.sol"; 4 | import "./KIP17Metadata.sol"; 5 | import "./KIP17Enumerable.sol"; 6 | import "./roles/MinterRole.sol"; 7 | import "./math/SafeMath.sol"; 8 | import "./utils/String.sol"; 9 | import "./MerkleProof.sol"; 10 | 11 | contract KIP17Kbirdz is KIP17, KIP17Enumerable, KIP17Metadata, MinterRole { 12 | 13 | // To prevent bot attack, we record the last contract call block number. 14 | mapping (address => uint256) private _lastCallBlockNumber; 15 | uint256 private _antibotInterval; 16 | 17 | // If someone burns NFT in the middle of minting, 18 | // the tokenId will go wrong, so use the index instead of totalSupply(). 19 | uint256 private _mintIndexForSale; 20 | 21 | uint256 private _mintLimitPerBlock; // Maximum purchase nft per person per block 22 | uint256 private _mintLimitPerSale; // Maximum purchase nft per person per sale 23 | 24 | string private _tokenBaseURI; 25 | uint256 private _mintStartBlockNumber; // In blockchain, blocknumber is the standard of time. 26 | uint256 private _maxSaleAmount; // Maximum purchase volume of normal sale. 27 | uint256 private _mintPrice; // 1 KLAY = 1000000000000000000 28 | 29 | string baseURI; 30 | string notRevealedUri; 31 | bool public revealed = false; 32 | bool public publicMintEnabled = false; 33 | 34 | function _baseURI() internal view returns (string memory) { 35 | return baseURI; 36 | } 37 | 38 | function _notRevealedURI() internal view returns (string memory) { 39 | return notRevealedUri; 40 | } 41 | 42 | function setBaseURI(string memory _newBaseURI) public onlyMinter { 43 | baseURI = _newBaseURI; 44 | } 45 | 46 | function setNotRevealedURI(string memory _newNotRevealedURI) public onlyMinter { 47 | notRevealedUri = _newNotRevealedURI; 48 | } 49 | 50 | function reveal(bool _state) public onlyMinter { 51 | revealed = _state; 52 | } 53 | 54 | function tokenURI(uint256 tokenId) 55 | public 56 | view 57 | returns (string memory) 58 | { 59 | require( 60 | _exists(tokenId), 61 | "KIP17Metadata: URI query for nonexistent token" 62 | ); 63 | 64 | if(revealed == false) { 65 | string memory currentNotRevealedUri = _notRevealedURI(); 66 | return bytes(currentNotRevealedUri).length > 0 67 | ? string(abi.encodePacked(currentNotRevealedUri, String.uint2str(tokenId), ".json")) 68 | : ""; 69 | } 70 | string memory currentBaseURI = _baseURI(); 71 | return bytes(currentBaseURI).length > 0 72 | ? string(abi.encodePacked(currentBaseURI, String.uint2str(tokenId), ".json")) 73 | : ""; 74 | } 75 | 76 | constructor () public { 77 | //init explicitly. 78 | _mintIndexForSale = 1; 79 | } 80 | 81 | function withdraw() external onlyMinter{ 82 | // This code transfers 5% of the withdraw to JoCoding as a donation. 83 | // ============================================================================= 84 | 0x3e944Ca8B08a0a0D3245B05ABF01586B9142f52C.transfer(address(this).balance * 5 / 100); 85 | // ============================================================================= 86 | // This will transfer the remaining contract balance to the owner. 87 | // Do not remove this otherwise you will not be able to withdraw the funds. 88 | // ============================================================================= 89 | msg.sender.transfer(address(this).balance); 90 | // ============================================================================= 91 | } 92 | 93 | function mintingInformation() external view returns (uint256[7] memory){ 94 | uint256[7] memory info = 95 | [_antibotInterval, _mintIndexForSale, _mintLimitPerBlock, _mintLimitPerSale, 96 | _mintStartBlockNumber, _maxSaleAmount, _mintPrice]; 97 | return info; 98 | } 99 | 100 | function setPublicMintEnabled(bool _state) public onlyMinter { 101 | publicMintEnabled = _state; 102 | } 103 | 104 | function setupSale(uint256 newAntibotInterval, 105 | uint256 newMintLimitPerBlock, 106 | uint256 newMintLimitPerSale, 107 | uint256 newMintStartBlockNumber, 108 | uint256 newMintIndexForSale, 109 | uint256 newMaxSaleAmount, 110 | uint256 newMintPrice) external onlyMinter{ 111 | _antibotInterval = newAntibotInterval; 112 | _mintLimitPerBlock = newMintLimitPerBlock; 113 | _mintLimitPerSale = newMintLimitPerSale; 114 | _mintStartBlockNumber = newMintStartBlockNumber; 115 | _mintIndexForSale = newMintIndexForSale; 116 | _maxSaleAmount = newMaxSaleAmount; 117 | _mintPrice = newMintPrice; 118 | } 119 | 120 | //Public Mint 121 | function publicMint(uint256 requestedCount) external payable { 122 | require(publicMintEnabled, "The public sale is not enabled!"); 123 | require(_lastCallBlockNumber[msg.sender].add(_antibotInterval) < block.number, "Bot is not allowed"); 124 | require(block.number >= _mintStartBlockNumber, "Not yet started"); 125 | require(requestedCount > 0 && requestedCount <= _mintLimitPerBlock, "Too many requests or zero request"); 126 | require(msg.value == _mintPrice.mul(requestedCount), "Not enough Klay"); 127 | require(_mintIndexForSale.add(requestedCount) <= _maxSaleAmount + 1, "Exceed max amount"); 128 | require(balanceOf(msg.sender) + requestedCount <= _mintLimitPerSale, "Exceed max amount per person"); 129 | 130 | for(uint256 i = 0; i < requestedCount; i++) { 131 | _mint(msg.sender, _mintIndexForSale); 132 | _mintIndexForSale = _mintIndexForSale.add(1); 133 | } 134 | _lastCallBlockNumber[msg.sender] = block.number; 135 | } 136 | 137 | //Whitelist Mint 138 | bytes32 public merkleRoot; 139 | mapping(address => bool) public whitelistClaimed; 140 | bool public whitelistMintEnabled = false; 141 | 142 | function setMerkleRoot(bytes32 _merkleRoot) public onlyMinter { 143 | merkleRoot = _merkleRoot; 144 | } 145 | 146 | function setWhitelistMintEnabled(bool _state) public onlyMinter { 147 | whitelistMintEnabled = _state; 148 | } 149 | 150 | function whitelistMint(uint256 requestedCount, bytes32[] calldata _merkleProof) external payable { 151 | require(whitelistMintEnabled, "The whitelist sale is not enabled!"); 152 | require(msg.value == _mintPrice.mul(requestedCount), "Not enough Klay"); 153 | require(!whitelistClaimed[msg.sender], 'Address already claimed!'); 154 | require(requestedCount > 0 && requestedCount <= _mintLimitPerBlock, "Too many requests or zero request"); 155 | bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); 156 | require(MerkleProof.verify(_merkleProof, merkleRoot, leaf), 'Invalid proof!'); 157 | 158 | for(uint256 i = 0; i < requestedCount; i++) { 159 | _mint(msg.sender, _mintIndexForSale); 160 | _mintIndexForSale = _mintIndexForSale.add(1); 161 | } 162 | 163 | whitelistClaimed[msg.sender] = true; 164 | } 165 | 166 | //Airdrop Mint 167 | function airDropMint(address user, uint256 requestedCount) external onlyMinter { 168 | require(requestedCount > 0, "zero request"); 169 | for(uint256 i = 0; i < requestedCount; i++) { 170 | _mint(user, _mintIndexForSale); 171 | _mintIndexForSale = _mintIndexForSale.add(1); 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /contracts/KIP17KbirdzToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17Full.sol"; 4 | import "./KIP17MetadataMintable.sol"; 5 | import "./KIP17Mintable.sol"; 6 | import "./KIP17Burnable.sol"; 7 | import "./KIP17Pausable.sol"; 8 | 9 | contract KIP17KbirdzToken is KIP17Full, KIP17Mintable, KIP17MetadataMintable, KIP17Burnable, KIP17Pausable { 10 | constructor (string memory name, string memory symbol) public KIP17Full(name, symbol) { 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/KIP17Metadata.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17.sol"; 4 | import "./IKIP17Metadata.sol"; 5 | import "./introspection/KIP13.sol"; 6 | 7 | contract KIP17Metadata is KIP13, KIP17, IKIP17Metadata { 8 | // Token name 9 | string private _name; 10 | 11 | // Token symbol 12 | string private _symbol; 13 | 14 | // Optional mapping for token URIs 15 | mapping(uint256 => string) private _tokenURIs; 16 | 17 | /* 18 | * bytes4(keccak256('name()')) == 0x06fdde03 19 | * bytes4(keccak256('symbol()')) == 0x95d89b41 20 | * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd 21 | * 22 | * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f 23 | */ 24 | bytes4 private constant _INTERFACE_ID_KIP17_METADATA = 0x5b5e139f; 25 | 26 | /** 27 | * @dev Constructor function 28 | */ 29 | constructor (string memory name, string memory symbol) public { 30 | _name = name; 31 | _symbol = symbol; 32 | 33 | // register the supported interfaces to conform to KIP17 via KIP13 34 | _registerInterface(_INTERFACE_ID_KIP17_METADATA); 35 | } 36 | 37 | /** 38 | * @dev Gets the token name. 39 | * @return string representing the token name 40 | */ 41 | function name() external view returns (string memory) { 42 | return _name; 43 | } 44 | 45 | /** 46 | * @dev Gets the token symbol. 47 | * @return string representing the token symbol 48 | */ 49 | function symbol() external view returns (string memory) { 50 | return _symbol; 51 | } 52 | 53 | /** 54 | * @dev Returns an URI for a given token ID. 55 | * Throws if the token ID does not exist. May return an empty string. 56 | * @param tokenId uint256 ID of the token to query 57 | */ 58 | function tokenURI(uint256 tokenId) external view returns (string memory) { 59 | require(_exists(tokenId), "KIP17Metadata: URI query for nonexistent token"); 60 | return _tokenURIs[tokenId]; 61 | } 62 | 63 | /** 64 | * @dev Internal function to set the token URI for a given token. 65 | * Reverts if the token ID does not exist. 66 | * @param tokenId uint256 ID of the token to set its URI 67 | * @param uri string URI to assign 68 | */ 69 | function _setTokenURI(uint256 tokenId, string memory uri) internal { 70 | require(_exists(tokenId), "KIP17Metadata: URI set of nonexistent token"); 71 | _tokenURIs[tokenId] = uri; 72 | } 73 | 74 | /** 75 | * @dev Internal function to burn a specific token. 76 | * Reverts if the token does not exist. 77 | * Deprecated, use _burn(uint256) instead. 78 | * @param owner owner of the token to burn 79 | * @param tokenId uint256 ID of the token being burned by the msg.sender 80 | */ 81 | function _burn(address owner, uint256 tokenId) internal { 82 | super._burn(owner, tokenId); 83 | 84 | // Clear metadata (if any) 85 | if (bytes(_tokenURIs[tokenId]).length != 0) { 86 | delete _tokenURIs[tokenId]; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /contracts/KIP17MetadataMintable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17Metadata.sol"; 4 | import "./roles/MinterRole.sol"; 5 | import "./introspection/KIP13.sol"; 6 | 7 | 8 | /** 9 | * @title KIP17MetadataMintable 10 | * @dev KIP17 minting logic with metadata. 11 | */ 12 | contract KIP17MetadataMintable is KIP13, KIP17, KIP17Metadata, MinterRole { 13 | /* 14 | * bytes4(keccak256('mintWithTokenURI(address,uint256,string)')) == 0x50bb4e7f 15 | * bytes4(keccak256('isMinter(address)')) == 0xaa271e1a 16 | * bytes4(keccak256('addMinter(address)')) == 0x983b2d56 17 | * bytes4(keccak256('renounceMinter()')) == 0x98650275 18 | * 19 | * => 0x50bb4e7f ^ 0xaa271e1a ^ 0x983b2d56 ^ 0x98650275 == 0xfac27f46 20 | */ 21 | bytes4 private constant _INTERFACE_ID_KIP17_METADATA_MINTABLE = 0xfac27f46; 22 | 23 | /** 24 | * @dev Constructor function. 25 | */ 26 | constructor () public { 27 | // register the supported interface to conform to KIP17Mintable via KIP13 28 | _registerInterface(_INTERFACE_ID_KIP17_METADATA_MINTABLE); 29 | } 30 | 31 | /** 32 | * @dev Function to mint tokens. 33 | * @param to The address that will receive the minted tokens. 34 | * @param tokenId The token id to mint. 35 | * @param tokenURI The token URI of the minted token. 36 | * @return A boolean that indicates if the operation was successful. 37 | */ 38 | function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) { 39 | _mint(to, tokenId); 40 | _setTokenURI(tokenId, tokenURI); 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/KIP17Mintable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17.sol"; 4 | import "./roles/MinterRole.sol"; 5 | 6 | /** 7 | * @title KIP17Mintable 8 | * @dev KIP17 minting logic. 9 | */ 10 | contract KIP17Mintable is KIP17, MinterRole { 11 | /* 12 | * bytes4(keccak256('isMinter(address)')) == 0xaa271e1a 13 | * bytes4(keccak256('addMinter(address)')) == 0x983b2d56 14 | * bytes4(keccak256('renounceMinter()')) == 0x98650275 15 | * bytes4(keccak256('mint(address,uint256)')) == 0x40c10f19 16 | * 17 | * => 0xaa271e1a ^ 0x983b2d56 ^ 0x98650275 ^ 0x40c10f19 == 0xeab83e20 18 | */ 19 | bytes4 private constant _INTERFACE_ID_KIP17_MINTABLE = 0xeab83e20; 20 | 21 | /** 22 | * @dev Constructor function. 23 | */ 24 | constructor () public { 25 | // register the supported interface to conform to KIP17Mintable via KIP13 26 | _registerInterface(_INTERFACE_ID_KIP17_MINTABLE); 27 | } 28 | 29 | /** 30 | * @dev Function to mint tokens. 31 | * @param to The address that will receive the minted tokens. 32 | * @param tokenId The token id to mint. 33 | * @return A boolean that indicates if the operation was successful. 34 | */ 35 | function mint(address to, uint256 tokenId) public onlyMinter returns (bool) { 36 | _mint(to, tokenId); 37 | return true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/KIP17Pausable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17.sol"; 4 | import "./lifecycle/Pausable.sol"; 5 | import "./introspection/KIP13.sol"; 6 | 7 | /** 8 | * @title KIP17 Non-Fungible Pausable token 9 | * @dev KIP17 modified with pausable transfers. 10 | */ 11 | contract KIP17Pausable is KIP13, KIP17, Pausable { 12 | /* 13 | * bytes4(keccak256('paused()')) == 0x5c975abb 14 | * bytes4(keccak256('pause()')) == 0x8456cb59 15 | * bytes4(keccak256('unpause()')) == 0x3f4ba83a 16 | * bytes4(keccak256('isPauser(address)')) == 0x46fbf68e 17 | * bytes4(keccak256('addPauser(address)')) == 0x82dc1ec4 18 | * bytes4(keccak256('renouncePauser()')) == 0x6ef8d66d 19 | * 20 | * => 0x5c975abb ^ 0x8456cb59 ^ 0x3f4ba83a ^ 0x46fbf68e ^ 0x82dc1ec4 ^ 0x6ef8d66d == 0x4d5507ff 21 | */ 22 | bytes4 private constant _INTERFACE_ID_KIP17_PAUSABLE = 0x4d5507ff; 23 | 24 | /** 25 | * @dev Constructor function. 26 | */ 27 | constructor () public { 28 | // register the supported interface to conform to KIP17Pausable via KIP13 29 | _registerInterface(_INTERFACE_ID_KIP17_PAUSABLE); 30 | } 31 | 32 | function approve(address to, uint256 tokenId) public whenNotPaused { 33 | super.approve(to, tokenId); 34 | } 35 | 36 | function setApprovalForAll(address to, bool approved) public whenNotPaused { 37 | super.setApprovalForAll(to, approved); 38 | } 39 | 40 | function transferFrom(address from, address to, uint256 tokenId) public whenNotPaused { 41 | super.transferFrom(from, to, tokenId); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/KIP17Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./KIP17Full.sol"; 4 | import "./KIP17MetadataMintable.sol"; 5 | import "./KIP17Mintable.sol"; 6 | import "./KIP17Burnable.sol"; 7 | import "./KIP17Pausable.sol"; 8 | 9 | contract KIP17Token is KIP17Full, KIP17Mintable, KIP17MetadataMintable, KIP17Burnable, KIP17Pausable { 10 | constructor (string memory name, string memory symbol) public KIP17Full(name, symbol) { 11 | } 12 | } -------------------------------------------------------------------------------- /contracts/MerkleProof.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol) 3 | 4 | pragma solidity ^0.5.0; 5 | 6 | /** 7 | * @dev These functions deal with verification of Merkle Trees proofs. 8 | * 9 | * The proofs can be generated using the JavaScript library 10 | * https://github.com/miguelmota/merkletreejs[merkletreejs]. 11 | * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. 12 | * 13 | * See `test/utils/cryptography/MerkleProof.test.js` for some examples. 14 | * 15 | * WARNING: You should avoid using leaf values that are 64 bytes long prior to 16 | * hashing, or use a hash function other than keccak256 for hashing leaves. 17 | * This is because the concatenation of a sorted pair of internal nodes in 18 | * the merkle tree could be reinterpreted as a leaf value. 19 | */ 20 | library MerkleProof { 21 | /** 22 | * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree 23 | * defined by `root`. For this, a `proof` must be provided, containing 24 | * sibling hashes on the branch from the leaf to the root of the tree. Each 25 | * pair of leaves and each pair of pre-images are assumed to be sorted. 26 | */ 27 | function verify( 28 | bytes32[] memory proof, 29 | bytes32 root, 30 | bytes32 leaf 31 | ) internal pure returns (bool) { 32 | return processProof(proof, leaf) == root; 33 | } 34 | 35 | /** 36 | * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up 37 | * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt 38 | * hash matches the root of the tree. When processing the proof, the pairs 39 | * of leafs & pre-images are assumed to be sorted. 40 | * 41 | * _Available since v4.4._ 42 | */ 43 | function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { 44 | bytes32 computedHash = leaf; 45 | for (uint256 i = 0; i < proof.length; i++) { 46 | bytes32 proofElement = proof[i]; 47 | if (computedHash <= proofElement) { 48 | // Hash(current computed hash + current element of the proof) 49 | computedHash = _efficientHash(computedHash, proofElement); 50 | } else { 51 | // Hash(current element of the proof + current computed hash) 52 | computedHash = _efficientHash(proofElement, computedHash); 53 | } 54 | } 55 | return computedHash; 56 | } 57 | 58 | function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { 59 | assembly { 60 | mstore(0x00, a) 61 | mstore(0x20, b) 62 | value := keccak256(0x00, 0x40) 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /contracts/drafts/Counters.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../math/SafeMath.sol"; 4 | 5 | /** 6 | * @title Counters 7 | * @author Matt Condon (@shrugs) 8 | * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number 9 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 10 | * 11 | * Include with `using Counters for Counters.Counter;` 12 | * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath 13 | * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never 14 | * directly accessed. 15 | */ 16 | library Counters { 17 | using SafeMath for uint256; 18 | 19 | struct Counter { 20 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 21 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 22 | // this feature: see https://github.com/ethereum/solidity/issues/4637 23 | uint256 _value; // default: 0 24 | } 25 | 26 | function current(Counter storage counter) internal view returns (uint256) { 27 | return counter._value; 28 | } 29 | 30 | function increment(Counter storage counter) internal { 31 | counter._value += 1; 32 | } 33 | 34 | function decrement(Counter storage counter) internal { 35 | counter._value = counter._value.sub(1); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/introspection/IKIP13.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Interface of the KIP-13 standard, as defined in the 5 | * [KIP-13](http://kips.klaytn.com/KIPs/kip-13-interface_query_standard). 6 | * 7 | * Implementers can declare support of contract interfaces, which can then be 8 | * queried by others. 9 | * 10 | * For an implementation, see `KIP13`. 11 | */ 12 | interface IKIP13 { 13 | /** 14 | * @dev Returns true if this contract implements the interface defined by 15 | * `interfaceId`. See the corresponding 16 | * [KIP-13 section](http://kips.klaytn.com/KIPs/kip-13-interface_query_standard#how-interface-identifiers-are-defined) 17 | * to learn more about how these ids are created. 18 | * 19 | * This function call must use less than 30 000 gas. 20 | */ 21 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 22 | } 23 | -------------------------------------------------------------------------------- /contracts/introspection/KIP13.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./IKIP13.sol"; 4 | 5 | /** 6 | * @dev Implementation of the `IKIP13` interface. 7 | * 8 | * Contracts may inherit from this and call `_registerInterface` to declare 9 | * their support of an interface. 10 | */ 11 | contract KIP13 is IKIP13 { 12 | /* 13 | * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 14 | */ 15 | bytes4 private constant _INTERFACE_ID_KIP13 = 0x01ffc9a7; 16 | 17 | /** 18 | * @dev Mapping of interface ids to whether or not it's supported. 19 | */ 20 | mapping(bytes4 => bool) private _supportedInterfaces; 21 | 22 | constructor () internal { 23 | // Derived contracts need only register support for their own interfaces, 24 | // we register support for KIP13 itself here 25 | _registerInterface(_INTERFACE_ID_KIP13); 26 | } 27 | 28 | /** 29 | * @dev See `IKIP13.supportsInterface`. 30 | * 31 | * Time complexity O(1), guaranteed to always use less than 30 000 gas. 32 | */ 33 | function supportsInterface(bytes4 interfaceId) external view returns (bool) { 34 | return _supportedInterfaces[interfaceId]; 35 | } 36 | 37 | /** 38 | * @dev Registers the contract as an implementer of the interface defined by 39 | * `interfaceId`. Support of the actual KIP13 interface is automatic and 40 | * registering its interface id is not required. 41 | * 42 | * See `IKIP13.supportsInterface`. 43 | * 44 | * Requirements: 45 | * 46 | * - `interfaceId` cannot be the KIP13 invalid interface (`0xffffffff`). 47 | */ 48 | function _registerInterface(bytes4 interfaceId) internal { 49 | require(interfaceId != 0xffffffff, "KIP13: invalid interface id"); 50 | _supportedInterfaces[interfaceId] = true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /contracts/introspection/KIP13Checker.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Library used to query support of an interface declared via `IKIP13`. 5 | * 6 | * Note that these functions return the actual result of the query: they do not 7 | * `revert` if an interface is not supported. It is up to the caller to decide 8 | * what to do in these cases. 9 | */ 10 | library KIP13Checker { 11 | // As per the EIP-165 spec, no interface should ever match 0xffffffff 12 | bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; 13 | 14 | /* 15 | * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 16 | */ 17 | bytes4 private constant _INTERFACE_ID_KIP13 = 0x01ffc9a7; 18 | 19 | /** 20 | * @dev Returns true if `account` supports the `IKIP13` interface, 21 | */ 22 | function _supportsKIP13(address account) internal view returns (bool) { 23 | // Any contract that implements KIP13 must explicitly indicate support of 24 | // InterfaceId_KIP13 and explicitly indicate non-support of InterfaceId_Invalid 25 | return _supportsKIP13Interface(account, _INTERFACE_ID_KIP13) && 26 | !_supportsKIP13Interface(account, _INTERFACE_ID_INVALID); 27 | } 28 | 29 | /** 30 | * @dev Returns true if `account` supports the interface defined by 31 | * `interfaceId`. Support for `IKIP13` itself is queried automatically. 32 | * 33 | * See `IKIP13.supportsInterface`. 34 | */ 35 | function _supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { 36 | // query support of both KIP13 as per the spec and support of _interfaceId 37 | return _supportsKIP13(account) && 38 | _supportsKIP13Interface(account, interfaceId); 39 | } 40 | 41 | /** 42 | * @dev Returns true if `account` supports all the interfaces defined in 43 | * `interfaceIds`. Support for `IKIP13` itself is queried automatically. 44 | * 45 | * Batch-querying can lead to gas savings by skipping repeated checks for 46 | * `IKIP13` support. 47 | * 48 | * See `IKIP13.supportsInterface`. 49 | */ 50 | function _supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { 51 | // query support of KIP13 itself 52 | if (!_supportsKIP13(account)) { 53 | return false; 54 | } 55 | 56 | // query support of each interface in _interfaceIds 57 | for (uint256 i = 0; i < interfaceIds.length; i++) { 58 | if (!_supportsKIP13Interface(account, interfaceIds[i])) { 59 | return false; 60 | } 61 | } 62 | 63 | // all interfaces supported 64 | return true; 65 | } 66 | 67 | /** 68 | * @notice Query if a contract implements an interface, does not check KIP13 support 69 | * @param account The address of the contract to query for support of an interface 70 | * @param interfaceId The interface identifier, as specified in ERC-165 71 | * @return true if the contract at account indicates support of the interface with 72 | * identifier interfaceId, false otherwise 73 | * @dev Assumes that account contains a contract that supports KIP13, otherwise 74 | * the behavior of this method is undefined. This precondition can be checked 75 | * with the `supportsKIP13` method in this library. 76 | * Interface identification is specified in ERC-165. 77 | */ 78 | function _supportsKIP13Interface(address account, bytes4 interfaceId) private view returns (bool) { 79 | // success determines whether the staticcall succeeded and result determines 80 | // whether the contract at account indicates support of _interfaceId 81 | (bool success, bool result) = _callKIP13SupportsInterface(account, interfaceId); 82 | 83 | return (success && result); 84 | } 85 | 86 | /** 87 | * @notice Calls the function with selector 0x01ffc9a7 (KIP13) and suppresses throw 88 | * @param account The address of the contract to query for support of an interface 89 | * @param interfaceId The interface identifier, as specified in ERC-165 90 | * @return success true if the STATICCALL succeeded, false otherwise 91 | * @return result true if the STATICCALL succeeded and the contract at account 92 | * indicates support of the interface with identifier interfaceId, false otherwise 93 | */ 94 | function _callKIP13SupportsInterface(address account, bytes4 interfaceId) 95 | private 96 | view 97 | returns (bool success, bool result) 98 | { 99 | bytes memory encodedParams = abi.encodeWithSelector(_INTERFACE_ID_KIP13, interfaceId); 100 | 101 | // solhint-disable-next-line no-inline-assembly 102 | assembly { 103 | let encodedParams_data := add(0x20, encodedParams) 104 | let encodedParams_size := mload(encodedParams) 105 | 106 | let output := mload(0x40) // Find empty storage location using "free memory pointer" 107 | mstore(output, 0x0) 108 | 109 | success := staticcall( 110 | 30000, // 30k gas 111 | account, // To addr 112 | encodedParams_data, 113 | encodedParams_size, 114 | output, 115 | 0x20 // Outputs are 32 bytes long 116 | ) 117 | 118 | result := mload(output) // Load the result 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /contracts/lifecycle/Pausable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "../roles/PauserRole.sol"; 4 | 5 | /** 6 | * @dev Contract module which allows children to implement an emergency stop 7 | * mechanism that can be triggered by an authorized account. 8 | * 9 | * This module is used through inheritance. It will make available the 10 | * modifiers `whenNotPaused` and `whenPaused`, which can be applied to 11 | * the functions of your contract. Note that they will not be pausable by 12 | * simply including this module, only once the modifiers are put in place. 13 | */ 14 | contract Pausable is PauserRole { 15 | /** 16 | * @dev Emitted when the pause is triggered by a pauser (`account`). 17 | */ 18 | event Paused(address account); 19 | 20 | /** 21 | * @dev Emitted when the pause is lifted by a pauser (`account`). 22 | */ 23 | event Unpaused(address account); 24 | 25 | bool private _paused; 26 | 27 | /** 28 | * @dev Initializes the contract in unpaused state. Assigns the Pauser role 29 | * to the deployer. 30 | */ 31 | constructor () internal { 32 | _paused = false; 33 | } 34 | 35 | /** 36 | * @dev Returns true if the contract is paused, and false otherwise. 37 | */ 38 | function paused() public view returns (bool) { 39 | return _paused; 40 | } 41 | 42 | /** 43 | * @dev Modifier to make a function callable only when the contract is not paused. 44 | */ 45 | modifier whenNotPaused() { 46 | require(!_paused, "Pausable: paused"); 47 | _; 48 | } 49 | 50 | /** 51 | * @dev Modifier to make a function callable only when the contract is paused. 52 | */ 53 | modifier whenPaused() { 54 | require(_paused, "Pausable: not paused"); 55 | _; 56 | } 57 | 58 | /** 59 | * @dev Called by a pauser to pause, triggers stopped state. 60 | */ 61 | function pause() public onlyPauser whenNotPaused { 62 | _paused = true; 63 | emit Paused(msg.sender); 64 | } 65 | 66 | /** 67 | * @dev Called by a pauser to unpause, returns to normal state. 68 | */ 69 | function unpause() public onlyPauser whenPaused { 70 | _paused = false; 71 | emit Unpaused(msg.sender); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/math/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 5 | * checks. 6 | * 7 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 8 | * in bugs, because programmers usually assume that an overflow raises an 9 | * error, which is the standard behavior in high level programming languages. 10 | * `SafeMath` restores this intuition by reverting the transaction when an 11 | * operation overflows. 12 | * 13 | * Using this library instead of the unchecked operations eliminates an entire 14 | * class of bugs, so it's recommended to use it always. 15 | */ 16 | library SafeMath { 17 | /** 18 | * @dev Returns the addition of two unsigned integers, reverting on 19 | * overflow. 20 | * 21 | * Counterpart to Solidity's `+` operator. 22 | * 23 | * Requirements: 24 | * - Addition cannot overflow. 25 | */ 26 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 27 | uint256 c = a + b; 28 | require(c >= a, "SafeMath: addition overflow"); 29 | 30 | return c; 31 | } 32 | 33 | /** 34 | * @dev Returns the subtraction of two unsigned integers, reverting on 35 | * overflow (when the result is negative). 36 | * 37 | * Counterpart to Solidity's `-` operator. 38 | * 39 | * Requirements: 40 | * - Subtraction cannot overflow. 41 | */ 42 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 43 | return sub(a, b, "SafeMath: subtraction overflow"); 44 | } 45 | 46 | /** 47 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 48 | * overflow (when the result is negative). 49 | * 50 | * Counterpart to Solidity's `-` operator. 51 | * 52 | * Requirements: 53 | * - Subtraction cannot overflow. 54 | * 55 | * _Available since v2.4.0._ 56 | */ 57 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 58 | require(b <= a, errorMessage); 59 | uint256 c = a - b; 60 | 61 | return c; 62 | } 63 | 64 | /** 65 | * @dev Returns the multiplication of two unsigned integers, reverting on 66 | * overflow. 67 | * 68 | * Counterpart to Solidity's `*` operator. 69 | * 70 | * Requirements: 71 | * - Multiplication cannot overflow. 72 | */ 73 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 74 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 75 | // benefit is lost if 'b' is also tested. 76 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 77 | if (a == 0) { 78 | return 0; 79 | } 80 | 81 | uint256 c = a * b; 82 | require(c / a == b, "SafeMath: multiplication overflow"); 83 | 84 | return c; 85 | } 86 | 87 | /** 88 | * @dev Returns the integer division of two unsigned integers. Reverts on 89 | * division by zero. The result is rounded towards zero. 90 | * 91 | * Counterpart to Solidity's `/` operator. Note: this function uses a 92 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 93 | * uses an invalid opcode to revert (consuming all remaining gas). 94 | * 95 | * Requirements: 96 | * - The divisor cannot be zero. 97 | */ 98 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 99 | return div(a, b, "SafeMath: division by zero"); 100 | } 101 | 102 | /** 103 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 104 | * division by zero. The result is rounded towards zero. 105 | * 106 | * Counterpart to Solidity's `/` operator. Note: this function uses a 107 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 108 | * uses an invalid opcode to revert (consuming all remaining gas). 109 | * 110 | * Requirements: 111 | * - The divisor cannot be zero. 112 | * 113 | * _Available since v2.4.0._ 114 | */ 115 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 116 | // Solidity only automatically asserts when dividing by 0 117 | require(b > 0, errorMessage); 118 | uint256 c = a / b; 119 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 120 | 121 | return c; 122 | } 123 | 124 | /** 125 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 126 | * Reverts when dividing by zero. 127 | * 128 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 129 | * opcode (which leaves remaining gas untouched) while Solidity uses an 130 | * invalid opcode to revert (consuming all remaining gas). 131 | * 132 | * Requirements: 133 | * - The divisor cannot be zero. 134 | */ 135 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 136 | return mod(a, b, "SafeMath: modulo by zero"); 137 | } 138 | 139 | /** 140 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 141 | * Reverts with custom message when dividing by zero. 142 | * 143 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 144 | * opcode (which leaves remaining gas untouched) while Solidity uses an 145 | * invalid opcode to revert (consuming all remaining gas). 146 | * 147 | * Requirements: 148 | * - The divisor cannot be zero. 149 | * 150 | * _Available since v2.4.0._ 151 | */ 152 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 153 | require(b != 0, errorMessage); 154 | return a % b; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /contracts/ownership/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Contract module which provides a basic access control mechanism, where 5 | * there is an account (an owner) that can be granted exclusive access to 6 | * specific functions. 7 | * 8 | * This module is used through inheritance. It will make available the modifier 9 | * `onlyOwner`, which can be aplied to your functions to restrict their use to 10 | * the owner. 11 | */ 12 | contract Ownable { 13 | address payable private _owner; 14 | 15 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 16 | 17 | /** 18 | * @dev Initializes the contract setting the deployer as the initial owner. 19 | */ 20 | constructor () internal { 21 | _owner = msg.sender; 22 | emit OwnershipTransferred(address(0), _owner); 23 | } 24 | 25 | /** 26 | * @dev Returns the address of the current owner. 27 | */ 28 | function owner() public view returns (address payable) { 29 | return _owner; 30 | } 31 | 32 | /** 33 | * @dev Throws if called by any account other than the owner. 34 | */ 35 | modifier onlyOwner() { 36 | require(isOwner(), "Ownable: caller is not the owner"); 37 | _; 38 | } 39 | 40 | /** 41 | * @dev Returns true if the caller is the current owner. 42 | */ 43 | function isOwner() public view returns (bool) { 44 | return msg.sender == _owner; 45 | } 46 | 47 | /** 48 | * @dev Leaves the contract without owner. It will not be possible to call 49 | * `onlyOwner` functions anymore. Can only be called by the current owner. 50 | * 51 | * > Note: Renouncing ownership will leave the contract without an owner, 52 | * thereby removing any functionality that is only available to the owner. 53 | */ 54 | function renounceOwnership() public onlyOwner { 55 | emit OwnershipTransferred(_owner, address(0)); 56 | _owner = address(0); 57 | } 58 | 59 | /** 60 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 61 | * Can only be called by the current owner. 62 | */ 63 | function transferOwnership(address payable newOwner) public onlyOwner { 64 | _transferOwnership(newOwner); 65 | } 66 | 67 | /** 68 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 69 | */ 70 | function _transferOwnership(address payable newOwner) internal { 71 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 72 | emit OwnershipTransferred(_owner, newOwner); 73 | _owner = newOwner; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/roles/MinterRole.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./Roles.sol"; 4 | 5 | contract MinterRole { 6 | using Roles for Roles.Role; 7 | 8 | event MinterAdded(address indexed account); 9 | event MinterRemoved(address indexed account); 10 | 11 | Roles.Role private _minters; 12 | 13 | constructor () internal { 14 | _addMinter(msg.sender); 15 | } 16 | 17 | modifier onlyMinter() { 18 | require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role"); 19 | _; 20 | } 21 | 22 | function isMinter(address account) public view returns (bool) { 23 | return _minters.has(account); 24 | } 25 | 26 | function addMinter(address account) public onlyMinter { 27 | _addMinter(account); 28 | } 29 | 30 | function renounceMinter() public { 31 | _removeMinter(msg.sender); 32 | } 33 | 34 | function _addMinter(address account) internal { 35 | _minters.add(account); 36 | emit MinterAdded(account); 37 | } 38 | 39 | function _removeMinter(address account) internal { 40 | _minters.remove(account); 41 | emit MinterRemoved(account); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/roles/PauserRole.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | import "./Roles.sol"; 4 | 5 | contract PauserRole { 6 | using Roles for Roles.Role; 7 | 8 | event PauserAdded(address indexed account); 9 | event PauserRemoved(address indexed account); 10 | 11 | Roles.Role private _pausers; 12 | 13 | constructor () internal { 14 | _addPauser(msg.sender); 15 | } 16 | 17 | modifier onlyPauser() { 18 | require(isPauser(msg.sender), "PauserRole: caller does not have the Pauser role"); 19 | _; 20 | } 21 | 22 | function isPauser(address account) public view returns (bool) { 23 | return _pausers.has(account); 24 | } 25 | 26 | function addPauser(address account) public onlyPauser { 27 | _addPauser(account); 28 | } 29 | 30 | function renouncePauser() public { 31 | _removePauser(msg.sender); 32 | } 33 | 34 | function _addPauser(address account) internal { 35 | _pausers.add(account); 36 | emit PauserAdded(account); 37 | } 38 | 39 | function _removePauser(address account) internal { 40 | _pausers.remove(account); 41 | emit PauserRemoved(account); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/roles/Roles.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @title Roles 5 | * @dev Library for managing addresses assigned to a Role. 6 | */ 7 | library Roles { 8 | struct Role { 9 | mapping (address => bool) bearer; 10 | } 11 | 12 | /** 13 | * @dev Give an account access to this role. 14 | */ 15 | function add(Role storage role, address account) internal { 16 | require(!has(role, account), "Roles: account already has role"); 17 | role.bearer[account] = true; 18 | } 19 | 20 | /** 21 | * @dev Remove an account's access to this role. 22 | */ 23 | function remove(Role storage role, address account) internal { 24 | require(has(role, account), "Roles: account does not have role"); 25 | role.bearer[account] = false; 26 | } 27 | 28 | /** 29 | * @dev Check if an account has this role. 30 | * @return bool 31 | */ 32 | function has(Role storage role, address account) internal view returns (bool) { 33 | require(account != address(0), "Roles: account is the zero address"); 34 | return role.bearer[account]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/utils/Address.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @dev Collection of functions related to the address type, 5 | */ 6 | library Address { 7 | /** 8 | * @dev Returns true if `account` is a contract. 9 | * 10 | * This test is non-exhaustive, and there may be false-negatives: during the 11 | * execution of a contract's constructor, its address will be reported as 12 | * not containing a contract. 13 | * 14 | * > It is unsafe to assume that an address for which this function returns 15 | * false is an externally-owned account (EOA) and not a contract. 16 | */ 17 | function isContract(address account) internal view returns (bool) { 18 | // This method relies in extcodesize, which returns 0 for contracts in 19 | // construction, since the code is only stored at the end of the 20 | // constructor execution. 21 | 22 | uint256 size; 23 | // solhint-disable-next-line no-inline-assembly 24 | assembly { size := extcodesize(account) } 25 | return size > 0; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/utils/String.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | library String { 4 | 5 | function uint2str(uint _i) internal pure returns (string memory _uintAsString) { 6 | if (_i == 0) { 7 | return "0"; 8 | } 9 | uint j = _i; 10 | uint len; 11 | while (j != 0) { 12 | len++; 13 | j /= 10; 14 | } 15 | bytes memory bstr = new bytes(len); 16 | uint k = len - 1; 17 | while (_i != 0) { 18 | bstr[k--] = byte(uint8(48 + _i % 10)); 19 | _i /= 10; 20 | } 21 | return string(bstr); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /flatten/KIP17KbirdzTokenFlatten.sol: -------------------------------------------------------------------------------- 1 | // File: contracts\introspection\IKIP13.sol 2 | 3 | pragma solidity ^0.5.0; 4 | 5 | /** 6 | * @dev Interface of the KIP-13 standard, as defined in the 7 | * [KIP-13](http://kips.klaytn.com/KIPs/kip-13-interface_query_standard). 8 | * 9 | * Implementers can declare support of contract interfaces, which can then be 10 | * queried by others. 11 | * 12 | * For an implementation, see `KIP13`. 13 | */ 14 | interface IKIP13 { 15 | /** 16 | * @dev Returns true if this contract implements the interface defined by 17 | * `interfaceId`. See the corresponding 18 | * [KIP-13 section](http://kips.klaytn.com/KIPs/kip-13-interface_query_standard#how-interface-identifiers-are-defined) 19 | * to learn more about how these ids are created. 20 | * 21 | * This function call must use less than 30 000 gas. 22 | */ 23 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 24 | } 25 | 26 | // File: contracts\IKIP17.sol 27 | 28 | pragma solidity ^0.5.0; 29 | 30 | /** 31 | * @dev Required interface of an KIP17 compliant contract. 32 | */ 33 | contract IKIP17 is IKIP13 { 34 | event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 35 | event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); 36 | event ApprovalForAll(address indexed owner, address indexed operator, bool approved); 37 | 38 | /** 39 | * @dev Returns the number of NFTs in `owner`'s account. 40 | */ 41 | function balanceOf(address owner) public view returns (uint256 balance); 42 | 43 | /** 44 | * @dev Returns the owner of the NFT specified by `tokenId`. 45 | */ 46 | function ownerOf(uint256 tokenId) public view returns (address owner); 47 | 48 | /** 49 | * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to 50 | * another (`to`). 51 | * 52 | * Requirements: 53 | * - `from`, `to` cannot be zero. 54 | * - `tokenId` must be owned by `from`. 55 | * - If the caller is not `from`, it must be have been allowed to move this 56 | * NFT by either `approve` or `setApproveForAll`. 57 | */ 58 | function safeTransferFrom(address from, address to, uint256 tokenId) public; 59 | 60 | /** 61 | * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to 62 | * another (`to`). 63 | * 64 | * Requirements: 65 | * - If the caller is not `from`, it must be approved to move this NFT by 66 | * either `approve` or `setApproveForAll`. 67 | */ 68 | function transferFrom(address from, address to, uint256 tokenId) public; 69 | function approve(address to, uint256 tokenId) public; 70 | function getApproved(uint256 tokenId) public view returns (address operator); 71 | 72 | function setApprovalForAll(address operator, bool _approved) public; 73 | function isApprovedForAll(address owner, address operator) public view returns (bool); 74 | 75 | 76 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; 77 | } 78 | 79 | // File: contracts\IERC721Receiver.sol 80 | 81 | pragma solidity ^0.5.0; 82 | 83 | /** 84 | * @title ERC721 token receiver interface 85 | * @dev Interface for any contract that wants to support safeTransfers 86 | * from ERC721 asset contracts. 87 | */ 88 | contract IERC721Receiver { 89 | /** 90 | * @notice Handle the receipt of an NFT 91 | * @dev The ERC721 smart contract calls this function on the recipient 92 | * after a `safeTransfer`. This function MUST return the function selector, 93 | * otherwise the caller will revert the transaction. The selector to be 94 | * returned can be obtained as `this.onERC721Received.selector`. This 95 | * function MAY throw to revert and reject the transfer. 96 | * Note: the ERC721 contract address is always the message sender. 97 | * @param operator The address which called `safeTransferFrom` function 98 | * @param from The address which previously owned the token 99 | * @param tokenId The NFT identifier which is being transferred 100 | * @param data Additional data with no specified format 101 | * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 102 | */ 103 | function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) 104 | public returns (bytes4); 105 | } 106 | 107 | // File: contracts\IKIP17Receiver.sol 108 | 109 | pragma solidity ^0.5.0; 110 | 111 | /** 112 | * @title KIP17 token receiver interface 113 | * @dev Interface for any contract that wants to support safeTransfers 114 | * from KIP17 asset contracts. 115 | * @dev see http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 116 | */ 117 | contract IKIP17Receiver { 118 | /** 119 | * @notice Handle the receipt of an NFT 120 | * @dev The KIP17 smart contract calls this function on the recipient 121 | * after a `safeTransfer`. This function MUST return the function selector, 122 | * otherwise the caller will revert the transaction. The selector to be 123 | * returned can be obtained as `this.onKIP17Received.selector`. This 124 | * function MAY throw to revert and reject the transfer. 125 | * Note: the KIP17 contract address is always the message sender. 126 | * @param operator The address which called `safeTransferFrom` function 127 | * @param from The address which previously owned the token 128 | * @param tokenId The NFT identifier which is being transferred 129 | * @param data Additional data with no specified format 130 | * @return bytes4 `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))` 131 | */ 132 | function onKIP17Received(address operator, address from, uint256 tokenId, bytes memory data) 133 | public returns (bytes4); 134 | } 135 | 136 | // File: contracts\math\SafeMath.sol 137 | 138 | pragma solidity ^0.5.0; 139 | 140 | /** 141 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 142 | * checks. 143 | * 144 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 145 | * in bugs, because programmers usually assume that an overflow raises an 146 | * error, which is the standard behavior in high level programming languages. 147 | * `SafeMath` restores this intuition by reverting the transaction when an 148 | * operation overflows. 149 | * 150 | * Using this library instead of the unchecked operations eliminates an entire 151 | * class of bugs, so it's recommended to use it always. 152 | */ 153 | library SafeMath { 154 | /** 155 | * @dev Returns the addition of two unsigned integers, reverting on 156 | * overflow. 157 | * 158 | * Counterpart to Solidity's `+` operator. 159 | * 160 | * Requirements: 161 | * - Addition cannot overflow. 162 | */ 163 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 164 | uint256 c = a + b; 165 | require(c >= a, "SafeMath: addition overflow"); 166 | 167 | return c; 168 | } 169 | 170 | /** 171 | * @dev Returns the subtraction of two unsigned integers, reverting on 172 | * overflow (when the result is negative). 173 | * 174 | * Counterpart to Solidity's `-` operator. 175 | * 176 | * Requirements: 177 | * - Subtraction cannot overflow. 178 | */ 179 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 180 | return sub(a, b, "SafeMath: subtraction overflow"); 181 | } 182 | 183 | /** 184 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 185 | * overflow (when the result is negative). 186 | * 187 | * Counterpart to Solidity's `-` operator. 188 | * 189 | * Requirements: 190 | * - Subtraction cannot overflow. 191 | * 192 | * _Available since v2.4.0._ 193 | */ 194 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 195 | require(b <= a, errorMessage); 196 | uint256 c = a - b; 197 | 198 | return c; 199 | } 200 | 201 | /** 202 | * @dev Returns the multiplication of two unsigned integers, reverting on 203 | * overflow. 204 | * 205 | * Counterpart to Solidity's `*` operator. 206 | * 207 | * Requirements: 208 | * - Multiplication cannot overflow. 209 | */ 210 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 211 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 212 | // benefit is lost if 'b' is also tested. 213 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 214 | if (a == 0) { 215 | return 0; 216 | } 217 | 218 | uint256 c = a * b; 219 | require(c / a == b, "SafeMath: multiplication overflow"); 220 | 221 | return c; 222 | } 223 | 224 | /** 225 | * @dev Returns the integer division of two unsigned integers. Reverts on 226 | * division by zero. The result is rounded towards zero. 227 | * 228 | * Counterpart to Solidity's `/` operator. Note: this function uses a 229 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 230 | * uses an invalid opcode to revert (consuming all remaining gas). 231 | * 232 | * Requirements: 233 | * - The divisor cannot be zero. 234 | */ 235 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 236 | return div(a, b, "SafeMath: division by zero"); 237 | } 238 | 239 | /** 240 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 241 | * division by zero. The result is rounded towards zero. 242 | * 243 | * Counterpart to Solidity's `/` operator. Note: this function uses a 244 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 245 | * uses an invalid opcode to revert (consuming all remaining gas). 246 | * 247 | * Requirements: 248 | * - The divisor cannot be zero. 249 | * 250 | * _Available since v2.4.0._ 251 | */ 252 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 253 | // Solidity only automatically asserts when dividing by 0 254 | require(b > 0, errorMessage); 255 | uint256 c = a / b; 256 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 257 | 258 | return c; 259 | } 260 | 261 | /** 262 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 263 | * Reverts when dividing by zero. 264 | * 265 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 266 | * opcode (which leaves remaining gas untouched) while Solidity uses an 267 | * invalid opcode to revert (consuming all remaining gas). 268 | * 269 | * Requirements: 270 | * - The divisor cannot be zero. 271 | */ 272 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 273 | return mod(a, b, "SafeMath: modulo by zero"); 274 | } 275 | 276 | /** 277 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 278 | * Reverts with custom message when dividing by zero. 279 | * 280 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 281 | * opcode (which leaves remaining gas untouched) while Solidity uses an 282 | * invalid opcode to revert (consuming all remaining gas). 283 | * 284 | * Requirements: 285 | * - The divisor cannot be zero. 286 | * 287 | * _Available since v2.4.0._ 288 | */ 289 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 290 | require(b != 0, errorMessage); 291 | return a % b; 292 | } 293 | } 294 | 295 | // File: contracts\utils\Address.sol 296 | 297 | pragma solidity ^0.5.0; 298 | 299 | /** 300 | * @dev Collection of functions related to the address type, 301 | */ 302 | library Address { 303 | /** 304 | * @dev Returns true if `account` is a contract. 305 | * 306 | * This test is non-exhaustive, and there may be false-negatives: during the 307 | * execution of a contract's constructor, its address will be reported as 308 | * not containing a contract. 309 | * 310 | * > It is unsafe to assume that an address for which this function returns 311 | * false is an externally-owned account (EOA) and not a contract. 312 | */ 313 | function isContract(address account) internal view returns (bool) { 314 | // This method relies in extcodesize, which returns 0 for contracts in 315 | // construction, since the code is only stored at the end of the 316 | // constructor execution. 317 | 318 | uint256 size; 319 | // solhint-disable-next-line no-inline-assembly 320 | assembly { size := extcodesize(account) } 321 | return size > 0; 322 | } 323 | } 324 | 325 | // File: contracts\drafts\Counters.sol 326 | 327 | pragma solidity ^0.5.0; 328 | 329 | /** 330 | * @title Counters 331 | * @author Matt Condon (@shrugs) 332 | * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number 333 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 334 | * 335 | * Include with `using Counters for Counters.Counter;` 336 | * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath 337 | * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never 338 | * directly accessed. 339 | */ 340 | library Counters { 341 | using SafeMath for uint256; 342 | 343 | struct Counter { 344 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 345 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 346 | // this feature: see https://github.com/ethereum/solidity/issues/4637 347 | uint256 _value; // default: 0 348 | } 349 | 350 | function current(Counter storage counter) internal view returns (uint256) { 351 | return counter._value; 352 | } 353 | 354 | function increment(Counter storage counter) internal { 355 | counter._value += 1; 356 | } 357 | 358 | function decrement(Counter storage counter) internal { 359 | counter._value = counter._value.sub(1); 360 | } 361 | } 362 | 363 | // File: contracts\introspection\KIP13.sol 364 | 365 | pragma solidity ^0.5.0; 366 | 367 | /** 368 | * @dev Implementation of the `IKIP13` interface. 369 | * 370 | * Contracts may inherit from this and call `_registerInterface` to declare 371 | * their support of an interface. 372 | */ 373 | contract KIP13 is IKIP13 { 374 | /* 375 | * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 376 | */ 377 | bytes4 private constant _INTERFACE_ID_KIP13 = 0x01ffc9a7; 378 | 379 | /** 380 | * @dev Mapping of interface ids to whether or not it's supported. 381 | */ 382 | mapping(bytes4 => bool) private _supportedInterfaces; 383 | 384 | constructor () internal { 385 | // Derived contracts need only register support for their own interfaces, 386 | // we register support for KIP13 itself here 387 | _registerInterface(_INTERFACE_ID_KIP13); 388 | } 389 | 390 | /** 391 | * @dev See `IKIP13.supportsInterface`. 392 | * 393 | * Time complexity O(1), guaranteed to always use less than 30 000 gas. 394 | */ 395 | function supportsInterface(bytes4 interfaceId) external view returns (bool) { 396 | return _supportedInterfaces[interfaceId]; 397 | } 398 | 399 | /** 400 | * @dev Registers the contract as an implementer of the interface defined by 401 | * `interfaceId`. Support of the actual KIP13 interface is automatic and 402 | * registering its interface id is not required. 403 | * 404 | * See `IKIP13.supportsInterface`. 405 | * 406 | * Requirements: 407 | * 408 | * - `interfaceId` cannot be the KIP13 invalid interface (`0xffffffff`). 409 | */ 410 | function _registerInterface(bytes4 interfaceId) internal { 411 | require(interfaceId != 0xffffffff, "KIP13: invalid interface id"); 412 | _supportedInterfaces[interfaceId] = true; 413 | } 414 | } 415 | 416 | // File: contracts\KIP17.sol 417 | 418 | pragma solidity ^0.5.0; 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | /** 427 | * @title KIP17 Non-Fungible Token Standard basic implementation 428 | * @dev see http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 429 | */ 430 | contract KIP17 is KIP13, IKIP17 { 431 | using SafeMath for uint256; 432 | using Address for address; 433 | using Counters for Counters.Counter; 434 | 435 | // Equals to `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))` 436 | // which can be also obtained as `IKIP17Receiver(0).onKIP17Received.selector` 437 | bytes4 private constant _KIP17_RECEIVED = 0x6745782b; 438 | 439 | // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 440 | // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` 441 | bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; 442 | 443 | // Mapping from token ID to owner 444 | mapping (uint256 => address) private _tokenOwner; 445 | 446 | // Mapping from token ID to approved address 447 | mapping (uint256 => address) private _tokenApprovals; 448 | 449 | // Mapping from owner to number of owned token 450 | mapping (address => Counters.Counter) private _ownedTokensCount; 451 | 452 | // Mapping from owner to operator approvals 453 | mapping (address => mapping (address => bool)) private _operatorApprovals; 454 | 455 | /* 456 | * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 457 | * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e 458 | * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 459 | * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc 460 | * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 461 | * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c 462 | * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd 463 | * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e 464 | * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde 465 | * 466 | * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ 467 | * 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd 468 | */ 469 | bytes4 private constant _INTERFACE_ID_KIP17 = 0x80ac58cd; 470 | 471 | constructor () public { 472 | // register the supported interfaces to conform to KIP17 via KIP13 473 | _registerInterface(_INTERFACE_ID_KIP17); 474 | } 475 | 476 | /** 477 | * @dev Gets the balance of the specified address. 478 | * @param owner address to query the balance of 479 | * @return uint256 representing the amount owned by the passed address 480 | */ 481 | function balanceOf(address owner) public view returns (uint256) { 482 | require(owner != address(0), "KIP17: balance query for the zero address"); 483 | 484 | return _ownedTokensCount[owner].current(); 485 | } 486 | 487 | /** 488 | * @dev Gets the owner of the specified token ID. 489 | * @param tokenId uint256 ID of the token to query the owner of 490 | * @return address currently marked as the owner of the given token ID 491 | */ 492 | function ownerOf(uint256 tokenId) public view returns (address) { 493 | address owner = _tokenOwner[tokenId]; 494 | require(owner != address(0), "KIP17: owner query for nonexistent token"); 495 | 496 | return owner; 497 | } 498 | 499 | /** 500 | * @dev Approves another address to transfer the given token ID 501 | * The zero address indicates there is no approved address. 502 | * There can only be one approved address per token at a given time. 503 | * Can only be called by the token owner or an approved operator. 504 | * @param to address to be approved for the given token ID 505 | * @param tokenId uint256 ID of the token to be approved 506 | */ 507 | function approve(address to, uint256 tokenId) public { 508 | address owner = ownerOf(tokenId); 509 | require(to != owner, "KIP17: approval to current owner"); 510 | 511 | require(msg.sender == owner || isApprovedForAll(owner, msg.sender), 512 | "KIP17: approve caller is not owner nor approved for all" 513 | ); 514 | 515 | _tokenApprovals[tokenId] = to; 516 | emit Approval(owner, to, tokenId); 517 | } 518 | 519 | /** 520 | * @dev Gets the approved address for a token ID, or zero if no address set 521 | * Reverts if the token ID does not exist. 522 | * @param tokenId uint256 ID of the token to query the approval of 523 | * @return address currently approved for the given token ID 524 | */ 525 | function getApproved(uint256 tokenId) public view returns (address) { 526 | require(_exists(tokenId), "KIP17: approved query for nonexistent token"); 527 | 528 | return _tokenApprovals[tokenId]; 529 | } 530 | 531 | /** 532 | * @dev Sets or unsets the approval of a given operator 533 | * An operator is allowed to transfer all tokens of the sender on their behalf. 534 | * @param to operator address to set the approval 535 | * @param approved representing the status of the approval to be set 536 | */ 537 | function setApprovalForAll(address to, bool approved) public { 538 | require(to != msg.sender, "KIP17: approve to caller"); 539 | 540 | _operatorApprovals[msg.sender][to] = approved; 541 | emit ApprovalForAll(msg.sender, to, approved); 542 | } 543 | 544 | /** 545 | * @dev Tells whether an operator is approved by a given owner. 546 | * @param owner owner address which you want to query the approval of 547 | * @param operator operator address which you want to query the approval of 548 | * @return bool whether the given operator is approved by the given owner 549 | */ 550 | function isApprovedForAll(address owner, address operator) public view returns (bool) { 551 | return _operatorApprovals[owner][operator]; 552 | } 553 | 554 | /** 555 | * @dev Transfers the ownership of a given token ID to another address. 556 | * Usage of this method is discouraged, use `safeTransferFrom` whenever possible. 557 | * Requires the msg.sender to be the owner, approved, or operator. 558 | * @param from current owner of the token 559 | * @param to address to receive the ownership of the given token ID 560 | * @param tokenId uint256 ID of the token to be transferred 561 | */ 562 | function transferFrom(address from, address to, uint256 tokenId) public { 563 | //solhint-disable-next-line max-line-length 564 | require(_isApprovedOrOwner(msg.sender, tokenId), "KIP17: transfer caller is not owner nor approved"); 565 | 566 | _transferFrom(from, to, tokenId); 567 | } 568 | 569 | /** 570 | * @dev Safely transfers the ownership of a given token ID to another address 571 | * If the target address is a contract, it must implement `onKIP17Received`, 572 | * which is called upon a safe transfer, and return the magic value 573 | * `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))`; otherwise, 574 | * the transfer is reverted. 575 | * Requires the msg.sender to be the owner, approved, or operator 576 | * @param from current owner of the token 577 | * @param to address to receive the ownership of the given token ID 578 | * @param tokenId uint256 ID of the token to be transferred 579 | */ 580 | function safeTransferFrom(address from, address to, uint256 tokenId) public { 581 | safeTransferFrom(from, to, tokenId, ""); 582 | } 583 | 584 | /** 585 | * @dev Safely transfers the ownership of a given token ID to another address 586 | * If the target address is a contract, it must implement `onKIP17Received`, 587 | * which is called upon a safe transfer, and return the magic value 588 | * `bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"))`; otherwise, 589 | * the transfer is reverted. 590 | * Requires the msg.sender to be the owner, approved, or operator 591 | * @param from current owner of the token 592 | * @param to address to receive the ownership of the given token ID 593 | * @param tokenId uint256 ID of the token to be transferred 594 | * @param _data bytes data to send along with a safe transfer check 595 | */ 596 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { 597 | transferFrom(from, to, tokenId); 598 | require(_checkOnKIP17Received(from, to, tokenId, _data), "KIP17: transfer to non KIP17Receiver implementer"); 599 | } 600 | 601 | /** 602 | * @dev Returns whether the specified token exists. 603 | * @param tokenId uint256 ID of the token to query the existence of 604 | * @return bool whether the token exists 605 | */ 606 | function _exists(uint256 tokenId) internal view returns (bool) { 607 | address owner = _tokenOwner[tokenId]; 608 | return owner != address(0); 609 | } 610 | 611 | /** 612 | * @dev Returns whether the given spender can transfer a given token ID. 613 | * @param spender address of the spender to query 614 | * @param tokenId uint256 ID of the token to be transferred 615 | * @return bool whether the msg.sender is approved for the given token ID, 616 | * is an operator of the owner, or is the owner of the token 617 | */ 618 | function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { 619 | require(_exists(tokenId), "KIP17: operator query for nonexistent token"); 620 | address owner = ownerOf(tokenId); 621 | return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); 622 | } 623 | 624 | /** 625 | * @dev Internal function to mint a new token. 626 | * Reverts if the given token ID already exists. 627 | * @param to The address that will own the minted token 628 | * @param tokenId uint256 ID of the token to be minted 629 | */ 630 | function _mint(address to, uint256 tokenId) internal { 631 | require(to != address(0), "KIP17: mint to the zero address"); 632 | require(!_exists(tokenId), "KIP17: token already minted"); 633 | 634 | _tokenOwner[tokenId] = to; 635 | _ownedTokensCount[to].increment(); 636 | 637 | emit Transfer(address(0), to, tokenId); 638 | } 639 | 640 | /** 641 | * @dev Internal function to burn a specific token. 642 | * Reverts if the token does not exist. 643 | * Deprecated, use _burn(uint256) instead. 644 | * @param owner owner of the token to burn 645 | * @param tokenId uint256 ID of the token being burned 646 | */ 647 | function _burn(address owner, uint256 tokenId) internal { 648 | require(ownerOf(tokenId) == owner, "KIP17: burn of token that is not own"); 649 | 650 | _clearApproval(tokenId); 651 | 652 | _ownedTokensCount[owner].decrement(); 653 | _tokenOwner[tokenId] = address(0); 654 | 655 | emit Transfer(owner, address(0), tokenId); 656 | } 657 | 658 | /** 659 | * @dev Internal function to burn a specific token. 660 | * Reverts if the token does not exist. 661 | * @param tokenId uint256 ID of the token being burned 662 | */ 663 | function _burn(uint256 tokenId) internal { 664 | _burn(ownerOf(tokenId), tokenId); 665 | } 666 | 667 | /** 668 | * @dev Internal function to transfer ownership of a given token ID to another address. 669 | * As opposed to transferFrom, this imposes no restrictions on msg.sender. 670 | * @param from current owner of the token 671 | * @param to address to receive the ownership of the given token ID 672 | * @param tokenId uint256 ID of the token to be transferred 673 | */ 674 | function _transferFrom(address from, address to, uint256 tokenId) internal { 675 | require(ownerOf(tokenId) == from, "KIP17: transfer of token that is not own"); 676 | require(to != address(0), "KIP17: transfer to the zero address"); 677 | 678 | _clearApproval(tokenId); 679 | 680 | _ownedTokensCount[from].decrement(); 681 | _ownedTokensCount[to].increment(); 682 | 683 | _tokenOwner[tokenId] = to; 684 | 685 | emit Transfer(from, to, tokenId); 686 | } 687 | 688 | /** 689 | * @dev Internal function to invoke `onKIP17Received` on a target address. 690 | * The call is not executed if the target address is not a contract. 691 | * 692 | * This function is deprecated. 693 | * @param from address representing the previous owner of the given token ID 694 | * @param to target address that will receive the tokens 695 | * @param tokenId uint256 ID of the token to be transferred 696 | * @param _data bytes optional data to send along with the call 697 | * @return bool whether the call correctly returned the expected magic value 698 | */ 699 | function _checkOnKIP17Received(address from, address to, uint256 tokenId, bytes memory _data) 700 | internal returns (bool) 701 | { 702 | bool success; 703 | bytes memory returndata; 704 | 705 | if (!to.isContract()) { 706 | return true; 707 | } 708 | 709 | // Logic for compatibility with ERC721. 710 | (success, returndata) = to.call( 711 | abi.encodeWithSelector(_ERC721_RECEIVED, msg.sender, from, tokenId, _data) 712 | ); 713 | if (returndata.length != 0 && abi.decode(returndata, (bytes4)) == _ERC721_RECEIVED) { 714 | return true; 715 | } 716 | 717 | (success, returndata) = to.call( 718 | abi.encodeWithSelector(_KIP17_RECEIVED, msg.sender, from, tokenId, _data) 719 | ); 720 | if (returndata.length != 0 && abi.decode(returndata, (bytes4)) == _KIP17_RECEIVED) { 721 | return true; 722 | } 723 | 724 | return false; 725 | } 726 | 727 | /** 728 | * @dev Private function to clear current approval of a given token ID. 729 | * @param tokenId uint256 ID of the token to be transferred 730 | */ 731 | function _clearApproval(uint256 tokenId) private { 732 | if (_tokenApprovals[tokenId] != address(0)) { 733 | _tokenApprovals[tokenId] = address(0); 734 | } 735 | } 736 | } 737 | 738 | // File: contracts\IKIP17Enumerable.sol 739 | 740 | pragma solidity ^0.5.0; 741 | 742 | /** 743 | * @title KIP-17 Non-Fungible Token Standard, optional enumeration extension 744 | * @dev See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 745 | */ 746 | contract IKIP17Enumerable is IKIP17 { 747 | function totalSupply() public view returns (uint256); 748 | function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId); 749 | 750 | function tokenByIndex(uint256 index) public view returns (uint256); 751 | } 752 | 753 | // File: contracts\KIP17Enumerable.sol 754 | 755 | pragma solidity ^0.5.0; 756 | 757 | 758 | 759 | /** 760 | * @title KIP-17 Non-Fungible Token with optional enumeration extension logic 761 | * @dev See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 762 | */ 763 | contract KIP17Enumerable is KIP13, KIP17, IKIP17Enumerable { 764 | // Mapping from owner to list of owned token IDs 765 | mapping(address => uint256[]) private _ownedTokens; 766 | 767 | // Mapping from token ID to index of the owner tokens list 768 | mapping(uint256 => uint256) private _ownedTokensIndex; 769 | 770 | // Array with all token ids, used for enumeration 771 | uint256[] private _allTokens; 772 | 773 | // Mapping from token id to position in the allTokens array 774 | mapping(uint256 => uint256) private _allTokensIndex; 775 | 776 | /* 777 | * bytes4(keccak256('totalSupply()')) == 0x18160ddd 778 | * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 779 | * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 780 | * 781 | * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 782 | */ 783 | bytes4 private constant _INTERFACE_ID_KIP17_ENUMERABLE = 0x780e9d63; 784 | 785 | /** 786 | * @dev Constructor function. 787 | */ 788 | constructor () public { 789 | // register the supported interface to conform to KIP17Enumerable via KIP13 790 | _registerInterface(_INTERFACE_ID_KIP17_ENUMERABLE); 791 | } 792 | 793 | /** 794 | * @dev Gets the token ID at a given index of the tokens list of the requested owner. 795 | * @param owner address owning the tokens list to be accessed 796 | * @param index uint256 representing the index to be accessed of the requested tokens list 797 | * @return uint256 token ID at the given index of the tokens list owned by the requested address 798 | */ 799 | function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) { 800 | require(index < balanceOf(owner), "KIP17Enumerable: owner index out of bounds"); 801 | return _ownedTokens[owner][index]; 802 | } 803 | 804 | /** 805 | * @dev Gets the total amount of tokens stored by the contract. 806 | * @return uint256 representing the total amount of tokens 807 | */ 808 | function totalSupply() public view returns (uint256) { 809 | return _allTokens.length; 810 | } 811 | 812 | /** 813 | * @dev Gets the token ID at a given index of all the tokens in this contract 814 | * Reverts if the index is greater or equal to the total number of tokens. 815 | * @param index uint256 representing the index to be accessed of the tokens list 816 | * @return uint256 token ID at the given index of the tokens list 817 | */ 818 | function tokenByIndex(uint256 index) public view returns (uint256) { 819 | require(index < totalSupply(), "KIP17Enumerable: global index out of bounds"); 820 | return _allTokens[index]; 821 | } 822 | 823 | /** 824 | * @dev Internal function to transfer ownership of a given token ID to another address. 825 | * As opposed to transferFrom, this imposes no restrictions on msg.sender. 826 | * @param from current owner of the token 827 | * @param to address to receive the ownership of the given token ID 828 | * @param tokenId uint256 ID of the token to be transferred 829 | */ 830 | function _transferFrom(address from, address to, uint256 tokenId) internal { 831 | super._transferFrom(from, to, tokenId); 832 | 833 | _removeTokenFromOwnerEnumeration(from, tokenId); 834 | 835 | _addTokenToOwnerEnumeration(to, tokenId); 836 | } 837 | 838 | /** 839 | * @dev Internal function to mint a new token. 840 | * Reverts if the given token ID already exists. 841 | * @param to address the beneficiary that will own the minted token 842 | * @param tokenId uint256 ID of the token to be minted 843 | */ 844 | function _mint(address to, uint256 tokenId) internal { 845 | super._mint(to, tokenId); 846 | 847 | _addTokenToOwnerEnumeration(to, tokenId); 848 | 849 | _addTokenToAllTokensEnumeration(tokenId); 850 | } 851 | 852 | /** 853 | * @dev Internal function to burn a specific token. 854 | * Reverts if the token does not exist. 855 | * Deprecated, use _burn(uint256) instead. 856 | * @param owner owner of the token to burn 857 | * @param tokenId uint256 ID of the token being burned 858 | */ 859 | function _burn(address owner, uint256 tokenId) internal { 860 | super._burn(owner, tokenId); 861 | 862 | _removeTokenFromOwnerEnumeration(owner, tokenId); 863 | // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund 864 | _ownedTokensIndex[tokenId] = 0; 865 | 866 | _removeTokenFromAllTokensEnumeration(tokenId); 867 | } 868 | 869 | /** 870 | * @dev Gets the list of token IDs of the requested owner. 871 | * @param owner address owning the tokens 872 | * @return uint256[] List of token IDs owned by the requested address 873 | */ 874 | function _tokensOfOwner(address owner) internal view returns (uint256[] storage) { 875 | return _ownedTokens[owner]; 876 | } 877 | 878 | /** 879 | * @dev Private function to add a token to this extension's ownership-tracking data structures. 880 | * @param to address representing the new owner of the given token ID 881 | * @param tokenId uint256 ID of the token to be added to the tokens list of the given address 882 | */ 883 | function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { 884 | _ownedTokensIndex[tokenId] = _ownedTokens[to].length; 885 | _ownedTokens[to].push(tokenId); 886 | } 887 | 888 | /** 889 | * @dev Private function to add a token to this extension's token tracking data structures. 890 | * @param tokenId uint256 ID of the token to be added to the tokens list 891 | */ 892 | function _addTokenToAllTokensEnumeration(uint256 tokenId) private { 893 | _allTokensIndex[tokenId] = _allTokens.length; 894 | _allTokens.push(tokenId); 895 | } 896 | 897 | /** 898 | * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that 899 | * while the token is not assigned a new owner, the _ownedTokensIndex mapping is _not_ updated: this allows for 900 | * gas optimizations e.g. when performing a transfer operation (avoiding double writes). 901 | * This has O(1) time complexity, but alters the order of the _ownedTokens array. 902 | * @param from address representing the previous owner of the given token ID 903 | * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address 904 | */ 905 | function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { 906 | // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and 907 | // then delete the last slot (swap and pop). 908 | 909 | uint256 lastTokenIndex = _ownedTokens[from].length.sub(1); 910 | uint256 tokenIndex = _ownedTokensIndex[tokenId]; 911 | 912 | // When the token to delete is the last token, the swap operation is unnecessary 913 | if (tokenIndex != lastTokenIndex) { 914 | uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; 915 | 916 | _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token 917 | _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index 918 | } 919 | 920 | // This also deletes the contents at the last position of the array 921 | _ownedTokens[from].length--; 922 | 923 | // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by 924 | // lastTokenId, or just over the end of the array if the token was the last one). 925 | } 926 | 927 | /** 928 | * @dev Private function to remove a token from this extension's token tracking data structures. 929 | * This has O(1) time complexity, but alters the order of the _allTokens array. 930 | * @param tokenId uint256 ID of the token to be removed from the tokens list 931 | */ 932 | function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { 933 | // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and 934 | // then delete the last slot (swap and pop). 935 | 936 | uint256 lastTokenIndex = _allTokens.length.sub(1); 937 | uint256 tokenIndex = _allTokensIndex[tokenId]; 938 | 939 | // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so 940 | // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding 941 | // an 'if' statement (like in _removeTokenFromOwnerEnumeration) 942 | uint256 lastTokenId = _allTokens[lastTokenIndex]; 943 | 944 | _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token 945 | _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index 946 | 947 | // This also deletes the contents at the last position of the array 948 | _allTokens.length--; 949 | _allTokensIndex[tokenId] = 0; 950 | } 951 | } 952 | 953 | // File: contracts\IKIP17Metadata.sol 954 | 955 | pragma solidity ^0.5.0; 956 | 957 | /** 958 | * @title KIP-17 Non-Fungible Token Standard, optional metadata extension 959 | * @dev See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 960 | */ 961 | contract IKIP17Metadata is IKIP17 { 962 | function name() external view returns (string memory); 963 | function symbol() external view returns (string memory); 964 | function tokenURI(uint256 tokenId) external view returns (string memory); 965 | } 966 | 967 | // File: contracts\KIP17Metadata.sol 968 | 969 | pragma solidity ^0.5.0; 970 | 971 | 972 | 973 | contract KIP17Metadata is KIP13, KIP17, IKIP17Metadata { 974 | // Token name 975 | string private _name; 976 | 977 | // Token symbol 978 | string private _symbol; 979 | 980 | // Optional mapping for token URIs 981 | mapping(uint256 => string) private _tokenURIs; 982 | 983 | /* 984 | * bytes4(keccak256('name()')) == 0x06fdde03 985 | * bytes4(keccak256('symbol()')) == 0x95d89b41 986 | * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd 987 | * 988 | * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f 989 | */ 990 | bytes4 private constant _INTERFACE_ID_KIP17_METADATA = 0x5b5e139f; 991 | 992 | /** 993 | * @dev Constructor function 994 | */ 995 | constructor (string memory name, string memory symbol) public { 996 | _name = name; 997 | _symbol = symbol; 998 | 999 | // register the supported interfaces to conform to KIP17 via KIP13 1000 | _registerInterface(_INTERFACE_ID_KIP17_METADATA); 1001 | } 1002 | 1003 | /** 1004 | * @dev Gets the token name. 1005 | * @return string representing the token name 1006 | */ 1007 | function name() external view returns (string memory) { 1008 | return _name; 1009 | } 1010 | 1011 | /** 1012 | * @dev Gets the token symbol. 1013 | * @return string representing the token symbol 1014 | */ 1015 | function symbol() external view returns (string memory) { 1016 | return _symbol; 1017 | } 1018 | 1019 | /** 1020 | * @dev Returns an URI for a given token ID. 1021 | * Throws if the token ID does not exist. May return an empty string. 1022 | * @param tokenId uint256 ID of the token to query 1023 | */ 1024 | function tokenURI(uint256 tokenId) external view returns (string memory) { 1025 | require(_exists(tokenId), "KIP17Metadata: URI query for nonexistent token"); 1026 | return _tokenURIs[tokenId]; 1027 | } 1028 | 1029 | /** 1030 | * @dev Internal function to set the token URI for a given token. 1031 | * Reverts if the token ID does not exist. 1032 | * @param tokenId uint256 ID of the token to set its URI 1033 | * @param uri string URI to assign 1034 | */ 1035 | function _setTokenURI(uint256 tokenId, string memory uri) internal { 1036 | require(_exists(tokenId), "KIP17Metadata: URI set of nonexistent token"); 1037 | _tokenURIs[tokenId] = uri; 1038 | } 1039 | 1040 | /** 1041 | * @dev Internal function to burn a specific token. 1042 | * Reverts if the token does not exist. 1043 | * Deprecated, use _burn(uint256) instead. 1044 | * @param owner owner of the token to burn 1045 | * @param tokenId uint256 ID of the token being burned by the msg.sender 1046 | */ 1047 | function _burn(address owner, uint256 tokenId) internal { 1048 | super._burn(owner, tokenId); 1049 | 1050 | // Clear metadata (if any) 1051 | if (bytes(_tokenURIs[tokenId]).length != 0) { 1052 | delete _tokenURIs[tokenId]; 1053 | } 1054 | } 1055 | } 1056 | 1057 | // File: contracts\ownership\Ownable.sol 1058 | 1059 | pragma solidity ^0.5.0; 1060 | 1061 | /** 1062 | * @dev Contract module which provides a basic access control mechanism, where 1063 | * there is an account (an owner) that can be granted exclusive access to 1064 | * specific functions. 1065 | * 1066 | * This module is used through inheritance. It will make available the modifier 1067 | * `onlyOwner`, which can be aplied to your functions to restrict their use to 1068 | * the owner. 1069 | */ 1070 | contract Ownable { 1071 | address payable private _owner; 1072 | 1073 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 1074 | 1075 | /** 1076 | * @dev Initializes the contract setting the deployer as the initial owner. 1077 | */ 1078 | constructor () internal { 1079 | _owner = msg.sender; 1080 | emit OwnershipTransferred(address(0), _owner); 1081 | } 1082 | 1083 | /** 1084 | * @dev Returns the address of the current owner. 1085 | */ 1086 | function owner() public view returns (address payable) { 1087 | return _owner; 1088 | } 1089 | 1090 | /** 1091 | * @dev Throws if called by any account other than the owner. 1092 | */ 1093 | modifier onlyOwner() { 1094 | require(isOwner(), "Ownable: caller is not the owner"); 1095 | _; 1096 | } 1097 | 1098 | /** 1099 | * @dev Returns true if the caller is the current owner. 1100 | */ 1101 | function isOwner() public view returns (bool) { 1102 | return msg.sender == _owner; 1103 | } 1104 | 1105 | /** 1106 | * @dev Leaves the contract without owner. It will not be possible to call 1107 | * `onlyOwner` functions anymore. Can only be called by the current owner. 1108 | * 1109 | * > Note: Renouncing ownership will leave the contract without an owner, 1110 | * thereby removing any functionality that is only available to the owner. 1111 | */ 1112 | function renounceOwnership() public onlyOwner { 1113 | emit OwnershipTransferred(_owner, address(0)); 1114 | _owner = address(0); 1115 | } 1116 | 1117 | /** 1118 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 1119 | * Can only be called by the current owner. 1120 | */ 1121 | function transferOwnership(address payable newOwner) public onlyOwner { 1122 | _transferOwnership(newOwner); 1123 | } 1124 | 1125 | /** 1126 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 1127 | */ 1128 | function _transferOwnership(address payable newOwner) internal { 1129 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 1130 | emit OwnershipTransferred(_owner, newOwner); 1131 | _owner = newOwner; 1132 | } 1133 | } 1134 | 1135 | // File: contracts\roles\Roles.sol 1136 | 1137 | pragma solidity ^0.5.0; 1138 | 1139 | /** 1140 | * @title Roles 1141 | * @dev Library for managing addresses assigned to a Role. 1142 | */ 1143 | library Roles { 1144 | struct Role { 1145 | mapping (address => bool) bearer; 1146 | } 1147 | 1148 | /** 1149 | * @dev Give an account access to this role. 1150 | */ 1151 | function add(Role storage role, address account) internal { 1152 | require(!has(role, account), "Roles: account already has role"); 1153 | role.bearer[account] = true; 1154 | } 1155 | 1156 | /** 1157 | * @dev Remove an account's access to this role. 1158 | */ 1159 | function remove(Role storage role, address account) internal { 1160 | require(has(role, account), "Roles: account does not have role"); 1161 | role.bearer[account] = false; 1162 | } 1163 | 1164 | /** 1165 | * @dev Check if an account has this role. 1166 | * @return bool 1167 | */ 1168 | function has(Role storage role, address account) internal view returns (bool) { 1169 | require(account != address(0), "Roles: account is the zero address"); 1170 | return role.bearer[account]; 1171 | } 1172 | } 1173 | 1174 | // File: contracts\roles\MinterRole.sol 1175 | 1176 | pragma solidity ^0.5.0; 1177 | 1178 | contract MinterRole { 1179 | using Roles for Roles.Role; 1180 | 1181 | event MinterAdded(address indexed account); 1182 | event MinterRemoved(address indexed account); 1183 | 1184 | Roles.Role private _minters; 1185 | 1186 | constructor () internal { 1187 | _addMinter(msg.sender); 1188 | } 1189 | 1190 | modifier onlyMinter() { 1191 | require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role"); 1192 | _; 1193 | } 1194 | 1195 | function isMinter(address account) public view returns (bool) { 1196 | return _minters.has(account); 1197 | } 1198 | 1199 | function addMinter(address account) public onlyMinter { 1200 | _addMinter(account); 1201 | } 1202 | 1203 | function renounceMinter() public { 1204 | _removeMinter(msg.sender); 1205 | } 1206 | 1207 | function _addMinter(address account) internal { 1208 | _minters.add(account); 1209 | emit MinterAdded(account); 1210 | } 1211 | 1212 | function _removeMinter(address account) internal { 1213 | _minters.remove(account); 1214 | emit MinterRemoved(account); 1215 | } 1216 | } 1217 | 1218 | // File: contracts\utils\String.sol 1219 | 1220 | pragma solidity ^0.5.0; 1221 | 1222 | library String { 1223 | 1224 | function uint2str(uint _i) internal pure returns (string memory _uintAsString) { 1225 | if (_i == 0) { 1226 | return "0"; 1227 | } 1228 | uint j = _i; 1229 | uint len; 1230 | while (j != 0) { 1231 | len++; 1232 | j /= 10; 1233 | } 1234 | bytes memory bstr = new bytes(len); 1235 | uint k = len - 1; 1236 | while (_i != 0) { 1237 | bstr[k--] = byte(uint8(48 + _i % 10)); 1238 | _i /= 10; 1239 | } 1240 | return string(bstr); 1241 | } 1242 | 1243 | } 1244 | 1245 | // File: contracts\MerkleProof.sol 1246 | 1247 | // SPDX-License-Identifier: MIT 1248 | // OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol) 1249 | 1250 | pragma solidity ^0.5.0; 1251 | 1252 | /** 1253 | * @dev These functions deal with verification of Merkle Trees proofs. 1254 | * 1255 | * The proofs can be generated using the JavaScript library 1256 | * https://github.com/miguelmota/merkletreejs[merkletreejs]. 1257 | * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. 1258 | * 1259 | * See `test/utils/cryptography/MerkleProof.test.js` for some examples. 1260 | * 1261 | * WARNING: You should avoid using leaf values that are 64 bytes long prior to 1262 | * hashing, or use a hash function other than keccak256 for hashing leaves. 1263 | * This is because the concatenation of a sorted pair of internal nodes in 1264 | * the merkle tree could be reinterpreted as a leaf value. 1265 | */ 1266 | library MerkleProof { 1267 | /** 1268 | * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree 1269 | * defined by `root`. For this, a `proof` must be provided, containing 1270 | * sibling hashes on the branch from the leaf to the root of the tree. Each 1271 | * pair of leaves and each pair of pre-images are assumed to be sorted. 1272 | */ 1273 | function verify( 1274 | bytes32[] memory proof, 1275 | bytes32 root, 1276 | bytes32 leaf 1277 | ) internal pure returns (bool) { 1278 | return processProof(proof, leaf) == root; 1279 | } 1280 | 1281 | /** 1282 | * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up 1283 | * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt 1284 | * hash matches the root of the tree. When processing the proof, the pairs 1285 | * of leafs & pre-images are assumed to be sorted. 1286 | * 1287 | * _Available since v4.4._ 1288 | */ 1289 | function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { 1290 | bytes32 computedHash = leaf; 1291 | for (uint256 i = 0; i < proof.length; i++) { 1292 | bytes32 proofElement = proof[i]; 1293 | if (computedHash <= proofElement) { 1294 | // Hash(current computed hash + current element of the proof) 1295 | computedHash = _efficientHash(computedHash, proofElement); 1296 | } else { 1297 | // Hash(current element of the proof + current computed hash) 1298 | computedHash = _efficientHash(proofElement, computedHash); 1299 | } 1300 | } 1301 | return computedHash; 1302 | } 1303 | 1304 | function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { 1305 | assembly { 1306 | mstore(0x00, a) 1307 | mstore(0x20, b) 1308 | value := keccak256(0x00, 0x40) 1309 | } 1310 | } 1311 | } 1312 | 1313 | // File: contracts\KIP17Kbirdz.sol 1314 | 1315 | pragma solidity ^0.5.0; 1316 | contract KIP17Kbirdz is KIP17, KIP17Enumerable, KIP17Metadata, MinterRole { 1317 | 1318 | // To prevent bot attack, we record the last contract call block number. 1319 | mapping (address => uint256) private _lastCallBlockNumber; 1320 | uint256 private _antibotInterval; 1321 | 1322 | // If someone burns NFT in the middle of minting, 1323 | // the tokenId will go wrong, so use the index instead of totalSupply(). 1324 | uint256 private _mintIndexForSale; 1325 | 1326 | uint256 private _mintLimitPerBlock; // Maximum purchase nft per person per block 1327 | uint256 private _mintLimitPerSale; // Maximum purchase nft per person per sale 1328 | 1329 | string private _tokenBaseURI; 1330 | uint256 private _mintStartBlockNumber; // In blockchain, blocknumber is the standard of time. 1331 | uint256 private _maxSaleAmount; // Maximum purchase volume of normal sale. 1332 | uint256 private _mintPrice; // 1 KLAY = 1000000000000000000 1333 | 1334 | string baseURI; 1335 | string notRevealedUri; 1336 | bool public revealed = false; 1337 | bool public publicMintEnabled = false; 1338 | 1339 | function _baseURI() internal view returns (string memory) { 1340 | return baseURI; 1341 | } 1342 | 1343 | function _notRevealedURI() internal view returns (string memory) { 1344 | return notRevealedUri; 1345 | } 1346 | 1347 | function setBaseURI(string memory _newBaseURI) public onlyMinter { 1348 | baseURI = _newBaseURI; 1349 | } 1350 | 1351 | function setNotRevealedURI(string memory _newNotRevealedURI) public onlyMinter { 1352 | notRevealedUri = _newNotRevealedURI; 1353 | } 1354 | 1355 | function reveal(bool _state) public onlyMinter { 1356 | revealed = _state; 1357 | } 1358 | 1359 | function tokenURI(uint256 tokenId) 1360 | public 1361 | view 1362 | returns (string memory) 1363 | { 1364 | require( 1365 | _exists(tokenId), 1366 | "KIP17Metadata: URI query for nonexistent token" 1367 | ); 1368 | 1369 | if(revealed == false) { 1370 | string memory currentNotRevealedUri = _notRevealedURI(); 1371 | return bytes(currentNotRevealedUri).length > 0 1372 | ? string(abi.encodePacked(currentNotRevealedUri, String.uint2str(tokenId), ".json")) 1373 | : ""; 1374 | } 1375 | string memory currentBaseURI = _baseURI(); 1376 | return bytes(currentBaseURI).length > 0 1377 | ? string(abi.encodePacked(currentBaseURI, String.uint2str(tokenId), ".json")) 1378 | : ""; 1379 | } 1380 | 1381 | constructor () public { 1382 | //init explicitly. 1383 | _mintIndexForSale = 1; 1384 | } 1385 | 1386 | function withdraw() external onlyMinter{ 1387 | // This code transfers 5% of the withdraw to JoCoding as a donation. 1388 | // ============================================================================= 1389 | 0x3e944Ca8B08a0a0D3245B05ABF01586B9142f52C.transfer(address(this).balance * 5 / 100); 1390 | // ============================================================================= 1391 | // This will transfer the remaining contract balance to the owner. 1392 | // Do not remove this otherwise you will not be able to withdraw the funds. 1393 | // ============================================================================= 1394 | msg.sender.transfer(address(this).balance); 1395 | // ============================================================================= 1396 | } 1397 | 1398 | function mintingInformation() external view returns (uint256[7] memory){ 1399 | uint256[7] memory info = 1400 | [_antibotInterval, _mintIndexForSale, _mintLimitPerBlock, _mintLimitPerSale, 1401 | _mintStartBlockNumber, _maxSaleAmount, _mintPrice]; 1402 | return info; 1403 | } 1404 | 1405 | function setPublicMintEnabled(bool _state) public onlyMinter { 1406 | publicMintEnabled = _state; 1407 | } 1408 | 1409 | function setupSale(uint256 newAntibotInterval, 1410 | uint256 newMintLimitPerBlock, 1411 | uint256 newMintLimitPerSale, 1412 | uint256 newMintStartBlockNumber, 1413 | uint256 newMintIndexForSale, 1414 | uint256 newMaxSaleAmount, 1415 | uint256 newMintPrice) external onlyMinter{ 1416 | _antibotInterval = newAntibotInterval; 1417 | _mintLimitPerBlock = newMintLimitPerBlock; 1418 | _mintLimitPerSale = newMintLimitPerSale; 1419 | _mintStartBlockNumber = newMintStartBlockNumber; 1420 | _mintIndexForSale = newMintIndexForSale; 1421 | _maxSaleAmount = newMaxSaleAmount; 1422 | _mintPrice = newMintPrice; 1423 | } 1424 | 1425 | //Public Mint 1426 | function publicMint(uint256 requestedCount) external payable { 1427 | require(publicMintEnabled, "The public sale is not enabled!"); 1428 | require(_lastCallBlockNumber[msg.sender].add(_antibotInterval) < block.number, "Bot is not allowed"); 1429 | require(block.number >= _mintStartBlockNumber, "Not yet started"); 1430 | require(requestedCount > 0 && requestedCount <= _mintLimitPerBlock, "Too many requests or zero request"); 1431 | require(msg.value == _mintPrice.mul(requestedCount), "Not enough Klay"); 1432 | require(_mintIndexForSale.add(requestedCount) <= _maxSaleAmount + 1, "Exceed max amount"); 1433 | require(balanceOf(msg.sender) + requestedCount <= _mintLimitPerSale, "Exceed max amount per person"); 1434 | 1435 | for(uint256 i = 0; i < requestedCount; i++) { 1436 | _mint(msg.sender, _mintIndexForSale); 1437 | _mintIndexForSale = _mintIndexForSale.add(1); 1438 | } 1439 | _lastCallBlockNumber[msg.sender] = block.number; 1440 | } 1441 | 1442 | //Whitelist Mint 1443 | bytes32 public merkleRoot; 1444 | mapping(address => bool) public whitelistClaimed; 1445 | bool public whitelistMintEnabled = false; 1446 | 1447 | function setMerkleRoot(bytes32 _merkleRoot) public onlyMinter { 1448 | merkleRoot = _merkleRoot; 1449 | } 1450 | 1451 | function setWhitelistMintEnabled(bool _state) public onlyMinter { 1452 | whitelistMintEnabled = _state; 1453 | } 1454 | 1455 | function whitelistMint(uint256 requestedCount, bytes32[] calldata _merkleProof) external payable { 1456 | require(whitelistMintEnabled, "The whitelist sale is not enabled!"); 1457 | require(msg.value == _mintPrice.mul(requestedCount), "Not enough Klay"); 1458 | require(!whitelistClaimed[msg.sender], 'Address already claimed!'); 1459 | require(requestedCount > 0 && requestedCount <= _mintLimitPerBlock, "Too many requests or zero request"); 1460 | bytes32 leaf = keccak256(abi.encodePacked(msg.sender)); 1461 | require(MerkleProof.verify(_merkleProof, merkleRoot, leaf), 'Invalid proof!'); 1462 | 1463 | for(uint256 i = 0; i < requestedCount; i++) { 1464 | _mint(msg.sender, _mintIndexForSale); 1465 | _mintIndexForSale = _mintIndexForSale.add(1); 1466 | } 1467 | 1468 | whitelistClaimed[msg.sender] = true; 1469 | } 1470 | 1471 | //Airdrop Mint 1472 | function airDropMint(address user, uint256 requestedCount) external onlyMinter { 1473 | require(requestedCount > 0, "zero request"); 1474 | for(uint256 i = 0; i < requestedCount; i++) { 1475 | _mint(user, _mintIndexForSale); 1476 | _mintIndexForSale = _mintIndexForSale.add(1); 1477 | } 1478 | } 1479 | } 1480 | 1481 | // File: contracts\KIP17Full.sol 1482 | 1483 | pragma solidity ^0.5.0; 1484 | 1485 | 1486 | 1487 | 1488 | 1489 | /** 1490 | * @title Full KIP-17 Token 1491 | * This implementation includes all the required and some optional functionality of the KIP-17 standard 1492 | * Moreover, it includes approve all functionality using operator terminology 1493 | * @dev see http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 1494 | */ 1495 | contract KIP17Full is KIP17, KIP17Enumerable, KIP17Metadata, Ownable, KIP17Kbirdz { 1496 | constructor (string memory name, string memory symbol) public KIP17Metadata(name, symbol) { 1497 | // solhint-disable-previous-line no-empty-blocks 1498 | } 1499 | } 1500 | 1501 | // File: contracts\KIP17MetadataMintable.sol 1502 | 1503 | pragma solidity ^0.5.0; 1504 | 1505 | 1506 | 1507 | /** 1508 | * @title KIP17MetadataMintable 1509 | * @dev KIP17 minting logic with metadata. 1510 | */ 1511 | contract KIP17MetadataMintable is KIP13, KIP17, KIP17Metadata, MinterRole { 1512 | /* 1513 | * bytes4(keccak256('mintWithTokenURI(address,uint256,string)')) == 0x50bb4e7f 1514 | * bytes4(keccak256('isMinter(address)')) == 0xaa271e1a 1515 | * bytes4(keccak256('addMinter(address)')) == 0x983b2d56 1516 | * bytes4(keccak256('renounceMinter()')) == 0x98650275 1517 | * 1518 | * => 0x50bb4e7f ^ 0xaa271e1a ^ 0x983b2d56 ^ 0x98650275 == 0xfac27f46 1519 | */ 1520 | bytes4 private constant _INTERFACE_ID_KIP17_METADATA_MINTABLE = 0xfac27f46; 1521 | 1522 | /** 1523 | * @dev Constructor function. 1524 | */ 1525 | constructor () public { 1526 | // register the supported interface to conform to KIP17Mintable via KIP13 1527 | _registerInterface(_INTERFACE_ID_KIP17_METADATA_MINTABLE); 1528 | } 1529 | 1530 | /** 1531 | * @dev Function to mint tokens. 1532 | * @param to The address that will receive the minted tokens. 1533 | * @param tokenId The token id to mint. 1534 | * @param tokenURI The token URI of the minted token. 1535 | * @return A boolean that indicates if the operation was successful. 1536 | */ 1537 | function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) { 1538 | _mint(to, tokenId); 1539 | _setTokenURI(tokenId, tokenURI); 1540 | return true; 1541 | } 1542 | } 1543 | 1544 | // File: contracts\KIP17Mintable.sol 1545 | 1546 | pragma solidity ^0.5.0; 1547 | 1548 | 1549 | /** 1550 | * @title KIP17Mintable 1551 | * @dev KIP17 minting logic. 1552 | */ 1553 | contract KIP17Mintable is KIP17, MinterRole { 1554 | /* 1555 | * bytes4(keccak256('isMinter(address)')) == 0xaa271e1a 1556 | * bytes4(keccak256('addMinter(address)')) == 0x983b2d56 1557 | * bytes4(keccak256('renounceMinter()')) == 0x98650275 1558 | * bytes4(keccak256('mint(address,uint256)')) == 0x40c10f19 1559 | * 1560 | * => 0xaa271e1a ^ 0x983b2d56 ^ 0x98650275 ^ 0x40c10f19 == 0xeab83e20 1561 | */ 1562 | bytes4 private constant _INTERFACE_ID_KIP17_MINTABLE = 0xeab83e20; 1563 | 1564 | /** 1565 | * @dev Constructor function. 1566 | */ 1567 | constructor () public { 1568 | // register the supported interface to conform to KIP17Mintable via KIP13 1569 | _registerInterface(_INTERFACE_ID_KIP17_MINTABLE); 1570 | } 1571 | 1572 | /** 1573 | * @dev Function to mint tokens. 1574 | * @param to The address that will receive the minted tokens. 1575 | * @param tokenId The token id to mint. 1576 | * @return A boolean that indicates if the operation was successful. 1577 | */ 1578 | function mint(address to, uint256 tokenId) public onlyMinter returns (bool) { 1579 | _mint(to, tokenId); 1580 | return true; 1581 | } 1582 | } 1583 | 1584 | // File: contracts\KIP17Burnable.sol 1585 | 1586 | pragma solidity ^0.5.0; 1587 | 1588 | 1589 | /** 1590 | * @title KIP17 Burnable Token 1591 | * @dev KIP17 Token that can be irreversibly burned (destroyed). 1592 | * See http://kips.klaytn.com/KIPs/kip-17-non_fungible_token 1593 | */ 1594 | contract KIP17Burnable is KIP13, KIP17 { 1595 | /* 1596 | * bytes4(keccak256('burn(uint256)')) == 0x42966c68 1597 | * 1598 | * => 0x42966c68 == 0x42966c68 1599 | */ 1600 | bytes4 private constant _INTERFACE_ID_KIP17_BURNABLE = 0x42966c68; 1601 | 1602 | /** 1603 | * @dev Constructor function. 1604 | */ 1605 | constructor () public { 1606 | // register the supported interface to conform to KIP17Burnable via KIP13 1607 | _registerInterface(_INTERFACE_ID_KIP17_BURNABLE); 1608 | } 1609 | 1610 | /** 1611 | * @dev Burns a specific KIP17 token. 1612 | * @param tokenId uint256 id of the KIP17 token to be burned. 1613 | */ 1614 | function burn(uint256 tokenId) public { 1615 | //solhint-disable-next-line max-line-length 1616 | require(_isApprovedOrOwner(msg.sender, tokenId), "KIP17Burnable: caller is not owner nor approved"); 1617 | _burn(tokenId); 1618 | } 1619 | } 1620 | 1621 | // File: contracts\roles\PauserRole.sol 1622 | 1623 | pragma solidity ^0.5.0; 1624 | 1625 | contract PauserRole { 1626 | using Roles for Roles.Role; 1627 | 1628 | event PauserAdded(address indexed account); 1629 | event PauserRemoved(address indexed account); 1630 | 1631 | Roles.Role private _pausers; 1632 | 1633 | constructor () internal { 1634 | _addPauser(msg.sender); 1635 | } 1636 | 1637 | modifier onlyPauser() { 1638 | require(isPauser(msg.sender), "PauserRole: caller does not have the Pauser role"); 1639 | _; 1640 | } 1641 | 1642 | function isPauser(address account) public view returns (bool) { 1643 | return _pausers.has(account); 1644 | } 1645 | 1646 | function addPauser(address account) public onlyPauser { 1647 | _addPauser(account); 1648 | } 1649 | 1650 | function renouncePauser() public { 1651 | _removePauser(msg.sender); 1652 | } 1653 | 1654 | function _addPauser(address account) internal { 1655 | _pausers.add(account); 1656 | emit PauserAdded(account); 1657 | } 1658 | 1659 | function _removePauser(address account) internal { 1660 | _pausers.remove(account); 1661 | emit PauserRemoved(account); 1662 | } 1663 | } 1664 | 1665 | // File: contracts\lifecycle\Pausable.sol 1666 | 1667 | pragma solidity ^0.5.0; 1668 | 1669 | /** 1670 | * @dev Contract module which allows children to implement an emergency stop 1671 | * mechanism that can be triggered by an authorized account. 1672 | * 1673 | * This module is used through inheritance. It will make available the 1674 | * modifiers `whenNotPaused` and `whenPaused`, which can be applied to 1675 | * the functions of your contract. Note that they will not be pausable by 1676 | * simply including this module, only once the modifiers are put in place. 1677 | */ 1678 | contract Pausable is PauserRole { 1679 | /** 1680 | * @dev Emitted when the pause is triggered by a pauser (`account`). 1681 | */ 1682 | event Paused(address account); 1683 | 1684 | /** 1685 | * @dev Emitted when the pause is lifted by a pauser (`account`). 1686 | */ 1687 | event Unpaused(address account); 1688 | 1689 | bool private _paused; 1690 | 1691 | /** 1692 | * @dev Initializes the contract in unpaused state. Assigns the Pauser role 1693 | * to the deployer. 1694 | */ 1695 | constructor () internal { 1696 | _paused = false; 1697 | } 1698 | 1699 | /** 1700 | * @dev Returns true if the contract is paused, and false otherwise. 1701 | */ 1702 | function paused() public view returns (bool) { 1703 | return _paused; 1704 | } 1705 | 1706 | /** 1707 | * @dev Modifier to make a function callable only when the contract is not paused. 1708 | */ 1709 | modifier whenNotPaused() { 1710 | require(!_paused, "Pausable: paused"); 1711 | _; 1712 | } 1713 | 1714 | /** 1715 | * @dev Modifier to make a function callable only when the contract is paused. 1716 | */ 1717 | modifier whenPaused() { 1718 | require(_paused, "Pausable: not paused"); 1719 | _; 1720 | } 1721 | 1722 | /** 1723 | * @dev Called by a pauser to pause, triggers stopped state. 1724 | */ 1725 | function pause() public onlyPauser whenNotPaused { 1726 | _paused = true; 1727 | emit Paused(msg.sender); 1728 | } 1729 | 1730 | /** 1731 | * @dev Called by a pauser to unpause, returns to normal state. 1732 | */ 1733 | function unpause() public onlyPauser whenPaused { 1734 | _paused = false; 1735 | emit Unpaused(msg.sender); 1736 | } 1737 | } 1738 | 1739 | // File: contracts\KIP17Pausable.sol 1740 | 1741 | pragma solidity ^0.5.0; 1742 | 1743 | 1744 | 1745 | /** 1746 | * @title KIP17 Non-Fungible Pausable token 1747 | * @dev KIP17 modified with pausable transfers. 1748 | */ 1749 | contract KIP17Pausable is KIP13, KIP17, Pausable { 1750 | /* 1751 | * bytes4(keccak256('paused()')) == 0x5c975abb 1752 | * bytes4(keccak256('pause()')) == 0x8456cb59 1753 | * bytes4(keccak256('unpause()')) == 0x3f4ba83a 1754 | * bytes4(keccak256('isPauser(address)')) == 0x46fbf68e 1755 | * bytes4(keccak256('addPauser(address)')) == 0x82dc1ec4 1756 | * bytes4(keccak256('renouncePauser()')) == 0x6ef8d66d 1757 | * 1758 | * => 0x5c975abb ^ 0x8456cb59 ^ 0x3f4ba83a ^ 0x46fbf68e ^ 0x82dc1ec4 ^ 0x6ef8d66d == 0x4d5507ff 1759 | */ 1760 | bytes4 private constant _INTERFACE_ID_KIP17_PAUSABLE = 0x4d5507ff; 1761 | 1762 | /** 1763 | * @dev Constructor function. 1764 | */ 1765 | constructor () public { 1766 | // register the supported interface to conform to KIP17Pausable via KIP13 1767 | _registerInterface(_INTERFACE_ID_KIP17_PAUSABLE); 1768 | } 1769 | 1770 | function approve(address to, uint256 tokenId) public whenNotPaused { 1771 | super.approve(to, tokenId); 1772 | } 1773 | 1774 | function setApprovalForAll(address to, bool approved) public whenNotPaused { 1775 | super.setApprovalForAll(to, approved); 1776 | } 1777 | 1778 | function transferFrom(address from, address to, uint256 tokenId) public whenNotPaused { 1779 | super.transferFrom(from, to, tokenId); 1780 | } 1781 | } 1782 | 1783 | // File: contracts\KIP17KbirdzToken.sol 1784 | 1785 | pragma solidity ^0.5.0; 1786 | 1787 | 1788 | 1789 | 1790 | 1791 | contract KIP17KbirdzToken is KIP17Full, KIP17Mintable, KIP17MetadataMintable, KIP17Burnable, KIP17Pausable { 1792 | constructor (string memory name, string memory symbol) public KIP17Full(name, symbol) { 1793 | } 1794 | } 1795 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function (deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /test/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JoCoding-Blockchain/kbirdz-contract/f3d2b6abd984fe281419dba41b828a6f66829fb0/test/.gitkeep -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * trufflesuite.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura accounts 13 | * are available for free at: infura.io/register. 14 | * 15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 17 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 18 | * 19 | */ 20 | 21 | // const HDWalletProvider = require('@truffle/hdwallet-provider'); 22 | // 23 | // const fs = require('fs'); 24 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 25 | 26 | module.exports = { 27 | /** 28 | * Networks define how you connect to your ethereum client and let you set the 29 | * defaults web3 uses to send transactions. If you don't specify one truffle 30 | * will spin up a development blockchain for you on port 9545 when you 31 | * run `develop` or `test`. You can ask a truffle command to use a specific 32 | * network from the command line, e.g 33 | * 34 | * $ truffle test --network 35 | */ 36 | 37 | networks: { 38 | // Useful for testing. The `development` name is special - truffle uses it by default 39 | // if it's defined here and no other network is specified at the command line. 40 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 41 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 42 | // options below to some value. 43 | // 44 | // development: { 45 | // host: "127.0.0.1", // Localhost (default: none) 46 | // port: 8545, // Standard Ethereum port (default: none) 47 | // network_id: "*", // Any network (default: none) 48 | // }, 49 | // Another network with more advanced options... 50 | // advanced: { 51 | // port: 8777, // Custom port 52 | // network_id: 1342, // Custom network 53 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 54 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 55 | // from:
, // Account to send txs from (default: accounts[0]) 56 | // websocket: true // Enable EventEmitter interface for web3 (default: false) 57 | // }, 58 | // Useful for deploying to a public network. 59 | // NB: It's important to wrap the provider as a function. 60 | // ropsten: { 61 | // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`), 62 | // network_id: 3, // Ropsten's id 63 | // gas: 5500000, // Ropsten has a lower block limit than mainnet 64 | // confirmations: 2, // # of confs to wait between deployments. (default: 0) 65 | // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 66 | // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 67 | // }, 68 | // Useful for private networks 69 | // private: { 70 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 71 | // network_id: 2111, // This network is yours, in the cloud. 72 | // production: true // Treats this network as if it was a public net. (default: false) 73 | // } 74 | }, 75 | 76 | // Set default mocha options here, use special reporters etc. 77 | mocha: { 78 | // timeout: 100000 79 | }, 80 | 81 | // Configure your compilers 82 | compilers: { 83 | solc: { 84 | version: "0.8.12", // Fetch exact version from solc-bin (default: truffle's version) 85 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 86 | // settings: { // See the solidity docs for advice about optimization and evmVersion 87 | // optimizer: { 88 | // enabled: false, 89 | // runs: 200 90 | // }, 91 | // evmVersion: "byzantium" 92 | // } 93 | } 94 | }, 95 | 96 | // Truffle DB is currently disabled by default; to enable it, change enabled: 97 | // false to enabled: true. The default storage location can also be 98 | // overridden by specifying the adapter settings, as shown in the commented code below. 99 | // 100 | // NOTE: It is not possible to migrate your contracts to truffle DB and you should 101 | // make a backup of your artifacts to a safe location before enabling this feature. 102 | // 103 | // After you backed up your artifacts you can utilize db by running migrate as follows: 104 | // $ truffle migrate --reset --compile-all 105 | // 106 | // db: { 107 | // enabled: false, 108 | // host: "127.0.0.1", 109 | // adapter: { 110 | // name: "sqlite", 111 | // settings: { 112 | // directory: ".db" 113 | // } 114 | // } 115 | // } 116 | }; 117 | --------------------------------------------------------------------------------