├── SUMMARY.md ├── .babelrc ├── image.png ├── public ├── favicon.ico ├── favicon.png ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png └── index.html ├── src ├── components │ ├── Loading │ │ ├── loading.gif │ │ └── Loading.jsx │ ├── Navbar │ │ ├── favicon-32x32.png │ │ └── Navbar.jsx │ ├── App.css │ ├── ContractNotDeployed │ │ └── ContractNotDeployed.jsx │ ├── AccountDetails │ │ └── AccountDetails.jsx │ ├── ConnectMetamask │ │ ├── ConnectToMetamask.jsx │ │ └── metamask.svg │ ├── MyCryptoBoyNFTDetails │ │ └── MyCryptoBoyNFTDetails.jsx │ ├── AllCryptoBoys │ │ └── AllCryptoBoys.jsx │ ├── MyCryptoBoys │ │ └── MyCryptoBoys.jsx │ ├── CryptoBoyNFTImage │ │ └── CryptoBoyNFTImage.jsx │ ├── Queries │ │ └── Queries.jsx │ ├── CryptoBoyNFTDetails │ │ └── CryptoBoyNFTDetails.jsx │ ├── App.js │ └── FormAndPreview │ │ └── FormAndPreview.jsx ├── index.js ├── contracts │ ├── Migrations.sol │ └── CryptoBoys.sol ├── serviceWorker.js └── abis │ └── Migrations.json ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── .gitignore ├── truffle-config.js ├── package.json ├── README.md └── test └── CryptoBoys.test.js /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [README](README.md) 4 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2", "stage-3"] 3 | } 4 | -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/image.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/public/favicon.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/components/Loading/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/src/components/Loading/loading.gif -------------------------------------------------------------------------------- /src/components/Navbar/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-Nova0211/Eth_Kervan_NFT_Marketplace/HEAD/src/components/Navbar/favicon-32x32.png -------------------------------------------------------------------------------- /src/components/App.css: -------------------------------------------------------------------------------- 1 | input::-webkit-input-placeholder { 2 | font-size: 1rem; 3 | } 4 | 5 | input[type="color"]:hover { 6 | cursor: pointer; 7 | } 8 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const CryptoBoys = artifacts.require("CryptoBoys"); 2 | 3 | module.exports = async function(deployer) { 4 | await deployer.deploy(CryptoBoys); 5 | }; 6 | -------------------------------------------------------------------------------- /src/components/Loading/Loading.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import loadingGIF from "./loading.gif"; 3 | 4 | const Loading = () => { 5 | return Loading..; 6 | }; 7 | 8 | export default Loading; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # Local Netlify folder 27 | .netlify -------------------------------------------------------------------------------- /src/components/ContractNotDeployed/ContractNotDeployed.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const ContractNotDeployed = () => { 4 | return ( 5 |
6 |

Crypto Boys Contract Not Deployed To This Network.

7 |
8 |

9 | Connect Metamask to Kovan Testnet Or Localhost 7545 running a custom RPC 10 | like Ganache. 11 |

12 |
13 | ); 14 | }; 15 | 16 | export default ContractNotDeployed; 17 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | require("babel-register"); 2 | require("babel-polyfill"); 3 | 4 | module.exports = { 5 | networks: { 6 | development: { 7 | host: "127.0.0.1", 8 | port: 7545, 9 | network_id: "*", // Match any network id 10 | }, 11 | }, 12 | contracts_directory: "./src/contracts/", 13 | contracts_build_directory: "./src/abis/", 14 | compilers: { 15 | solc: { 16 | version: "pragma", 17 | optimizer: { 18 | enabled: true, 19 | runs: 200, 20 | }, 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./components/App"; 4 | import * as serviceWorker from "./serviceWorker"; 5 | 6 | import "./bootstrap.min.css"; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById("root") 13 | ); 14 | 15 | // If you want your app to work offline and load faster, you can change 16 | // unregister() to register() below. Note this comes with some pitfalls. 17 | // Learn more about service workers: https://bit.ly/CRA-PWA 18 | serviceWorker.unregister(); 19 | -------------------------------------------------------------------------------- /src/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.21 <0.8.0; 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | constructor() { 9 | owner = msg.sender; 10 | } 11 | 12 | modifier restricted() { 13 | if (msg.sender == owner) _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | 20 | function upgrade(address new_address) public restricted { 21 | Migrations upgraded = Migrations(new_address); 22 | upgraded.setCompleted(last_completed_migration); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/AccountDetails/AccountDetails.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const AccountDetails = ({ accountAddress, accountBalance }) => { 4 | return ( 5 |
6 |
7 |

CryptoBoy NFT Marketplace

8 |

9 | This is an NFT marketplace where you can mint ERC721 implemented{" "} 10 | Crypto Boy NFTs and manage them. 11 |

12 |
13 |

Account address :

14 |

{accountAddress}

15 |

Account balance :

16 |

{accountBalance} Ξ

17 |
18 |
19 | ); 20 | }; 21 | 22 | export default AccountDetails; 23 | -------------------------------------------------------------------------------- /src/components/ConnectMetamask/ConnectToMetamask.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import metamaskIcon from "./metamask.svg"; 3 | 4 | const ConnectToMetamask = ({ connectToMetamask }) => { 5 | return ( 6 |
7 |

8 | CryptoBoy NFT Marketplace 9 |

10 |

11 | This is an NFT marketplace where you can mint your ERC721 implemented{" "} 12 | Crypto Boy NFTs and manage them. 13 |

14 |
15 | 27 |
28 | ); 29 | }; 30 | 31 | export default ConnectToMetamask; 32 | -------------------------------------------------------------------------------- /src/components/MyCryptoBoyNFTDetails/MyCryptoBoyNFTDetails.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const MyCryptoBoyNFTDetails = (props) => { 4 | const { 5 | tokenId, 6 | tokenName, 7 | price, 8 | mintedBy, 9 | previousOwner, 10 | numberOfTransfers, 11 | } = props.cryptoboy; 12 | return ( 13 |
14 |

15 | Token Id :{" "} 16 | {tokenId.toNumber()} 17 |

18 |

19 | Name : {tokenName} 20 |

21 |

22 | Price :{" "} 23 | {window.web3.utils.fromWei(price.toString(), "Ether")} Ξ 24 |

25 |

26 | No. of Transfers :{" "} 27 | {numberOfTransfers.toNumber()} 28 |

29 | {props.accountAddress === mintedBy && 30 | props.accountAddress !== previousOwner ? ( 31 |
32 | Minted 33 |
34 | ) : ( 35 |
Bought
36 | )} 37 |
38 | ); 39 | }; 40 | 41 | export default MyCryptoBoyNFTDetails; 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cryptoboys", 3 | "version": "0.1.0", 4 | "description": "Crypto Boys NFT Marketplace", 5 | "author": "devpavan04", 6 | "homepage": "https://devpavan04.github.io/cryptoboys-nft-marketplace", 7 | "dependencies": { 8 | "@openzeppelin/contracts": "^3.4.1", 9 | "babel-polyfill": "6.26.0", 10 | "babel-preset-env": "1.7.0", 11 | "babel-preset-es2015": "6.24.1", 12 | "babel-preset-stage-2": "6.24.1", 13 | "babel-preset-stage-3": "6.24.1", 14 | "babel-register": "6.26.0", 15 | "bootstrap": "4.3.1", 16 | "chai": "4.2.0", 17 | "chai-as-promised": "7.1.1", 18 | "chai-bignumber": "3.0.0", 19 | "dayjs": "^1.10.4", 20 | "ipfs-http-client": "^49.0.2", 21 | "react": "16.8.4", 22 | "react-bootstrap": "1.0.0-beta.5", 23 | "react-dom": "16.8.4", 24 | "react-router-dom": "^5.2.0", 25 | "react-scripts": "2.1.3", 26 | "truffle": "5.0.5", 27 | "truffle-flattener": "^1.5.0", 28 | "web3": "1.0.0-beta.55" 29 | }, 30 | "scripts": { 31 | "start": "react-scripts start", 32 | "build": "react-scripts build && cp build/index.html build/404.html", 33 | "test": "react-scripts test", 34 | "eject": "react-scripts eject", 35 | "predeploy": "npm run build", 36 | "deploy": "gh-pages -d build" 37 | }, 38 | "eslintConfig": { 39 | "extends": "react-app" 40 | }, 41 | "browserslist": [ 42 | ">0.2%", 43 | "not dead", 44 | "not ie <= 11", 45 | "not op_mini all" 46 | ], 47 | "devDependencies": { 48 | "gh-pages": "^3.1.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/components/Navbar/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import icon from "./favicon-32x32.png"; 3 | import { Link } from "react-router-dom"; 4 | 5 | const Navbar = () => { 6 | return ( 7 | 54 | ); 55 | }; 56 | 57 | export default Navbar; 58 | -------------------------------------------------------------------------------- /src/components/AllCryptoBoys/AllCryptoBoys.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import CryptoBoyNFTImage from "../CryptoBoyNFTImage/CryptoBoyNFTImage"; 3 | import CryptoBoyNFTDetails from "../CryptoBoyNFTDetails/CryptoBoyNFTDetails"; 4 | import Loading from "../Loading/Loading"; 5 | 6 | const AllCryptoBoys = ({ 7 | cryptoBoys, 8 | accountAddress, 9 | totalTokensMinted, 10 | changeTokenPrice, 11 | toggleForSale, 12 | buyCryptoBoy, 13 | }) => { 14 | const [loading, setLoading] = useState(false); 15 | 16 | useEffect(() => { 17 | if (cryptoBoys.length !== 0) { 18 | if (cryptoBoys[0].metaData !== undefined) { 19 | setLoading(loading); 20 | } else { 21 | setLoading(false); 22 | } 23 | } 24 | }, [cryptoBoys]); 25 | 26 | return ( 27 |
28 |
29 |
30 |
31 | Total No. of CryptoBoy's Minted On The Platform :{" "} 32 | {totalTokensMinted} 33 |
34 |
35 |
36 |
37 | {cryptoBoys.map((cryptoboy) => { 38 | return ( 39 |
43 | {!loading ? ( 44 | 51 | ) : ( 52 | 53 | )} 54 | 61 |
62 | ); 63 | })} 64 |
65 |
66 | ); 67 | }; 68 | 69 | export default AllCryptoBoys; 70 | -------------------------------------------------------------------------------- /src/components/MyCryptoBoys/MyCryptoBoys.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import CryptoBoyNFTImage from "../CryptoBoyNFTImage/CryptoBoyNFTImage"; 3 | import MyCryptoBoyNFTDetails from "../MyCryptoBoyNFTDetails/MyCryptoBoyNFTDetails"; 4 | import Loading from "../Loading/Loading"; 5 | 6 | const MyCryptoBoys = ({ 7 | accountAddress, 8 | cryptoBoys, 9 | totalTokensOwnedByAccount, 10 | }) => { 11 | const [loading, setLoading] = useState(false); 12 | const [myCryptoBoys, setMyCryptoBoys] = useState([]); 13 | 14 | useEffect(() => { 15 | if (cryptoBoys.length !== 0) { 16 | if (cryptoBoys[0].metaData !== undefined) { 17 | setLoading(loading); 18 | } else { 19 | setLoading(false); 20 | } 21 | } 22 | const my_crypto_boys = cryptoBoys.filter( 23 | (cryptoboy) => cryptoboy.currentOwner === accountAddress 24 | ); 25 | setMyCryptoBoys(my_crypto_boys); 26 | }, [cryptoBoys]); 27 | 28 | return ( 29 |
30 |
31 |
32 |
33 | Total No. of CryptoBoy's You Own : {totalTokensOwnedByAccount} 34 |
35 |
36 |
37 |
38 | {myCryptoBoys.map((cryptoboy) => { 39 | return ( 40 |
44 |
45 |
46 | {!loading ? ( 47 | 54 | ) : ( 55 | 56 | )} 57 |
58 |
59 | 63 |
64 |
65 |
66 | ); 67 | })} 68 |
69 |
70 | ); 71 | }; 72 | 73 | export default MyCryptoBoys; 74 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | 28 | 29 | 30 | 31 | Crypto Boy NFT 32 | 33 | 34 | 35 |
36 | 46 | 47 | 52 | 57 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Crypto Boy NFT Marketplace 4 | 5 | _NFT marketplace DApp where users mint ERC721 implemented Crypto Boy NFTs._ 6 | 7 | #### Features 8 | 9 | * Mint custom ERC721 implemented Crypto Boy Tokens. 10 | * Sell Crypto Boy tokens on the marketplace. 11 | * Set desired token price. 12 | * Toggle between keeping the token for sale and not for sale. 13 | * Keeps track of all the tokens owned by an account - minted and bought. 14 | * Query blockchain for token owner and token metadata. 15 | * User can mint a token only after every 5 minutes. 16 | 17 | ## 18 | 19 | #### Stack 20 | 21 | * [Solidity](https://docs.soliditylang.org/en/v0.7.6/) - Object-oriented, high-level language for implementing smart contracts. 22 | * [Bootstrap 4](https://getbootstrap.com/) - CSS framework for faster and easier web development. 23 | * [React.js](https://reactjs.org/) - JavaScript library for building user interfaces. 24 | * [web3.js](https://web3js.readthedocs.io/en/v1.3.4/) - Allows users to interact with a local or remote ethereum node using HTTP, IPC or WebSocket. 25 | * [Truffle](https://www.trufflesuite.com/truffle) - Development environment, testing framework and asset pipeline for blockchains using the Ethereum Virtual Machine (EVM). 26 | * [Ganache](https://www.trufflesuite.com/ganache) - Personal blockchain for Ethereum development used to deploy contracts, develop DApps, and run tests. 27 | 28 | ## 29 | 30 | #### Interact with the deployed DApp 31 | 32 | * Crypto Boy Marketplace DApp requires [Metamask](https://metamask.io/) browser wallet extension to interact with. 33 | * Connect metamask browser wallet to Kovan Test Network. 34 | * Request and get test etheres for the metamask account from [Kovan Faucet](https://gitter.im/kovan-testnet/faucet) to make transactions. 35 | * Crypto Boy Marketplace Smart Contract is deployed to Kovan Testnet - [0x420d2a6E87D87992EB01e5BFe762B3F437dBfD85](https://kovan.etherscan.io/address/0x420d2a6e87d87992eb01e5bfe762b3f437dbfd85) 36 | * Access Crypto Boy Marketplace DApp at [cryptoboys-NFT-marketplace](https://devpavan04.github.io/cryptoboys-nft-marketplace/) and start minting your Crypto Boys. 37 | 38 | ## 39 | 40 | #### Run the DApp Locally 41 | 42 | **Install truffle** 43 | 44 | ``` 45 | npm install -g truffle 46 | ``` 47 | 48 | **Install ganache-cli** 49 | 50 | ``` 51 | npm i ganache-cli 52 | ``` 53 | 54 | **Run ganache-cli** 55 | 56 | ``` 57 | ganache-cli --port 7545 58 | ``` 59 | 60 | **Open new terminal window and clone this repository** 61 | 62 | ``` 63 | git clone https://github.com/devpavan04/cryptoboys-NFT-marketplace.git 64 | ``` 65 | 66 | **Install dependencies** 67 | 68 | ``` 69 | cd cryptoboys-NFT-marketplace 70 | npm install 71 | ``` 72 | 73 | **Compile smart contract** 74 | 75 | ``` 76 | truffle compile 77 | ``` 78 | 79 | **Deploy smart contract to ganache** 80 | 81 | ``` 82 | truffle migrate 83 | ``` 84 | 85 | **Test smart contract** 86 | 87 | ``` 88 | truffle test 89 | ``` 90 | 91 | **Start DApp** 92 | 93 | ``` 94 | npm start 95 | ``` 96 | 97 | * Open metamask browser wallet and connect network to Localhost 7545. 98 | * Import accounts from ganache-cli into the metamask browser wallet to make transactions on the DApp. 99 | -------------------------------------------------------------------------------- /src/components/ConnectMetamask/metamask.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/CryptoBoyNFTImage/CryptoBoyNFTImage.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const CryptoBoyNFTImage = ({ colors }) => { 4 | const { 5 | cardBorderColor, 6 | cardBackgroundColor, 7 | headBorderColor, 8 | headBackgroundColor, 9 | leftEyeBorderColor, 10 | rightEyeBorderColor, 11 | leftEyeBackgroundColor, 12 | rightEyeBackgroundColor, 13 | leftPupilBackgroundColor, 14 | rightPupilBackgroundColor, 15 | mouthColor, 16 | neckBackgroundColor, 17 | neckBorderColor, 18 | bodyBackgroundColor, 19 | bodyBorderColor, 20 | } = colors; 21 | 22 | const cryptoboy_card = { 23 | width: "280px", 24 | height: "260px", 25 | margin: "auto", 26 | backgroundColor: `${cardBackgroundColor}`, 27 | border: `10px solid ${cardBorderColor}`, 28 | }; 29 | 30 | const head = { 31 | zIndex: "1", 32 | width: "100px", 33 | height: "100px", 34 | borderRadius: "50%", 35 | margin: "2rem auto 0", 36 | border: `8px solid ${headBorderColor}`, 37 | backgroundColor: `${headBackgroundColor}`, 38 | position: "relative", 39 | }; 40 | 41 | const eyeLeft = { 42 | zIndex: "1", 43 | width: "60px", 44 | height: "60px", 45 | backgroundColor: `${leftEyeBackgroundColor}`, 46 | borderRadius: "50%", 47 | position: "absolute", 48 | top: "0rem", 49 | left: "-1.5rem", 50 | border: `6px solid ${leftEyeBorderColor}`, 51 | }; 52 | 53 | const eyeRight = { 54 | zIndex: "1", 55 | width: "70px", 56 | height: "70px", 57 | backgroundColor: `${rightEyeBackgroundColor}`, 58 | borderRadius: "50%", 59 | position: "absolute", 60 | top: "-1.2rem", 61 | left: "2.8rem", 62 | border: `6px solid ${rightEyeBorderColor}`, 63 | }; 64 | 65 | const pupilLeft = { 66 | width: "20px", 67 | height: "20px", 68 | backgroundColor: `${leftPupilBackgroundColor}`, 69 | borderRadius: "50%", 70 | position: "absolute", 71 | left: "1rem", 72 | top: "1rem", 73 | }; 74 | 75 | const pupilRight = { 76 | width: "30px", 77 | height: "30px", 78 | backgroundColor: `${rightPupilBackgroundColor}`, 79 | borderRadius: "50%", 80 | position: "absolute", 81 | left: "1rem", 82 | top: "1rem", 83 | }; 84 | 85 | const mouth = { 86 | position: "absolute", 87 | top: "12px", 88 | left: "0", 89 | right: "0", 90 | height: "60px", 91 | width: "60px", 92 | margin: "3px auto", 93 | borderRadius: "100%", 94 | borderBottom: `8px solid ${mouthColor}`, 95 | }; 96 | 97 | const neck = { 98 | position: "relative", 99 | left: "7.7rem", 100 | top: "-0.1rem", 101 | width: "15px", 102 | height: "30px", 103 | backgroundColor: `${neckBackgroundColor}`, 104 | border: `4px solid ${neckBorderColor}`, 105 | }; 106 | 107 | const body = { 108 | height: "50px", 109 | width: "90px", 110 | margin: "-0.4rem auto", 111 | border: `5px solid ${bodyBorderColor}`, 112 | borderRadius: "100% 100% 100% 100% / 100% 100% 0% 0%", 113 | backgroundColor: `${bodyBackgroundColor}`, 114 | position: "relative", 115 | left: "0.1rem", 116 | }; 117 | 118 | const leftHand = { 119 | position: "absolute", 120 | top: "20px", 121 | width: "15px", 122 | height: "20px", 123 | borderRight: `5px solid ${bodyBorderColor}`, 124 | }; 125 | 126 | const rightHand = { 127 | position: "absolute", 128 | top: "20px", 129 | width: "15px", 130 | height: "20px", 131 | borderRight: `5px solid ${bodyBorderColor}`, 132 | right: "1rem", 133 | }; 134 | 135 | return ( 136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 | ); 153 | }; 154 | 155 | export default CryptoBoyNFTImage; 156 | -------------------------------------------------------------------------------- /src/components/Queries/Queries.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | 3 | const Queries = (props) => { 4 | const [tokenIdForOwner, setTokenIdForOwner] = useState(""); 5 | const [tokenOwner, setTokenOwner] = useState(""); 6 | const [tokenIdForOwnerNotFound, setTokenIdForOwnerNotFound] = useState(false); 7 | 8 | const [tokenIdForMetadata, setTokenIdForMetadata] = useState(""); 9 | const [tokenMetadata, setTokenMetadata] = useState(""); 10 | const [tokenMetadataLink, setTokenMetadataLink] = useState(""); 11 | const [tokenIdForMetadataNotFound, setTokenIdForMetadataNotFound] = useState( 12 | false 13 | ); 14 | 15 | const getTokenOwner = async (e) => { 16 | e.preventDefault(); 17 | try { 18 | const owner = await props.cryptoBoysContract.methods 19 | .getTokenOwner(tokenIdForOwner) 20 | .call(); 21 | setTokenOwner(owner); 22 | setTimeout(() => { 23 | setTokenOwner(""); 24 | setTokenIdForOwner(""); 25 | }, 5000); 26 | } catch (e) { 27 | setTokenIdForOwnerNotFound(true); 28 | setTokenIdForOwner(""); 29 | } 30 | }; 31 | 32 | const getTokenMetadata = async (e) => { 33 | e.preventDefault(); 34 | try { 35 | const metadata = await props.cryptoBoysContract.methods 36 | .getTokenMetaData(tokenIdForMetadata) 37 | .call(); 38 | setTokenMetadata( 39 | metadata.substr(0, 60) + "..." + metadata.slice(metadata.length - 5) 40 | ); 41 | setTokenMetadataLink(metadata); 42 | setTimeout(() => { 43 | setTokenMetadata(""); 44 | setTokenIdForMetadata(""); 45 | }, 5000); 46 | } catch (e) { 47 | setTokenIdForMetadataNotFound(true); 48 | setTokenIdForMetadata(""); 49 | } 50 | }; 51 | 52 | return ( 53 |
54 |
55 |
56 |
Queries
57 |
58 |
59 |
60 |
61 |
62 |
Get Token Owner
63 |
64 |
65 | setTokenIdForOwner(e.target.value)} 72 | /> 73 |
74 | 77 | {tokenIdForOwnerNotFound ? ( 78 |
79 | 82 | Non-Existent Token Id 83 |
84 | ) : null} 85 |
86 |

{tokenOwner}

87 |
88 |
89 |
Get Token Metadata
90 |
91 |
92 | setTokenIdForMetadata(e.target.value)} 99 | /> 100 |
101 | 104 | {tokenIdForMetadataNotFound ? ( 105 |
106 | 109 | Non-Existent Token Id 110 |
111 | ) : null} 112 |
113 |

114 | 119 | {tokenMetadata} 120 | 121 |

122 |
123 |
124 |
125 |
126 | ); 127 | }; 128 | 129 | export default Queries; 130 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/components/CryptoBoyNFTDetails/CryptoBoyNFTDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | class CryptoBoyNFTDetails extends Component { 4 | constructor(props) { 5 | super(props); 6 | this.state = { 7 | newCryptoBoyPrice: "", 8 | }; 9 | } 10 | 11 | callChangeTokenPriceFromApp = (tokenId, newPrice) => { 12 | this.props.changeTokenPrice(tokenId, newPrice); 13 | }; 14 | 15 | render() { 16 | return ( 17 |
18 |

19 | Token Id :{" "} 20 | {this.props.cryptoboy.tokenId.toNumber()} 21 |

22 |

23 | Name :{" "} 24 | {this.props.cryptoboy.tokenName} 25 |

26 |

27 | Minted By :{" "} 28 | {this.props.cryptoboy.mintedBy.substr(0, 5) + 29 | "..." + 30 | this.props.cryptoboy.mintedBy.slice( 31 | this.props.cryptoboy.mintedBy.length - 5 32 | )} 33 |

34 |

35 | Owned By :{" "} 36 | {this.props.cryptoboy.currentOwner.substr(0, 5) + 37 | "..." + 38 | this.props.cryptoboy.currentOwner.slice( 39 | this.props.cryptoboy.currentOwner.length - 5 40 | )} 41 |

42 |

43 | Previous Owner :{" "} 44 | {this.props.cryptoboy.previousOwner.substr(0, 5) + 45 | "..." + 46 | this.props.cryptoboy.previousOwner.slice( 47 | this.props.cryptoboy.previousOwner.length - 5 48 | )} 49 |

50 |

51 | Price :{" "} 52 | {window.web3.utils.fromWei( 53 | this.props.cryptoboy.price.toString(), 54 | "Ether" 55 | )}{" "} 56 | Ξ 57 |

58 |

59 | No. of Transfers :{" "} 60 | {this.props.cryptoboy.numberOfTransfers.toNumber()} 61 |

62 |
63 | {this.props.accountAddress === this.props.cryptoboy.currentOwner ? ( 64 |
{ 66 | e.preventDefault(); 67 | this.callChangeTokenPriceFromApp( 68 | this.props.cryptoboy.tokenId.toNumber(), 69 | this.state.newCryptoBoyPrice 70 | ); 71 | }} 72 | > 73 |
74 | {" "} 77 | 86 | this.setState({ 87 | newCryptoBoyPrice: e.target.value, 88 | }) 89 | } 90 | /> 91 |
92 | 99 |
100 | ) : null} 101 |
102 |
103 | {this.props.accountAddress === this.props.cryptoboy.currentOwner ? ( 104 | this.props.cryptoboy.forSale ? ( 105 | 116 | ) : ( 117 | 128 | ) 129 | ) : null} 130 |
131 |
132 | {this.props.accountAddress !== this.props.cryptoboy.currentOwner ? ( 133 | this.props.cryptoboy.forSale ? ( 134 | 152 | ) : ( 153 | <> 154 | 166 |

Currently not for sale!

167 | 168 | ) 169 | ) : null} 170 |
171 |
172 | ); 173 | } 174 | } 175 | 176 | export default CryptoBoyNFTDetails; 177 | -------------------------------------------------------------------------------- /src/contracts/CryptoBoys.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.21 <0.8.0; 3 | pragma abicoder v2; 4 | 5 | // import ERC721 iterface 6 | import "./ERC721.sol"; 7 | 8 | // CryptoBoys smart contract inherits ERC721 interface 9 | contract CryptoBoys is ERC721 { 10 | 11 | // this contract's token collection name 12 | string public collectionName; 13 | // this contract's token symbol 14 | string public collectionNameSymbol; 15 | // total number of crypto boys minted 16 | uint256 public cryptoBoyCounter; 17 | 18 | // define crypto boy struct 19 | struct CryptoBoy { 20 | uint256 tokenId; 21 | string tokenName; 22 | string tokenURI; 23 | address payable mintedBy; 24 | address payable currentOwner; 25 | address payable previousOwner; 26 | uint256 price; 27 | uint256 numberOfTransfers; 28 | bool forSale; 29 | } 30 | 31 | // map cryptoboy's token id to crypto boy 32 | mapping(uint256 => CryptoBoy) public allCryptoBoys; 33 | // check if token name exists 34 | mapping(string => bool) public tokenNameExists; 35 | // check if color exists 36 | mapping(string => bool) public colorExists; 37 | // check if token URI exists 38 | mapping(string => bool) public tokenURIExists; 39 | 40 | // initialize contract while deployment with contract's collection name and token 41 | constructor() ERC721("Crypto Boys Collection", "CB") { 42 | collectionName = name(); 43 | collectionNameSymbol = symbol(); 44 | } 45 | 46 | // mint a new crypto boy 47 | function mintCryptoBoy(string memory _name, string memory _tokenURI, uint256 _price, string[] calldata _colors) external { 48 | // check if thic fucntion caller is not an zero address account 49 | require(msg.sender != address(0)); 50 | // increment counter 51 | cryptoBoyCounter ++; 52 | // check if a token exists with the above token id => incremented counter 53 | require(!_exists(cryptoBoyCounter)); 54 | 55 | // loop through the colors passed and check if each colors already exists or not 56 | for(uint i=0; i<_colors.length; i++) { 57 | require(!colorExists[_colors[i]]); 58 | } 59 | // check if the token URI already exists or not 60 | require(!tokenURIExists[_tokenURI]); 61 | // check if the token name already exists or not 62 | require(!tokenNameExists[_name]); 63 | 64 | // mint the token 65 | _mint(msg.sender, cryptoBoyCounter); 66 | // set token URI (bind token id with the passed in token URI) 67 | _setTokenURI(cryptoBoyCounter, _tokenURI); 68 | 69 | // loop through the colors passed and make each of the colors as exists since the token is already minted 70 | for (uint i=0; i<_colors.length; i++) { 71 | colorExists[_colors[i]] = true; 72 | } 73 | // make passed token URI as exists 74 | tokenURIExists[_tokenURI] = true; 75 | // make token name passed as exists 76 | tokenNameExists[_name] = true; 77 | 78 | // creat a new crypto boy (struct) and pass in new values 79 | CryptoBoy memory newCryptoBoy = CryptoBoy( 80 | cryptoBoyCounter, 81 | _name, 82 | _tokenURI, 83 | msg.sender, 84 | msg.sender, 85 | address(0), 86 | _price, 87 | 0, 88 | true); 89 | // add the token id and it's crypto boy to all crypto boys mapping 90 | allCryptoBoys[cryptoBoyCounter] = newCryptoBoy; 91 | } 92 | 93 | // get owner of the token 94 | function getTokenOwner(uint256 _tokenId) public view returns(address) { 95 | address _tokenOwner = ownerOf(_tokenId); 96 | return _tokenOwner; 97 | } 98 | 99 | // get metadata of the token 100 | function getTokenMetaData(uint _tokenId) public view returns(string memory) { 101 | string memory tokenMetaData = tokenURI(_tokenId); 102 | return tokenMetaData; 103 | } 104 | 105 | // get total number of tokens minted so far 106 | function getNumberOfTokensMinted() public view returns(uint256) { 107 | uint256 totalNumberOfTokensMinted = totalSupply(); 108 | return totalNumberOfTokensMinted; 109 | } 110 | 111 | // get total number of tokens owned by an address 112 | function getTotalNumberOfTokensOwnedByAnAddress(address _owner) public view returns(uint256) { 113 | uint256 totalNumberOfTokensOwned = balanceOf(_owner); 114 | return totalNumberOfTokensOwned; 115 | } 116 | 117 | // check if the token already exists 118 | function getTokenExists(uint256 _tokenId) public view returns(bool) { 119 | bool tokenExists = _exists(_tokenId); 120 | return tokenExists; 121 | } 122 | 123 | // by a token by passing in the token's id 124 | function buyToken(uint256 _tokenId) public payable { 125 | // check if the function caller is not an zero account address 126 | require(msg.sender != address(0)); 127 | // check if the token id of the token being bought exists or not 128 | require(_exists(_tokenId)); 129 | // get the token's owner 130 | address tokenOwner = ownerOf(_tokenId); 131 | // token's owner should not be an zero address account 132 | require(tokenOwner != address(0)); 133 | // the one who wants to buy the token should not be the token's owner 134 | require(tokenOwner != msg.sender); 135 | // get that token from all crypto boys mapping and create a memory of it defined as (struct => CryptoBoy) 136 | CryptoBoy memory cryptoboy = allCryptoBoys[_tokenId]; 137 | // price sent in to buy should be equal to or more than the token's price 138 | require(msg.value >= cryptoboy.price); 139 | // token should be for sale 140 | require(cryptoboy.forSale); 141 | // transfer the token from owner to the caller of the function (buyer) 142 | _transfer(tokenOwner, msg.sender, _tokenId); 143 | // get owner of the token 144 | address payable sendTo = cryptoboy.currentOwner; 145 | // send token's worth of ethers to the owner 146 | sendTo.transfer(msg.value); 147 | // update the token's previous owner 148 | cryptoboy.previousOwner = cryptoboy.currentOwner; 149 | // update the token's current owner 150 | cryptoboy.currentOwner = msg.sender; 151 | // update the how many times this token was transfered 152 | cryptoboy.numberOfTransfers += 1; 153 | // set and update that token in the mapping 154 | allCryptoBoys[_tokenId] = cryptoboy; 155 | } 156 | 157 | function changeTokenPrice(uint256 _tokenId, uint256 _newPrice) public { 158 | // require caller of the function is not an empty address 159 | require(msg.sender != address(0)); 160 | // require that token should exist 161 | require(_exists(_tokenId)); 162 | // get the token's owner 163 | address tokenOwner = ownerOf(_tokenId); 164 | // check that token's owner should be equal to the caller of the function 165 | require(tokenOwner == msg.sender); 166 | // get that token from all crypto boys mapping and create a memory of it defined as (struct => CryptoBoy) 167 | CryptoBoy memory cryptoboy = allCryptoBoys[_tokenId]; 168 | // update token's price with new price 169 | cryptoboy.price = _newPrice; 170 | // set and update that token in the mapping 171 | allCryptoBoys[_tokenId] = cryptoboy; 172 | } 173 | 174 | // switch between set for sale and set not for sale 175 | function toggleForSale(uint256 _tokenId) public { 176 | // require caller of the function is not an empty address 177 | require(msg.sender != address(0)); 178 | // require that token should exist 179 | require(_exists(_tokenId)); 180 | // get the token's owner 181 | address tokenOwner = ownerOf(_tokenId); 182 | // check that token's owner should be equal to the caller of the function 183 | require(tokenOwner == msg.sender); 184 | // get that token from all crypto boys mapping and create a memory of it defined as (struct => CryptoBoy) 185 | CryptoBoy memory cryptoboy = allCryptoBoys[_tokenId]; 186 | // if token's forSale is false make it true and vice versa 187 | if(cryptoboy.forSale) { 188 | cryptoboy.forSale = false; 189 | } else { 190 | cryptoboy.forSale = true; 191 | } 192 | // set and update that token in the mapping 193 | allCryptoBoys[_tokenId] = cryptoboy; 194 | } 195 | } -------------------------------------------------------------------------------- /src/components/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { HashRouter, Route } from "react-router-dom"; 3 | import "./App.css"; 4 | import Web3 from "web3"; 5 | import CryptoBoys from "../abis/CryptoBoys.json"; 6 | 7 | import FormAndPreview from "../components/FormAndPreview/FormAndPreview"; 8 | import AllCryptoBoys from "./AllCryptoBoys/AllCryptoBoys"; 9 | import AccountDetails from "./AccountDetails/AccountDetails"; 10 | import ContractNotDeployed from "./ContractNotDeployed/ContractNotDeployed"; 11 | import ConnectToMetamask from "./ConnectMetamask/ConnectToMetamask"; 12 | import Loading from "./Loading/Loading"; 13 | import Navbar from "./Navbar/Navbar"; 14 | import MyCryptoBoys from "./MyCryptoBoys/MyCryptoBoys"; 15 | import Queries from "./Queries/Queries"; 16 | 17 | const ipfsClient = require("ipfs-http-client"); 18 | const ipfs = ipfsClient({ 19 | host: "ipfs.infura.io", 20 | port: 5001, 21 | protocol: "https", 22 | }); 23 | 24 | class App extends Component { 25 | constructor(props) { 26 | super(props); 27 | this.state = { 28 | accountAddress: "", 29 | accountBalance: "", 30 | cryptoBoysContract: null, 31 | cryptoBoysCount: 0, 32 | cryptoBoys: [], 33 | loading: true, 34 | metamaskConnected: false, 35 | contractDetected: false, 36 | totalTokensMinted: 0, 37 | totalTokensOwnedByAccount: 0, 38 | nameIsUsed: false, 39 | colorIsUsed: false, 40 | colorsUsed: [], 41 | lastMintTime: null, 42 | }; 43 | } 44 | 45 | componentWillMount = async () => { 46 | await this.loadWeb3(); 47 | await this.loadBlockchainData(); 48 | await this.setMetaData(); 49 | await this.setMintBtnTimer(); 50 | }; 51 | 52 | setMintBtnTimer = () => { 53 | const mintBtn = document.getElementById("mintBtn"); 54 | if (mintBtn !== undefined && mintBtn !== null) { 55 | this.setState({ 56 | lastMintTime: localStorage.getItem(this.state.accountAddress), 57 | }); 58 | this.state.lastMintTime === undefined || this.state.lastMintTime === null 59 | ? (mintBtn.innerHTML = "Mint My Crypto Boy") 60 | : this.checkIfCanMint(parseInt(this.state.lastMintTime)); 61 | } 62 | }; 63 | 64 | checkIfCanMint = (lastMintTime) => { 65 | const mintBtn = document.getElementById("mintBtn"); 66 | const timeGap = 300000; //5min in milliseconds 67 | const countDownTime = lastMintTime + timeGap; 68 | const interval = setInterval(() => { 69 | const now = new Date().getTime(); 70 | const diff = countDownTime - now; 71 | if (diff < 0) { 72 | mintBtn.removeAttribute("disabled"); 73 | mintBtn.innerHTML = "Mint My Crypto Boy"; 74 | localStorage.removeItem(this.state.accountAddress); 75 | clearInterval(interval); 76 | } else { 77 | const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); 78 | const seconds = Math.floor((diff % (1000 * 60)) / 1000); 79 | mintBtn.setAttribute("disabled", true); 80 | mintBtn.innerHTML = `Next mint in ${minutes}m ${seconds}s`; 81 | } 82 | }, 1000); 83 | }; 84 | 85 | loadWeb3 = async () => { 86 | if (window.ethereum) { 87 | window.web3 = new Web3(window.ethereum); 88 | } else if (window.web3) { 89 | window.web3 = new Web3(window.web3.currentProvider); 90 | } else { 91 | window.alert( 92 | "Non-Ethereum browser detected. You should consider trying MetaMask!" 93 | ); 94 | } 95 | }; 96 | 97 | loadBlockchainData = async () => { 98 | const web3 = window.web3; 99 | const accounts = await web3.eth.getAccounts(); 100 | if (accounts.length === 0) { 101 | this.setState({ metamaskConnected: false }); 102 | } else { 103 | this.setState({ metamaskConnected: true }); 104 | this.setState({ loading: true }); 105 | this.setState({ accountAddress: accounts[0] }); 106 | let accountBalance = await web3.eth.getBalance(accounts[0]); 107 | accountBalance = web3.utils.fromWei(accountBalance, "Ether"); 108 | this.setState({ accountBalance }); 109 | this.setState({ loading: false }); 110 | const networkId = await web3.eth.net.getId(); 111 | const networkData = CryptoBoys.networks[networkId]; 112 | if (networkData) { 113 | this.setState({ loading: true }); 114 | const cryptoBoysContract = web3.eth.Contract( 115 | CryptoBoys.abi, 116 | networkData.address 117 | ); 118 | this.setState({ cryptoBoysContract }); 119 | this.setState({ contractDetected: true }); 120 | const cryptoBoysCount = await cryptoBoysContract.methods 121 | .cryptoBoyCounter() 122 | .call(); 123 | this.setState({ cryptoBoysCount }); 124 | for (var i = 1; i <= cryptoBoysCount; i++) { 125 | const cryptoBoy = await cryptoBoysContract.methods 126 | .allCryptoBoys(i) 127 | .call(); 128 | this.setState({ 129 | cryptoBoys: [...this.state.cryptoBoys, cryptoBoy], 130 | }); 131 | } 132 | let totalTokensMinted = await cryptoBoysContract.methods 133 | .getNumberOfTokensMinted() 134 | .call(); 135 | totalTokensMinted = totalTokensMinted.toNumber(); 136 | this.setState({ totalTokensMinted }); 137 | let totalTokensOwnedByAccount = await cryptoBoysContract.methods 138 | .getTotalNumberOfTokensOwnedByAnAddress(this.state.accountAddress) 139 | .call(); 140 | totalTokensOwnedByAccount = totalTokensOwnedByAccount.toNumber(); 141 | this.setState({ totalTokensOwnedByAccount }); 142 | this.setState({ loading: false }); 143 | } else { 144 | this.setState({ contractDetected: false }); 145 | } 146 | } 147 | }; 148 | 149 | connectToMetamask = async () => { 150 | await window.ethereum.enable(); 151 | this.setState({ metamaskConnected: true }); 152 | window.location.reload(); 153 | }; 154 | 155 | setMetaData = async () => { 156 | if (this.state.cryptoBoys.length !== 0) { 157 | this.state.cryptoBoys.map(async (cryptoboy) => { 158 | const result = await fetch(cryptoboy.tokenURI); 159 | const metaData = await result.json(); 160 | this.setState({ 161 | cryptoBoys: this.state.cryptoBoys.map((cryptoboy) => 162 | cryptoboy.tokenId.toNumber() === Number(metaData.tokenId) 163 | ? { 164 | ...cryptoboy, 165 | metaData, 166 | } 167 | : cryptoboy 168 | ), 169 | }); 170 | }); 171 | } 172 | }; 173 | 174 | mintMyNFT = async (colors, name, tokenPrice) => { 175 | this.setState({ loading: true }); 176 | const colorsArray = Object.values(colors); 177 | let colorsUsed = []; 178 | for (let i = 0; i < colorsArray.length; i++) { 179 | if (colorsArray[i] !== "") { 180 | let colorIsUsed = await this.state.cryptoBoysContract.methods 181 | .colorExists(colorsArray[i]) 182 | .call(); 183 | if (colorIsUsed) { 184 | colorsUsed = [...colorsUsed, colorsArray[i]]; 185 | } else { 186 | continue; 187 | } 188 | } 189 | } 190 | const nameIsUsed = await this.state.cryptoBoysContract.methods 191 | .tokenNameExists(name) 192 | .call(); 193 | if (colorsUsed.length === 0 && !nameIsUsed) { 194 | const { 195 | cardBorderColor, 196 | cardBackgroundColor, 197 | headBorderColor, 198 | headBackgroundColor, 199 | leftEyeBorderColor, 200 | rightEyeBorderColor, 201 | leftEyeBackgroundColor, 202 | rightEyeBackgroundColor, 203 | leftPupilBackgroundColor, 204 | rightPupilBackgroundColor, 205 | mouthColor, 206 | neckBackgroundColor, 207 | neckBorderColor, 208 | bodyBackgroundColor, 209 | bodyBorderColor, 210 | } = colors; 211 | let previousTokenId; 212 | previousTokenId = await this.state.cryptoBoysContract.methods 213 | .cryptoBoyCounter() 214 | .call(); 215 | previousTokenId = previousTokenId.toNumber(); 216 | const tokenId = previousTokenId + 1; 217 | const tokenObject = { 218 | tokenName: "Crypto Boy", 219 | tokenSymbol: "CB", 220 | tokenId: `${tokenId}`, 221 | name: name, 222 | metaData: { 223 | type: "color", 224 | colors: { 225 | cardBorderColor, 226 | cardBackgroundColor, 227 | headBorderColor, 228 | headBackgroundColor, 229 | leftEyeBorderColor, 230 | rightEyeBorderColor, 231 | leftEyeBackgroundColor, 232 | rightEyeBackgroundColor, 233 | leftPupilBackgroundColor, 234 | rightPupilBackgroundColor, 235 | mouthColor, 236 | neckBackgroundColor, 237 | neckBorderColor, 238 | bodyBackgroundColor, 239 | bodyBorderColor, 240 | }, 241 | }, 242 | }; 243 | const cid = await ipfs.add(JSON.stringify(tokenObject)); 244 | let tokenURI = `https://ipfs.infura.io/ipfs/${cid.path}`; 245 | const price = window.web3.utils.toWei(tokenPrice.toString(), "Ether"); 246 | this.state.cryptoBoysContract.methods 247 | .mintCryptoBoy(name, tokenURI, price, colorsArray) 248 | .send({ from: this.state.accountAddress }) 249 | .on("confirmation", () => { 250 | localStorage.setItem(this.state.accountAddress, new Date().getTime()); 251 | this.setState({ loading: false }); 252 | window.location.reload(); 253 | }); 254 | } else { 255 | if (nameIsUsed) { 256 | this.setState({ nameIsUsed: true }); 257 | this.setState({ loading: false }); 258 | } else if (colorsUsed.length !== 0) { 259 | this.setState({ colorIsUsed: true }); 260 | this.setState({ colorsUsed }); 261 | this.setState({ loading: false }); 262 | } 263 | } 264 | }; 265 | 266 | toggleForSale = (tokenId) => { 267 | this.setState({ loading: true }); 268 | this.state.cryptoBoysContract.methods 269 | .toggleForSale(tokenId) 270 | .send({ from: this.state.accountAddress }) 271 | .on("confirmation", () => { 272 | this.setState({ loading: false }); 273 | window.location.reload(); 274 | }); 275 | }; 276 | 277 | changeTokenPrice = (tokenId, newPrice) => { 278 | this.setState({ loading: true }); 279 | const newTokenPrice = window.web3.utils.toWei(newPrice, "Ether"); 280 | this.state.cryptoBoysContract.methods 281 | .changeTokenPrice(tokenId, newTokenPrice) 282 | .send({ from: this.state.accountAddress }) 283 | .on("confirmation", () => { 284 | this.setState({ loading: false }); 285 | window.location.reload(); 286 | }); 287 | }; 288 | 289 | buyCryptoBoy = (tokenId, price) => { 290 | this.setState({ loading: true }); 291 | this.state.cryptoBoysContract.methods 292 | .buyToken(tokenId) 293 | .send({ from: this.state.accountAddress, value: price }) 294 | .on("confirmation", () => { 295 | this.setState({ loading: false }); 296 | window.location.reload(); 297 | }); 298 | }; 299 | 300 | render() { 301 | return ( 302 |
303 | {!this.state.metamaskConnected ? ( 304 | 305 | ) : !this.state.contractDetected ? ( 306 | 307 | ) : this.state.loading ? ( 308 | 309 | ) : ( 310 | <> 311 | 312 | 313 | ( 317 | 321 | )} 322 | /> 323 | ( 326 | 333 | )} 334 | /> 335 | ( 338 | 346 | )} 347 | /> 348 | ( 351 | 358 | )} 359 | /> 360 | ( 363 | 364 | )} 365 | /> 366 | 367 | 368 | )} 369 |
370 | ); 371 | } 372 | } 373 | 374 | export default App; 375 | -------------------------------------------------------------------------------- /test/CryptoBoys.test.js: -------------------------------------------------------------------------------- 1 | const { assert } = require("chai"); 2 | 3 | const CryptoBoys = artifacts.require("./CryptoBoys.sol"); 4 | 5 | require("chai") 6 | .use(require("chai-as-promised")) 7 | .should(); 8 | 9 | contract("Crypto Boys", async (accounts) => { 10 | let cryptoBoys, result, cryptoBoyCount; 11 | 12 | before(async () => { 13 | cryptoBoys = await CryptoBoys.deployed(); 14 | }); 15 | 16 | describe("Deployment", async () => { 17 | it("contract has an address", async () => { 18 | const address = await cryptoBoys.address; 19 | assert.notEqual(address, 0x0); 20 | assert.notEqual(address, ""); 21 | assert.notEqual(address, null); 22 | assert.notEqual(address, undefined); 23 | }); 24 | 25 | it("has a name", async () => { 26 | const name = await cryptoBoys.collectionName(); 27 | assert.equal(name, "Crypto Boys Collection"); 28 | }); 29 | 30 | it("has a symbol", async () => { 31 | const symbol = await cryptoBoys.collectionNameSymbol(); 32 | assert.equal(symbol, "CB"); 33 | }); 34 | }); 35 | 36 | describe("application features", async () => { 37 | it("allows users to mint ERC721 token", async () => { 38 | cryptoBoyCount = await cryptoBoys.cryptoBoyCounter(); 39 | assert.equal(cryptoBoyCount.toNumber(), 0); 40 | 41 | let tokenExists; 42 | tokenExists = await cryptoBoys.getTokenExists(1, { from: accounts[0] }); 43 | assert.equal(tokenExists, false); 44 | 45 | let tokenURIExists; 46 | tokenURIExists = await cryptoBoys.tokenURIExists( 47 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPHRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 48 | { from: accounts[0] } 49 | ); 50 | assert.equal(tokenURIExists, false); 51 | 52 | let tokenNameExists; 53 | tokenNameExists = await cryptoBoys.tokenNameExists("myCBNFT", { 54 | from: accounts[0], 55 | }); 56 | assert.equal(tokenNameExists, false); 57 | 58 | let colorExists; 59 | const colorsArray1 = [ 60 | "#2a2b2e", 61 | "#5a5a66", 62 | "#a4c2a8", 63 | "#aceb98", 64 | "#87ff65", 65 | "#995d81", 66 | "#eb8258", 67 | "#f6f740", 68 | "#d8dc6a", 69 | "#6689a1", 70 | "#fe938c", 71 | "#e6b89c", 72 | "#ead2ac", 73 | "#9cafb7", 74 | "#4281a4", 75 | ]; 76 | for (let i = 0; i < colorsArray1.length; i++) { 77 | colorExists = await cryptoBoys.colorExists(colorsArray1[i], { 78 | from: accounts[0], 79 | }); 80 | assert.equal(colorExists, false); 81 | } 82 | 83 | result = await cryptoBoys.mintCryptoBoy( 84 | "myCBNFT", 85 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPHRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 86 | web3.utils.toWei("1", "Ether"), 87 | colorsArray1, 88 | { from: accounts[0] } 89 | ); 90 | 91 | cryptoBoyCount = await cryptoBoys.cryptoBoyCounter(); 92 | assert.equal(cryptoBoyCount.toNumber(), 1); 93 | 94 | tokenExists = await cryptoBoys.getTokenExists(1, { from: accounts[0] }); 95 | assert.equal(tokenExists, true); 96 | 97 | tokenURIExists = await cryptoBoys.tokenURIExists( 98 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPHRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 99 | { from: accounts[0] } 100 | ); 101 | assert.equal(tokenURIExists, true); 102 | 103 | tokenNameExists = await cryptoBoys.tokenNameExists("myCBNFT", { 104 | from: accounts[0], 105 | }); 106 | assert.equal(tokenNameExists, true); 107 | 108 | for (let i = 0; i < colorsArray1.length; i++) { 109 | colorExists = await cryptoBoys.colorExists(colorsArray1[i], { 110 | from: accounts[0], 111 | }); 112 | assert.equal(colorExists, true); 113 | } 114 | 115 | let cryptoboy; 116 | cryptoboy = await cryptoBoys.allCryptoBoys(1, { 117 | from: accounts[0], 118 | }); 119 | assert.equal(cryptoboy.tokenId.toNumber(), 1); 120 | assert.equal(cryptoboy.tokenName, "myCBNFT"); 121 | assert.equal( 122 | cryptoboy.tokenURI, 123 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPHRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2" 124 | ); 125 | assert.equal(cryptoboy.mintedBy, accounts[0]); 126 | assert.equal(cryptoboy.currentOwner, accounts[0]); 127 | assert.equal( 128 | cryptoboy.previousOwner, 129 | 0x0000000000000000000000000000000000000000 130 | ); 131 | assert.equal(web3.utils.fromWei(cryptoboy.price, "ether"), 1); 132 | assert.equal(cryptoboy.numberOfTransfers.toNumber(), 0); 133 | assert.equal(cryptoboy.forSale, true); 134 | 135 | const colorsArray2 = [ 136 | "#212b2e", 137 | "#515a66", 138 | "#a1c2a8", 139 | "#a1eb98", 140 | "#81ff65", 141 | "#915d81", 142 | "#e18258", 143 | "#f1f740", 144 | "#d1dc6a", 145 | "#6189a1", 146 | "#f1938c", 147 | "#e1b89c", 148 | "#e1d2ac", 149 | "#91afb7", 150 | "#4181a4", 151 | ]; 152 | 153 | await cryptoBoys.mintCryptoBoy( 154 | "myCBNFT2", 155 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPQRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 156 | web3.utils.toWei("1", "Ether"), 157 | colorsArray2, 158 | { from: accounts[1] } 159 | ); 160 | 161 | const colorsArray3 = [ 162 | "#232b2e", 163 | "#535a66", 164 | "#a3c2a8", 165 | "#a3eb98", 166 | "#83ff65", 167 | "#935d81", 168 | "#e38258", 169 | "#f3f740", 170 | "#d3dc6a", 171 | "#6389a1", 172 | "#f3938c", 173 | "#e3b89c", 174 | "#e3d2ac", 175 | "#93afb7", 176 | "#4381a4", 177 | ]; 178 | 179 | // same token uri -reject 180 | await cryptoBoys.mintCryptoBoy( 181 | "myCBNFT3", 182 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPQRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 183 | web3.utils.toWei("1", "Ether"), 184 | colorsArray3, 185 | { from: accounts[3] } 186 | ).should.be.rejected; 187 | 188 | const colorsArray4 = [ 189 | "#252b2e", 190 | "#555a66", 191 | "#a5c2a8", 192 | "#a5eb98", 193 | "#85ff65", 194 | "#955d81", 195 | "#e58258", 196 | "#f5f740", 197 | "#d5dc6a", 198 | "#6589a1", 199 | "#f5938c", 200 | "#e5b89c", 201 | "#e5d2ac", 202 | "#95afb7", 203 | "#4581a4", 204 | ]; 205 | 206 | // 0x0 adress sending txn - reject 207 | await cryptoBoys.mintCryptoBoy( 208 | "myCBNFT4", 209 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPQRYN14Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 210 | web3.utils.toWei("1", "Ether"), 211 | colorsArray4, 212 | { from: 0x0000000000000000000000000000000000000000 } 213 | ).should.be.rejected; 214 | 215 | const colorsArray5 = [ 216 | "#2d2b2e", 217 | "#5d5a66", 218 | "#adc2a8", 219 | "#adeb98", 220 | "#8dff65", 221 | "#9d5d81", 222 | "#ed8258", 223 | "#fdf740", 224 | "#dddc6a", 225 | "#6d89a1", 226 | "#fd938c", 227 | "#edb89c", 228 | "#edd2ac", 229 | "#9dafb7", 230 | "#4d81a4", 231 | ]; 232 | 233 | await cryptoBoys.mintCryptoBoy( 234 | "myCBNFT5", 235 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPRRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 236 | web3.utils.toWei("1", "Ether"), 237 | colorsArray5, 238 | { from: accounts[0] } 239 | ); 240 | 241 | const colorsArray6 = [ 242 | "#2f2b2e", 243 | "#5f5a66", 244 | "#afc2a8", 245 | "#afeb98", 246 | "#8fff65", 247 | "#9f5d81", 248 | "#ef8258", 249 | "#fff740", 250 | "#dfdc6a", 251 | "#6f89a1", 252 | "#ff938c", 253 | "#efb89c", 254 | "#efd2ac", 255 | "#9fafb7", 256 | "#4f81a4", 257 | ]; 258 | 259 | await cryptoBoys.mintCryptoBoy( 260 | "myCBNFT6", 261 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPSRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2", 262 | web3.utils.toWei("1", "Ether"), 263 | colorsArray6, 264 | { from: accounts[0] } 265 | ); 266 | 267 | const colorsArray7 = [ 268 | "#2a2b22", 269 | "#5a5a62", 270 | "#a4c2a2", 271 | "#aceb92", 272 | "#87ff62", 273 | "#995d82", 274 | "#eb8252", 275 | "#f6f742", 276 | "#d8dc62", 277 | "#6689a2", 278 | "#fe9382", 279 | "#e6b892", 280 | "#ead2a2", 281 | "#9cafb2", 282 | "#4281a2", 283 | ]; 284 | 285 | // same token name - reject 286 | await cryptoBoys.mintCryptoBoy( 287 | "myCBNFT6", 288 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPSRYN15Xdv4aLd3o4Aq63y1e4GgN6kj5aK/2", 289 | web3.utils.toWei("1", "Ether"), 290 | colorsArray7, 291 | { from: accounts[0] } 292 | ).should.be.rejected; 293 | 294 | const colorsArray8 = [ 295 | "#2a242e", 296 | "#5a5466", 297 | "#a4c4a8", 298 | "#ace498", 299 | "#87f465", 300 | "#995481", 301 | "#eb8458", 302 | "#f6f440", 303 | "#d8d46a", 304 | "#6684a1", 305 | "#fe948c", 306 | "#e6b49c", 307 | "#f6f740", 308 | "#9ca4b7", 309 | "#4284a4", 310 | ]; 311 | 312 | // same color/colors - reject (13th value of array8 is same as 8th value of array1) 313 | await cryptoBoys.mintCryptoBoy( 314 | "myCBNFT8", 315 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPSRYN15Xdv4aLd3o4Bq46y1f4GgN6kj5aK/2", 316 | web3.utils.toWei("1", "Ether"), 317 | colorsArray8, 318 | { from: accounts[0] } 319 | ).should.be.rejected; 320 | }); 321 | 322 | it("returns address of the token's owner", async () => { 323 | const tokenOwner = await cryptoBoys.getTokenOwner(2); 324 | assert.equal(tokenOwner, accounts[1]); 325 | }); 326 | 327 | // returns tokenURI of the token 328 | it("returns metadata of a token", async () => { 329 | const tokenMetaData = await cryptoBoys.getTokenMetaData(2); 330 | assert.equal( 331 | tokenMetaData, 332 | "https://gateway.pinata.cloud/ipfs/QmYFmJgQGH4uPQRYN15Xdv4aLd9o4Aq63y1e4GgN6kj5aK/2" 333 | ); 334 | }); 335 | 336 | it("returns total number of tokens minted so far", async () => { 337 | const totalNumberOfTokensMinted = await cryptoBoys.getNumberOfTokensMinted(); 338 | assert.equal(totalNumberOfTokensMinted.toNumber(), 4); 339 | }); 340 | 341 | it("returns total number of tokens owned by an address", async () => { 342 | const totalNumberOfTokensOwnedByAnAddress = await cryptoBoys.getTotalNumberOfTokensOwnedByAnAddress( 343 | accounts[0] 344 | ); 345 | assert.equal(totalNumberOfTokensOwnedByAnAddress.toNumber(), 3); 346 | }); 347 | 348 | it("allows users to buy token for specified ethers", async () => { 349 | const oldTokenOwner = await cryptoBoys.getTokenOwner(1); 350 | assert.equal(oldTokenOwner, accounts[0]); 351 | 352 | let oldTokenOwnerBalance; 353 | oldTokenOwnerBalance = await web3.eth.getBalance(accounts[0]); 354 | oldTokenOwnerBalance = new web3.utils.BN(oldTokenOwnerBalance); 355 | 356 | let oldTotalNumberOfTokensOwnedBySeller; 357 | oldTotalNumberOfTokensOwnedBySeller = await cryptoBoys.getTotalNumberOfTokensOwnedByAnAddress( 358 | accounts[0] 359 | ); 360 | assert.equal(oldTotalNumberOfTokensOwnedBySeller.toNumber(), 3); 361 | 362 | let cryptoBoy; 363 | cryptoBoy = await cryptoBoys.allCryptoBoys(1, { 364 | from: accounts[0], 365 | }); 366 | assert.equal(cryptoBoy.numberOfTransfers.toNumber(), 0); 367 | 368 | result = await cryptoBoys.buyToken(1, { 369 | from: accounts[2], 370 | value: web3.utils.toWei("1", "Ether"), 371 | }); 372 | 373 | const newTokenOwner = await cryptoBoys.getTokenOwner(1); 374 | assert.equal(newTokenOwner, accounts[2]); 375 | 376 | let newTokenOwnerBalance; 377 | newTokenOwnerBalance = await web3.eth.getBalance(accounts[0]); 378 | newTokenOwnerBalance = new web3.utils.BN(newTokenOwnerBalance); 379 | 380 | let newTotalNumberOfTokensOwnedBySeller; 381 | newTotalNumberOfTokensOwnedBySeller = await cryptoBoys.getTotalNumberOfTokensOwnedByAnAddress( 382 | accounts[0] 383 | ); 384 | assert.equal(newTotalNumberOfTokensOwnedBySeller.toNumber(), 2); 385 | 386 | cryptoBoy = await cryptoBoys.allCryptoBoys(1, { 387 | from: accounts[0], 388 | }); 389 | assert.equal(cryptoBoy.numberOfTransfers.toNumber(), 1); 390 | 391 | let price; 392 | price = web3.utils.toWei("1", "Ether"); 393 | price = new web3.utils.BN(price); 394 | 395 | const exepectedBalance = oldTokenOwnerBalance.add(price); 396 | assert.equal( 397 | newTokenOwnerBalance.toString(), 398 | exepectedBalance.toString() 399 | ); 400 | 401 | cryptoBoy = await cryptoBoys.allCryptoBoys(1, { 402 | from: accounts[0], 403 | }); 404 | assert.equal(cryptoBoy.currentOwner, accounts[2]); 405 | 406 | await cryptoBoys.buyToken(2, { 407 | from: 0x0000000000000000000000000000000000000000, 408 | value: web3.utils.toWei("1", "Ether"), 409 | }).should.be.rejected; 410 | 411 | await cryptoBoys.buyToken(56, { 412 | from: accounts[4], 413 | value: web3.utils.toWei("1", "Ether"), 414 | }).should.be.rejected; 415 | 416 | await cryptoBoys.buyToken(3, { 417 | from: accounts[0], 418 | value: web3.utils.toWei("1", "Ether"), 419 | }).should.be.rejected; 420 | }); 421 | 422 | it("allows users to change token price", async () => { 423 | let cryptoBoyPrice; 424 | cryptoBoyPrice = await cryptoBoys.allCryptoBoys(1, { 425 | from: accounts[0], 426 | }); 427 | assert.equal(web3.utils.fromWei(cryptoBoyPrice.price, "ether"), 1); 428 | 429 | result = await cryptoBoys.changeTokenPrice( 430 | 1, 431 | web3.utils.toWei("2", "Ether"), 432 | { 433 | from: accounts[2], 434 | } 435 | ); 436 | 437 | cryptoBoyPrice = await cryptoBoys.allCryptoBoys(1, { 438 | from: accounts[0], 439 | }); 440 | assert.equal(web3.utils.fromWei(cryptoBoyPrice.price, "ether"), 2); 441 | 442 | await cryptoBoys.changeTokenPrice(1, web3.utils.toWei("3", "Ether"), { 443 | from: 0x0000000000000000000000000000000000000000, 444 | }).should.be.rejected; 445 | 446 | await cryptoBoys.changeTokenPrice(82, web3.utils.toWei("3", "Ether"), { 447 | from: accounts[2], 448 | }).should.be.rejected; 449 | 450 | await cryptoBoys.changeTokenPrice(1, web3.utils.toWei("3", "Ether"), { 451 | from: accounts[6], 452 | }).should.be.rejected; 453 | }); 454 | 455 | it("allows users to toggle between setting the token for sale or not for sale", async () => { 456 | let cryptoboy; 457 | cryptoboy = await cryptoBoys.allCryptoBoys(1, { 458 | from: accounts[0], 459 | }); 460 | assert.equal(cryptoboy.forSale, true); 461 | 462 | result = await cryptoBoys.toggleForSale(1, { from: accounts[2] }); 463 | 464 | cryptoboy = await cryptoBoys.allCryptoBoys(1, { 465 | from: accounts[0], 466 | }); 467 | assert.equal(cryptoboy.forSale, false); 468 | 469 | result = await cryptoBoys.toggleForSale(1, { from: accounts[2] }); 470 | 471 | cryptoboy = await cryptoBoys.allCryptoBoys(1, { 472 | from: accounts[0], 473 | }); 474 | assert.equal(cryptoboy.forSale, true); 475 | 476 | await cryptoBoys.toggleForSale(1, { 477 | from: 0x0000000000000000000000000000000000000000, 478 | }).should.be.rejected; 479 | 480 | await cryptoBoys.toggleForSale(94, { from: accounts[2] }).should.be 481 | .rejected; 482 | 483 | await cryptoBoys.toggleForSale(1, { from: accounts[8] }).should.be 484 | .rejected; 485 | }); 486 | }); 487 | }); 488 | -------------------------------------------------------------------------------- /src/components/FormAndPreview/FormAndPreview.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import CryptoBoyNFTImage from "../CryptoBoyNFTImage/CryptoBoyNFTImage"; 3 | 4 | class FormAndPreview extends Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | userSelectedColors: [ 9 | { 10 | cardBorderColor: "", 11 | cardBackgroundColor: "", 12 | headBorderColor: "", 13 | headBackgroundColor: "", 14 | leftEyeBorderColor: "", 15 | rightEyeBorderColor: "", 16 | leftEyeBackgroundColor: "", 17 | rightEyeBackgroundColor: "", 18 | leftPupilBackgroundColor: "", 19 | rightPupilBackgroundColor: "", 20 | mouthColor: "", 21 | neckBackgroundColor: "", 22 | neckBorderColor: "", 23 | bodyBackgroundColor: "", 24 | bodyBorderColor: "", 25 | }, 26 | ], 27 | cryptoBoyName: "", 28 | cryptoBoyPrice: "", 29 | }; 30 | } 31 | 32 | componentDidMount = async () => { 33 | await this.props.setMintBtnTimer(); 34 | }; 35 | 36 | callMintMyNFTFromApp = (e) => { 37 | e.preventDefault(); 38 | this.props.mintMyNFT( 39 | this.state.userSelectedColors[0], 40 | this.state.cryptoBoyName, 41 | this.state.cryptoBoyPrice 42 | ); 43 | }; 44 | 45 | render() { 46 | return ( 47 |
48 |
49 |
50 |
Color Your Crypto Boy As You Want It To be!
51 |
52 |
53 |
54 |
55 |
56 |
57 | 58 | 66 | this.setState({ 67 | userSelectedColors: [ 68 | { 69 | ...this.state.userSelectedColors[0], 70 | cardBorderColor: e.target.value, 71 | }, 72 | ], 73 | }) 74 | } 75 | /> 76 |
77 |
78 | 81 | 89 | this.setState({ 90 | userSelectedColors: [ 91 | { 92 | ...this.state.userSelectedColors[0], 93 | cardBackgroundColor: e.target.value, 94 | }, 95 | ], 96 | }) 97 | } 98 | /> 99 |
100 |
101 | 102 | 110 | this.setState({ 111 | userSelectedColors: [ 112 | { 113 | ...this.state.userSelectedColors[0], 114 | headBorderColor: e.target.value, 115 | }, 116 | ], 117 | }) 118 | } 119 | /> 120 |
121 |
122 | 125 | 133 | this.setState({ 134 | userSelectedColors: [ 135 | { 136 | ...this.state.userSelectedColors[0], 137 | headBackgroundColor: e.target.value, 138 | }, 139 | ], 140 | }) 141 | } 142 | /> 143 |
144 |
145 |
146 |
147 | 150 | 158 | this.setState({ 159 | userSelectedColors: [ 160 | { 161 | ...this.state.userSelectedColors[0], 162 | leftEyeBorderColor: e.target.value, 163 | }, 164 | ], 165 | }) 166 | } 167 | /> 168 |
169 |
170 | 173 | 181 | this.setState({ 182 | userSelectedColors: [ 183 | { 184 | ...this.state.userSelectedColors[0], 185 | rightEyeBorderColor: e.target.value, 186 | }, 187 | ], 188 | }) 189 | } 190 | /> 191 |
192 |
193 | 196 | 206 | this.setState({ 207 | userSelectedColors: [ 208 | { 209 | ...this.state.userSelectedColors[0], 210 | leftEyeBackgroundColor: e.target.value, 211 | }, 212 | ], 213 | }) 214 | } 215 | /> 216 |
217 |
218 | 221 | 231 | this.setState({ 232 | userSelectedColors: [ 233 | { 234 | ...this.state.userSelectedColors[0], 235 | rightEyeBackgroundColor: e.target.value, 236 | }, 237 | ], 238 | }) 239 | } 240 | /> 241 |
242 |
243 |
244 | 245 |
246 |
247 |
248 |
249 |
250 | 253 | 263 | this.setState({ 264 | userSelectedColors: [ 265 | { 266 | ...this.state.userSelectedColors[0], 267 | leftPupilBackgroundColor: e.target.value, 268 | }, 269 | ], 270 | }) 271 | } 272 | /> 273 |
274 |
275 | 278 | 288 | this.setState({ 289 | userSelectedColors: [ 290 | { 291 | ...this.state.userSelectedColors[0], 292 | rightPupilBackgroundColor: e.target.value, 293 | }, 294 | ], 295 | }) 296 | } 297 | /> 298 |
299 |
300 | 301 | 309 | this.setState({ 310 | userSelectedColors: [ 311 | { 312 | ...this.state.userSelectedColors[0], 313 | mouthColor: e.target.value, 314 | }, 315 | ], 316 | }) 317 | } 318 | /> 319 |
320 |
321 | 324 | 332 | this.setState({ 333 | userSelectedColors: [ 334 | { 335 | ...this.state.userSelectedColors[0], 336 | neckBackgroundColor: e.target.value, 337 | }, 338 | ], 339 | }) 340 | } 341 | /> 342 |
343 |
344 |
345 |
346 | 347 | 355 | this.setState({ 356 | userSelectedColors: [ 357 | { 358 | ...this.state.userSelectedColors[0], 359 | neckBorderColor: e.target.value, 360 | }, 361 | ], 362 | }) 363 | } 364 | /> 365 |
366 |
367 | 370 | 378 | this.setState({ 379 | userSelectedColors: [ 380 | { 381 | ...this.state.userSelectedColors[0], 382 | bodyBackgroundColor: e.target.value, 383 | }, 384 | ], 385 | }) 386 | } 387 | /> 388 |
389 |
390 | 391 | 399 | this.setState({ 400 | userSelectedColors: [ 401 | { 402 | ...this.state.userSelectedColors[0], 403 | bodyBorderColor: e.target.value, 404 | }, 405 | ], 406 | }) 407 | } 408 | /> 409 |
410 |
411 |
412 |
413 | 414 | 421 | this.setState({ cryptoBoyName: e.target.value }) 422 | } 423 | /> 424 |
425 |
426 | 427 | 436 | this.setState({ cryptoBoyPrice: e.target.value }) 437 | } 438 | /> 439 |
440 | 448 |
449 | {this.props.nameIsUsed ? ( 450 |
451 | 458 | This name is taken! 459 |
460 | ) : this.props.colorIsUsed ? ( 461 | <> 462 |
463 | 470 | {this.props.colorsUsed.length > 1 ? ( 471 | These colors are taken! 472 | ) : ( 473 | This color is taken! 474 | )} 475 |
476 |
484 | {this.props.colorsUsed.map((color, index) => ( 485 |
493 | ))} 494 |
495 | 496 | ) : null} 497 |
498 |
499 |
500 |
501 |
502 | ); 503 | } 504 | } 505 | 506 | export default FormAndPreview; 507 | -------------------------------------------------------------------------------- /src/abis/Migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "Migrations", 3 | "abi": [ 4 | { 5 | "inputs": [], 6 | "stateMutability": "nonpayable", 7 | "type": "constructor" 8 | }, 9 | { 10 | "inputs": [], 11 | "name": "last_completed_migration", 12 | "outputs": [ 13 | { 14 | "internalType": "uint256", 15 | "name": "", 16 | "type": "uint256" 17 | } 18 | ], 19 | "stateMutability": "view", 20 | "type": "function", 21 | "constant": true 22 | }, 23 | { 24 | "inputs": [], 25 | "name": "owner", 26 | "outputs": [ 27 | { 28 | "internalType": "address", 29 | "name": "", 30 | "type": "address" 31 | } 32 | ], 33 | "stateMutability": "view", 34 | "type": "function", 35 | "constant": true 36 | }, 37 | { 38 | "inputs": [ 39 | { 40 | "internalType": "uint256", 41 | "name": "completed", 42 | "type": "uint256" 43 | } 44 | ], 45 | "name": "setCompleted", 46 | "outputs": [], 47 | "stateMutability": "nonpayable", 48 | "type": "function" 49 | }, 50 | { 51 | "inputs": [ 52 | { 53 | "internalType": "address", 54 | "name": "new_address", 55 | "type": "address" 56 | } 57 | ], 58 | "name": "upgrade", 59 | "outputs": [], 60 | "stateMutability": "nonpayable", 61 | "type": "function" 62 | } 63 | ], 64 | "metadata": "{\"compiler\":{\"version\":\"0.7.6+commit.7338295f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"last_completed_migration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"completed\",\"type\":\"uint256\"}],\"name\":\"setCompleted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"new_address\",\"type\":\"address\"}],\"name\":\"upgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"/home/pavansoratur/Github/cryptoboys-NFT-marketplace/src/contracts/Migrations.sol\":\"Migrations\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"/home/pavansoratur/Github/cryptoboys-NFT-marketplace/src/contracts/Migrations.sol\":{\"keccak256\":\"0x12e875f75583a6d74b23acfbb440c0cb8c4161eb4b6e401b5a047a8241cc5365\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://549b5653fb3ba12444dec07d5728b35f2b229faa8f8c524c403492dcc6847da6\",\"dweb:/ipfs/QmYqExk3AbYPmBAaMS6wFhV9jgLdWWQydhy9v3Sfcv5ynN\"]}},\"version\":1}", 65 | "bytecode": "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061029f806100606000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80630900f01014610051578063445df0ac146100955780638da5cb5b146100b3578063fdacd576146100e7575b600080fd5b6100936004803603602081101561006757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610115565b005b61009d6101e0565b6040518082815260200191505060405180910390f35b6100bb6101e6565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610113600480360360208110156100fd57600080fd5b810190808035906020019092919050505061020a565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156101dd5760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156101c357600080fd5b505af11580156101d7573d6000803e3d6000fd5b50505050505b50565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026657806001819055505b5056fea26469706673582212206e5d0441122dbe0dff89068ada8bd4dc77aff4a709b45219e239268a9bfa623b64736f6c63430007060033", 66 | "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80630900f01014610051578063445df0ac146100955780638da5cb5b146100b3578063fdacd576146100e7575b600080fd5b6100936004803603602081101561006757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610115565b005b61009d6101e0565b6040518082815260200191505060405180910390f35b6100bb6101e6565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610113600480360360208110156100fd57600080fd5b810190808035906020019092919050505061020a565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156101dd5760008190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156101c357600080fd5b505af11580156101d7573d6000803e3d6000fd5b50505050505b50565b60015481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026657806001819055505b5056fea26469706673582212206e5d0441122dbe0dff89068ada8bd4dc77aff4a709b45219e239268a9bfa623b64736f6c63430007060033", 67 | "immutableReferences": {}, 68 | "generatedSources": [], 69 | "deployedGeneratedSources": [], 70 | "sourceMap": "66:473:2:-:0;;;155:43;;;;;;;;;;183:10;175:5;;:18;;;;;;;;;;;;;;;;;;66:473;;;;;;", 71 | "deployedSourceMap": "66:473:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;372:165;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;114:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;90:20;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;265:103;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;372:165;248:5;;;;;;;;;;234:19;;:10;:19;;;230:26;;;434:19:::1;467:11;434:45;;485:8;:21;;;507:24;;485:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;255:1;230:26:::0;372:165;:::o;114:36::-;;;;:::o;90:20::-;;;;;;;;;;;;:::o;265:103::-;248:5;;;;;;;;;;234:19;;:10;:19;;;230:26;;;354:9:::1;327:24;:36;;;;230:26:::0;265:103;:::o", 72 | "source": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.21 <0.8.0;\n\ncontract Migrations {\n address public owner;\n uint public last_completed_migration;\n\n constructor() {\n owner = msg.sender;\n }\n\n modifier restricted() {\n if (msg.sender == owner) _;\n }\n\n function setCompleted(uint completed) public restricted {\n last_completed_migration = completed;\n }\n\n function upgrade(address new_address) public restricted {\n Migrations upgraded = Migrations(new_address);\n upgraded.setCompleted(last_completed_migration);\n }\n}\n", 73 | "sourcePath": "/home/pavansoratur/Github/cryptoboys-NFT-marketplace/src/contracts/Migrations.sol", 74 | "ast": { 75 | "absolutePath": "/home/pavansoratur/Github/cryptoboys-NFT-marketplace/src/contracts/Migrations.sol", 76 | "exportedSymbols": { 77 | "Migrations": [ 78 | 3555 79 | ] 80 | }, 81 | "id": 3556, 82 | "license": "MIT", 83 | "nodeType": "SourceUnit", 84 | "nodes": [ 85 | { 86 | "id": 3500, 87 | "literals": [ 88 | "solidity", 89 | ">=", 90 | "0.4", 91 | ".21", 92 | "<", 93 | "0.8", 94 | ".0" 95 | ], 96 | "nodeType": "PragmaDirective", 97 | "src": "32:32:2" 98 | }, 99 | { 100 | "abstract": false, 101 | "baseContracts": [], 102 | "contractDependencies": [], 103 | "contractKind": "contract", 104 | "fullyImplemented": true, 105 | "id": 3555, 106 | "linearizedBaseContracts": [ 107 | 3555 108 | ], 109 | "name": "Migrations", 110 | "nodeType": "ContractDefinition", 111 | "nodes": [ 112 | { 113 | "constant": false, 114 | "functionSelector": "8da5cb5b", 115 | "id": 3502, 116 | "mutability": "mutable", 117 | "name": "owner", 118 | "nodeType": "VariableDeclaration", 119 | "scope": 3555, 120 | "src": "90:20:2", 121 | "stateVariable": true, 122 | "storageLocation": "default", 123 | "typeDescriptions": { 124 | "typeIdentifier": "t_address", 125 | "typeString": "address" 126 | }, 127 | "typeName": { 128 | "id": 3501, 129 | "name": "address", 130 | "nodeType": "ElementaryTypeName", 131 | "src": "90:7:2", 132 | "stateMutability": "nonpayable", 133 | "typeDescriptions": { 134 | "typeIdentifier": "t_address", 135 | "typeString": "address" 136 | } 137 | }, 138 | "visibility": "public" 139 | }, 140 | { 141 | "constant": false, 142 | "functionSelector": "445df0ac", 143 | "id": 3504, 144 | "mutability": "mutable", 145 | "name": "last_completed_migration", 146 | "nodeType": "VariableDeclaration", 147 | "scope": 3555, 148 | "src": "114:36:2", 149 | "stateVariable": true, 150 | "storageLocation": "default", 151 | "typeDescriptions": { 152 | "typeIdentifier": "t_uint256", 153 | "typeString": "uint256" 154 | }, 155 | "typeName": { 156 | "id": 3503, 157 | "name": "uint", 158 | "nodeType": "ElementaryTypeName", 159 | "src": "114:4:2", 160 | "typeDescriptions": { 161 | "typeIdentifier": "t_uint256", 162 | "typeString": "uint256" 163 | } 164 | }, 165 | "visibility": "public" 166 | }, 167 | { 168 | "body": { 169 | "id": 3512, 170 | "nodeType": "Block", 171 | "src": "169:29:2", 172 | "statements": [ 173 | { 174 | "expression": { 175 | "id": 3510, 176 | "isConstant": false, 177 | "isLValue": false, 178 | "isPure": false, 179 | "lValueRequested": false, 180 | "leftHandSide": { 181 | "id": 3507, 182 | "name": "owner", 183 | "nodeType": "Identifier", 184 | "overloadedDeclarations": [], 185 | "referencedDeclaration": 3502, 186 | "src": "175:5:2", 187 | "typeDescriptions": { 188 | "typeIdentifier": "t_address", 189 | "typeString": "address" 190 | } 191 | }, 192 | "nodeType": "Assignment", 193 | "operator": "=", 194 | "rightHandSide": { 195 | "expression": { 196 | "id": 3508, 197 | "name": "msg", 198 | "nodeType": "Identifier", 199 | "overloadedDeclarations": [], 200 | "referencedDeclaration": 4294967281, 201 | "src": "183:3:2", 202 | "typeDescriptions": { 203 | "typeIdentifier": "t_magic_message", 204 | "typeString": "msg" 205 | } 206 | }, 207 | "id": 3509, 208 | "isConstant": false, 209 | "isLValue": false, 210 | "isPure": false, 211 | "lValueRequested": false, 212 | "memberName": "sender", 213 | "nodeType": "MemberAccess", 214 | "src": "183:10:2", 215 | "typeDescriptions": { 216 | "typeIdentifier": "t_address_payable", 217 | "typeString": "address payable" 218 | } 219 | }, 220 | "src": "175:18:2", 221 | "typeDescriptions": { 222 | "typeIdentifier": "t_address", 223 | "typeString": "address" 224 | } 225 | }, 226 | "id": 3511, 227 | "nodeType": "ExpressionStatement", 228 | "src": "175:18:2" 229 | } 230 | ] 231 | }, 232 | "id": 3513, 233 | "implemented": true, 234 | "kind": "constructor", 235 | "modifiers": [], 236 | "name": "", 237 | "nodeType": "FunctionDefinition", 238 | "parameters": { 239 | "id": 3505, 240 | "nodeType": "ParameterList", 241 | "parameters": [], 242 | "src": "166:2:2" 243 | }, 244 | "returnParameters": { 245 | "id": 3506, 246 | "nodeType": "ParameterList", 247 | "parameters": [], 248 | "src": "169:0:2" 249 | }, 250 | "scope": 3555, 251 | "src": "155:43:2", 252 | "stateMutability": "nonpayable", 253 | "virtual": false, 254 | "visibility": "public" 255 | }, 256 | { 257 | "body": { 258 | "id": 3521, 259 | "nodeType": "Block", 260 | "src": "224:37:2", 261 | "statements": [ 262 | { 263 | "condition": { 264 | "commonType": { 265 | "typeIdentifier": "t_address", 266 | "typeString": "address" 267 | }, 268 | "id": 3518, 269 | "isConstant": false, 270 | "isLValue": false, 271 | "isPure": false, 272 | "lValueRequested": false, 273 | "leftExpression": { 274 | "expression": { 275 | "id": 3515, 276 | "name": "msg", 277 | "nodeType": "Identifier", 278 | "overloadedDeclarations": [], 279 | "referencedDeclaration": 4294967281, 280 | "src": "234:3:2", 281 | "typeDescriptions": { 282 | "typeIdentifier": "t_magic_message", 283 | "typeString": "msg" 284 | } 285 | }, 286 | "id": 3516, 287 | "isConstant": false, 288 | "isLValue": false, 289 | "isPure": false, 290 | "lValueRequested": false, 291 | "memberName": "sender", 292 | "nodeType": "MemberAccess", 293 | "src": "234:10:2", 294 | "typeDescriptions": { 295 | "typeIdentifier": "t_address_payable", 296 | "typeString": "address payable" 297 | } 298 | }, 299 | "nodeType": "BinaryOperation", 300 | "operator": "==", 301 | "rightExpression": { 302 | "id": 3517, 303 | "name": "owner", 304 | "nodeType": "Identifier", 305 | "overloadedDeclarations": [], 306 | "referencedDeclaration": 3502, 307 | "src": "248:5:2", 308 | "typeDescriptions": { 309 | "typeIdentifier": "t_address", 310 | "typeString": "address" 311 | } 312 | }, 313 | "src": "234:19:2", 314 | "typeDescriptions": { 315 | "typeIdentifier": "t_bool", 316 | "typeString": "bool" 317 | } 318 | }, 319 | "id": 3520, 320 | "nodeType": "IfStatement", 321 | "src": "230:26:2", 322 | "trueBody": { 323 | "id": 3519, 324 | "nodeType": "PlaceholderStatement", 325 | "src": "255:1:2" 326 | } 327 | } 328 | ] 329 | }, 330 | "id": 3522, 331 | "name": "restricted", 332 | "nodeType": "ModifierDefinition", 333 | "parameters": { 334 | "id": 3514, 335 | "nodeType": "ParameterList", 336 | "parameters": [], 337 | "src": "221:2:2" 338 | }, 339 | "src": "202:59:2", 340 | "virtual": false, 341 | "visibility": "internal" 342 | }, 343 | { 344 | "body": { 345 | "id": 3533, 346 | "nodeType": "Block", 347 | "src": "321:47:2", 348 | "statements": [ 349 | { 350 | "expression": { 351 | "id": 3531, 352 | "isConstant": false, 353 | "isLValue": false, 354 | "isPure": false, 355 | "lValueRequested": false, 356 | "leftHandSide": { 357 | "id": 3529, 358 | "name": "last_completed_migration", 359 | "nodeType": "Identifier", 360 | "overloadedDeclarations": [], 361 | "referencedDeclaration": 3504, 362 | "src": "327:24:2", 363 | "typeDescriptions": { 364 | "typeIdentifier": "t_uint256", 365 | "typeString": "uint256" 366 | } 367 | }, 368 | "nodeType": "Assignment", 369 | "operator": "=", 370 | "rightHandSide": { 371 | "id": 3530, 372 | "name": "completed", 373 | "nodeType": "Identifier", 374 | "overloadedDeclarations": [], 375 | "referencedDeclaration": 3524, 376 | "src": "354:9:2", 377 | "typeDescriptions": { 378 | "typeIdentifier": "t_uint256", 379 | "typeString": "uint256" 380 | } 381 | }, 382 | "src": "327:36:2", 383 | "typeDescriptions": { 384 | "typeIdentifier": "t_uint256", 385 | "typeString": "uint256" 386 | } 387 | }, 388 | "id": 3532, 389 | "nodeType": "ExpressionStatement", 390 | "src": "327:36:2" 391 | } 392 | ] 393 | }, 394 | "functionSelector": "fdacd576", 395 | "id": 3534, 396 | "implemented": true, 397 | "kind": "function", 398 | "modifiers": [ 399 | { 400 | "id": 3527, 401 | "modifierName": { 402 | "id": 3526, 403 | "name": "restricted", 404 | "nodeType": "Identifier", 405 | "overloadedDeclarations": [], 406 | "referencedDeclaration": 3522, 407 | "src": "310:10:2", 408 | "typeDescriptions": { 409 | "typeIdentifier": "t_modifier$__$", 410 | "typeString": "modifier ()" 411 | } 412 | }, 413 | "nodeType": "ModifierInvocation", 414 | "src": "310:10:2" 415 | } 416 | ], 417 | "name": "setCompleted", 418 | "nodeType": "FunctionDefinition", 419 | "parameters": { 420 | "id": 3525, 421 | "nodeType": "ParameterList", 422 | "parameters": [ 423 | { 424 | "constant": false, 425 | "id": 3524, 426 | "mutability": "mutable", 427 | "name": "completed", 428 | "nodeType": "VariableDeclaration", 429 | "scope": 3534, 430 | "src": "287:14:2", 431 | "stateVariable": false, 432 | "storageLocation": "default", 433 | "typeDescriptions": { 434 | "typeIdentifier": "t_uint256", 435 | "typeString": "uint256" 436 | }, 437 | "typeName": { 438 | "id": 3523, 439 | "name": "uint", 440 | "nodeType": "ElementaryTypeName", 441 | "src": "287:4:2", 442 | "typeDescriptions": { 443 | "typeIdentifier": "t_uint256", 444 | "typeString": "uint256" 445 | } 446 | }, 447 | "visibility": "internal" 448 | } 449 | ], 450 | "src": "286:16:2" 451 | }, 452 | "returnParameters": { 453 | "id": 3528, 454 | "nodeType": "ParameterList", 455 | "parameters": [], 456 | "src": "321:0:2" 457 | }, 458 | "scope": 3555, 459 | "src": "265:103:2", 460 | "stateMutability": "nonpayable", 461 | "virtual": false, 462 | "visibility": "public" 463 | }, 464 | { 465 | "body": { 466 | "id": 3553, 467 | "nodeType": "Block", 468 | "src": "428:109:2", 469 | "statements": [ 470 | { 471 | "assignments": [ 472 | 3542 473 | ], 474 | "declarations": [ 475 | { 476 | "constant": false, 477 | "id": 3542, 478 | "mutability": "mutable", 479 | "name": "upgraded", 480 | "nodeType": "VariableDeclaration", 481 | "scope": 3553, 482 | "src": "434:19:2", 483 | "stateVariable": false, 484 | "storageLocation": "default", 485 | "typeDescriptions": { 486 | "typeIdentifier": "t_contract$_Migrations_$3555", 487 | "typeString": "contract Migrations" 488 | }, 489 | "typeName": { 490 | "id": 3541, 491 | "name": "Migrations", 492 | "nodeType": "UserDefinedTypeName", 493 | "referencedDeclaration": 3555, 494 | "src": "434:10:2", 495 | "typeDescriptions": { 496 | "typeIdentifier": "t_contract$_Migrations_$3555", 497 | "typeString": "contract Migrations" 498 | } 499 | }, 500 | "visibility": "internal" 501 | } 502 | ], 503 | "id": 3546, 504 | "initialValue": { 505 | "arguments": [ 506 | { 507 | "id": 3544, 508 | "name": "new_address", 509 | "nodeType": "Identifier", 510 | "overloadedDeclarations": [], 511 | "referencedDeclaration": 3536, 512 | "src": "467:11:2", 513 | "typeDescriptions": { 514 | "typeIdentifier": "t_address", 515 | "typeString": "address" 516 | } 517 | } 518 | ], 519 | "expression": { 520 | "argumentTypes": [ 521 | { 522 | "typeIdentifier": "t_address", 523 | "typeString": "address" 524 | } 525 | ], 526 | "id": 3543, 527 | "name": "Migrations", 528 | "nodeType": "Identifier", 529 | "overloadedDeclarations": [], 530 | "referencedDeclaration": 3555, 531 | "src": "456:10:2", 532 | "typeDescriptions": { 533 | "typeIdentifier": "t_type$_t_contract$_Migrations_$3555_$", 534 | "typeString": "type(contract Migrations)" 535 | } 536 | }, 537 | "id": 3545, 538 | "isConstant": false, 539 | "isLValue": false, 540 | "isPure": false, 541 | "kind": "typeConversion", 542 | "lValueRequested": false, 543 | "names": [], 544 | "nodeType": "FunctionCall", 545 | "src": "456:23:2", 546 | "tryCall": false, 547 | "typeDescriptions": { 548 | "typeIdentifier": "t_contract$_Migrations_$3555", 549 | "typeString": "contract Migrations" 550 | } 551 | }, 552 | "nodeType": "VariableDeclarationStatement", 553 | "src": "434:45:2" 554 | }, 555 | { 556 | "expression": { 557 | "arguments": [ 558 | { 559 | "id": 3550, 560 | "name": "last_completed_migration", 561 | "nodeType": "Identifier", 562 | "overloadedDeclarations": [], 563 | "referencedDeclaration": 3504, 564 | "src": "507:24:2", 565 | "typeDescriptions": { 566 | "typeIdentifier": "t_uint256", 567 | "typeString": "uint256" 568 | } 569 | } 570 | ], 571 | "expression": { 572 | "argumentTypes": [ 573 | { 574 | "typeIdentifier": "t_uint256", 575 | "typeString": "uint256" 576 | } 577 | ], 578 | "expression": { 579 | "id": 3547, 580 | "name": "upgraded", 581 | "nodeType": "Identifier", 582 | "overloadedDeclarations": [], 583 | "referencedDeclaration": 3542, 584 | "src": "485:8:2", 585 | "typeDescriptions": { 586 | "typeIdentifier": "t_contract$_Migrations_$3555", 587 | "typeString": "contract Migrations" 588 | } 589 | }, 590 | "id": 3549, 591 | "isConstant": false, 592 | "isLValue": false, 593 | "isPure": false, 594 | "lValueRequested": false, 595 | "memberName": "setCompleted", 596 | "nodeType": "MemberAccess", 597 | "referencedDeclaration": 3534, 598 | "src": "485:21:2", 599 | "typeDescriptions": { 600 | "typeIdentifier": "t_function_external_nonpayable$_t_uint256_$returns$__$", 601 | "typeString": "function (uint256) external" 602 | } 603 | }, 604 | "id": 3551, 605 | "isConstant": false, 606 | "isLValue": false, 607 | "isPure": false, 608 | "kind": "functionCall", 609 | "lValueRequested": false, 610 | "names": [], 611 | "nodeType": "FunctionCall", 612 | "src": "485:47:2", 613 | "tryCall": false, 614 | "typeDescriptions": { 615 | "typeIdentifier": "t_tuple$__$", 616 | "typeString": "tuple()" 617 | } 618 | }, 619 | "id": 3552, 620 | "nodeType": "ExpressionStatement", 621 | "src": "485:47:2" 622 | } 623 | ] 624 | }, 625 | "functionSelector": "0900f010", 626 | "id": 3554, 627 | "implemented": true, 628 | "kind": "function", 629 | "modifiers": [ 630 | { 631 | "id": 3539, 632 | "modifierName": { 633 | "id": 3538, 634 | "name": "restricted", 635 | "nodeType": "Identifier", 636 | "overloadedDeclarations": [], 637 | "referencedDeclaration": 3522, 638 | "src": "417:10:2", 639 | "typeDescriptions": { 640 | "typeIdentifier": "t_modifier$__$", 641 | "typeString": "modifier ()" 642 | } 643 | }, 644 | "nodeType": "ModifierInvocation", 645 | "src": "417:10:2" 646 | } 647 | ], 648 | "name": "upgrade", 649 | "nodeType": "FunctionDefinition", 650 | "parameters": { 651 | "id": 3537, 652 | "nodeType": "ParameterList", 653 | "parameters": [ 654 | { 655 | "constant": false, 656 | "id": 3536, 657 | "mutability": "mutable", 658 | "name": "new_address", 659 | "nodeType": "VariableDeclaration", 660 | "scope": 3554, 661 | "src": "389:19:2", 662 | "stateVariable": false, 663 | "storageLocation": "default", 664 | "typeDescriptions": { 665 | "typeIdentifier": "t_address", 666 | "typeString": "address" 667 | }, 668 | "typeName": { 669 | "id": 3535, 670 | "name": "address", 671 | "nodeType": "ElementaryTypeName", 672 | "src": "389:7:2", 673 | "stateMutability": "nonpayable", 674 | "typeDescriptions": { 675 | "typeIdentifier": "t_address", 676 | "typeString": "address" 677 | } 678 | }, 679 | "visibility": "internal" 680 | } 681 | ], 682 | "src": "388:21:2" 683 | }, 684 | "returnParameters": { 685 | "id": 3540, 686 | "nodeType": "ParameterList", 687 | "parameters": [], 688 | "src": "428:0:2" 689 | }, 690 | "scope": 3555, 691 | "src": "372:165:2", 692 | "stateMutability": "nonpayable", 693 | "virtual": false, 694 | "visibility": "public" 695 | } 696 | ], 697 | "scope": 3556, 698 | "src": "66:473:2" 699 | } 700 | ], 701 | "src": "32:508:2" 702 | }, 703 | "legacyAST": { 704 | "attributes": { 705 | "absolutePath": "/home/pavansoratur/Github/cryptoboys-NFT-marketplace/src/contracts/Migrations.sol", 706 | "exportedSymbols": { 707 | "Migrations": [ 708 | 3555 709 | ] 710 | }, 711 | "license": "MIT" 712 | }, 713 | "children": [ 714 | { 715 | "attributes": { 716 | "literals": [ 717 | "solidity", 718 | ">=", 719 | "0.4", 720 | ".21", 721 | "<", 722 | "0.8", 723 | ".0" 724 | ] 725 | }, 726 | "id": 3500, 727 | "name": "PragmaDirective", 728 | "src": "32:32:2" 729 | }, 730 | { 731 | "attributes": { 732 | "abstract": false, 733 | "baseContracts": [ 734 | null 735 | ], 736 | "contractDependencies": [ 737 | null 738 | ], 739 | "contractKind": "contract", 740 | "fullyImplemented": true, 741 | "linearizedBaseContracts": [ 742 | 3555 743 | ], 744 | "name": "Migrations", 745 | "scope": 3556 746 | }, 747 | "children": [ 748 | { 749 | "attributes": { 750 | "constant": false, 751 | "functionSelector": "8da5cb5b", 752 | "mutability": "mutable", 753 | "name": "owner", 754 | "scope": 3555, 755 | "stateVariable": true, 756 | "storageLocation": "default", 757 | "type": "address", 758 | "visibility": "public" 759 | }, 760 | "children": [ 761 | { 762 | "attributes": { 763 | "name": "address", 764 | "stateMutability": "nonpayable", 765 | "type": "address" 766 | }, 767 | "id": 3501, 768 | "name": "ElementaryTypeName", 769 | "src": "90:7:2" 770 | } 771 | ], 772 | "id": 3502, 773 | "name": "VariableDeclaration", 774 | "src": "90:20:2" 775 | }, 776 | { 777 | "attributes": { 778 | "constant": false, 779 | "functionSelector": "445df0ac", 780 | "mutability": "mutable", 781 | "name": "last_completed_migration", 782 | "scope": 3555, 783 | "stateVariable": true, 784 | "storageLocation": "default", 785 | "type": "uint256", 786 | "visibility": "public" 787 | }, 788 | "children": [ 789 | { 790 | "attributes": { 791 | "name": "uint", 792 | "type": "uint256" 793 | }, 794 | "id": 3503, 795 | "name": "ElementaryTypeName", 796 | "src": "114:4:2" 797 | } 798 | ], 799 | "id": 3504, 800 | "name": "VariableDeclaration", 801 | "src": "114:36:2" 802 | }, 803 | { 804 | "attributes": { 805 | "implemented": true, 806 | "isConstructor": true, 807 | "kind": "constructor", 808 | "modifiers": [ 809 | null 810 | ], 811 | "name": "", 812 | "scope": 3555, 813 | "stateMutability": "nonpayable", 814 | "virtual": false, 815 | "visibility": "public" 816 | }, 817 | "children": [ 818 | { 819 | "attributes": { 820 | "parameters": [ 821 | null 822 | ] 823 | }, 824 | "children": [], 825 | "id": 3505, 826 | "name": "ParameterList", 827 | "src": "166:2:2" 828 | }, 829 | { 830 | "attributes": { 831 | "parameters": [ 832 | null 833 | ] 834 | }, 835 | "children": [], 836 | "id": 3506, 837 | "name": "ParameterList", 838 | "src": "169:0:2" 839 | }, 840 | { 841 | "children": [ 842 | { 843 | "children": [ 844 | { 845 | "attributes": { 846 | "isConstant": false, 847 | "isLValue": false, 848 | "isPure": false, 849 | "lValueRequested": false, 850 | "operator": "=", 851 | "type": "address" 852 | }, 853 | "children": [ 854 | { 855 | "attributes": { 856 | "overloadedDeclarations": [ 857 | null 858 | ], 859 | "referencedDeclaration": 3502, 860 | "type": "address", 861 | "value": "owner" 862 | }, 863 | "id": 3507, 864 | "name": "Identifier", 865 | "src": "175:5:2" 866 | }, 867 | { 868 | "attributes": { 869 | "isConstant": false, 870 | "isLValue": false, 871 | "isPure": false, 872 | "lValueRequested": false, 873 | "member_name": "sender", 874 | "type": "address payable" 875 | }, 876 | "children": [ 877 | { 878 | "attributes": { 879 | "overloadedDeclarations": [ 880 | null 881 | ], 882 | "referencedDeclaration": 4294967281, 883 | "type": "msg", 884 | "value": "msg" 885 | }, 886 | "id": 3508, 887 | "name": "Identifier", 888 | "src": "183:3:2" 889 | } 890 | ], 891 | "id": 3509, 892 | "name": "MemberAccess", 893 | "src": "183:10:2" 894 | } 895 | ], 896 | "id": 3510, 897 | "name": "Assignment", 898 | "src": "175:18:2" 899 | } 900 | ], 901 | "id": 3511, 902 | "name": "ExpressionStatement", 903 | "src": "175:18:2" 904 | } 905 | ], 906 | "id": 3512, 907 | "name": "Block", 908 | "src": "169:29:2" 909 | } 910 | ], 911 | "id": 3513, 912 | "name": "FunctionDefinition", 913 | "src": "155:43:2" 914 | }, 915 | { 916 | "attributes": { 917 | "name": "restricted", 918 | "virtual": false, 919 | "visibility": "internal" 920 | }, 921 | "children": [ 922 | { 923 | "attributes": { 924 | "parameters": [ 925 | null 926 | ] 927 | }, 928 | "children": [], 929 | "id": 3514, 930 | "name": "ParameterList", 931 | "src": "221:2:2" 932 | }, 933 | { 934 | "children": [ 935 | { 936 | "attributes": {}, 937 | "children": [ 938 | { 939 | "attributes": { 940 | "commonType": { 941 | "typeIdentifier": "t_address", 942 | "typeString": "address" 943 | }, 944 | "isConstant": false, 945 | "isLValue": false, 946 | "isPure": false, 947 | "lValueRequested": false, 948 | "operator": "==", 949 | "type": "bool" 950 | }, 951 | "children": [ 952 | { 953 | "attributes": { 954 | "isConstant": false, 955 | "isLValue": false, 956 | "isPure": false, 957 | "lValueRequested": false, 958 | "member_name": "sender", 959 | "type": "address payable" 960 | }, 961 | "children": [ 962 | { 963 | "attributes": { 964 | "overloadedDeclarations": [ 965 | null 966 | ], 967 | "referencedDeclaration": 4294967281, 968 | "type": "msg", 969 | "value": "msg" 970 | }, 971 | "id": 3515, 972 | "name": "Identifier", 973 | "src": "234:3:2" 974 | } 975 | ], 976 | "id": 3516, 977 | "name": "MemberAccess", 978 | "src": "234:10:2" 979 | }, 980 | { 981 | "attributes": { 982 | "overloadedDeclarations": [ 983 | null 984 | ], 985 | "referencedDeclaration": 3502, 986 | "type": "address", 987 | "value": "owner" 988 | }, 989 | "id": 3517, 990 | "name": "Identifier", 991 | "src": "248:5:2" 992 | } 993 | ], 994 | "id": 3518, 995 | "name": "BinaryOperation", 996 | "src": "234:19:2" 997 | }, 998 | { 999 | "id": 3519, 1000 | "name": "PlaceholderStatement", 1001 | "src": "255:1:2" 1002 | } 1003 | ], 1004 | "id": 3520, 1005 | "name": "IfStatement", 1006 | "src": "230:26:2" 1007 | } 1008 | ], 1009 | "id": 3521, 1010 | "name": "Block", 1011 | "src": "224:37:2" 1012 | } 1013 | ], 1014 | "id": 3522, 1015 | "name": "ModifierDefinition", 1016 | "src": "202:59:2" 1017 | }, 1018 | { 1019 | "attributes": { 1020 | "functionSelector": "fdacd576", 1021 | "implemented": true, 1022 | "isConstructor": false, 1023 | "kind": "function", 1024 | "name": "setCompleted", 1025 | "scope": 3555, 1026 | "stateMutability": "nonpayable", 1027 | "virtual": false, 1028 | "visibility": "public" 1029 | }, 1030 | "children": [ 1031 | { 1032 | "children": [ 1033 | { 1034 | "attributes": { 1035 | "constant": false, 1036 | "mutability": "mutable", 1037 | "name": "completed", 1038 | "scope": 3534, 1039 | "stateVariable": false, 1040 | "storageLocation": "default", 1041 | "type": "uint256", 1042 | "visibility": "internal" 1043 | }, 1044 | "children": [ 1045 | { 1046 | "attributes": { 1047 | "name": "uint", 1048 | "type": "uint256" 1049 | }, 1050 | "id": 3523, 1051 | "name": "ElementaryTypeName", 1052 | "src": "287:4:2" 1053 | } 1054 | ], 1055 | "id": 3524, 1056 | "name": "VariableDeclaration", 1057 | "src": "287:14:2" 1058 | } 1059 | ], 1060 | "id": 3525, 1061 | "name": "ParameterList", 1062 | "src": "286:16:2" 1063 | }, 1064 | { 1065 | "attributes": { 1066 | "parameters": [ 1067 | null 1068 | ] 1069 | }, 1070 | "children": [], 1071 | "id": 3528, 1072 | "name": "ParameterList", 1073 | "src": "321:0:2" 1074 | }, 1075 | { 1076 | "attributes": {}, 1077 | "children": [ 1078 | { 1079 | "attributes": { 1080 | "overloadedDeclarations": [ 1081 | null 1082 | ], 1083 | "referencedDeclaration": 3522, 1084 | "type": "modifier ()", 1085 | "value": "restricted" 1086 | }, 1087 | "id": 3526, 1088 | "name": "Identifier", 1089 | "src": "310:10:2" 1090 | } 1091 | ], 1092 | "id": 3527, 1093 | "name": "ModifierInvocation", 1094 | "src": "310:10:2" 1095 | }, 1096 | { 1097 | "children": [ 1098 | { 1099 | "children": [ 1100 | { 1101 | "attributes": { 1102 | "isConstant": false, 1103 | "isLValue": false, 1104 | "isPure": false, 1105 | "lValueRequested": false, 1106 | "operator": "=", 1107 | "type": "uint256" 1108 | }, 1109 | "children": [ 1110 | { 1111 | "attributes": { 1112 | "overloadedDeclarations": [ 1113 | null 1114 | ], 1115 | "referencedDeclaration": 3504, 1116 | "type": "uint256", 1117 | "value": "last_completed_migration" 1118 | }, 1119 | "id": 3529, 1120 | "name": "Identifier", 1121 | "src": "327:24:2" 1122 | }, 1123 | { 1124 | "attributes": { 1125 | "overloadedDeclarations": [ 1126 | null 1127 | ], 1128 | "referencedDeclaration": 3524, 1129 | "type": "uint256", 1130 | "value": "completed" 1131 | }, 1132 | "id": 3530, 1133 | "name": "Identifier", 1134 | "src": "354:9:2" 1135 | } 1136 | ], 1137 | "id": 3531, 1138 | "name": "Assignment", 1139 | "src": "327:36:2" 1140 | } 1141 | ], 1142 | "id": 3532, 1143 | "name": "ExpressionStatement", 1144 | "src": "327:36:2" 1145 | } 1146 | ], 1147 | "id": 3533, 1148 | "name": "Block", 1149 | "src": "321:47:2" 1150 | } 1151 | ], 1152 | "id": 3534, 1153 | "name": "FunctionDefinition", 1154 | "src": "265:103:2" 1155 | }, 1156 | { 1157 | "attributes": { 1158 | "functionSelector": "0900f010", 1159 | "implemented": true, 1160 | "isConstructor": false, 1161 | "kind": "function", 1162 | "name": "upgrade", 1163 | "scope": 3555, 1164 | "stateMutability": "nonpayable", 1165 | "virtual": false, 1166 | "visibility": "public" 1167 | }, 1168 | "children": [ 1169 | { 1170 | "children": [ 1171 | { 1172 | "attributes": { 1173 | "constant": false, 1174 | "mutability": "mutable", 1175 | "name": "new_address", 1176 | "scope": 3554, 1177 | "stateVariable": false, 1178 | "storageLocation": "default", 1179 | "type": "address", 1180 | "visibility": "internal" 1181 | }, 1182 | "children": [ 1183 | { 1184 | "attributes": { 1185 | "name": "address", 1186 | "stateMutability": "nonpayable", 1187 | "type": "address" 1188 | }, 1189 | "id": 3535, 1190 | "name": "ElementaryTypeName", 1191 | "src": "389:7:2" 1192 | } 1193 | ], 1194 | "id": 3536, 1195 | "name": "VariableDeclaration", 1196 | "src": "389:19:2" 1197 | } 1198 | ], 1199 | "id": 3537, 1200 | "name": "ParameterList", 1201 | "src": "388:21:2" 1202 | }, 1203 | { 1204 | "attributes": { 1205 | "parameters": [ 1206 | null 1207 | ] 1208 | }, 1209 | "children": [], 1210 | "id": 3540, 1211 | "name": "ParameterList", 1212 | "src": "428:0:2" 1213 | }, 1214 | { 1215 | "attributes": {}, 1216 | "children": [ 1217 | { 1218 | "attributes": { 1219 | "overloadedDeclarations": [ 1220 | null 1221 | ], 1222 | "referencedDeclaration": 3522, 1223 | "type": "modifier ()", 1224 | "value": "restricted" 1225 | }, 1226 | "id": 3538, 1227 | "name": "Identifier", 1228 | "src": "417:10:2" 1229 | } 1230 | ], 1231 | "id": 3539, 1232 | "name": "ModifierInvocation", 1233 | "src": "417:10:2" 1234 | }, 1235 | { 1236 | "children": [ 1237 | { 1238 | "attributes": { 1239 | "assignments": [ 1240 | 3542 1241 | ] 1242 | }, 1243 | "children": [ 1244 | { 1245 | "attributes": { 1246 | "constant": false, 1247 | "mutability": "mutable", 1248 | "name": "upgraded", 1249 | "scope": 3553, 1250 | "stateVariable": false, 1251 | "storageLocation": "default", 1252 | "type": "contract Migrations", 1253 | "visibility": "internal" 1254 | }, 1255 | "children": [ 1256 | { 1257 | "attributes": { 1258 | "name": "Migrations", 1259 | "referencedDeclaration": 3555, 1260 | "type": "contract Migrations" 1261 | }, 1262 | "id": 3541, 1263 | "name": "UserDefinedTypeName", 1264 | "src": "434:10:2" 1265 | } 1266 | ], 1267 | "id": 3542, 1268 | "name": "VariableDeclaration", 1269 | "src": "434:19:2" 1270 | }, 1271 | { 1272 | "attributes": { 1273 | "isConstant": false, 1274 | "isLValue": false, 1275 | "isPure": false, 1276 | "isStructConstructorCall": false, 1277 | "lValueRequested": false, 1278 | "names": [ 1279 | null 1280 | ], 1281 | "tryCall": false, 1282 | "type": "contract Migrations", 1283 | "type_conversion": true 1284 | }, 1285 | "children": [ 1286 | { 1287 | "attributes": { 1288 | "argumentTypes": [ 1289 | { 1290 | "typeIdentifier": "t_address", 1291 | "typeString": "address" 1292 | } 1293 | ], 1294 | "overloadedDeclarations": [ 1295 | null 1296 | ], 1297 | "referencedDeclaration": 3555, 1298 | "type": "type(contract Migrations)", 1299 | "value": "Migrations" 1300 | }, 1301 | "id": 3543, 1302 | "name": "Identifier", 1303 | "src": "456:10:2" 1304 | }, 1305 | { 1306 | "attributes": { 1307 | "overloadedDeclarations": [ 1308 | null 1309 | ], 1310 | "referencedDeclaration": 3536, 1311 | "type": "address", 1312 | "value": "new_address" 1313 | }, 1314 | "id": 3544, 1315 | "name": "Identifier", 1316 | "src": "467:11:2" 1317 | } 1318 | ], 1319 | "id": 3545, 1320 | "name": "FunctionCall", 1321 | "src": "456:23:2" 1322 | } 1323 | ], 1324 | "id": 3546, 1325 | "name": "VariableDeclarationStatement", 1326 | "src": "434:45:2" 1327 | }, 1328 | { 1329 | "children": [ 1330 | { 1331 | "attributes": { 1332 | "isConstant": false, 1333 | "isLValue": false, 1334 | "isPure": false, 1335 | "isStructConstructorCall": false, 1336 | "lValueRequested": false, 1337 | "names": [ 1338 | null 1339 | ], 1340 | "tryCall": false, 1341 | "type": "tuple()", 1342 | "type_conversion": false 1343 | }, 1344 | "children": [ 1345 | { 1346 | "attributes": { 1347 | "argumentTypes": [ 1348 | { 1349 | "typeIdentifier": "t_uint256", 1350 | "typeString": "uint256" 1351 | } 1352 | ], 1353 | "isConstant": false, 1354 | "isLValue": false, 1355 | "isPure": false, 1356 | "lValueRequested": false, 1357 | "member_name": "setCompleted", 1358 | "referencedDeclaration": 3534, 1359 | "type": "function (uint256) external" 1360 | }, 1361 | "children": [ 1362 | { 1363 | "attributes": { 1364 | "overloadedDeclarations": [ 1365 | null 1366 | ], 1367 | "referencedDeclaration": 3542, 1368 | "type": "contract Migrations", 1369 | "value": "upgraded" 1370 | }, 1371 | "id": 3547, 1372 | "name": "Identifier", 1373 | "src": "485:8:2" 1374 | } 1375 | ], 1376 | "id": 3549, 1377 | "name": "MemberAccess", 1378 | "src": "485:21:2" 1379 | }, 1380 | { 1381 | "attributes": { 1382 | "overloadedDeclarations": [ 1383 | null 1384 | ], 1385 | "referencedDeclaration": 3504, 1386 | "type": "uint256", 1387 | "value": "last_completed_migration" 1388 | }, 1389 | "id": 3550, 1390 | "name": "Identifier", 1391 | "src": "507:24:2" 1392 | } 1393 | ], 1394 | "id": 3551, 1395 | "name": "FunctionCall", 1396 | "src": "485:47:2" 1397 | } 1398 | ], 1399 | "id": 3552, 1400 | "name": "ExpressionStatement", 1401 | "src": "485:47:2" 1402 | } 1403 | ], 1404 | "id": 3553, 1405 | "name": "Block", 1406 | "src": "428:109:2" 1407 | } 1408 | ], 1409 | "id": 3554, 1410 | "name": "FunctionDefinition", 1411 | "src": "372:165:2" 1412 | } 1413 | ], 1414 | "id": 3555, 1415 | "name": "ContractDefinition", 1416 | "src": "66:473:2" 1417 | } 1418 | ], 1419 | "id": 3556, 1420 | "name": "SourceUnit", 1421 | "src": "32:508:2" 1422 | }, 1423 | "compiler": { 1424 | "name": "solc", 1425 | "version": "0.7.6+commit.7338295f.Emscripten.clang" 1426 | }, 1427 | "networks": { 1428 | "1615634045645": { 1429 | "events": {}, 1430 | "links": {}, 1431 | "address": "0x5d9186563E9A90303C4d1BE43Cba06Ce6D82E3F3", 1432 | "transactionHash": "0x5441a1e14bf24a0072912be5ec290ba5cbc7f3e4e57c36af556910a06b15b60b" 1433 | }, 1434 | "1615634582841": { 1435 | "events": {}, 1436 | "links": {}, 1437 | "address": "0x5e44a8f8E81Aa59c0cEE5e6B3eEF841875740EeA", 1438 | "transactionHash": "0xe8002ac7e696334701655d3f949c8e31cdb11bc2d06b1966ba58c2d05d8b6905" 1439 | }, 1440 | "1615642927363": { 1441 | "events": {}, 1442 | "links": {}, 1443 | "address": "0x699eC1a8057dfAdbc88Bb806D1d88883eD5bb46E", 1444 | "transactionHash": "0x45ade6371d82fefd9d56f89dc73118bc99f2dd474fa0e4dc242d87d4bcfd7ede" 1445 | } 1446 | }, 1447 | "schemaVersion": "3.3.4", 1448 | "updatedAt": "2021-03-13T13:42:33.729Z", 1449 | "networkType": "ethereum", 1450 | "devdoc": { 1451 | "kind": "dev", 1452 | "methods": {}, 1453 | "version": 1 1454 | }, 1455 | "userdoc": { 1456 | "kind": "user", 1457 | "methods": {}, 1458 | "version": 1 1459 | } 1460 | } --------------------------------------------------------------------------------