├── images ├── 1.png ├── 2.png ├── 3.png └── 4.png ├── README.md ├── metadata ├── 1.json ├── 2.json ├── 3.json └── 4.json └── AINFT.sol /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dappuniversity/ai_nft/HEAD/images/1.png -------------------------------------------------------------------------------- /images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dappuniversity/ai_nft/HEAD/images/2.png -------------------------------------------------------------------------------- /images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dappuniversity/ai_nft/HEAD/images/3.png -------------------------------------------------------------------------------- /images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dappuniversity/ai_nft/HEAD/images/4.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Example Token URIs: 2 | 3 | https://ipfs.io/ipfs/QmTNTBzDZ4XuWH2HTFoPHo4JVEt8WVySmZiJeKynqEGbJd/1.json 4 | https://ipfs.io/ipfs/QmTNTBzDZ4XuWH2HTFoPHo4JVEt8WVySmZiJeKynqEGbJd/2.json 5 | https://ipfs.io/ipfs/QmTNTBzDZ4XuWH2HTFoPHo4JVEt8WVySmZiJeKynqEGbJd/3.json 6 | https://ipfs.io/ipfs/QmTNTBzDZ4XuWH2HTFoPHo4JVEt8WVySmZiJeKynqEGbJd/4.json 7 | 8 | -------------------------------------------------------------------------------- /metadata/1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "AI NFT #1", 3 | "description": "My Special AI NFT #1", 4 | "image" : "https://ipfs.io/ipfs/QmR3JiWJdQL6QrzoWMFNbcZVNbcafXB6vurA2EY5fYA7AT/1.png", 5 | "attributes": [ 6 | { 7 | "trait_type": "Strength", 8 | "value": 6, 9 | "max_value": 10 10 | }, 11 | { 12 | "trait_type": "Speed", 13 | "value": 10, 14 | "max_value": 10 15 | }, 16 | { 17 | "trait_type": "Jump", 18 | "value": 10, 19 | "max_value": 10 20 | }, 21 | { 22 | "trait_type": "Intelligence", 23 | "value": 5, 24 | "max_value": 10 25 | }, 26 | { 27 | "display_type": "boost_number", 28 | "trait_type": "Jump", 29 | "value": 1 30 | }, 31 | { 32 | "display_type": "boost_percentage", 33 | "trait_type": "Speed", 34 | "value": 20 35 | }, 36 | { 37 | "display_type": "number", 38 | "trait_type": "Generation", 39 | "value": 1 40 | }, 41 | { 42 | "trait_type": "Humble", 43 | "value": "True" 44 | }, 45 | { 46 | "trait_type": "Kind", 47 | "value": "True" 48 | } 49 | 50 | ] 51 | } -------------------------------------------------------------------------------- /metadata/2.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "AI NFT #2", 3 | "description": "My Special AI NFT #2", 4 | "image" : "https://ipfs.io/ipfs/QmR3JiWJdQL6QrzoWMFNbcZVNbcafXB6vurA2EY5fYA7AT/1.png", 5 | "attributes": [ 6 | { 7 | "trait_type": "Strength", 8 | "value": 6, 9 | "max_value": 10 10 | }, 11 | { 12 | "trait_type": "Speed", 13 | "value": 10, 14 | "max_value": 10 15 | }, 16 | { 17 | "trait_type": "Jump", 18 | "value": 10, 19 | "max_value": 10 20 | }, 21 | { 22 | "trait_type": "Intelligence", 23 | "value": 5, 24 | "max_value": 10 25 | }, 26 | { 27 | "display_type": "boost_number", 28 | "trait_type": "Jump", 29 | "value": 1 30 | }, 31 | { 32 | "display_type": "boost_percentage", 33 | "trait_type": "Speed", 34 | "value": 20 35 | }, 36 | { 37 | "display_type": "number", 38 | "trait_type": "Generation", 39 | "value": 1 40 | }, 41 | { 42 | "trait_type": "Humble", 43 | "value": "True" 44 | }, 45 | { 46 | "trait_type": "Kind", 47 | "value": "True" 48 | } 49 | 50 | ] 51 | } -------------------------------------------------------------------------------- /metadata/3.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "AI NFT #3", 3 | "description": "My Special AI NFT #3", 4 | "image" : "https://ipfs.io/ipfs/QmR3JiWJdQL6QrzoWMFNbcZVNbcafXB6vurA2EY5fYA7AT/1.png", 5 | "attributes": [ 6 | { 7 | "trait_type": "Strength", 8 | "value": 6, 9 | "max_value": 10 10 | }, 11 | { 12 | "trait_type": "Speed", 13 | "value": 10, 14 | "max_value": 10 15 | }, 16 | { 17 | "trait_type": "Jump", 18 | "value": 10, 19 | "max_value": 10 20 | }, 21 | { 22 | "trait_type": "Intelligence", 23 | "value": 5, 24 | "max_value": 10 25 | }, 26 | { 27 | "display_type": "boost_number", 28 | "trait_type": "Jump", 29 | "value": 1 30 | }, 31 | { 32 | "display_type": "boost_percentage", 33 | "trait_type": "Speed", 34 | "value": 20 35 | }, 36 | { 37 | "display_type": "number", 38 | "trait_type": "Generation", 39 | "value": 1 40 | }, 41 | { 42 | "trait_type": "Humble", 43 | "value": "True" 44 | }, 45 | { 46 | "trait_type": "Kind", 47 | "value": "True" 48 | } 49 | 50 | ] 51 | } -------------------------------------------------------------------------------- /metadata/4.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "AI NFT #4", 3 | "description": "My Special AI NFT #4", 4 | "image" : "https://ipfs.io/ipfs/QmR3JiWJdQL6QrzoWMFNbcZVNbcafXB6vurA2EY5fYA7AT/1.png", 5 | "attributes": [ 6 | { 7 | "trait_type": "Strength", 8 | "value": 6, 9 | "max_value": 10 10 | }, 11 | { 12 | "trait_type": "Speed", 13 | "value": 10, 14 | "max_value": 10 15 | }, 16 | { 17 | "trait_type": "Jump", 18 | "value": 10, 19 | "max_value": 10 20 | }, 21 | { 22 | "trait_type": "Intelligence", 23 | "value": 5, 24 | "max_value": 10 25 | }, 26 | { 27 | "display_type": "boost_number", 28 | "trait_type": "Jump", 29 | "value": 1 30 | }, 31 | { 32 | "display_type": "boost_percentage", 33 | "trait_type": "Speed", 34 | "value": 20 35 | }, 36 | { 37 | "display_type": "number", 38 | "trait_type": "Generation", 39 | "value": 1 40 | }, 41 | { 42 | "trait_type": "Humble", 43 | "value": "True" 44 | }, 45 | { 46 | "trait_type": "Kind", 47 | "value": "True" 48 | } 49 | 50 | ] 51 | } -------------------------------------------------------------------------------- /AINFT.sol: -------------------------------------------------------------------------------- 1 | 2 | pragma solidity ^0.8.0; 3 | 4 | /** 5 | * @title Counters 6 | * @author Matt Condon (@shrugs) 7 | * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number 8 | * of elements in a mapping, issuing ERC721 ids, or counting request ids. 9 | * 10 | * Include with `using Counters for Counters.Counter;` 11 | */ 12 | library Counters { 13 | struct Counter { 14 | // This variable should never be directly accessed by users of the library: interactions must be restricted to 15 | // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add 16 | // this feature: see https://github.com/ethereum/solidity/issues/4637 17 | uint256 _value; // default: 0 18 | } 19 | 20 | function current(Counter storage counter) internal view returns (uint256) { 21 | return counter._value; 22 | } 23 | 24 | function increment(Counter storage counter) internal { 25 | unchecked { 26 | counter._value += 1; 27 | } 28 | } 29 | 30 | function decrement(Counter storage counter) internal { 31 | uint256 value = counter._value; 32 | require(value > 0, "Counter: decrement overflow"); 33 | unchecked { 34 | counter._value = value - 1; 35 | } 36 | } 37 | 38 | function reset(Counter storage counter) internal { 39 | counter._value = 0; 40 | } 41 | } 42 | 43 | // File: @openzeppelin/contracts/utils/Strings.sol 44 | 45 | 46 | // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) 47 | 48 | pragma solidity ^0.8.0; 49 | 50 | /** 51 | * @dev String operations. 52 | */ 53 | library Strings { 54 | bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; 55 | 56 | /** 57 | * @dev Converts a `uint256` to its ASCII `string` decimal representation. 58 | */ 59 | function toString(uint256 value) internal pure returns (string memory) { 60 | // Inspired by OraclizeAPI's implementation - MIT licence 61 | // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol 62 | 63 | if (value == 0) { 64 | return "0"; 65 | } 66 | uint256 temp = value; 67 | uint256 digits; 68 | while (temp != 0) { 69 | digits++; 70 | temp /= 10; 71 | } 72 | bytes memory buffer = new bytes(digits); 73 | while (value != 0) { 74 | digits -= 1; 75 | buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); 76 | value /= 10; 77 | } 78 | return string(buffer); 79 | } 80 | 81 | /** 82 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 83 | */ 84 | function toHexString(uint256 value) internal pure returns (string memory) { 85 | if (value == 0) { 86 | return "0x00"; 87 | } 88 | uint256 temp = value; 89 | uint256 length = 0; 90 | while (temp != 0) { 91 | length++; 92 | temp >>= 8; 93 | } 94 | return toHexString(value, length); 95 | } 96 | 97 | /** 98 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 99 | */ 100 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 101 | bytes memory buffer = new bytes(2 * length + 2); 102 | buffer[0] = "0"; 103 | buffer[1] = "x"; 104 | for (uint256 i = 2 * length + 1; i > 1; --i) { 105 | buffer[i] = _HEX_SYMBOLS[value & 0xf]; 106 | value >>= 4; 107 | } 108 | require(value == 0, "Strings: hex length insufficient"); 109 | return string(buffer); 110 | } 111 | } 112 | 113 | // File: @openzeppelin/contracts/utils/Context.sol 114 | 115 | 116 | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) 117 | 118 | pragma solidity ^0.8.0; 119 | 120 | /** 121 | * @dev Provides information about the current execution context, including the 122 | * sender of the transaction and its data. While these are generally available 123 | * via msg.sender and msg.data, they should not be accessed in such a direct 124 | * manner, since when dealing with meta-transactions the account sending and 125 | * paying for execution may not be the actual sender (as far as an application 126 | * is concerned). 127 | * 128 | * This contract is only required for intermediate, library-like contracts. 129 | */ 130 | abstract contract Context { 131 | function _msgSender() internal view virtual returns (address) { 132 | return msg.sender; 133 | } 134 | 135 | function _msgData() internal view virtual returns (bytes calldata) { 136 | return msg.data; 137 | } 138 | } 139 | 140 | // File: @openzeppelin/contracts/utils/Address.sol 141 | 142 | 143 | // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) 144 | 145 | pragma solidity ^0.8.1; 146 | 147 | /** 148 | * @dev Collection of functions related to the address type 149 | */ 150 | library Address { 151 | /** 152 | * @dev Returns true if `account` is a contract. 153 | * 154 | * [IMPORTANT] 155 | * ==== 156 | * It is unsafe to assume that an address for which this function returns 157 | * false is an externally-owned account (EOA) and not a contract. 158 | * 159 | * Among others, `isContract` will return false for the following 160 | * types of addresses: 161 | * 162 | * - an externally-owned account 163 | * - a contract in construction 164 | * - an address where a contract will be created 165 | * - an address where a contract lived, but was destroyed 166 | * ==== 167 | * 168 | * [IMPORTANT] 169 | * ==== 170 | * You shouldn't rely on `isContract` to protect against flash loan attacks! 171 | * 172 | * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets 173 | * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract 174 | * constructor. 175 | * ==== 176 | */ 177 | function isContract(address account) internal view returns (bool) { 178 | // This method relies on extcodesize/address.code.length, which returns 0 179 | // for contracts in construction, since the code is only stored at the end 180 | // of the constructor execution. 181 | 182 | return account.code.length > 0; 183 | } 184 | 185 | /** 186 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 187 | * `recipient`, forwarding all available gas and reverting on errors. 188 | * 189 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 190 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 191 | * imposed by `transfer`, making them unable to receive funds via 192 | * `transfer`. {sendValue} removes this limitation. 193 | * 194 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 195 | * 196 | * IMPORTANT: because control is transferred to `recipient`, care must be 197 | * taken to not create reentrancy vulnerabilities. Consider using 198 | * {ReentrancyGuard} or the 199 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 200 | */ 201 | function sendValue(address payable recipient, uint256 amount) internal { 202 | require(address(this).balance >= amount, "Address: insufficient balance"); 203 | 204 | (bool success, ) = recipient.call{value: amount}(""); 205 | require(success, "Address: unable to send value, recipient may have reverted"); 206 | } 207 | 208 | /** 209 | * @dev Performs a Solidity function call using a low level `call`. A 210 | * plain `call` is an unsafe replacement for a function call: use this 211 | * function instead. 212 | * 213 | * If `target` reverts with a revert reason, it is bubbled up by this 214 | * function (like regular Solidity function calls). 215 | * 216 | * Returns the raw returned data. To convert to the expected return value, 217 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 218 | * 219 | * Requirements: 220 | * 221 | * - `target` must be a contract. 222 | * - calling `target` with `data` must not revert. 223 | * 224 | * _Available since v3.1._ 225 | */ 226 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 227 | return functionCall(target, data, "Address: low-level call failed"); 228 | } 229 | 230 | /** 231 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 232 | * `errorMessage` as a fallback revert reason when `target` reverts. 233 | * 234 | * _Available since v3.1._ 235 | */ 236 | function functionCall( 237 | address target, 238 | bytes memory data, 239 | string memory errorMessage 240 | ) internal returns (bytes memory) { 241 | return functionCallWithValue(target, data, 0, errorMessage); 242 | } 243 | 244 | /** 245 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 246 | * but also transferring `value` wei to `target`. 247 | * 248 | * Requirements: 249 | * 250 | * - the calling contract must have an ETH balance of at least `value`. 251 | * - the called Solidity function must be `payable`. 252 | * 253 | * _Available since v3.1._ 254 | */ 255 | function functionCallWithValue( 256 | address target, 257 | bytes memory data, 258 | uint256 value 259 | ) internal returns (bytes memory) { 260 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 261 | } 262 | 263 | /** 264 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 265 | * with `errorMessage` as a fallback revert reason when `target` reverts. 266 | * 267 | * _Available since v3.1._ 268 | */ 269 | function functionCallWithValue( 270 | address target, 271 | bytes memory data, 272 | uint256 value, 273 | string memory errorMessage 274 | ) internal returns (bytes memory) { 275 | require(address(this).balance >= value, "Address: insufficient balance for call"); 276 | require(isContract(target), "Address: call to non-contract"); 277 | 278 | (bool success, bytes memory returndata) = target.call{value: value}(data); 279 | return verifyCallResult(success, returndata, errorMessage); 280 | } 281 | 282 | /** 283 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 284 | * but performing a static call. 285 | * 286 | * _Available since v3.3._ 287 | */ 288 | function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { 289 | return functionStaticCall(target, data, "Address: low-level static call failed"); 290 | } 291 | 292 | /** 293 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 294 | * but performing a static call. 295 | * 296 | * _Available since v3.3._ 297 | */ 298 | function functionStaticCall( 299 | address target, 300 | bytes memory data, 301 | string memory errorMessage 302 | ) internal view returns (bytes memory) { 303 | require(isContract(target), "Address: static call to non-contract"); 304 | 305 | (bool success, bytes memory returndata) = target.staticcall(data); 306 | return verifyCallResult(success, returndata, errorMessage); 307 | } 308 | 309 | /** 310 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 311 | * but performing a delegate call. 312 | * 313 | * _Available since v3.4._ 314 | */ 315 | function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { 316 | return functionDelegateCall(target, data, "Address: low-level delegate call failed"); 317 | } 318 | 319 | /** 320 | * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], 321 | * but performing a delegate call. 322 | * 323 | * _Available since v3.4._ 324 | */ 325 | function functionDelegateCall( 326 | address target, 327 | bytes memory data, 328 | string memory errorMessage 329 | ) internal returns (bytes memory) { 330 | require(isContract(target), "Address: delegate call to non-contract"); 331 | 332 | (bool success, bytes memory returndata) = target.delegatecall(data); 333 | return verifyCallResult(success, returndata, errorMessage); 334 | } 335 | 336 | /** 337 | * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the 338 | * revert reason using the provided one. 339 | * 340 | * _Available since v4.3._ 341 | */ 342 | function verifyCallResult( 343 | bool success, 344 | bytes memory returndata, 345 | string memory errorMessage 346 | ) internal pure returns (bytes memory) { 347 | if (success) { 348 | return returndata; 349 | } else { 350 | // Look for revert reason and bubble it up if present 351 | if (returndata.length > 0) { 352 | // The easiest way to bubble the revert reason is using memory via assembly 353 | 354 | assembly { 355 | let returndata_size := mload(returndata) 356 | revert(add(32, returndata), returndata_size) 357 | } 358 | } else { 359 | revert(errorMessage); 360 | } 361 | } 362 | } 363 | } 364 | 365 | // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol 366 | 367 | 368 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol) 369 | 370 | pragma solidity ^0.8.0; 371 | 372 | /** 373 | * @title ERC721 token receiver interface 374 | * @dev Interface for any contract that wants to support safeTransfers 375 | * from ERC721 asset contracts. 376 | */ 377 | interface IERC721Receiver { 378 | /** 379 | * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} 380 | * by `operator` from `from`, this function is called. 381 | * 382 | * It must return its Solidity selector to confirm the token transfer. 383 | * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. 384 | * 385 | * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. 386 | */ 387 | function onERC721Received( 388 | address operator, 389 | address from, 390 | uint256 tokenId, 391 | bytes calldata data 392 | ) external returns (bytes4); 393 | } 394 | 395 | // File: @openzeppelin/contracts/utils/introspection/IERC165.sol 396 | 397 | 398 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) 399 | 400 | pragma solidity ^0.8.0; 401 | 402 | /** 403 | * @dev Interface of the ERC165 standard, as defined in the 404 | * https://eips.ethereum.org/EIPS/eip-165[EIP]. 405 | * 406 | * Implementers can declare support of contract interfaces, which can then be 407 | * queried by others ({ERC165Checker}). 408 | * 409 | * For an implementation, see {ERC165}. 410 | */ 411 | interface IERC165 { 412 | /** 413 | * @dev Returns true if this contract implements the interface defined by 414 | * `interfaceId`. See the corresponding 415 | * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] 416 | * to learn more about how these ids are created. 417 | * 418 | * This function call must use less than 30 000 gas. 419 | */ 420 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 421 | } 422 | 423 | // File: @openzeppelin/contracts/utils/introspection/ERC165.sol 424 | 425 | 426 | // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) 427 | 428 | pragma solidity ^0.8.0; 429 | 430 | 431 | /** 432 | * @dev Implementation of the {IERC165} interface. 433 | * 434 | * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check 435 | * for the additional interface id that will be supported. For example: 436 | * 437 | * ```solidity 438 | * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 439 | * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); 440 | * } 441 | * ``` 442 | * 443 | * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. 444 | */ 445 | abstract contract ERC165 is IERC165 { 446 | /** 447 | * @dev See {IERC165-supportsInterface}. 448 | */ 449 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 450 | return interfaceId == type(IERC165).interfaceId; 451 | } 452 | } 453 | 454 | // File: @openzeppelin/contracts/token/ERC721/IERC721.sol 455 | 456 | 457 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) 458 | 459 | pragma solidity ^0.8.0; 460 | 461 | 462 | /** 463 | * @dev Required interface of an ERC721 compliant contract. 464 | */ 465 | interface IERC721 is IERC165 { 466 | /** 467 | * @dev Emitted when `tokenId` token is transferred from `from` to `to`. 468 | */ 469 | event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 470 | 471 | /** 472 | * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. 473 | */ 474 | event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); 475 | 476 | /** 477 | * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. 478 | */ 479 | event ApprovalForAll(address indexed owner, address indexed operator, bool approved); 480 | 481 | /** 482 | * @dev Returns the number of tokens in ``owner``'s account. 483 | */ 484 | function balanceOf(address owner) external view returns (uint256 balance); 485 | 486 | /** 487 | * @dev Returns the owner of the `tokenId` token. 488 | * 489 | * Requirements: 490 | * 491 | * - `tokenId` must exist. 492 | */ 493 | function ownerOf(uint256 tokenId) external view returns (address owner); 494 | 495 | /** 496 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 497 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 498 | * 499 | * Requirements: 500 | * 501 | * - `from` cannot be the zero address. 502 | * - `to` cannot be the zero address. 503 | * - `tokenId` token must exist and be owned by `from`. 504 | * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. 505 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 506 | * 507 | * Emits a {Transfer} event. 508 | */ 509 | function safeTransferFrom( 510 | address from, 511 | address to, 512 | uint256 tokenId 513 | ) external; 514 | 515 | /** 516 | * @dev Transfers `tokenId` token from `from` to `to`. 517 | * 518 | * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. 519 | * 520 | * Requirements: 521 | * 522 | * - `from` cannot be the zero address. 523 | * - `to` cannot be the zero address. 524 | * - `tokenId` token must be owned by `from`. 525 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 526 | * 527 | * Emits a {Transfer} event. 528 | */ 529 | function transferFrom( 530 | address from, 531 | address to, 532 | uint256 tokenId 533 | ) external; 534 | 535 | /** 536 | * @dev Gives permission to `to` to transfer `tokenId` token to another account. 537 | * The approval is cleared when the token is transferred. 538 | * 539 | * Only a single account can be approved at a time, so approving the zero address clears previous approvals. 540 | * 541 | * Requirements: 542 | * 543 | * - The caller must own the token or be an approved operator. 544 | * - `tokenId` must exist. 545 | * 546 | * Emits an {Approval} event. 547 | */ 548 | function approve(address to, uint256 tokenId) external; 549 | 550 | /** 551 | * @dev Returns the account approved for `tokenId` token. 552 | * 553 | * Requirements: 554 | * 555 | * - `tokenId` must exist. 556 | */ 557 | function getApproved(uint256 tokenId) external view returns (address operator); 558 | 559 | /** 560 | * @dev Approve or remove `operator` as an operator for the caller. 561 | * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. 562 | * 563 | * Requirements: 564 | * 565 | * - The `operator` cannot be the caller. 566 | * 567 | * Emits an {ApprovalForAll} event. 568 | */ 569 | function setApprovalForAll(address operator, bool _approved) external; 570 | 571 | /** 572 | * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. 573 | * 574 | * See {setApprovalForAll} 575 | */ 576 | function isApprovedForAll(address owner, address operator) external view returns (bool); 577 | 578 | /** 579 | * @dev Safely transfers `tokenId` token from `from` to `to`. 580 | * 581 | * Requirements: 582 | * 583 | * - `from` cannot be the zero address. 584 | * - `to` cannot be the zero address. 585 | * - `tokenId` token must exist and be owned by `from`. 586 | * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. 587 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 588 | * 589 | * Emits a {Transfer} event. 590 | */ 591 | function safeTransferFrom( 592 | address from, 593 | address to, 594 | uint256 tokenId, 595 | bytes calldata data 596 | ) external; 597 | } 598 | 599 | // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol 600 | 601 | 602 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) 603 | 604 | pragma solidity ^0.8.0; 605 | 606 | 607 | /** 608 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 609 | * @dev See https://eips.ethereum.org/EIPS/eip-721 610 | */ 611 | interface IERC721Metadata is IERC721 { 612 | /** 613 | * @dev Returns the token collection name. 614 | */ 615 | function name() external view returns (string memory); 616 | 617 | /** 618 | * @dev Returns the token collection symbol. 619 | */ 620 | function symbol() external view returns (string memory); 621 | 622 | /** 623 | * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. 624 | */ 625 | function tokenURI(uint256 tokenId) external view returns (string memory); 626 | } 627 | 628 | // File: @openzeppelin/contracts/token/ERC721/ERC721.sol 629 | 630 | 631 | // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/ERC721.sol) 632 | 633 | pragma solidity ^0.8.0; 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | /** 643 | * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including 644 | * the Metadata extension, but not including the Enumerable extension, which is available separately as 645 | * {ERC721Enumerable}. 646 | */ 647 | contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { 648 | using Address for address; 649 | using Strings for uint256; 650 | 651 | // Token name 652 | string private _name; 653 | 654 | // Token symbol 655 | string private _symbol; 656 | 657 | // Mapping from token ID to owner address 658 | mapping(uint256 => address) private _owners; 659 | 660 | // Mapping owner address to token count 661 | mapping(address => uint256) private _balances; 662 | 663 | // Mapping from token ID to approved address 664 | mapping(uint256 => address) private _tokenApprovals; 665 | 666 | // Mapping from owner to operator approvals 667 | mapping(address => mapping(address => bool)) private _operatorApprovals; 668 | 669 | /** 670 | * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. 671 | */ 672 | constructor(string memory name_, string memory symbol_) { 673 | _name = name_; 674 | _symbol = symbol_; 675 | } 676 | 677 | /** 678 | * @dev See {IERC165-supportsInterface}. 679 | */ 680 | function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { 681 | return 682 | interfaceId == type(IERC721).interfaceId || 683 | interfaceId == type(IERC721Metadata).interfaceId || 684 | super.supportsInterface(interfaceId); 685 | } 686 | 687 | /** 688 | * @dev See {IERC721-balanceOf}. 689 | */ 690 | function balanceOf(address owner) public view virtual override returns (uint256) { 691 | require(owner != address(0), "ERC721: balance query for the zero address"); 692 | return _balances[owner]; 693 | } 694 | 695 | /** 696 | * @dev See {IERC721-ownerOf}. 697 | */ 698 | function ownerOf(uint256 tokenId) public view virtual override returns (address) { 699 | address owner = _owners[tokenId]; 700 | require(owner != address(0), "ERC721: owner query for nonexistent token"); 701 | return owner; 702 | } 703 | 704 | /** 705 | * @dev See {IERC721Metadata-name}. 706 | */ 707 | function name() public view virtual override returns (string memory) { 708 | return _name; 709 | } 710 | 711 | /** 712 | * @dev See {IERC721Metadata-symbol}. 713 | */ 714 | function symbol() public view virtual override returns (string memory) { 715 | return _symbol; 716 | } 717 | 718 | /** 719 | * @dev See {IERC721Metadata-tokenURI}. 720 | */ 721 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 722 | require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); 723 | 724 | string memory baseURI = _baseURI(); 725 | return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; 726 | } 727 | 728 | /** 729 | * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each 730 | * token will be the concatenation of the `baseURI` and the `tokenId`. Empty 731 | * by default, can be overriden in child contracts. 732 | */ 733 | function _baseURI() internal view virtual returns (string memory) { 734 | return ""; 735 | } 736 | 737 | /** 738 | * @dev See {IERC721-approve}. 739 | */ 740 | function approve(address to, uint256 tokenId) public virtual override { 741 | address owner = ERC721.ownerOf(tokenId); 742 | require(to != owner, "ERC721: approval to current owner"); 743 | 744 | require( 745 | _msgSender() == owner || isApprovedForAll(owner, _msgSender()), 746 | "ERC721: approve caller is not owner nor approved for all" 747 | ); 748 | 749 | _approve(to, tokenId); 750 | } 751 | 752 | /** 753 | * @dev See {IERC721-getApproved}. 754 | */ 755 | function getApproved(uint256 tokenId) public view virtual override returns (address) { 756 | require(_exists(tokenId), "ERC721: approved query for nonexistent token"); 757 | 758 | return _tokenApprovals[tokenId]; 759 | } 760 | 761 | /** 762 | * @dev See {IERC721-setApprovalForAll}. 763 | */ 764 | function setApprovalForAll(address operator, bool approved) public virtual override { 765 | _setApprovalForAll(_msgSender(), operator, approved); 766 | } 767 | 768 | /** 769 | * @dev See {IERC721-isApprovedForAll}. 770 | */ 771 | function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { 772 | return _operatorApprovals[owner][operator]; 773 | } 774 | 775 | /** 776 | * @dev See {IERC721-transferFrom}. 777 | */ 778 | function transferFrom( 779 | address from, 780 | address to, 781 | uint256 tokenId 782 | ) public virtual override { 783 | //solhint-disable-next-line max-line-length 784 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 785 | 786 | _transfer(from, to, tokenId); 787 | } 788 | 789 | /** 790 | * @dev See {IERC721-safeTransferFrom}. 791 | */ 792 | function safeTransferFrom( 793 | address from, 794 | address to, 795 | uint256 tokenId 796 | ) public virtual override { 797 | safeTransferFrom(from, to, tokenId, ""); 798 | } 799 | 800 | /** 801 | * @dev See {IERC721-safeTransferFrom}. 802 | */ 803 | function safeTransferFrom( 804 | address from, 805 | address to, 806 | uint256 tokenId, 807 | bytes memory _data 808 | ) public virtual override { 809 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 810 | _safeTransfer(from, to, tokenId, _data); 811 | } 812 | 813 | /** 814 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 815 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 816 | * 817 | * `_data` is additional data, it has no specified format and it is sent in call to `to`. 818 | * 819 | * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. 820 | * implement alternative mechanisms to perform token transfer, such as signature-based. 821 | * 822 | * Requirements: 823 | * 824 | * - `from` cannot be the zero address. 825 | * - `to` cannot be the zero address. 826 | * - `tokenId` token must exist and be owned by `from`. 827 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 828 | * 829 | * Emits a {Transfer} event. 830 | */ 831 | function _safeTransfer( 832 | address from, 833 | address to, 834 | uint256 tokenId, 835 | bytes memory _data 836 | ) internal virtual { 837 | _transfer(from, to, tokenId); 838 | require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); 839 | } 840 | 841 | /** 842 | * @dev Returns whether `tokenId` exists. 843 | * 844 | * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. 845 | * 846 | * Tokens start existing when they are minted (`_mint`), 847 | * and stop existing when they are burned (`_burn`). 848 | */ 849 | function _exists(uint256 tokenId) internal view virtual returns (bool) { 850 | return _owners[tokenId] != address(0); 851 | } 852 | 853 | /** 854 | * @dev Returns whether `spender` is allowed to manage `tokenId`. 855 | * 856 | * Requirements: 857 | * 858 | * - `tokenId` must exist. 859 | */ 860 | function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { 861 | require(_exists(tokenId), "ERC721: operator query for nonexistent token"); 862 | address owner = ERC721.ownerOf(tokenId); 863 | return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); 864 | } 865 | 866 | /** 867 | * @dev Safely mints `tokenId` and transfers it to `to`. 868 | * 869 | * Requirements: 870 | * 871 | * - `tokenId` must not exist. 872 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 873 | * 874 | * Emits a {Transfer} event. 875 | */ 876 | function _safeMint(address to, uint256 tokenId) internal virtual { 877 | _safeMint(to, tokenId, ""); 878 | } 879 | 880 | /** 881 | * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is 882 | * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. 883 | */ 884 | function _safeMint( 885 | address to, 886 | uint256 tokenId, 887 | bytes memory _data 888 | ) internal virtual { 889 | _mint(to, tokenId); 890 | require( 891 | _checkOnERC721Received(address(0), to, tokenId, _data), 892 | "ERC721: transfer to non ERC721Receiver implementer" 893 | ); 894 | } 895 | 896 | /** 897 | * @dev Mints `tokenId` and transfers it to `to`. 898 | * 899 | * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible 900 | * 901 | * Requirements: 902 | * 903 | * - `tokenId` must not exist. 904 | * - `to` cannot be the zero address. 905 | * 906 | * Emits a {Transfer} event. 907 | */ 908 | function _mint(address to, uint256 tokenId) internal virtual { 909 | require(to != address(0), "ERC721: mint to the zero address"); 910 | require(!_exists(tokenId), "ERC721: token already minted"); 911 | 912 | _beforeTokenTransfer(address(0), to, tokenId); 913 | 914 | _balances[to] += 1; 915 | _owners[tokenId] = to; 916 | 917 | emit Transfer(address(0), to, tokenId); 918 | 919 | _afterTokenTransfer(address(0), to, tokenId); 920 | } 921 | 922 | /** 923 | * @dev Destroys `tokenId`. 924 | * The approval is cleared when the token is burned. 925 | * 926 | * Requirements: 927 | * 928 | * - `tokenId` must exist. 929 | * 930 | * Emits a {Transfer} event. 931 | */ 932 | function _burn(uint256 tokenId) internal virtual { 933 | address owner = ERC721.ownerOf(tokenId); 934 | 935 | _beforeTokenTransfer(owner, address(0), tokenId); 936 | 937 | // Clear approvals 938 | _approve(address(0), tokenId); 939 | 940 | _balances[owner] -= 1; 941 | delete _owners[tokenId]; 942 | 943 | emit Transfer(owner, address(0), tokenId); 944 | 945 | _afterTokenTransfer(owner, address(0), tokenId); 946 | } 947 | 948 | /** 949 | * @dev Transfers `tokenId` from `from` to `to`. 950 | * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. 951 | * 952 | * Requirements: 953 | * 954 | * - `to` cannot be the zero address. 955 | * - `tokenId` token must be owned by `from`. 956 | * 957 | * Emits a {Transfer} event. 958 | */ 959 | function _transfer( 960 | address from, 961 | address to, 962 | uint256 tokenId 963 | ) internal virtual { 964 | require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); 965 | require(to != address(0), "ERC721: transfer to the zero address"); 966 | 967 | _beforeTokenTransfer(from, to, tokenId); 968 | 969 | // Clear approvals from the previous owner 970 | _approve(address(0), tokenId); 971 | 972 | _balances[from] -= 1; 973 | _balances[to] += 1; 974 | _owners[tokenId] = to; 975 | 976 | emit Transfer(from, to, tokenId); 977 | 978 | _afterTokenTransfer(from, to, tokenId); 979 | } 980 | 981 | /** 982 | * @dev Approve `to` to operate on `tokenId` 983 | * 984 | * Emits a {Approval} event. 985 | */ 986 | function _approve(address to, uint256 tokenId) internal virtual { 987 | _tokenApprovals[tokenId] = to; 988 | emit Approval(ERC721.ownerOf(tokenId), to, tokenId); 989 | } 990 | 991 | /** 992 | * @dev Approve `operator` to operate on all of `owner` tokens 993 | * 994 | * Emits a {ApprovalForAll} event. 995 | */ 996 | function _setApprovalForAll( 997 | address owner, 998 | address operator, 999 | bool approved 1000 | ) internal virtual { 1001 | require(owner != operator, "ERC721: approve to caller"); 1002 | _operatorApprovals[owner][operator] = approved; 1003 | emit ApprovalForAll(owner, operator, approved); 1004 | } 1005 | 1006 | /** 1007 | * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. 1008 | * The call is not executed if the target address is not a contract. 1009 | * 1010 | * @param from address representing the previous owner of the given token ID 1011 | * @param to target address that will receive the tokens 1012 | * @param tokenId uint256 ID of the token to be transferred 1013 | * @param _data bytes optional data to send along with the call 1014 | * @return bool whether the call correctly returned the expected magic value 1015 | */ 1016 | function _checkOnERC721Received( 1017 | address from, 1018 | address to, 1019 | uint256 tokenId, 1020 | bytes memory _data 1021 | ) private returns (bool) { 1022 | if (to.isContract()) { 1023 | try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { 1024 | return retval == IERC721Receiver.onERC721Received.selector; 1025 | } catch (bytes memory reason) { 1026 | if (reason.length == 0) { 1027 | revert("ERC721: transfer to non ERC721Receiver implementer"); 1028 | } else { 1029 | assembly { 1030 | revert(add(32, reason), mload(reason)) 1031 | } 1032 | } 1033 | } 1034 | } else { 1035 | return true; 1036 | } 1037 | } 1038 | 1039 | /** 1040 | * @dev Hook that is called before any token transfer. This includes minting 1041 | * and burning. 1042 | * 1043 | * Calling conditions: 1044 | * 1045 | * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be 1046 | * transferred to `to`. 1047 | * - When `from` is zero, `tokenId` will be minted for `to`. 1048 | * - When `to` is zero, ``from``'s `tokenId` will be burned. 1049 | * - `from` and `to` are never both zero. 1050 | * 1051 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 1052 | */ 1053 | function _beforeTokenTransfer( 1054 | address from, 1055 | address to, 1056 | uint256 tokenId 1057 | ) internal virtual {} 1058 | 1059 | /** 1060 | * @dev Hook that is called after any transfer of tokens. This includes 1061 | * minting and burning. 1062 | * 1063 | * Calling conditions: 1064 | * 1065 | * - when `from` and `to` are both non-zero. 1066 | * - `from` and `to` are never both zero. 1067 | * 1068 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 1069 | */ 1070 | function _afterTokenTransfer( 1071 | address from, 1072 | address to, 1073 | uint256 tokenId 1074 | ) internal virtual {} 1075 | } 1076 | 1077 | // File: @openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol 1078 | 1079 | 1080 | // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721URIStorage.sol) 1081 | 1082 | pragma solidity ^0.8.0; 1083 | 1084 | 1085 | /** 1086 | * @dev ERC721 token with storage based token URI management. 1087 | */ 1088 | abstract contract ERC721URIStorage is ERC721 { 1089 | using Strings for uint256; 1090 | 1091 | // Optional mapping for token URIs 1092 | mapping(uint256 => string) private _tokenURIs; 1093 | 1094 | /** 1095 | * @dev See {IERC721Metadata-tokenURI}. 1096 | */ 1097 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 1098 | require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token"); 1099 | 1100 | string memory _tokenURI = _tokenURIs[tokenId]; 1101 | string memory base = _baseURI(); 1102 | 1103 | // If there is no base URI, return the token URI. 1104 | if (bytes(base).length == 0) { 1105 | return _tokenURI; 1106 | } 1107 | // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). 1108 | if (bytes(_tokenURI).length > 0) { 1109 | return string(abi.encodePacked(base, _tokenURI)); 1110 | } 1111 | 1112 | return super.tokenURI(tokenId); 1113 | } 1114 | 1115 | /** 1116 | * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. 1117 | * 1118 | * Requirements: 1119 | * 1120 | * - `tokenId` must exist. 1121 | */ 1122 | function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { 1123 | require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token"); 1124 | _tokenURIs[tokenId] = _tokenURI; 1125 | } 1126 | 1127 | /** 1128 | * @dev Destroys `tokenId`. 1129 | * The approval is cleared when the token is burned. 1130 | * 1131 | * Requirements: 1132 | * 1133 | * - `tokenId` must exist. 1134 | * 1135 | * Emits a {Transfer} event. 1136 | */ 1137 | function _burn(uint256 tokenId) internal virtual override { 1138 | super._burn(tokenId); 1139 | 1140 | if (bytes(_tokenURIs[tokenId]).length != 0) { 1141 | delete _tokenURIs[tokenId]; 1142 | } 1143 | } 1144 | } 1145 | 1146 | // File: contracts/s.sol 1147 | 1148 | //SPDX-License-Identifier: Unlicense 1149 | pragma solidity ^0.8.2; 1150 | 1151 | 1152 | contract AINFT is ERC721URIStorage { 1153 | using Counters for Counters.Counter; 1154 | Counters.Counter private _tokenIds; 1155 | 1156 | constructor() ERC721("Artificial Intelligence NFT", "AINFT") {} 1157 | 1158 | function mint(string memory tokenURI) 1159 | public 1160 | returns (uint256) 1161 | { 1162 | _tokenIds.increment(); 1163 | 1164 | uint256 newItemId = _tokenIds.current(); 1165 | _mint(msg.sender, newItemId); 1166 | _setTokenURI(newItemId, tokenURI); 1167 | 1168 | return newItemId; 1169 | } 1170 | } 1171 | --------------------------------------------------------------------------------