├── .env.example ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc ├── .vscode └── settings.json ├── CODING_STYLE.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── Truffle ├── .gitattributes ├── LICENSE ├── contracts │ ├── ConvertLib.sol │ ├── MetaCoin.sol │ └── Migrations.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── scripts │ ├── contractInfo.js │ ├── deployContract.js │ └── devChain.js ├── test │ ├── TestMetaCoin.sol │ └── metacoin.js └── truffle-config.js ├── contracts ├── AssetFactory.sol ├── Asteroid.sol ├── Character.sol ├── Migrations.sol ├── Seed.sol └── Temp.sol ├── data ├── !blockHashes!0x0f74e4a069e1351c65f5e413aa8a59423fbb6fb28774a5bf1d15d174e72ded78 ├── !blockLogs!0 ├── !blockLogs!length ├── !blocks!0 ├── !blocks!length ├── !trie_db!0x120169d23be359eb486d3045833d98b8b8ba70c46cb85230b61009e2ab021b3d ├── !trie_db!0x14e87897e030e06525166a8bdd0b1f48eb6dc8fd04621d8019ddf4cf31d5e2c9 ├── !trie_db!0x2e19121b59afc8893fffc6f5aafa51c7e4cf2fb7e8c0b9de32f60534475d5920 ├── !trie_db!0x32fe5bcd434f4957892d28231a3fb4e46ca814ef5a79893bdba57f1f8580f936 ├── !trie_db!0x35014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97 ├── !trie_db!0x39e495c77a884486adeff235f317eac2cd8cf8ce2fd6615024a09b2e5790e123 ├── !trie_db!0x41c488877f4bd7f076e7a46574f86eb2e58bb101aad9fd4da0dbf9b60ec8c949 ├── !trie_db!0x4f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60 ├── !trie_db!0x54350d30b48d6984395cf168b20e31952619100e01a31e619f91393e34d80ab5 ├── !trie_db!0x57e6c57f0696fff6d2899b68e4bd548706a79e9afdb8ae86cc1e8ade9e716e25 ├── !trie_db!0x5911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554a ├── !trie_db!0x5ba9a4e84224a755038a22871e1ac01504284e8310d9a1bead13436262df56d9 ├── !trie_db!0x69dd78c3e9b114b19ce013965a5ee0e321a76fe8c92b9a585e0974745acc873b ├── !trie_db!0x7990c251ed46db92faa0d4dd67c1fdd73e39bfd35826f4e8749385d8c7fbf050 ├── !trie_db!0x8f3a7302947964ab8f164e327b664e87cb5ae0d754aaf8783e3ca976cef89186 ├── !trie_db!0xa35a3f80ed8e4c7578383351268eb6912f9f04886154748e805f81e2513434f5 ├── !trie_db!0xa46c31ed72743f82f5c6f08b8c24869f5573b136a5068b585868ef3899f3b10a ├── !trie_db!0xb03ac97afc708408787858fa34238c61db6d1fbef43e7dfc52fd576a62905d33 ├── !trie_db!0xb2eb81dfc2aec5b14c35f3b2358e64f83d8847ae5ac5c4e37df82c81a8acd180 ├── !trie_db!0xb5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0ba ├── !trie_db!0xbabf5f4cb3818cd560fc39c82a32be48f33e81414037aaba7195018865f8e14e ├── !trie_db!0xc405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f1603 ├── !trie_db!0xda019d29209036820e59b6a9d3fc0b19ea036272ffb21133f2610e16bbfe7a2a ├── !trie_db!0xe0521e193e31d300d3ad1c8b009a7952900965daf9d003990c08aa812dc81fb6 ├── !trie_db!0xec15f89b38d296209dd947aaa96a603dc9c44202c6f27232d9e520aa06a62260 ├── !trie_db!0xf639b43e2dfccab48f9beba3977e7d87868f615c6b19f56ab412fa08c0a1f1c1 ├── !trie_db!0xf956e2b82e637ac5c7498bca94b241f2d7fb8b06625006eb6f441c23cb7468c5 ├── !trie_db!0xf9692db8728415303f5dbfa78395a02b21b42f81ccda60a0692fbc00638b3f66 └── !trie_db!0xfef353cbd1b475375fc608ccbc1ee0b24f6b6282efdf72a8e7cbd0944b355c8c ├── jsconfig.json ├── migrations ├── 1_initial_migration.js ├── 2_token_migration.js ├── 3_character_migration.js └── 4_object_migration.js ├── package-lock.json ├── package.json ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── assets │ └── imgs │ │ └── multipass.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html └── manifest.json ├── src ├── App.jsx ├── components │ ├── Account │ │ ├── Account.jsx │ │ ├── WalletIcons │ │ │ ├── Coin98.png │ │ │ ├── MathWallet.svg │ │ │ ├── SafePal.svg │ │ │ ├── TokenPocket.svg │ │ │ ├── TrustWallet.png │ │ │ ├── metamaskWallet.png │ │ │ └── wallet-connect.svg │ │ └── config.js │ ├── Address │ │ ├── Address.jsx │ │ └── identicon.css │ ├── AddressInput.jsx │ ├── Blockie.jsx │ ├── Chains │ │ ├── Chains.jsx │ │ ├── Logos.jsx │ │ └── index.js │ ├── Cloud │ │ └── CloudFile.js │ ├── Contract │ │ ├── Contract.jsx │ │ ├── ContractMethods.jsx │ │ └── ContractResolver.jsx │ ├── DEX │ │ ├── DEX.jsx │ │ ├── components │ │ │ └── InchModal.jsx │ │ └── index.js │ ├── ERC20Balance.jsx │ ├── ERC20Transfers │ │ ├── ERC20Transfers.jsx │ │ └── index.js │ ├── Hashtro.jsx │ ├── MenuItems.jsx │ ├── NFTBalance.jsx │ ├── NativeBalance.jsx │ ├── NativeTransactions │ │ ├── NativeTransactions.jsx │ │ ├── index.js │ │ └── styles.js │ ├── QuickStart.jsx │ ├── Ramper.jsx │ ├── TokenPrice.jsx │ ├── Uploader │ │ ├── Batcher.jsx │ │ ├── Updater.jsx │ │ ├── Uploader.jsx │ │ └── index.js │ └── Wallet │ │ ├── Wallet.jsx │ │ ├── components │ │ ├── AssetSelector.jsx │ │ └── Transfer.jsx │ │ └── index.js ├── constants │ ├── abis │ │ ├── Character.json │ │ └── Token.json │ └── contants.js ├── context.js ├── contracts │ └── contractInfo.json ├── helpers │ ├── formatters.js │ └── networks.js ├── hooks │ ├── useAPIContract.js │ ├── useERC20Balance.js │ ├── useERC20Transfers.js │ ├── useIPFS.js │ ├── useInchDex.js │ ├── useNativeTransactions.js │ ├── useTokenPrice.js │ └── useVerifyMetadata.js ├── index.css ├── index.js ├── service-worker.js ├── serviceWorkerRegistration.js ├── style.css └── uikit │ └── Flex │ └── Flex.jsx ├── test └── .gitkeep ├── truffle-config.js └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | # Mandatory info for starting the app 2 | REACT_APP_MORALIS_APPLICATION_ID = 3 | REACT_APP_MORALIS_SERVER_URL = 4 | REACT_APP_MASTER_KEY= 5 | REACT_APP_API_URL= 6 | REACT_APP_API_KEY= 7 | REACT_APP_CHAR_CONTRACT= 8 | 9 | # Optional info for connecting your localChain and Moralis Database 10 | moralisApiKey = xxxxx 11 | moralisApiSecret = xxxxxxx 12 | frpcPath = F:\frpc\frpc.exe 13 | chain = ganache 14 | moralisSubdomain = xxxxxxx.usemoralis.com 15 | abiPath = "F:\ethereum-boilerplate\Truffle\build\contracts\Contract.json" -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | yarn.lock 4 | package-lock.json 5 | Truffle/ -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "react": { 4 | "version": "detect" 5 | } 6 | }, 7 | "env": { 8 | "browser": true, 9 | "node": true, 10 | "es2021": true, 11 | "jest": true 12 | }, 13 | "extends": [ 14 | "eslint:recommended", 15 | "plugin:react/jsx-runtime", 16 | "plugin:react/recommended", 17 | "plugin:react-hooks/recommended" 18 | ], 19 | "parserOptions": { 20 | "ecmaFeatures": { 21 | "jsx": true 22 | }, 23 | "ecmaVersion": 12, 24 | "sourceType": "module" 25 | }, 26 | "plugins": ["react"], 27 | "rules": { 28 | "react/react-in-jsx-scope": "off", 29 | "react/prop-types": "off", 30 | "react/jsx-key": "off", 31 | "react/no-unescaped-entities": "off", 32 | "no-unused-vars": "off" 33 | } 34 | } -------------------------------------------------------------------------------- /.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 | node_modules 27 | .env 28 | coverage 29 | coverage.json 30 | typechain 31 | 32 | #Truffle files 33 | /Truffle/build 34 | /Truffle/data 35 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run format -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | yarn.lock 4 | package-lock.json 5 | Truffle/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "tabWidth": 2, 4 | "printWidth": 80, 5 | "singleQuote": false, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } 4 | -------------------------------------------------------------------------------- /CODING_STYLE.md: -------------------------------------------------------------------------------- 1 | # Coding Style 2 | 3 | - Most importantly, match the existing code style as much as possible. 4 | - Follow the ESlint rules for code-styling and Prettier rules for formatting 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `ethereum-boilerplate` 2 | 3 | ## Setting up the project for debugging and contributing 4 | 5 | ### Setting up you local machine: 6 | 7 | - [Fork](https://github.com/ethereum-boilerplate/ethereum-boilerplate) this project and clone the fork on your local machine: 8 | 9 | ```sh 10 | git clone https://github.com/ethereum-boilerplate/ethereum-boilerplate.git 11 | cd ethereum-boilerplate # go into the clone directory 12 | npm install # install all the node dependencies 13 | ``` 14 | 15 | Make sure to have a ESlint and Prettier plugin installed to check for code-smells and auto-formatting. 16 | 17 | ### Pull Requests 18 | 19 | 1. Fork the repo and create your branch from `main`. 20 | 2. Make sure your code lints and is correctly formatted. 21 | 22 | ### Known Issues 23 | 24 | We use GitHub issues to track public bugs. We will keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new issue, try to make sure your problem doesn't already exist. 25 | 26 | ### Coding Style 27 | 28 | Please follow the [Coding Style](https://github.com/ethereum-boilerplate/ethereum-boilerplate/blob/main/CODING_STYLE.md). 29 | 30 | ## License 31 | 32 | By contributing to the ethereum-boilerplate, you agree that your contributions will be licensed under its license. 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Moralis Web3 Technology AB, 559307-5988 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `NFT Game Logic Sandbox` 2 | 3 | ### WARNING: ACTIVE WORK IN PROGRESS; CODE MARKED FOR COMPLETE RE-WORK. 4 | 5 | > That being said, the principles demonstrated in this codebase still apply, but could be handled and demonstrated more elegantly. 6 | > With the repo in its current form, it's recommended that you first authenticate as a user before testing its web3 functionality i.e. loading NFT assets from the included contract won't work unless logged-in/authenticated. 7 | 8 | ## About 9 | 10 | Aim: Save time and resources for game developers by e.g. facilitating the generation of in-game assets as NFTs via intuative UI. 11 | 12 | Built on [react-moralis](https://github.com/MoralisWeb3/react-moralis) and [Moralis](https://moralis.io?utm_source=ashbeech&utm_medium=readme&utm_campaign=ethereum-boilerplate). 13 |
14 | 15 | These tutorial videos are a great introduction.
16 | Part 1: [Link to Moralis YouTube Video](https://youtu.be/2nM1dTm2zww)
17 | Part 2: [Link to Moralis YouTube Video](https://youtu.be/a3zIFrJl7UU)
18 | Part 3: [Link to Moralis YouTube Video](https://youtu.be/NC7T1Li9wjE)
19 | Part 4: [Link to Moralis YouTube Video](https://youtu.be/u3SoK8A1SEA)
20 | 21 | ## Further Watching 22 | 23 | [NFT Game Design Principles](https://youtu.be/j4kyOTOWSRQ)
24 | [Build an NFT Game Smart Contract](https://youtu.be/xcCMTb5jpKE) 25 | 26 |
27 | 28 | ## Quick Launch 🚀 29 | 30 | Via terminal, navigate to your local dev directory and run: 31 | 32 | ```sh 33 | git clone https://github.com/ashbeech/moralis-nft-game.git 34 | 35 | ``` 36 | 37 | Then navigate into the cloned project's root directory to install all dependencies: 38 | 39 | ```sh 40 | npm install 41 | 42 | ``` 43 | 44 | Go to [Moralis.io](https://moralis.io?utm_source=ashbeech&utm_medium=readme&utm_campaign=ethereum-boilerplate) to create your server instance. Rename `.env.example` file to `.env` and add your Moralis server credentials. For help see ['How to start Moralis Server'](https://docs.moralis.io/moralis-server/getting-started/create-a-moralis-server). 45 | 46 | _Note_: To find your `"X-API-Key": API_KEY` here: https://deep-index.moralis.io/api-docs/#/storage/uploadFolder 47 | 48 | Run your app: 49 | 50 | ```sh 51 | npm start 52 | ``` 53 | 54 |
55 | 56 | ## Functionality 🛠 57 | 58 | ### `IPFS Metadata Uploads` 59 | 60 | Using [`axios`](https://www.npmjs.com/package/axios) lib, pointed at the [`API_URL`](https://deep-index.moralis.io/api-docs/#/storage/uploadFolder) you can upload files directly to [IPFS](https://ipfs.io/). 61 | 62 | ```jsx 63 | // upload to IPFS 64 | Promise.all(promiseArray).then(() => { 65 | axios 66 | .post(API_URL, ipfsArray, { 67 | headers: { 68 | "X-API-Key": API_KEY, 69 | "content-type": "application/json", 70 | accept: "application/json", 71 | }, 72 | }) 73 | .then((res) => { 74 | // successfully uploaded file to IPFS 75 | let fileCID = res.data[0].path.split("/")[4]; 76 | console.log("FILE CID:", fileCID); 77 | // pass IPFS folder CID to compile metadata 78 | uploadMetadata( 79 | API_URL, // <-- this is in .env 80 | API_KEY, // <-- this is in .env 81 | fileCID, 82 | totalFiles, 83 | _formValues, 84 | ); 85 | }) 86 | .catch((err) => { 87 | setLoading(false); 88 | setError(true); 89 | setErrorMessage(err); 90 | console.log(err); 91 | }); 92 | }); 93 | ``` 94 | 95 |
96 | 97 | ### `useWeb3ExecuteFunction()` 98 | 99 | You can use the [`useWeb3ExecuteFunction()`](https://www.npmjs.com/package/react-moralis#useWeb3ExecuteFunction) hook to execute on-chain functions. You need to provide the correct abi of the contract, the corresponding contractAddress, the functionName that you would like to execute, and any parameters (params) thet you need to send with the function. 100 | 101 | ```jsx 102 | const mintCharacter = async (_metaCID, _id, _formValues) => { 103 | // could be _mintAmount instead(?) i.e. 1 is just temp hardcoded 104 | let _url = ""; 105 | let paddedHex = ( 106 | "0000000000000000000000000000000000000000000000000000000000000000" + _id 107 | ).slice(-64); 108 | _url = `https://ipfs.moralis.io:2053/ipfs/${_metaCID}/metadata/${paddedHex}.json`; 109 | 110 | // set link for verifibility at end of upload -> mint process 111 | setIPFSLinkImage(_url); 112 | 113 | const options = { 114 | abi: charContractAbi, 115 | contractAddress: CHAR_CONTRACT, 116 | functionName: "mintToken", 117 | params: { 118 | _mintAmount: 1, 119 | _damage: _formValues.damage, 120 | _power: _formValues.power, 121 | _endurance: _formValues.endurance, 122 | _tokenURI: _url, 123 | }, 124 | }; 125 | 126 | console.log("META DATA URL:", _url); 127 | 128 | await fetch({ 129 | params: options, 130 | onSuccess: (response) => setInteractionData(response), 131 | onComplete: () => console.log("MINT COMPLETE"), 132 | onError: (error) => console.log("ERROR", error), 133 | }); 134 | }; 135 | ``` 136 | 137 |
138 | 139 | ### Minting Game Assets ⛓ 140 | 141 | Deploy Solidity contracts e.g. `Character.sol` to EVM blockchain via [Truffle (local)](https://trufflesuite.com/docs/ganache/overview.html) or [⚙️ Remix IDE](https://remix.ethereum.org/) for test or mainnet deployment. 142 | 143 | Metadata uploaded to IPFS (`_tokenURI`) is mapped to a token's ID via the inherited `_setTokenURI` function from [openzeppelin](https://www.npmjs.com/package/@openzeppelin/contracts): 144 | 145 | ```solidity 146 | function mintToken( 147 | uint256 _mintAmount, 148 | uint8 _damage, 149 | uint8 _power, 150 | uint256 _endurance, 151 | string memory _tokenURI 152 | ) public payable onlyOwner mintCompliance(_mintAmount) returns (uint256) { 153 | _tokenIDS.increment(); 154 | 155 | uint256 newCharID = _tokenIDS.current(); 156 | _tokenDetails[newCharID] = CharData( 157 | newCharID, 158 | _damage, 159 | _power, 160 | block.timestamp, 161 | _endurance, 162 | _tokenURI 163 | ); 164 | 165 | for (uint256 i = 1; i <= _mintAmount; i++) { 166 | addressMintedBalance[msg.sender]++; 167 | } 168 | 169 | _safeMint(msg.sender, newCharID); 170 | _setTokenURI(newCharID, _tokenURI); 171 | 172 | return newCharID; 173 | } 174 | ``` 175 | 176 |
177 | 178 | ### Much more to come [WIP] 179 | 180 | … 181 | 182 |
183 | 184 | ## Dependencies 🏗 185 | 186 | ### Backend 187 | 188 | `moralis`: [ℹ️ Docs](https://www.npmjs.com/package/moralis)
189 | `react-moralis`: [ℹ️ Docs](https://www.npmjs.com/package/react-moralis)
190 | `axios`: [ℹ️ Docs](https://www.npmjs.com/package/axios)
191 | `openzeppelin`: [ℹ️ Docs](https://www.npmjs.com/package/@openzeppelin/contracts) 192 | 193 | ### Frontend 194 | 195 | `chakra-ui`: [ℹ️ Docs](https://www.npmjs.com/package/chakra-ui)
196 | `react-dropzone`: [ℹ️ Docs](https://www.npmjs.com/package/react-dropzone) 197 |
198 | 199 | --- 200 | 201 | # 🤝 `Need help?` 202 | 203 | If you need help with setting up the app or have other questions - don't hesitate to write in our community forum and we will check asap. [Forum link](https://forum.moralis.io). The best thing about Moralis is the super active community ready to help at any time! We help each other. 204 | 205 | # ⭐️ `Star us` 206 | 207 | If this code brought you value, please star this project. 208 | 209 | This is bullish. 210 | -------------------------------------------------------------------------------- /Truffle/.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /Truffle/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Truffle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Truffle/contracts/ConvertLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.25 <0.7.0; 3 | 4 | library ConvertLib{ 5 | function convert(uint amount,uint conversionRate) public pure returns (uint convertedAmount) 6 | { 7 | return amount * conversionRate; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Truffle/contracts/MetaCoin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.25 <0.7.0; 3 | 4 | import "./ConvertLib.sol"; 5 | 6 | // This is just a simple example of a coin-like contract. 7 | // It is not standards compatible and cannot be expected to talk to other 8 | // coin/token contracts. If you want to create a standards-compliant 9 | // token, see: https://github.com/ConsenSys/Tokens. Cheers! 10 | 11 | contract MetaCoin { 12 | mapping(address => uint256) balances; 13 | 14 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 15 | 16 | constructor() public { 17 | balances[tx.origin] = 10000; 18 | } 19 | 20 | string public name = "Test Coin Nice"; 21 | 22 | function sendCoin(address receiver, uint256 amount) 23 | public 24 | returns (bool sufficient) 25 | { 26 | if (balances[msg.sender] < amount) return false; 27 | balances[msg.sender] -= amount; 28 | balances[receiver] += amount; 29 | emit Transfer(msg.sender, receiver, amount); 30 | return true; 31 | } 32 | 33 | function faucetCoin(address receiver, uint256 amount) 34 | public 35 | returns (bool sufficient) 36 | { 37 | balances[msg.sender] += amount; 38 | emit Transfer(msg.sender, receiver, amount); 39 | return true; 40 | } 41 | 42 | function getBalanceInEth(address addr) public view returns (uint256) { 43 | return ConvertLib.convert(getBalance(addr), 2); 44 | } 45 | 46 | function getBalance(address addr) public view returns (uint256) { 47 | return balances[addr]; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Truffle/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.25 <0.7.0; 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | if (msg.sender == owner) _; 10 | } 11 | 12 | constructor() public { 13 | owner = msg.sender; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Truffle/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function (deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /Truffle/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const ConvertLib = artifacts.require("ConvertLib"); 2 | const MetaCoin = artifacts.require("MetaCoin"); 3 | 4 | module.exports = function (deployer) { 5 | deployer.deploy(ConvertLib); 6 | deployer.link(ConvertLib, MetaCoin); 7 | deployer.deploy(MetaCoin); 8 | }; 9 | -------------------------------------------------------------------------------- /Truffle/scripts/contractInfo.js: -------------------------------------------------------------------------------- 1 | var fs = require("fs"); 2 | 3 | fs.copyFile( 4 | "build/contracts/Metacoin.json", 5 | "../src/contracts/contractInfo.json", 6 | (err) => { 7 | if (err) throw err; 8 | console.log("✅ Your contract's ABI was copied to the frontend"); 9 | }, 10 | ); 11 | -------------------------------------------------------------------------------- /Truffle/scripts/deployContract.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require("child_process"); 2 | 3 | const run = async () => { 4 | console.log("📄 Deploying and updating contracts..."); 5 | try { 6 | spawn( 7 | "cd Truffle && truffle migrate --reset --compile-all --network develop && node scripts/contractInfo.js", 8 | { 9 | shell: true, 10 | stdio: "inherit", 11 | }, 12 | ); 13 | } catch (e) { 14 | console.log(e); 15 | } 16 | }; 17 | run(); 18 | -------------------------------------------------------------------------------- /Truffle/scripts/devChain.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require("child_process"); 2 | 3 | const run = () => { 4 | console.log("🚀 Starting local dev chain..."); 5 | try { 6 | spawn("ganache-cli -d --db data -i 1337 --port 7545", { 7 | shell: true, 8 | stdio: "inherit", 9 | }); 10 | } catch (e) { 11 | console.log(e); 12 | } 13 | }; 14 | run(); 15 | -------------------------------------------------------------------------------- /Truffle/test/TestMetaCoin.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.25 <0.7.0; 2 | 3 | import "truffle/Assert.sol"; 4 | import "truffle/DeployedAddresses.sol"; 5 | import "../contracts/MetaCoin.sol"; 6 | 7 | contract TestMetaCoin { 8 | 9 | function testInitialBalanceUsingDeployedContract() public { 10 | MetaCoin meta = MetaCoin(DeployedAddresses.MetaCoin()); 11 | 12 | uint expected = 10000; 13 | 14 | Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); 15 | } 16 | 17 | function testInitialBalanceWithNewMetaCoin() public { 18 | MetaCoin meta = new MetaCoin(); 19 | 20 | uint expected = 10000; 21 | 22 | Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Truffle/test/metacoin.js: -------------------------------------------------------------------------------- 1 | const MetaCoin = artifacts.require("MetaCoin"); 2 | 3 | contract("MetaCoin", (accounts) => { 4 | it("should put 10000 MetaCoin in the first account", async () => { 5 | const metaCoinInstance = await MetaCoin.deployed(); 6 | const balance = await metaCoinInstance.getBalance.call(accounts[0]); 7 | 8 | assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account"); 9 | }); 10 | it("should call a function that depends on a linked library", async () => { 11 | const metaCoinInstance = await MetaCoin.deployed(); 12 | const metaCoinBalance = ( 13 | await metaCoinInstance.getBalance.call(accounts[0]) 14 | ).toNumber(); 15 | const metaCoinEthBalance = ( 16 | await metaCoinInstance.getBalanceInEth.call(accounts[0]) 17 | ).toNumber(); 18 | 19 | assert.equal( 20 | metaCoinEthBalance, 21 | 2 * metaCoinBalance, 22 | "Library function returned unexpected function, linkage may be broken", 23 | ); 24 | }); 25 | it("should send coin correctly", async () => { 26 | const metaCoinInstance = await MetaCoin.deployed(); 27 | 28 | // Setup 2 accounts. 29 | const accountOne = accounts[0]; 30 | const accountTwo = accounts[1]; 31 | 32 | // Get initial balances of first and second account. 33 | const accountOneStartingBalance = ( 34 | await metaCoinInstance.getBalance.call(accountOne) 35 | ).toNumber(); 36 | const accountTwoStartingBalance = ( 37 | await metaCoinInstance.getBalance.call(accountTwo) 38 | ).toNumber(); 39 | 40 | // Make transaction from first account to second. 41 | const amount = 10; 42 | await metaCoinInstance.sendCoin(accountTwo, amount, { from: accountOne }); 43 | 44 | // Get balances of first and second account after the transactions. 45 | const accountOneEndingBalance = ( 46 | await metaCoinInstance.getBalance.call(accountOne) 47 | ).toNumber(); 48 | const accountTwoEndingBalance = ( 49 | await metaCoinInstance.getBalance.call(accountTwo) 50 | ).toNumber(); 51 | 52 | assert.equal( 53 | accountOneEndingBalance, 54 | accountOneStartingBalance - amount, 55 | "Amount wasn't correctly taken from the sender", 56 | ); 57 | assert.equal( 58 | accountTwoEndingBalance, 59 | accountTwoStartingBalance + amount, 60 | "Amount wasn't correctly sent to the receiver", 61 | ); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /Truffle/truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | contracts_directory: "./contracts", 3 | 4 | // Uncommenting the defaults below 5 | // provides for an easier quick-start with Ganache. 6 | // You can also follow this format for other networks; 7 | // see 8 | // for more details on how to specify configuration options! 9 | // 10 | networks: { 11 | develop: { 12 | host: "127.0.0.1", 13 | port: 7545, 14 | chainId: 1337, 15 | network_id: 1337, 16 | deploymentPollingInterval: 10, 17 | }, 18 | }, 19 | // 20 | // Truffle DB is currently disabled by default; to enable it, change enabled: 21 | // false to enabled: true. The default storage location can also be 22 | // overridden by specifying the adapter settings, as shown in the commented code below. 23 | // 24 | // NOTE: It is not possible to migrate your contracts to truffle DB and you should 25 | // make a backup of your artifacts to a safe location before enabling this feature. 26 | // 27 | // After you backed up your artifacts you can utilize db by running migrate as follows: 28 | // $ truffle migrate --reset --compile-all 29 | // 30 | // db: { 31 | // enabled: true, 32 | // host: "127.0.0.1", 33 | // adapter: { 34 | // name: "sqlite", 35 | // settings: { 36 | // directory: ".db", 37 | // }, 38 | // }, 39 | // }, 40 | }; 41 | -------------------------------------------------------------------------------- /contracts/AssetFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | //imports for 1155 token contract from Openzeppelin 5 | import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; 6 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 7 | import "@openzeppelin/contracts/utils/Strings.sol"; 8 | import "@openzeppelin/contracts/access/AccessControl.sol"; 9 | import "@openzeppelin/contracts/access/Ownable.sol"; 10 | 11 | /* 12 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 13 | ░░░░░░░ Asset Factory ░░░░░░░ 14 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 15 | */ 16 | 17 | contract AssetFactory is ERC1155, AccessControl, Ownable { 18 | using SafeMath for uint256; 19 | using Strings for string; 20 | 21 | string public name; // Token name 22 | string public symbol; // Token symbol 23 | string public contractURI; // Token symbol 24 | uint256 public circulation; // Total circulating supply 25 | uint256 public cost; // Per token cost 26 | uint256 public expiry; // Whitelist expiry time i.e. 3600 27 | bool public paused = false; // Switch critical funcs to be paused 28 | 29 | // Whitelist data storage 30 | struct Whitelist { 31 | address buyer; 32 | uint256 timestamp; 33 | bool listed; 34 | } 35 | // Owner data storage 36 | struct Owners { 37 | address prev; 38 | address current; 39 | uint256 timestamp; 40 | uint256 total; 41 | } 42 | 43 | // Mapping each user to corresponding whitelist data 44 | mapping(uint256 => Whitelist) public whitelist; 45 | // Token owners 46 | mapping(uint256 => Owners) public owners; 47 | // Create role identifier for whitelisting 48 | bytes32 public constant WHITELISTER_ROLE = keccak256("WHITELISTER_ROLE"); 49 | 50 | event newOwner(address current, uint256 tokenId); 51 | 52 | event Whitelisted( 53 | uint256 indexed _tokenId, 54 | address _address, 55 | uint256 timestamp 56 | ); 57 | 58 | /* 59 | * @dev 60 | * One-time call on contract initialisation. 61 | * @params 62 | * _root - Address of deafult admin 63 | * _name - Short name 64 | * _symbol - Max 4 digit capitalised 65 | * _cost - wei amount per tx e.g. 10413000000000000 66 | * _uri - Link to token-level metadata 67 | * _cURI - Link to contract-level metadata 68 | */ 69 | constructor( 70 | address _root, 71 | string memory _name, 72 | string memory _symbol, 73 | string memory _uri, 74 | string memory _cURI, 75 | uint256 _expiry, 76 | uint256 _cost 77 | ) ERC1155(_uri) { 78 | _setupRole(DEFAULT_ADMIN_ROLE, _root); 79 | _setupRole(WHITELISTER_ROLE, _root); 80 | 81 | name = _name; 82 | symbol = _symbol; 83 | cost = _cost; 84 | expiry = _expiry; 85 | circulation = 0; 86 | contractURI = _cURI; 87 | } 88 | 89 | /* 90 | * @dev 91 | * See {IERC165-supportsInterface}. 92 | */ 93 | function supportsInterface(bytes4 interfaceId) 94 | public 95 | view 96 | virtual 97 | override(ERC1155, AccessControl) 98 | returns (bool) 99 | { 100 | return super.supportsInterface(interfaceId); 101 | } 102 | 103 | /* 104 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 105 | * MODS 106 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 107 | */ 108 | 109 | /* 110 | * @dev 111 | * Restricted to members of the admin role. 112 | */ 113 | modifier onlyAdmin() { 114 | require(isRole(DEFAULT_ADMIN_ROLE, msg.sender), "Restricted to admins."); 115 | _; 116 | } 117 | 118 | /* 119 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 120 | * ROLES 121 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 122 | */ 123 | 124 | /* 125 | * @dev 126 | * Create a new role with the specified admin role. 127 | */ 128 | function addAdmin(bytes32 roleId, bytes32 adminRoleId) external onlyAdmin { 129 | _setRoleAdmin(roleId, adminRoleId); 130 | //emit AdminRoleSet(roleId, adminRoleId); 131 | } 132 | 133 | /* 134 | * @dev 135 | * Add role permissions to an account. 136 | */ 137 | function addToRole(bytes32 roleId, address account) external onlyAdmin { 138 | grantRole(roleId, account); 139 | } 140 | 141 | /* 142 | * @dev 143 | * Remove oneself from the admin role. 144 | */ 145 | function renounceAdmin() external { 146 | renounceRole(DEFAULT_ADMIN_ROLE, msg.sender); 147 | } 148 | 149 | /* 150 | * @dev 151 | * Return `true` if the account belongs to the role specified. 152 | */ 153 | function isRole(bytes32 roleId, address account) public view returns (bool) { 154 | return hasRole(roleId, account); 155 | } 156 | 157 | /* 158 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 159 | * READ 160 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 161 | */ 162 | 163 | /* 164 | * @dev 165 | * Collection-level metadata. 166 | */ 167 | function getContractURI() public view returns (string memory) { 168 | return contractURI; // Contract-level metadata 169 | } 170 | 171 | /* 172 | * @dev 173 | * Check is an account is on the whitelist. 174 | */ 175 | function isWhitelisted(address _address, uint256 _tokenId) 176 | public 177 | view 178 | returns (bool) 179 | { 180 | bool userIsWhitelisted = false; 181 | if (whitelist[_tokenId].buyer == _address) { 182 | userIsWhitelisted = whitelist[_tokenId].listed; 183 | } 184 | return userIsWhitelisted; 185 | } 186 | 187 | /* 188 | * @dev 189 | * Get cost of buying token. 190 | Pegged to static fiat conversion i.e. 191 | $100 per token at any time. 192 | */ 193 | function getCost() external view returns (uint256) { 194 | return cost; 195 | } 196 | 197 | /* 198 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 199 | * WRITE 200 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 201 | * ADMIN: onlyOwner funcs (contract owner address) 202 | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 203 | */ 204 | 205 | /* 206 | * @dev 207 | * Batch mint tokens. 208 | * @params 209 | * _to - Address tokens will be sent 210 | * _tokenIds - Ids of tokens to be minted 211 | * _amounts - Number of token under ids (1155 caters for fungible/non-fungible mix) 212 | */ 213 | function batchMint( 214 | address _to, 215 | uint256[] memory _tokenIds, 216 | uint256[] memory _amounts 217 | ) external onlyAdmin { 218 | _mintBatch(_to, _tokenIds, _amounts, ""); 219 | 220 | if (_tokenIds.length > 0) { 221 | for (uint256 i = 0; i < _tokenIds.length; i++) { 222 | uint256 tokenId = _tokenIds[i]; 223 | owners[tokenId] = Owners( 224 | address(0), // prev 225 | address(this), // current 226 | block.timestamp, // timestamp 227 | 0 // number of owners 228 | ); 229 | circulation += _amounts[i]; // if amount is larger than 1 we need to make sure circulation is correctly incremented 230 | } 231 | } 232 | } 233 | 234 | /* 235 | * @dev 236 | * Set URI for token metadata. 237 | * @params 238 | * _uri - Updated link to JSON metadata per token 239 | */ 240 | function setURI(string memory _uri) public onlyAdmin { 241 | _setURI(_uri); 242 | } 243 | 244 | /* 245 | * @dev 246 | * Set expiry time for buying a token. 247 | */ 248 | function setExpiry(uint256 _expiry) external onlyAdmin { 249 | expiry = _expiry; 250 | } 251 | 252 | /* 253 | * @dev 254 | * Set cost of buying token. 255 | Pegged to static fiat conversion i.e. 256 | $100 per token at any time. 257 | */ 258 | function setCost(uint256 _newCost) external onlyAdmin { 259 | cost = _newCost; 260 | } 261 | 262 | /* 263 | * @dev 264 | * Set critical contract functions to be paused. 265 | */ 266 | function setPaused(bool _paused) external onlyAdmin { 267 | paused = _paused; 268 | } 269 | 270 | /* 271 | * @dev 272 | * Buyer authorisation func to add addresses to whitelist. 273 | Access to buy 1 token 'per session'. 274 | * @params 275 | * _address - Address to index tokens within whitelist 276 | * _tokenId - Token identifier to add to whitelist 277 | */ 278 | function addToWhitelist(uint256 _tokenId, address _address) 279 | external 280 | onlyRole(WHITELISTER_ROLE) 281 | { 282 | // Buyer address must not already own. 283 | require( 284 | owners[_tokenId].current != _address, 285 | "Address already owns this token." 286 | ); 287 | // Listing created/updated against address. 288 | whitelist[_tokenId] = Whitelist(_address, block.timestamp, true); 289 | emit Whitelisted(_tokenId, _address, block.timestamp); 290 | } 291 | 292 | /* 293 | * @dev 294 | * Remove addresses from whitelist, revoking access to buy. 295 | * @params 296 | * _address - Address to index tokens within whitelist 297 | */ 298 | function removeFromWhitelist(uint256 _tokenId) 299 | public 300 | onlyRole(WHITELISTER_ROLE) 301 | { 302 | require(whitelist[_tokenId].listed, "Address is not on the list."); 303 | delete whitelist[_tokenId]; 304 | } 305 | 306 | /* 307 | * @dev 308 | * Allow buyer to transfer token from owner wallet to theirs. 309 | Value transferred in tx is sent to owner address. 310 | * @params 311 | * _tokenId - token to be transferred 312 | * _buyer - Address fo buyer 313 | * _amount - Number of tokens to be transferred (1 by default) 314 | * _data - Aux byte data (not a requirment) 315 | */ 316 | function buy( 317 | uint256 _tokenId, 318 | address _buyer, 319 | uint256 _amount, 320 | bytes memory _data 321 | ) external payable { 322 | require(!paused, "Contract is currently paused."); 323 | 324 | address owner = owner(); 325 | uint256 available = balanceOf(owner, _tokenId); 326 | 327 | // Must be tokens remaining in owner balance. 328 | require(available >= _amount, "No tokens remaining."); 329 | 330 | if (isRole(DEFAULT_ADMIN_ROLE, _buyer) == true) { 331 | // Bypass payment if buyer is on excluded list. 332 | _safeTransferFrom(owner, _buyer, _tokenId, _amount, _data); 333 | return; 334 | } 335 | // Buyer address must not already own. 336 | require( 337 | owners[_tokenId].current != _buyer, 338 | "Address already owns this token." 339 | ); 340 | // Buyer must be whitelisted for token id. 341 | require( 342 | whitelist[_tokenId].buyer == _buyer, 343 | "Address is not listed for this token." 344 | ); 345 | // Buyer must be whitelisted. 346 | require(whitelist[_tokenId].listed, "Address is not on the list."); 347 | // Whitelist entry must not have expired. 348 | require( 349 | block.timestamp <= (whitelist[_tokenId].timestamp + expiry), 350 | "Whitelist entry expired." 351 | ); 352 | // Amount paid must meet token value. 353 | require(msg.value == cost, "Value is not correct."); 354 | // Commence transfer. 355 | _safeTransferFrom(owner, _buyer, _tokenId, _amount, _data); 356 | // Transfer amount paid into previous token owner's address. 357 | payable(owner).transfer(msg.value); 358 | } 359 | 360 | /* 361 | * @dev 362 | * Hook that is called before any token transfer. This includes minting 363 | and burning, as well as batched variants. 364 | 365 | * The same hook is called on both single and batched variants. For single 366 | transfers, the length of the `id` and `amount` arrays will be 1. 367 | */ 368 | function _beforeTokenTransfer( 369 | address operator, 370 | address from, 371 | address to, 372 | uint256[] memory ids, 373 | uint256[] memory amounts, 374 | bytes memory data 375 | ) internal virtual override { 376 | require(ids.length == amounts.length, "Mismatched params."); 377 | for (uint256 i = 0; i < ids.length; i++) { 378 | // Mark buyer address as owner. 379 | owners[ids[i]].prev = from; 380 | owners[ids[i]].current = to; 381 | owners[ids[i]].timestamp = block.timestamp; 382 | owners[ids[i]].total + 1; 383 | emit newOwner(to, ids[i]); 384 | } 385 | super._beforeTokenTransfer(operator, from, to, ids, amounts, data); 386 | } 387 | 388 | // Fund withdrawal function. 389 | function withdraw() external payable onlyAdmin { 390 | // This will transfer the remaining contract balance to the owner address. 391 | (bool os, ) = payable(owner()).call{value: address(this).balance}(""); 392 | require(os); 393 | } 394 | } 395 | -------------------------------------------------------------------------------- /contracts/Asteroid.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.12 <0.9.0; // 3 | 4 | //imports for 1155 token contract from Openzeppelin 5 | import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; // 6 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 7 | import "@openzeppelin/contracts/access/Ownable.sol"; 8 | import "@openzeppelin/contracts/utils/Counters.sol"; 9 | import "@openzeppelin/contracts/utils/Strings.sol"; 10 | 11 | contract Object is ERC1155, Ownable { 12 | using Counters for Counters.Counter; 13 | using SafeMath for uint256; 14 | using Strings for string; 15 | Counters.Counter private _tokenIDS; 16 | 17 | uint256 public cost = 0.00 ether; 18 | uint256 public maxSupply = 10000; 19 | 20 | // Asteroid struct can be used within arrays and mappings 21 | struct Asteroid { 22 | uint256 id; 23 | uint256 detected; 24 | uint8 level; 25 | string tokenURI; 26 | } 27 | // mapping that reference each Asteroid by their token id 28 | mapping(uint256 => Asteroid) private _tokenDetails; // 0 -> however many get created 29 | string public notRevealedUri = 30 | "ipfs://QmYjmj6AgVxGvWUck4ufmVCt8FSKPcyPRydAkqmZZA21T3/asteroids-hidden.json"; 31 | bool public paused = false; 32 | bool public revealed = false; 33 | 34 | string public name; 35 | string public symbol; 36 | uint256 public tokensInCirculation; 37 | 38 | constructor() 39 | ERC1155("ipfs://QmPJvYnCSeZUyqdiNpEgv4KWBVWK1SEh2Y8X1uScXWCCYg/{id}.json") 40 | { 41 | name = "Asteroid"; 42 | symbol = "AROID"; 43 | tokensInCirculation = 0; 44 | } 45 | 46 | /** func to apply conditions to token mint/creation 47 | * - condition: contract paused/unpaused 48 | * - condition: insufficient account balance 49 | * - condition: minting at least 1 or more 50 | * - condition: total minted + this potential tx is under maxsupply 51 | * - condition: minting limit per address 52 | */ 53 | modifier spawnCompliance(uint256 _mintAmount) { 54 | require(!paused, "The contract is paused!"); 55 | // condition: total minted + this potential tx is under maxsupply 56 | require( 57 | _tokenIDS.current() + _mintAmount <= maxSupply, 58 | "Max supply exceeded!" 59 | ); 60 | _; 61 | } 62 | 63 | // READ FUNCS 64 | 65 | // func to get tokenURI 66 | function uri(uint256 _id) public view override returns (string memory) { 67 | if (revealed == true) { 68 | return _tokenDetails[_id].tokenURI; 69 | } else { 70 | return notRevealedUri; 71 | } 72 | } 73 | 74 | /** func to get token details 75 | * - token by id 76 | * - returns array 77 | */ 78 | function getTokenDetails(uint256 _id) public view returns (Asteroid memory) { 79 | return _tokenDetails[_id]; 80 | } 81 | 82 | // func to get tokens in circulation 83 | function getTokenCirculations() public view returns (uint256) { 84 | return tokensInCirculation; 85 | } 86 | 87 | /** @dev Contract-level metadata for OpenSea. */ 88 | // Update for collection-specific metadata. 89 | function contractURI() public pure returns (string memory) { 90 | return 91 | "ipfs://QmYjmj6AgVxGvWUck4ufmVCt8FSKPcyPRydAkqmZZA21T3/asteroids.json"; // Contract-level metadata 92 | } 93 | 94 | // WRITE FUNCS 95 | 96 | // single mint is our publicly exposed func, _mint is parent contract's mint func 97 | function spawn(uint256 _id, uint256 _amount) public onlyOwner { 98 | for (uint256 i = 0; i < _amount; i++) { 99 | // only owner address can mint owner_address, token_id, bytecode 100 | _tokenDetails[tokensInCirculation] = Asteroid( 101 | _id, 102 | block.timestamp, 103 | 1, 104 | uri(_id) 105 | ); 106 | _mint(msg.sender, tokensInCirculation, 1, ""); // <- '1' in 1155 = NFT 107 | // iterate circulating tokens by minted amount above 108 | tokensInCirculation++; 109 | } 110 | } 111 | 112 | // batch mint 113 | function spawnBatch( 114 | address _to, 115 | uint256[] memory _ids, 116 | uint256[] memory _amounts 117 | ) external onlyOwner { 118 | _mintBatch(_to, _ids, _amounts, ""); 119 | if (_ids.length > 0) { 120 | for (uint256 i = tokensInCirculation; i < _ids.length; i++) { 121 | // only owner address can mint owner_address, token_id, bytecode 122 | _tokenDetails[tokensInCirculation] = Asteroid( 123 | i, 124 | block.timestamp, 125 | 0, 126 | uri(i) 127 | ); 128 | // iterate circulating tokens by minted amount above 129 | tokensInCirculation++; 130 | } 131 | } 132 | } 133 | 134 | function burn(uint256 _id, uint256 _amount) external { 135 | _burn(msg.sender, _id, _amount); 136 | } 137 | 138 | function burnBatch(uint256[] memory _ids, uint256[] memory _amounts) 139 | external 140 | { 141 | _burnBatch(msg.sender, _ids, _amounts); 142 | } 143 | 144 | function burnForMint( 145 | address _from, 146 | uint256[] memory _burnIds, 147 | uint256[] memory _burnAmounts, 148 | uint256[] memory _mintIds, 149 | uint256[] memory _mintAmounts 150 | ) external onlyOwner { 151 | _burnBatch(_from, _burnIds, _burnAmounts); 152 | _mintBatch(_from, _mintIds, _mintAmounts, ""); 153 | } 154 | 155 | function setCost(uint256 _newCost) public onlyOwner { 156 | cost = _newCost; 157 | } 158 | 159 | /** onlyOwner (contractOwner address) funcs 160 | */ 161 | // set hidden data 162 | function setNotHiddenURI(string memory _notRevealedURI) public onlyOwner { 163 | notRevealedUri = _notRevealedURI; 164 | } 165 | 166 | // reveal hidden data 167 | function reveal() public onlyOwner { 168 | if (revealed == true) { 169 | revealed = false; 170 | } else { 171 | revealed = true; 172 | } 173 | } 174 | 175 | function withdraw() external payable onlyOwner { 176 | // This will transfer the remaining contract balance to the owner (contractOwner address). 177 | // Do not remove this otherwise you will not be able to withdraw the funds. 178 | // ============================================================================= 179 | (bool os, ) = payable(owner()).call{value: address(this).balance}(""); 180 | require(os); 181 | // ============================================================================= 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /contracts/Character.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; // <-- version directive 3 | 4 | // imports 5 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; 6 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 7 | import "@openzeppelin/contracts/utils/Counters.sol"; 8 | import "@openzeppelin/contracts/access/Ownable.sol"; 9 | 10 | contract Character is ERC721URIStorage, Ownable { 11 | using Counters for Counters.Counter; 12 | using SafeMath for uint256; 13 | 14 | Counters.Counter private _tokenIds; 15 | 16 | // these are all optional params we might create for our characters 17 | uint256 fee = 0.00 ether; // <-- any fees we want to change on txs 18 | uint256 public constant maxSupply = 10000; // <-- max supply of tokens 19 | uint256 public maxMintAmountPerTx = 1; // <-- max mints per tx 20 | uint256 public perAddressLimit = 100; // <-- max 21 | string public notRevealedUri = "ipfs://INSERT_YOUR_CID/character-hidden.json"; // <-- link to metadata for e.g. hidden opensea listing of token 22 | bool public paused = false; // <-- stop interaction witb contract 23 | bool public revealed = true; // <-- is the collection revealled yet? 24 | address public contractOwner; // <-- game dev/studio wallet address 25 | 26 | // charcter traits (on-chain) 27 | // id, dna, level, rarity, evac, tokenURI 28 | struct Char { 29 | uint256 id; 30 | uint256 dna; 31 | uint8 level; 32 | uint8 rarity; 33 | uint256 evac; 34 | string tokenURI; 35 | } 36 | // mapping char to token count 37 | Char[maxSupply] public _tokenDetails; 38 | // set-up event for emitting once character minted to read out values 39 | event NewChar(address indexed owner, uint256 id, uint256 dna); 40 | mapping(address => uint256) public addressMintedBalance; // <-- used to check how many an account has minted for `maxMintAmountPerTx` 41 | 42 | // we begin constructing token: ERC721 standard 43 | constructor() ERC721("Character", "CHAR") { 44 | contractOwner = msg.sender; // <-- the game dev 45 | } 46 | 47 | // utils/helper funcs 48 | function _createRandomNum(uint256 _mod) internal view returns (uint256) { 49 | uint256 randomNum = uint256( 50 | keccak256(abi.encodePacked(block.timestamp, msg.sender)) 51 | ); 52 | return randomNum % _mod; 53 | } 54 | 55 | /** func to apply conditions to token mint/creation 56 | * - condition: contract paused/unpaused 57 | * - condition: insufficient account balance 58 | * - condition: minting at least 1 or more 59 | * - condition: total minted + this potential tx is under maxsupply 60 | * - condition: minting limit per address 61 | */ 62 | modifier mintCompliance(uint256 _mintAmount) { 63 | require(!paused, "The contract is paused."); 64 | 65 | // condition: insufficient account balance 66 | require(msg.value <= msg.sender.balance, "Insufficient balance."); 67 | 68 | // condition: minting at least 1 or more 69 | require( 70 | _mintAmount > 0 && _mintAmount <= maxMintAmountPerTx, 71 | "Invalid mint amount." 72 | ); 73 | 74 | // condition: total minted + this potential tx is under maxsupply 75 | require( 76 | _tokenIds.current() + _mintAmount <= maxSupply, 77 | "Max supply exceeded." 78 | ); 79 | 80 | // condition: value more than fee 81 | // TODO: opensea won't let list with fee(?) 82 | require(msg.value >= fee * _mintAmount, "Insufficient funds."); 83 | 84 | uint256 ownerMintedCount = addressMintedBalance[msg.sender]; 85 | // condition: minting limit per address 86 | require( 87 | ownerMintedCount + _mintAmount <= perAddressLimit, 88 | "Max NFT per address exceeded." 89 | ); 90 | _; 91 | } 92 | 93 | // READ FUNCS 94 | 95 | /** func to get token details 96 | * - token by id 97 | * - returns array 98 | */ 99 | function getTokenDetails(uint256 _id) public view returns (Char memory) { 100 | return _tokenDetails[_id]; 101 | } 102 | 103 | /** func to get total supply 104 | * 105 | */ 106 | function getTokenCirculations() public view returns (uint256) { 107 | return _tokenIds.current(); 108 | } 109 | 110 | /** func to link token to metadata 111 | * 112 | */ 113 | function tokenURI(uint256 _id) 114 | public 115 | view 116 | virtual 117 | override 118 | returns (string memory) 119 | { 120 | require(_exists(_id), "ERC721Metadata: URI query for nonexistent token"); 121 | if (revealed == true) { 122 | return _tokenDetails[_id].tokenURI; 123 | } else { 124 | return notRevealedUri; 125 | } 126 | } 127 | 128 | /** contract-level metadata for OpenSea. 129 | * - update for collection-specific metadata. 130 | */ 131 | function contractURI() public pure returns (string memory) { 132 | return "ipfs://INSERT_YOUR_CID/characters.json"; // Contract-level metadata 133 | } 134 | 135 | // WRITE FUNCS 136 | 137 | /** 138 | * func to mint/create token 139 | * - amount to be minted/created 140 | * - set link to token's metadata 141 | * - emits array of new token's details 142 | */ 143 | function mintToken(uint256 _mintAmount, string memory _tokenURI) 144 | public 145 | payable 146 | mintCompliance(_mintAmount) 147 | { 148 | _tokenIds.increment(); 149 | uint256 newCharID = _tokenIds.current(); 150 | 151 | _safeMint(msg.sender, newCharID); 152 | _setTokenURI(newCharID, _tokenURI); 153 | 154 | uint8 randRarity = uint8(_createRandomNum(100)); 155 | uint256 randDna = _createRandomNum(10**16); 156 | 157 | // id, dna, level, rarity, evac, tokenURI 158 | Char memory newChar = Char( 159 | newCharID, 160 | randDna, 161 | 1, 162 | randRarity, 163 | block.timestamp, 164 | _tokenURI 165 | ); 166 | 167 | _tokenDetails[newCharID] = newChar; 168 | 169 | // check for addresses already minted 170 | for (uint256 i = 1; i <= _mintAmount; i++) { 171 | addressMintedBalance[msg.sender]++; 172 | } 173 | 174 | emit NewChar(msg.sender, newCharID, randDna); 175 | } 176 | 177 | /** onlyOwner and/or ownerOf 178 | * metadata versioning 179 | * - update _tokenURI to metadata (previous version of metadata remains accessible) 180 | * - only contract owner or token owner can execute func 181 | */ 182 | function updateBio(uint256 _id, string memory _uri) public { 183 | require(_exists(_id), "ERC721URIStorage: URI set of nonexistent token"); 184 | require(ownerOf(_id) == msg.sender || contractOwner == msg.sender); 185 | _tokenDetails[_id].tokenURI = _uri; 186 | _setTokenURI(_id, _uri); 187 | } 188 | 189 | /** onlyOwner (contractOwner address) funcs 190 | 191 | * metadata versioning 192 | * - update _tokenURI to metadata (previous version of metadata remains accessible) 193 | * - only contract owner can execute func 194 | */ 195 | function updateMetadata( 196 | uint256 _id, 197 | string memory _uri, 198 | bool _levelUp 199 | ) public onlyOwner { 200 | require(_exists(_id), "ERC721URIStorage: URI set of nonexistent token"); 201 | Char storage char = _tokenDetails[_id]; 202 | char.tokenURI = _uri; 203 | _setTokenURI(_id, _uri); 204 | // level up 205 | if (_levelUp == true) { 206 | char.level++; 207 | } 208 | } 209 | 210 | function setMaxMintAmountPerTx( 211 | uint256 _newPerAddressLimit, 212 | uint256 _maxMintAmountPerTx 213 | ) public onlyOwner { 214 | perAddressLimit = _newPerAddressLimit; 215 | maxMintAmountPerTx = _maxMintAmountPerTx; 216 | } 217 | 218 | function reveal() public onlyOwner { 219 | revealed = true; 220 | } 221 | 222 | function updateFee(uint256 _fee) external onlyOwner { 223 | fee = _fee; 224 | } 225 | 226 | function withdraw() external payable onlyOwner { 227 | // This will transfer the remaining contract balance to the owner (contractOwner address). 228 | // Do not remove this otherwise you will not be able to withdraw the funds. 229 | // ============================================================================= 230 | (bool os, ) = payable(owner()).call{value: address(this).balance}(""); 231 | require(os); 232 | // ============================================================================= 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.22 <0.9.0; 3 | 4 | contract Migrations { 5 | address public owner = msg.sender; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | require( 10 | msg.sender == owner, 11 | "This function is restricted to the contract's owner" 12 | ); 13 | _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/Seed.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.12 <0.9.0; 3 | 4 | //imports for 1155 token contract from Openzeppelin 5 | import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; 6 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 7 | import "@openzeppelin/contracts/access/Ownable.sol"; 8 | import "@openzeppelin/contracts/utils/Counters.sol"; 9 | import "@openzeppelin/contracts/utils/Strings.sol"; 10 | 11 | contract Seed is ERC1155, Ownable { 12 | using Counters for Counters.Counter; 13 | using SafeMath for uint256; 14 | using Strings for string; 15 | Counters.Counter private _tokenIDS; 16 | 17 | uint256 public maxSupply = 10000000; 18 | 19 | // Seed struct can be used within arrays and mappings 20 | struct Seedling { 21 | uint256 id; 22 | uint8 status; 23 | string tokenURI; 24 | } 25 | // mapping that reference each Seed by their token id 26 | mapping(uint256 => Seedling) private _tokenDetails; // 0 -> however many get created 27 | string public notRevealedUri = 28 | "ipfs://QmPJvYnCSeZUyqdiNpEgv6KWBVWK1SEh2Y8X1uScXWCCYg/seeds-hidden.json"; 29 | bool public paused = false; 30 | 31 | string public name; 32 | string public symbol; 33 | uint256 public tokensInCirculation; 34 | 35 | constructor() 36 | ERC1155("ipfs://QmPJvYnCSeZUyqdiNpEgv6KWBVWK1SEh2Y8X1uScXWCCYg/{id}.json") 37 | { 38 | name = "Seedling"; 39 | symbol = "SEED"; 40 | tokensInCirculation = 0; 41 | } 42 | 43 | // READ FUNCS 44 | 45 | // func to get tokenURI 46 | function uri(uint256 _id) public view override returns (string memory) { 47 | return _tokenDetails[_id].tokenURI; 48 | } 49 | 50 | // WRITE FUNCS 51 | 52 | // single mint 53 | function spawn( 54 | address _to, 55 | uint256 _id, 56 | uint256 _amount 57 | ) external onlyOwner { 58 | _mint(_to, _id, _amount, ""); 59 | tokensInCirculation++; 60 | } 61 | 62 | // batch mint 63 | function spawnBatch( 64 | address _to, 65 | uint256[] memory _ids, 66 | uint256[] memory _amounts 67 | ) external onlyOwner { 68 | _mintBatch(_to, _ids, _amounts, ""); 69 | if (_ids.length > 0) { 70 | for (uint256 i = tokensInCirculation; i < _ids.length; i++) { 71 | // iterate circulating tokens by minted amount above 72 | tokensInCirculation++; 73 | } 74 | } 75 | } 76 | 77 | /** onlyOwner (contractOwner address) funcs 78 | */ 79 | function burnForMint( 80 | address _from, 81 | uint256[] memory _burnIds, 82 | uint256[] memory _burnAmounts, 83 | uint256[] memory _mintIds, 84 | uint256[] memory _mintAmounts 85 | ) external onlyOwner { 86 | _burnBatch(_from, _burnIds, _burnAmounts); 87 | _mintBatch(_from, _mintIds, _mintAmounts, ""); 88 | } 89 | 90 | function burn(uint256 _id, uint256 _amount) external { 91 | _burn(msg.sender, _id, _amount); 92 | } 93 | 94 | function burnBatch(uint256[] memory _ids, uint256[] memory _amounts) 95 | external 96 | { 97 | _burnBatch(msg.sender, _ids, _amounts); 98 | } 99 | 100 | /* 101 | * metadata versioning 102 | * - update _tokenURI to metadata (previous version of metadata remains accessible) 103 | * - only contract owner can execute func 104 | */ 105 | function updateMetadata( 106 | uint256 _id, 107 | string memory _uri, 108 | uint8 _status 109 | ) external onlyOwner { 110 | Seedling storage seed = _tokenDetails[_id]; 111 | seed.tokenURI = _uri; 112 | emit URI(_uri, _id); 113 | // status update 114 | if (_status > 0) { 115 | seed.status = _status; 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /data/!blockHashes!0x0f74e4a069e1351c65f5e413aa8a59423fbb6fb28774a5bf1d15d174e72ded78: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /data/!blockLogs!0: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /data/!blockLogs!length: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /data/!blocks!0: -------------------------------------------------------------------------------- 1 | {"header":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","uncleHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0xe0521e193e31d300d3ad1c8b009a7952900965daf9d003990c08aa812dc81fb6","transactionsTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptTrie":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","bloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x","number":"0x","gasLimit":"0x6691b7","gasUsed":"0x","timestamp":"0x61a4a70f","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000"},"transactions":[],"uncleHeaders":[]} -------------------------------------------------------------------------------- /data/!blocks!length: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /data/!trie_db!0x120169d23be359eb486d3045833d98b8b8ba70c46cb85230b61009e2ab021b3d: -------------------------------------------------------------------------------- 1 | "0xf8f1a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0baa0c405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f16038080808080a0babf5f4cb3818cd560fc39c82a32be48f33e81414037aaba7195018865f8e14ea02e19121b59afc8893fffc6f5aafa51c7e4cf2fb7e8c0b9de32f60534475d59208080a039e495c77a884486adeff235f317eac2cd8cf8ce2fd6615024a09b2e5790e123808080" -------------------------------------------------------------------------------- /data/!trie_db!0x14e87897e030e06525166a8bdd0b1f48eb6dc8fd04621d8019ddf4cf31d5e2c9: -------------------------------------------------------------------------------- 1 | "0xf8669420a8746e75304c0780e011bed21c72cd78cd535eb84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x2e19121b59afc8893fffc6f5aafa51c7e4cf2fb7e8c0b9de32f60534475d5920: -------------------------------------------------------------------------------- 1 | "0xf866943ca94ef8bd5ffee41947b4585a84bda5a3d3da6eb84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x32fe5bcd434f4957892d28231a3fb4e46ca814ef5a79893bdba57f1f8580f936: -------------------------------------------------------------------------------- 1 | "0xf8669420d491bde2303f2f43325b2108d26f1eaba1e32bb84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x35014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97: -------------------------------------------------------------------------------- 1 | "0xf866943df62f291b2e969fb0849d99d9ce41e2f137006eb84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x39e495c77a884486adeff235f317eac2cd8cf8ce2fd6615024a09b2e5790e123: -------------------------------------------------------------------------------- 1 | "0xf86694303ea8624c8c5987235048901fb614fdca89b117b84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x41c488877f4bd7f076e7a46574f86eb2e58bb101aad9fd4da0dbf9b60ec8c949: -------------------------------------------------------------------------------- 1 | "0xf6941000000000000000000000000000000000000000a0f956e2b82e637ac5c7498bca94b241f2d7fb8b06625006eb6f441c23cb7468c5" -------------------------------------------------------------------------------- /data/!trie_db!0x4f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60: -------------------------------------------------------------------------------- 1 | "0xf6940000000000000000000000000000000000000000a0f956e2b82e637ac5c7498bca94b241f2d7fb8b06625006eb6f441c23cb7468c5" -------------------------------------------------------------------------------- /data/!trie_db!0x54350d30b48d6984395cf168b20e31952619100e01a31e619f91393e34d80ab5: -------------------------------------------------------------------------------- 1 | "0xf85e95200000000000000000000000000000000000000001b846f8448080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x57e6c57f0696fff6d2899b68e4bd548706a79e9afdb8ae86cc1e8ade9e716e25: -------------------------------------------------------------------------------- 1 | "0xf8669432d491bde2303f2f43325b2108d26f1eaba1e32bb84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x5911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554a: -------------------------------------------------------------------------------- 1 | "0xf84920b846f8448080a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x5ba9a4e84224a755038a22871e1ac01504284e8310d9a1bead13436262df56d9: -------------------------------------------------------------------------------- 1 | "0xf891a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0baa0c405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f160380808080808080808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0x69dd78c3e9b114b19ce013965a5ee0e321a76fe8c92b9a585e0974745acc873b: -------------------------------------------------------------------------------- 1 | "0xf866943fcf8fdee72ac11b5c542428b35eef5769c409f0b84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0x7990c251ed46db92faa0d4dd67c1fdd73e39bfd35826f4e8749385d8c7fbf050: -------------------------------------------------------------------------------- 1 | "0xf90111a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0baa0c405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f16038080808080a0babf5f4cb3818cd560fc39c82a32be48f33e81414037aaba7195018865f8e14ea02e19121b59afc8893fffc6f5aafa51c7e4cf2fb7e8c0b9de32f60534475d59208080a039e495c77a884486adeff235f317eac2cd8cf8ce2fd6615024a09b2e5790e123a0f639b43e2dfccab48f9beba3977e7d87868f615c6b19f56ab412fa08c0a1f1c18080" -------------------------------------------------------------------------------- /data/!trie_db!0x8f3a7302947964ab8f164e327b664e87cb5ae0d754aaf8783e3ca976cef89186: -------------------------------------------------------------------------------- 1 | "0xf8669420ced938f7991cd0dfcb48f0a06a40fa1af46ebcb84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0xa35a3f80ed8e4c7578383351268eb6912f9f04886154748e805f81e2513434f5: -------------------------------------------------------------------------------- 1 | "0xf8b1a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0baa0c405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f16038080808080a0fef353cbd1b475375fc608ccbc1ee0b24f6b6282efdf72a8e7cbd0944b355c8c80808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xa46c31ed72743f82f5c6f08b8c24869f5573b136a5068b585868ef3899f3b10a: -------------------------------------------------------------------------------- 1 | "0xf8b1a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0baa0c405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f16038080808080a0babf5f4cb3818cd560fc39c82a32be48f33e81414037aaba7195018865f8e14e80808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xb03ac97afc708408787858fa34238c61db6d1fbef43e7dfc52fd576a62905d33: -------------------------------------------------------------------------------- 1 | "0xf8d1a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0baa0c405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f16038080808080a0babf5f4cb3818cd560fc39c82a32be48f33e81414037aaba7195018865f8e14ea02e19121b59afc8893fffc6f5aafa51c7e4cf2fb7e8c0b9de32f60534475d5920808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xb2eb81dfc2aec5b14c35f3b2358e64f83d8847ae5ac5c4e37df82c81a8acd180: -------------------------------------------------------------------------------- 1 | "0xf871a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0ba8080808080808080808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xb5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0ba: -------------------------------------------------------------------------------- 1 | "0xf8518080a032fe5bcd434f4957892d28231a3fb4e46ca814ef5a79893bdba57f1f8580f9368080808080a014e87897e030e06525166a8bdd0b1f48eb6dc8fd04621d8019ddf4cf31d5e2c98080808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xbabf5f4cb3818cd560fc39c82a32be48f33e81414037aaba7195018865f8e14e: -------------------------------------------------------------------------------- 1 | "0xf851a0ec15f89b38d296209dd947aaa96a603dc9c44202c6f27232d9e520aa06a6226080808080a08f3a7302947964ab8f164e327b664e87cb5ae0d754aaf8783e3ca976cef891868080808080808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xc405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f1603: -------------------------------------------------------------------------------- 1 | "0xf866943e5e9111ae8eb78fe1cc3bb8915d5d461f3ef9a9b84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0xda019d29209036820e59b6a9d3fc0b19ea036272ffb21133f2610e16bbfe7a2a: -------------------------------------------------------------------------------- 1 | "0xf851a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97808080808080808080808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xe0521e193e31d300d3ad1c8b009a7952900965daf9d003990c08aa812dc81fb6: -------------------------------------------------------------------------------- 1 | "0xf90131a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a0b5c26fd7ffd148b8d789fbff6fb48ba94f7a213690a05cabc20150baedc3a0baa0c405f5c23177395c512bb32240f4334f5e033c27445b6a52ac9ce82c663f16038080808080a0babf5f4cb3818cd560fc39c82a32be48f33e81414037aaba7195018865f8e14ea02e19121b59afc8893fffc6f5aafa51c7e4cf2fb7e8c0b9de32f60534475d59208080a039e495c77a884486adeff235f317eac2cd8cf8ce2fd6615024a09b2e5790e123a0f639b43e2dfccab48f9beba3977e7d87868f615c6b19f56ab412fa08c0a1f1c1a069dd78c3e9b114b19ce013965a5ee0e321a76fe8c92b9a585e0974745acc873b80" -------------------------------------------------------------------------------- /data/!trie_db!0xec15f89b38d296209dd947aaa96a603dc9c44202c6f27232d9e520aa06a62260: -------------------------------------------------------------------------------- 1 | "0xf8669420f8bf6a479f320ead074411a4b0e7944ea8c9c1b84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0xf639b43e2dfccab48f9beba3977e7d87868f615c6b19f56ab412fa08c0a1f1c1: -------------------------------------------------------------------------------- 1 | "0xf86694311ba2b4d45eaed5996cd0823791e0c93114882db84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /data/!trie_db!0xf956e2b82e637ac5c7498bca94b241f2d7fb8b06625006eb6f441c23cb7468c5: -------------------------------------------------------------------------------- 1 | "0xf9011180a05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554aa05911f24d96912350de50f297c2d34d5d10e136757bf4cfff5fa41bfca219554a8080808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xf9692db8728415303f5dbfa78395a02b21b42f81ccda60a0692fbc00638b3f66: -------------------------------------------------------------------------------- 1 | "0xf871a04f8ac85f76698e8e6d89a93c6289c5d9fbf770f17f408507fb4934a85a3b3d60a035014d7f40e0d69c0e17af80d234ebd34745267637b18435f5c96ceb6575ad97a057e6c57f0696fff6d2899b68e4bd548706a79e9afdb8ae86cc1e8ade9e716e258080808080808080808080808080" -------------------------------------------------------------------------------- /data/!trie_db!0xfef353cbd1b475375fc608ccbc1ee0b24f6b6282efdf72a8e7cbd0944b355c8c: -------------------------------------------------------------------------------- 1 | "0xf8669430f8bf6a479f320ead074411a4b0e7944ea8c9c1b84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { "baseUrl": "src" } 3 | } 4 | -------------------------------------------------------------------------------- /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_token_migration.js: -------------------------------------------------------------------------------- 1 | const Token = artifacts.require("Token"); 2 | module.exports = async function (deployer) { 3 | await deployer.deploy(Token); 4 | let tokenInstance = await Token.deployed(); 5 | await tokenInstance.mint(1, 1, 100, 200, 100000); // Token id 0 6 | let hashtro = await tokenInstance.getTokenDetails(0); 7 | console.log(hashtro); 8 | }; 9 | -------------------------------------------------------------------------------- /migrations/3_character_migration.js: -------------------------------------------------------------------------------- 1 | const Character = artifacts.require("Character"); 2 | module.exports = async function (deployer) { 3 | await deployer.deploy(Character); 4 | let charInstance = await Character.deployed(); 5 | // mint test char 6 | /* 7 | uint256 _mintAmount, 8 | uint8 _damage, 9 | uint8 _power, 10 | uint256 _endurance, 11 | string memory _tokenURI 12 | */ 13 | 14 | await charInstance.mintToken( 15 | 1, 16 | "ipfs://QmctH9PvqE2nApQppW25BWm4GZcYL5dEmWQHt1zsoFBhQu/0000000000000000000000000000000000000000000000000000000000000001.json", 17 | ); // Token id 1 18 | let character = await charInstance.getTokenDetails(1); 19 | console.log(character); 20 | }; 21 | -------------------------------------------------------------------------------- /migrations/4_object_migration.js: -------------------------------------------------------------------------------- 1 | const Object = artifacts.require("Object"); 2 | module.exports = async function (deployer) { 3 | await deployer.deploy(Object); 4 | let objInstance = await Object.deployed(); 5 | let objMetaInstance = await Object.deployed(); 6 | 7 | // mint test obj 8 | // 1155 9 | /* 10 | uint256 _amount, 11 | uint8 _damage, 12 | uint8 _power, 13 | uint256 _endurance 14 | */ 15 | await objInstance.mintToken(1, 1); // Token id 1 16 | let obj = await objInstance.getTokenDetails(0); 17 | console.log(obj); 18 | let objMeta = await objMetaInstance.uri(1); 19 | console.log(objMeta); 20 | }; 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ethereum-boilerplate", 3 | "version": "0.1.0", 4 | "dependencies": { 5 | "@ant-design/icons": "^4.7.0", 6 | "@chakra-ui/icons": "^1.1.1", 7 | "@chakra-ui/react": "^1.7.3", 8 | "@emotion/react": "^11.7.1", 9 | "@emotion/styled": "^11.6.0", 10 | "@openzeppelin/contracts": "^4.4.1", 11 | "@testing-library/jest-dom": "^5.11.4", 12 | "@testing-library/react": "^11.1.0", 13 | "@testing-library/user-event": "^12.1.10", 14 | "@walletconnect/web3-provider": "^1.6.6", 15 | "antd": "^4.16.13", 16 | "axios": "^0.24.0", 17 | "formik": "^2.2.9", 18 | "framer-motion": "^4.1.17", 19 | "magic-sdk": "7.0.0", 20 | "moralis": "^0.0.183", 21 | "moralis-admin-cli": "^2.1.16", 22 | "react": "^17.0.2", 23 | "react-blockies": "^1.4.1", 24 | "react-dom": "^17.0.2", 25 | "react-dropzone": "^11.5.1", 26 | "react-moralis": "^0.3.11", 27 | "react-router": "^5.2.1", 28 | "react-router-dom": "^5.3.0", 29 | "react-scripts": "4.0.3", 30 | "request": "^2.88.2", 31 | "web-vitals": "^1.0.1", 32 | "yarn": "^1.22.17" 33 | }, 34 | "scripts": { 35 | "start": "react-scripts start", 36 | "build": "react-scripts build", 37 | "test": "react-scripts test", 38 | "eject": "react-scripts eject", 39 | "devchain": "node Truffle/scripts/devChain.js", 40 | "connect": "moralis-admin-cli connect-local-devchain", 41 | "watch:events": "moralis-admin-cli add-contract", 42 | "deploy": "node Truffle/scripts/deployContract.js", 43 | "deploypage": "gh-pages -d build", 44 | "clean": "npx gh-pages-clean", 45 | "lint:check": "eslint .", 46 | "lint:fix": "eslint --fix", 47 | "prettier:check": "prettier --check .", 48 | "prettier:fix": "prettier --write \"**/*.{js,jsx,ts,tsx,css,md,json,html}\" .prettierrc --config ./.prettierrc", 49 | "format": "npm run lint:fix && npm run prettier:fix", 50 | "prepare": "husky install" 51 | }, 52 | "eslintConfig": { 53 | "extends": [ 54 | "react-app", 55 | "react-app/jest" 56 | ] 57 | }, 58 | "browserslist": { 59 | "production": [ 60 | ">0.2%", 61 | "not dead", 62 | "not op_mini all" 63 | ], 64 | "development": [ 65 | "last 1 chrome version", 66 | "last 1 firefox version", 67 | "last 1 safari version" 68 | ] 69 | }, 70 | "devDependencies": { 71 | "eslint": "^7.11.0", 72 | "eslint-config-prettier": "^8.3.0", 73 | "eslint-plugin-prettier": "^4.0.0", 74 | "eslint-plugin-react": "^7.28.0", 75 | "eslint-plugin-react-hooks": "^4.3.0", 76 | "gh-pages": "^3.2.3", 77 | "husky": "^7.0.0", 78 | "prettier": "^2.5.1" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/assets/imgs/multipass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/public/assets/imgs/multipass.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 21 | 27 | 28 | 32 | 33 | 37 | ethereum-boilerplate 38 | 39 | 40 | 41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Ethereum Boilerplate", 3 | "name": "Ethereum Boilerplate", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "android-chrome-192x192.png", 12 | "type": "image/png", 13 | "sizes": "192x192", 14 | "purpose": "any maskable" 15 | }, 16 | { 17 | "src": "android-chrome-512x512.png", 18 | "type": "image/png", 19 | "sizes": "512x512" 20 | } 21 | ], 22 | "orientation": "portrait", 23 | "scope": "/", 24 | "start_url": "/", 25 | "display": "standalone", 26 | "theme_color": "#000000", 27 | "background_color": "#ffffff" 28 | } 29 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useMoralis } from "react-moralis"; 3 | import { 4 | BrowserRouter as Router, 5 | Switch, 6 | Route, 7 | Redirect, 8 | } from "react-router-dom"; 9 | import Account from "components/Account/Account"; 10 | import Chains from "components/Chains"; 11 | //import TokenPrice from "components/TokenPrice"; 12 | //import ERC20Balance from "components/ERC20Balance"; 13 | //import ERC20Transfers from "components/ERC20Transfers"; 14 | //import DEX from "components/DEX"; 15 | //import NFTBalance from "components/NFTBalance"; 16 | import Wallet from "components/Wallet"; 17 | import { Layout /*Tabs*/ } from "antd"; 18 | import "antd/dist/antd.css"; 19 | //import NativeBalance from "components/NativeBalance"; 20 | import "./style.css"; 21 | import Hashtro from "components/Hashtro"; 22 | import Uploader from "components/Uploader/Uploader"; // <-- 👀 Currently working on building an IPFS uploader to assist in uploading game assets (incl. image + metadata) 23 | //import Batcher from "components/Uploader/Batcher"; // <-- 👀 Currently working on building an IPFS uploader to assist in uploading game assets (incl. image + metadata) 24 | import Updater from "components/Uploader/Updater"; // <-- 👀 Currently working on building an IPFS uploader to assist in uploading game assets (incl. image + metadata) 25 | //import QuickStart from "components/QuickStart"; 26 | //import Contract from "components/Contract/Contract"; 27 | //import Text from "antd/lib/typography/Text"; 28 | //import Ramper from "components/Ramper"; 29 | import MenuItems from "./components/MenuItems"; 30 | import { ChakraProvider } from "@chakra-ui/react"; 31 | const { Header, Footer } = Layout; 32 | 33 | const styles = { 34 | content: { 35 | display: "flex", 36 | justifyContent: "center", 37 | fontFamily: "Roboto, sans-serif", 38 | color: "#041836", 39 | marginTop: "130px", 40 | padding: "10px", 41 | }, 42 | header: { 43 | position: "fixed", 44 | zIndex: 1, 45 | width: "100%", 46 | background: "#fff", 47 | display: "flex", 48 | justifyContent: "space-between", 49 | alignItems: "center", 50 | fontFamily: "Roboto, sans-serif", 51 | borderBottom: "2px solid rgba(0, 0, 0, 0.06)", 52 | padding: "0 10px", 53 | boxShadow: "0 1px 10px rgb(151 164 175 / 10%)", 54 | }, 55 | headerRight: { 56 | display: "flex", 57 | gap: "20px", 58 | alignItems: "center", 59 | fontSize: "15px", 60 | fontWeight: "600", 61 | }, 62 | }; 63 | const App = ({ isServerInfo }) => { 64 | const { isWeb3Enabled, enableWeb3, isAuthenticated, isWeb3EnableLoading } = 65 | useMoralis(); 66 | 67 | useEffect(() => { 68 | const connectorId = window.localStorage.getItem("connectorId"); 69 | if (isAuthenticated && !isWeb3Enabled && !isWeb3EnableLoading) 70 | enableWeb3({ provider: connectorId }); 71 | // eslint-disable-next-line react-hooks/exhaustive-deps 72 | }, [isAuthenticated, isWeb3Enabled]); 73 | 74 | return ( 75 | 76 | 77 | 78 |
79 | 80 | 81 |
82 | 83 | {/* 84 | 90 | 91 | */} 92 | 93 |
94 |
95 | 96 |
97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | {/* 105 | 106 | */} 107 | 108 | 109 | 110 | 111 | 112 | 113 | {/* 114 | 115 | 116 | Ethereum} key="1"> 117 | 118 | 119 | Binance Smart Chain} key="2"> 120 | 121 | 122 | Polygon} key="3"> 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | */} 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | <>Please login using the "Authenticate" button 151 | 152 | 153 |
154 |
155 | 192 |
193 |
194 | ); 195 | }; 196 | 197 | export const Logo = () => ( 198 |
199 | 206 | 210 | 214 | 218 | 219 |
220 | ); 221 | 222 | export default App; 223 | -------------------------------------------------------------------------------- /src/components/Account/Account.jsx: -------------------------------------------------------------------------------- 1 | import { useMoralis } from "react-moralis"; 2 | import { getEllipsisTxt } from "helpers/formatters"; 3 | import Blockie from "../Blockie"; 4 | import { Button, Card, Modal } from "antd"; 5 | import { useState } from "react"; 6 | import Address from "../Address/Address"; 7 | import { SelectOutlined } from "@ant-design/icons"; 8 | import { getExplorer } from "helpers/networks"; 9 | import Text from "antd/lib/typography/Text"; 10 | import { connectors } from "./config"; 11 | const styles = { 12 | account: { 13 | height: "42px", 14 | padding: "0 15px", 15 | display: "flex", 16 | justifyContent: "center", 17 | alignItems: "center", 18 | width: "fit-content", 19 | borderRadius: "12px", 20 | backgroundColor: "rgb(244, 244, 244)", 21 | cursor: "pointer", 22 | }, 23 | text: { 24 | color: "#21BF96", 25 | }, 26 | connector: { 27 | alignItems: "center", 28 | display: "flex", 29 | flexDirection: "column", 30 | height: "auto", 31 | justifyContent: "center", 32 | marginLeft: "auto", 33 | marginRight: "auto", 34 | padding: "20px 5px", 35 | cursor: "pointer", 36 | }, 37 | icon: { 38 | alignSelf: "center", 39 | fill: "rgb(40, 13, 95)", 40 | flexShrink: "0", 41 | marginBottom: "8px", 42 | height: "30px", 43 | }, 44 | }; 45 | 46 | function Account() { 47 | const { authenticate, isAuthenticated, account, chainId, logout } = 48 | useMoralis(); 49 | const [isModalVisible, setIsModalVisible] = useState(false); 50 | const [isAuthModalVisible, setIsAuthModalVisible] = useState(false); 51 | 52 | if (!isAuthenticated || !account) { 53 | return ( 54 | <> 55 |
setIsAuthModalVisible(true)}> 56 |

Authenticate

57 |
58 | setIsAuthModalVisible(false)} 62 | bodyStyle={{ 63 | padding: "15px", 64 | fontSize: "17px", 65 | fontWeight: "500", 66 | }} 67 | style={{ fontSize: "16px", fontWeight: "500" }} 68 | width="340px" 69 | > 70 |
79 | Connect Wallet 80 |
81 |
82 | {connectors.map(({ title, icon, connectorId }, key) => ( 83 |
{ 87 | try { 88 | await authenticate({ provider: connectorId }); 89 | window.localStorage.setItem("connectorId", connectorId); 90 | setIsAuthModalVisible(false); 91 | } catch (e) { 92 | console.error(e); 93 | } 94 | }} 95 | > 96 | {title} 97 | {title} 98 |
99 | ))} 100 |
101 |
102 | 103 | ); 104 | } 105 | 106 | return ( 107 | <> 108 | {/* */} 124 |
setIsModalVisible(true)}> 125 |

126 | {getEllipsisTxt(account, 6)} 127 |

128 | 129 |
130 | setIsModalVisible(false)} 134 | bodyStyle={{ 135 | padding: "15px", 136 | fontSize: "17px", 137 | fontWeight: "500", 138 | }} 139 | style={{ fontSize: "16px", fontWeight: "500" }} 140 | width="400px" 141 | > 142 | Account 143 | 150 |
156 |
157 | 162 | 163 | View on Explorer 164 | 165 |
166 | 167 | 185 | 186 | 187 | ); 188 | } 189 | 190 | export default Account; 191 | -------------------------------------------------------------------------------- /src/components/Account/WalletIcons/Coin98.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/src/components/Account/WalletIcons/Coin98.png -------------------------------------------------------------------------------- /src/components/Account/WalletIcons/MathWallet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Logo_Icon_black 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/Account/WalletIcons/SafePal.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 形状结合 27 | 28 | 29 | 30 | 32 | 35 | 39 | 43 | 44 | 54 | 55 | 72 | 73 | 形状结合 75 | 81 | Created with Sketch. 83 | 88 | 89 | -------------------------------------------------------------------------------- /src/components/Account/WalletIcons/TokenPocket.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 22 | 26 | 27 | 30 | 33 | 34 | 37 | 40 | 41 | 44 | 47 | 48 | 51 | 55 | 56 | 59 | 62 | 63 | 66 | 69 | 70 | 73 | 77 | 78 | 81 | 84 | 85 | 88 | 92 | 93 | 101 | 105 | 109 | 110 | 119 | 123 | 127 | 128 | 129 | 143 | 145 | 146 | 148 | image/svg+xml 149 | 151 | 152 | 153 | 154 | 155 | 160 | 163 | 166 | 168 | 170 | 174 | 175 | 177 | 181 | 182 | 183 | 184 | 185 | 188 | 191 | 193 | 195 | 199 | 201 | 203 | 206 | 209 | 211 | 213 | 216 | 218 | 220 | 223 | 226 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 245 | 248 | 251 | 255 | 256 | 257 | 258 | 259 | 260 | -------------------------------------------------------------------------------- /src/components/Account/WalletIcons/TrustWallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/src/components/Account/WalletIcons/TrustWallet.png -------------------------------------------------------------------------------- /src/components/Account/WalletIcons/metamaskWallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashbeech/moralis-nft-game/d77e3ecf4c8440394c7e4914bd38f3359410d85d/src/components/Account/WalletIcons/metamaskWallet.png -------------------------------------------------------------------------------- /src/components/Account/config.js: -------------------------------------------------------------------------------- 1 | import Metamask from "./WalletIcons/metamaskWallet.png"; 2 | import Coin98 from "./WalletIcons/Coin98.png"; 3 | import WalletConnect from "./WalletIcons/wallet-connect.svg"; 4 | import MathWallet from "./WalletIcons/MathWallet.svg"; 5 | import TokenPocket from "./WalletIcons/TokenPocket.svg"; 6 | import SafePal from "./WalletIcons/SafePal.svg"; 7 | import TrustWallet from "./WalletIcons/TrustWallet.png"; 8 | 9 | export const connectors = [ 10 | { 11 | title: "Metamask", 12 | icon: Metamask, 13 | connectorId: "injected", 14 | priority: 1, 15 | }, 16 | { 17 | title: "WalletConnect", 18 | icon: WalletConnect, 19 | connectorId: "walletconnect", 20 | priority: 2, 21 | }, 22 | { 23 | title: "Trust Wallet", 24 | icon: TrustWallet, 25 | connectorId: "injected", 26 | priority: 3, 27 | }, 28 | { 29 | title: "MathWallet", 30 | icon: MathWallet, 31 | connectorId: "injected", 32 | priority: 999, 33 | }, 34 | { 35 | title: "TokenPocket", 36 | icon: TokenPocket, 37 | connectorId: "injected", 38 | priority: 999, 39 | }, 40 | { 41 | title: "SafePal", 42 | icon: SafePal, 43 | connectorId: "injected", 44 | priority: 999, 45 | }, 46 | { 47 | title: "Coin98", 48 | icon: Coin98, 49 | connectorId: "injected", 50 | priority: 999, 51 | }, 52 | ]; 53 | -------------------------------------------------------------------------------- /src/components/Address/Address.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { useState } from "react"; 3 | import { getEllipsisTxt } from "../../helpers/formatters"; 4 | import Blockie from "../Blockie"; 5 | import "./identicon.css"; 6 | import { useMoralis } from "react-moralis"; 7 | import { Skeleton } from "antd"; 8 | 9 | const styles = { 10 | address: { 11 | height: "36px", 12 | display: "flex", 13 | gap: "5px", 14 | backgroundColor: "rgba(255, 255, 255, 0.1)", 15 | borderRadius: "9px", 16 | alignItems: "center", 17 | }, 18 | }; 19 | 20 | function Address(props) { 21 | const { account, isAuthenticated } = useMoralis(); 22 | const [address, setAddress] = useState(); 23 | const [isClicked, setIsClicked] = useState(false); 24 | 25 | useEffect(() => { 26 | setAddress(props?.address || (isAuthenticated && account)); 27 | }, [account, isAuthenticated, props]); 28 | 29 | if (!address) 30 | return ( 31 | 32 | ); 33 | 34 | const Copy = () => ( 35 | { 47 | navigator.clipboard.writeText(address); 48 | setIsClicked(true); 49 | }} 50 | > 51 | 52 | 53 | 54 | 55 | Copy Address 56 | 57 | ); 58 | 59 | return ( 60 |
61 | {props.avatar === "left" && } 62 |

{props.size ? getEllipsisTxt(address, props.size) : address}

63 | {props.avatar === "right" && } 64 | {props.copyable && (isClicked ? : )} 65 |
66 | ); 67 | } 68 | 69 | export default Address; 70 | 71 | const Check = () => ( 72 | 82 | 83 | 84 | Copied! 85 | 86 | ); 87 | -------------------------------------------------------------------------------- /src/components/Address/identicon.css: -------------------------------------------------------------------------------- 1 | .identicon { 2 | border-radius: 50px; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/AddressInput.jsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef, useState } from "react"; 2 | import { useMoralis, useMoralisWeb3Api } from "react-moralis"; 3 | import { getEllipsisTxt } from "../helpers/formatters"; 4 | import Blockie from "./Blockie"; 5 | import { Input } from "antd"; 6 | import { SearchOutlined } from "@ant-design/icons"; 7 | 8 | function AddressInput(props) { 9 | const input = useRef(null); 10 | const { web3 } = useMoralis(); 11 | const [address, setAddress] = useState(""); 12 | const [validatedAddress, setValidatedAddress] = useState(""); 13 | const [isDomain, setIsDomain] = useState(false); 14 | const { 15 | resolve: { resolveDomain }, 16 | } = useMoralisWeb3Api(); 17 | 18 | // eslint-disable-next-line react-hooks/exhaustive-deps 19 | useEffect(() => { 20 | if (validatedAddress) props.onChange(isDomain ? validatedAddress : address); 21 | }, [props, validatedAddress, isDomain, address]); 22 | 23 | const updateAddress = useCallback( 24 | async (value) => { 25 | setAddress(value); 26 | if (isSupportedDomain(value)) { 27 | const processPromise = function (promise) { 28 | promise 29 | .then((addr) => { 30 | setValidatedAddress(addr); 31 | setIsDomain(true); 32 | }) 33 | .catch(() => { 34 | setValidatedAddress(""); 35 | }); 36 | }; 37 | if (value.endsWith(".eth")) { 38 | processPromise(web3?.eth?.ens?.getAddress(value)); 39 | } else { 40 | processPromise( 41 | resolveDomain({ 42 | domain: value, 43 | }).then((r) => r?.address), 44 | ); 45 | } 46 | } else if (value.length === 42) { 47 | setValidatedAddress(getEllipsisTxt(value, 10)); 48 | setIsDomain(false); 49 | } else { 50 | setValidatedAddress(""); 51 | setIsDomain(false); 52 | } 53 | }, 54 | [resolveDomain, web3?.eth?.ens], 55 | ); 56 | 57 | const Cross = () => ( 58 | { 69 | setValidatedAddress(""); 70 | setIsDomain(false); 71 | setTimeout(function () { 72 | input.current.focus(); 73 | }); 74 | }} 75 | style={{ cursor: "pointer" }} 76 | > 77 | 78 | 79 | 80 | 81 | ); 82 | 83 | return ( 84 | 95 | ) : ( 96 | 97 | ) 98 | } 99 | suffix={validatedAddress && } 100 | autoFocus={props.autoFocus} 101 | value={ 102 | isDomain 103 | ? `${address} (${getEllipsisTxt(validatedAddress)})` 104 | : validatedAddress || address 105 | } 106 | onChange={(e) => { 107 | updateAddress(e.target.value); 108 | }} 109 | disabled={validatedAddress} 110 | style={ 111 | validatedAddress 112 | ? { ...props?.style, border: "1px solid rgb(33, 191, 150)" } 113 | : { ...props?.style } 114 | } 115 | /> 116 | ); 117 | } 118 | 119 | function isSupportedDomain(domain) { 120 | return [ 121 | ".eth", 122 | ".crypto", 123 | ".coin", 124 | ".wallet", 125 | ".bitcoin", 126 | ".x", 127 | ".888", 128 | ".nft", 129 | ".dao", 130 | ".blockchain", 131 | ].some((tld) => domain.endsWith(tld)); 132 | } 133 | 134 | export default AddressInput; 135 | -------------------------------------------------------------------------------- /src/components/Blockie.jsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "antd"; 2 | import Blockies from "react-blockies"; 3 | import { useMoralis } from "react-moralis"; 4 | 5 | /** 6 | * Shows a blockie image for the provided wallet address 7 | * @param {*} props 8 | * @returns JSX Elemenet 9 | */ 10 | 11 | function Blockie(props) { 12 | const { account, isAuthenticated } = useMoralis(); 13 | if (!props.address && (!account || !isAuthenticated)) 14 | return ; 15 | 16 | return ( 17 | 26 | ); 27 | } 28 | 29 | export default Blockie; 30 | -------------------------------------------------------------------------------- /src/components/Chains/Chains.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { Menu, Dropdown, Button } from "antd"; 3 | import { DownOutlined } from "@ant-design/icons"; 4 | import { AvaxLogo, PolygonLogo, BSCLogo, ETHLogo } from "./Logos"; 5 | import { useChain, useMoralis } from "react-moralis"; 6 | 7 | const styles = { 8 | item: { 9 | display: "flex", 10 | alignItems: "center", 11 | height: "42px", 12 | fontWeight: "500", 13 | fontFamily: "Roboto, sans-serif", 14 | fontSize: "14px", 15 | padding: "0 10px", 16 | }, 17 | button: { 18 | border: "2px solid rgb(231, 234, 243)", 19 | borderRadius: "12px", 20 | }, 21 | }; 22 | 23 | const menuItems = [ 24 | { 25 | key: "0x1", 26 | value: "Ethereum", 27 | icon: , 28 | }, 29 | { 30 | key: "0x539", 31 | value: "Local Chain", 32 | icon: , 33 | }, 34 | { 35 | key: "0x3", 36 | value: "Ropsten Testnet", 37 | icon: , 38 | }, 39 | { 40 | key: "0x4", 41 | value: "Rinkeby Testnet", 42 | icon: , 43 | }, 44 | { 45 | key: "0x2a", 46 | value: "Kovan Testnet", 47 | icon: , 48 | }, 49 | { 50 | key: "0x5", 51 | value: "Goerli Testnet", 52 | icon: , 53 | }, 54 | { 55 | key: "0x38", 56 | value: "Binance", 57 | icon: , 58 | }, 59 | { 60 | key: "0x61", 61 | value: "Smart Chain Testnet", 62 | icon: , 63 | }, 64 | { 65 | key: "0x89", 66 | value: "Polygon", 67 | icon: , 68 | }, 69 | { 70 | key: "0x13881", 71 | value: "Mumbai", 72 | icon: , 73 | }, 74 | { 75 | key: "0xa86a", 76 | value: "Avalanche", 77 | icon: , 78 | }, 79 | { 80 | key: "0xa869", 81 | value: "Avalanche Testnet", 82 | icon: , 83 | }, 84 | ]; 85 | 86 | function Chains() { 87 | const { switchNetwork, chainId, chain } = useChain(); 88 | const { isAuthenticated } = useMoralis(); 89 | const [selected, setSelected] = useState({}); 90 | 91 | //console.log("chain", chain); 92 | 93 | useEffect(() => { 94 | if (!chainId) return null; 95 | const newSelected = menuItems.find((item) => item.key === chainId); 96 | setSelected(newSelected); 97 | console.log("current chainId: ", chainId); 98 | }, [chainId]); 99 | 100 | const handleMenuClick = (e) => { 101 | console.log("switch to: ", e.key); 102 | switchNetwork(e.key); 103 | }; 104 | 105 | const menu = ( 106 | 107 | {menuItems.map((item) => ( 108 | 109 | {item.value} 110 | 111 | ))} 112 | 113 | ); 114 | 115 | if (!chainId || !isAuthenticated) return null; 116 | 117 | return ( 118 |
119 | 120 | 128 | 129 |
130 | ); 131 | } 132 | 133 | export default Chains; 134 | -------------------------------------------------------------------------------- /src/components/Chains/Logos.jsx: -------------------------------------------------------------------------------- 1 | export const AvaxLogo = () => ( 2 | 9 | 13 | 17 | 18 | ); 19 | 20 | export const BSCLogo = () => ( 21 | 28 | 32 | 36 | 37 | ); 38 | 39 | export const ETHLogo = () => ( 40 | 47 | 51 | 56 | 57 | 62 | 63 | 68 | 73 | 74 | ); 75 | 76 | export const PolygonLogo = () => ( 77 | 84 | 88 | 92 | 93 | ); 94 | -------------------------------------------------------------------------------- /src/components/Chains/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./Chains"; 2 | -------------------------------------------------------------------------------- /src/components/Contract/Contract.jsx: -------------------------------------------------------------------------------- 1 | import { Card, Form, notification } from "antd"; 2 | import { useMemo, useState } from "react"; 3 | import Address from "components/Address/Address"; 4 | import { useMoralis, useMoralisQuery } from "react-moralis"; 5 | import { getEllipsisTxt } from "helpers/formatters"; 6 | import ContractMethods from "./ContractMethods"; 7 | import ContractResolver from "./ContractResolver"; 8 | 9 | export default function Contract() { 10 | const { Moralis, chainId } = useMoralis(); 11 | const [responses, setResponses] = useState({}); 12 | const [contract, setContract] = useState(); 13 | 14 | /**Moralis Live query for displaying contract's events*/ 15 | const { data } = useMoralisQuery("Events", (query) => query, [], { 16 | live: true, 17 | }); 18 | 19 | /** Automatically builds write and read components for interacting with contract*/ 20 | const displayedContractFunctions = useMemo(() => { 21 | if (!contract?.abi) return []; 22 | return contract.abi.filter((method) => method["type"] === "function"); 23 | }, [contract]); 24 | 25 | /** Returns true in case if contract is deployed to active chain in wallet */ 26 | const isDeployedToActiveChain = useMemo(() => { 27 | if (!contract?.networks) return undefined; 28 | return [parseInt(chainId, 16)] in contract.networks; 29 | }, [contract, chainId]); 30 | 31 | const contractAddress = useMemo(() => { 32 | if (!isDeployedToActiveChain) return null; 33 | return contract.networks[parseInt(chainId, 16)]?.["address"] || null; 34 | }, [chainId, contract, isDeployedToActiveChain]); 35 | 36 | /** Default function for showing notifications*/ 37 | const openNotification = ({ message, description }) => { 38 | notification.open({ 39 | placement: "bottomRight", 40 | message, 41 | description, 42 | }); 43 | }; 44 | 45 | return ( 46 |
55 | 64 | Your contract: {contract?.contractName} 65 |
71 |
72 | } 73 | size="large" 74 | style={{ 75 | width: "60%", 76 | boxShadow: "0 0.5rem 1.2rem rgb(189 197 209 / 20%)", 77 | border: "1px solid #e7eaf3", 78 | borderRadius: "0.5rem", 79 | }} 80 | > 81 | 82 | 83 | {isDeployedToActiveChain === true && ( 84 | { 86 | const params = forms[name].getFieldsValue(); 87 | 88 | let isView = false; 89 | 90 | for (let method of contract?.abi) { 91 | if (method.name !== name) continue; 92 | console.log(method); 93 | if (method.stateMutability === "view") isView = true; 94 | } 95 | 96 | const options = { 97 | contractAddress, 98 | functionName: name, 99 | abi: contract?.abi, 100 | params, 101 | }; 102 | 103 | if (!isView) { 104 | const tx = await Moralis.executeFunction({ 105 | awaitReceipt: false, 106 | ...options, 107 | }); 108 | tx.on("transactionHash", (hash) => { 109 | setResponses({ 110 | ...responses, 111 | [name]: { result: null, isLoading: true }, 112 | }); 113 | openNotification({ 114 | message: "🔊 New Transaction", 115 | description: `${hash}`, 116 | }); 117 | console.log("🔊 New Transaction", hash); 118 | }) 119 | .on("receipt", (receipt) => { 120 | setResponses({ 121 | ...responses, 122 | [name]: { result: null, isLoading: false }, 123 | }); 124 | openNotification({ 125 | message: "📃 New Receipt", 126 | description: `${receipt.transactionHash}`, 127 | }); 128 | console.log("🔊 New Receipt: ", receipt); 129 | }) 130 | .on("error", (error) => { 131 | console.error(error); 132 | }); 133 | } else { 134 | console.log("options22", options); 135 | Moralis.executeFunction(options).then((response) => 136 | setResponses({ 137 | ...responses, 138 | [name]: { result: response, isLoading: false }, 139 | }), 140 | ); 141 | } 142 | }} 143 | > 144 | 148 | 149 | )} 150 | {isDeployedToActiveChain === false && ( 151 | <>{`The contract is not deployed to the active ${chainId} chain. Switch your active chain or try agan later.`} 152 | )} 153 | 154 | 164 | {data.map((event, key) => ( 165 | 171 | {getEllipsisTxt(event.attributes.transaction_hash, 14)} 172 | 173 | ))} 174 | 175 | 176 | ); 177 | } 178 | -------------------------------------------------------------------------------- /src/components/Contract/ContractMethods.jsx: -------------------------------------------------------------------------------- 1 | import { Button, Card, Form, Input } from "antd"; 2 | import Text from "antd/lib/typography/Text"; 3 | 4 | const ContractMethods = ({ displayedContractFunctions, responses }) => { 5 | return displayedContractFunctions.map((item, key) => ( 6 | 12 |
13 | {item.inputs.map((input, key) => ( 14 | 21 | 22 | 23 | ))} 24 | 25 | 26 | {responses[item.name]?.result && 27 | `Response: ${JSON.stringify(responses[item.name]?.result)}`} 28 | 29 | 36 | 37 |
38 |
39 | )); 40 | }; 41 | 42 | export default ContractMethods; 43 | -------------------------------------------------------------------------------- /src/components/Contract/ContractResolver.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-hooks/exhaustive-deps */ 2 | import { InboxOutlined } from "@ant-design/icons"; 3 | import { message } from "antd"; 4 | import Dragger from "antd/lib/upload/Dragger"; 5 | import React, { useEffect, useMemo } from "react"; 6 | import contractInfo from "contracts/contractInfo.json"; 7 | 8 | export default function ContractResolver({ contract, setContract }) { 9 | useEffect(() => { 10 | /** Tries to load local contract JSON file or get 11 | * it from browser localStorage(works only if file was uploaded previosly by drag&drop component) */ 12 | if (contractInfo?.name) { 13 | setContract(contractInfo); 14 | } else if (window.localStorage.getItem("contract")) 15 | setContract(JSON.parse(window.localStorage.getItem("contract"))); 16 | else 17 | message.error( 18 | "No contract found. Upload it manually or deploy the contract again", 19 | ); 20 | }, [contractInfo]); 21 | 22 | // Props for drag and drop uploader 23 | const uploadProps = useMemo(() => { 24 | return { 25 | name: "file", 26 | accept: ".JSON", 27 | multiple: false, 28 | maxCount: 1, 29 | fileList: contract?.contractName 30 | ? [{ name: `${contract?.contractName}.json`, contract }] 31 | : [], 32 | onChange(info) { 33 | const { status } = info.file; 34 | if (status !== "uploading") { 35 | console.log(info.file, info.fileList); 36 | } 37 | if (status === "done") { 38 | message.success(`${info.file.name} file uploaded successfully.`); 39 | } else if (status === "error") { 40 | message.error(`${info.file.name} file upload failed.`); 41 | } 42 | }, 43 | onDrop(e) { 44 | console.log("Dropped files", e.dataTransfer.files); 45 | }, 46 | onRemove() { 47 | setContract(); 48 | window.localStorage.removeItem("contract"); 49 | }, 50 | beforeUpload: (file) => { 51 | async function fileToJSON(file) { 52 | return new Promise((resolve, reject) => { 53 | const fileReader = new FileReader(); 54 | fileReader.onload = (event) => 55 | resolve(JSON.parse(event.target.result)); 56 | fileReader.onerror = (error) => reject(error); 57 | fileReader.readAsText(file); 58 | }); 59 | } 60 | fileToJSON(file).then((resolvedContract) => { 61 | window.localStorage.setItem( 62 | "contract", 63 | JSON.stringify(resolvedContract), 64 | ); 65 | setContract(resolvedContract); 66 | }); 67 | return false; 68 | }, 69 | }; 70 | }, [contract]); 71 | 72 | return ( 73 | 74 | {!contract && ( 75 | <> 76 | {" "} 77 |

78 | 79 |

80 |

81 | Click or drag Contract file to this area to upload 82 |

83 |

84 | Supports JSON Contract data generated by Truffle and HardHat. JSON 85 | File should contain ABI, address and contract name 86 |

87 | 88 | )} 89 |
90 | ); 91 | } 92 | -------------------------------------------------------------------------------- /src/components/DEX/components/InchModal.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function InchModal({ open, onClose, setToken, tokenList }) { 4 | if (!open) return null; 5 | 6 | return ( 7 |
8 | {!tokenList 9 | ? null 10 | : Object.keys(tokenList).map((token, index) => ( 11 |
{ 19 | setToken(tokenList[token]); 20 | onClose(); 21 | }} 22 | key={index} 23 | > 24 | noLogo 33 |
34 |

{tokenList[token].name}

35 | 42 | {tokenList[token].symbol} 43 | 44 |
45 |
46 | ))} 47 |
48 | ); 49 | } 50 | 51 | export default InchModal; 52 | -------------------------------------------------------------------------------- /src/components/DEX/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./DEX"; 2 | -------------------------------------------------------------------------------- /src/components/ERC20Balance.jsx: -------------------------------------------------------------------------------- 1 | import { useMoralis, useERC20Balances } from "react-moralis"; 2 | import { Skeleton, Table } from "antd"; 3 | import { getEllipsisTxt } from "../helpers/formatters"; 4 | 5 | function ERC20Balance(props) { 6 | const { data: assets } = useERC20Balances(props); 7 | const { Moralis } = useMoralis(); 8 | 9 | const columns = [ 10 | { 11 | title: "", 12 | dataIndex: "logo", 13 | key: "logo", 14 | render: (logo) => ( 15 | nologo 21 | ), 22 | }, 23 | { 24 | title: "Name", 25 | dataIndex: "name", 26 | key: "name", 27 | render: (name) => name, 28 | }, 29 | { 30 | title: "Symbol", 31 | dataIndex: "symbol", 32 | key: "symbol", 33 | render: (symbol) => symbol, 34 | }, 35 | { 36 | title: "Balance", 37 | dataIndex: "balance", 38 | key: "balance", 39 | render: (value, item) => 40 | parseFloat(Moralis?.Units?.FromWei(value, item.decimals)).toFixed(6), 41 | }, 42 | { 43 | title: "Address", 44 | dataIndex: "token_address", 45 | key: "token_address", 46 | render: (address) => getEllipsisTxt(address, 5), 47 | }, 48 | ]; 49 | 50 | return ( 51 |
52 |

💰Token Balances

53 | 54 | { 58 | return record.token_address; 59 | }} 60 | /> 61 | 62 | 63 | ); 64 | } 65 | export default ERC20Balance; 66 | -------------------------------------------------------------------------------- /src/components/ERC20Transfers/ERC20Transfers.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useMoralis } from "react-moralis"; 3 | import { getEllipsisTxt } from "../../helpers/formatters"; 4 | import { getExplorer } from "../../helpers/networks"; 5 | import "antd/dist/antd.css"; 6 | import { Skeleton, Table } from "antd"; 7 | import { useERC20Transfers } from "hooks/useERC20Transfers"; 8 | 9 | function ERC20Transfers() { 10 | const { ERC20Transfers, chainId } = useERC20Transfers(); 11 | const { Moralis } = useMoralis(); 12 | 13 | const columns = [ 14 | { 15 | title: "Token", 16 | dataIndex: "address", 17 | key: "address", 18 | render: (token) => getEllipsisTxt(token, 8), 19 | }, 20 | { 21 | title: "From", 22 | dataIndex: "from_address", 23 | key: "from_address", 24 | render: (from) => getEllipsisTxt(from, 8), 25 | }, 26 | { 27 | title: "To", 28 | dataIndex: "to_address", 29 | key: "to_address", 30 | render: (to) => getEllipsisTxt(to, 8), 31 | }, 32 | { 33 | title: "Value", 34 | dataIndex: "value", 35 | key: "value", 36 | render: (value, item) => 37 | parseFloat(Moralis.Units.FromWei(value, item.decimals)).toFixed(6), 38 | }, 39 | { 40 | title: "Hash", 41 | dataIndex: "transaction_hash", 42 | key: "transaction_hash", 43 | render: (hash) => ( 44 | 49 | View Transaction 50 | 51 | ), 52 | }, 53 | ]; 54 | 55 | let key = 0; 56 | return ( 57 |
58 |

💸ERC20 Transfers

59 | 60 |
{ 64 | key++; 65 | return `${record.transaction_hash}-${key}`; 66 | }} 67 | /> 68 | 69 | 70 | ); 71 | } 72 | 73 | export default ERC20Transfers; 74 | -------------------------------------------------------------------------------- /src/components/ERC20Transfers/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./ERC20Transfers"; 2 | -------------------------------------------------------------------------------- /src/components/MenuItems.jsx: -------------------------------------------------------------------------------- 1 | import { useLocation } from "react-router"; 2 | import { Menu } from "antd"; 3 | import { NavLink } from "react-router-dom"; 4 | 5 | function MenuItems() { 6 | const { pathname } = useLocation(); 7 | 8 | return ( 9 | 21 | 22 | 🚀 Play 23 | 24 | 25 | ⬆️ Uploader 26 | 27 | {/* 28 | 29 | ⬆️ Batcher 30 | 31 | */} 32 | 33 | 🔃 Updater 34 | 35 | {/* 36 | 37 | 👛 Wallet 38 | 39 | 40 | 🏦 Dex 41 | 42 | 43 | 💵 Fiat 44 | 45 | 46 | 💰 Balances 47 | 48 | 49 | 💸 Transfers 50 | 51 | 52 | 🖼 NFTs 53 | 54 | 55 | 📄 Contract 56 | 57 | */} 58 | 59 | ); 60 | } 61 | 62 | export default MenuItems; 63 | -------------------------------------------------------------------------------- /src/components/NFTBalance.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { useMoralis, useNFTBalances } from "react-moralis"; 3 | import { Card, Image, Tooltip, Modal, Input, Skeleton } from "antd"; 4 | import { 5 | FileSearchOutlined, 6 | SendOutlined, 7 | ShoppingCartOutlined, 8 | } from "@ant-design/icons"; 9 | import { getExplorer } from "helpers/networks"; 10 | import AddressInput from "./AddressInput"; 11 | import { useVerifyMetadata } from "hooks/useVerifyMetadata"; 12 | 13 | const { Meta } = Card; 14 | 15 | const styles = { 16 | NFTs: { 17 | display: "flex", 18 | flexWrap: "wrap", 19 | WebkitBoxPack: "start", 20 | justifyContent: "flex-start", 21 | margin: "0 auto", 22 | maxWidth: "1000px", 23 | width: "100%", 24 | gap: "10px", 25 | }, 26 | }; 27 | 28 | function NFTBalance() { 29 | const { data: NFTBalances } = useNFTBalances(); 30 | const { Moralis, chainId } = useMoralis(); 31 | const [visible, setVisibility] = useState(false); 32 | const [receiverToSend, setReceiver] = useState(null); 33 | const [amountToSend, setAmount] = useState(null); 34 | const [nftToSend, setNftToSend] = useState(null); 35 | const [isPending, setIsPending] = useState(false); 36 | const { verifyMetadata } = useVerifyMetadata(); 37 | 38 | async function transfer(nft, amount, receiver) { 39 | console.log(nft, amount, receiver); 40 | const options = { 41 | type: nft?.contract_type?.toLowerCase(), 42 | tokenId: nft?.token_id, 43 | receiver, 44 | contractAddress: nft?.token_address, 45 | }; 46 | 47 | if (options.type === "erc1155") { 48 | options.amount = amount ?? nft.amount; 49 | } 50 | 51 | setIsPending(true); 52 | 53 | try { 54 | const tx = await Moralis.transfer(options); 55 | console.log(tx); 56 | setIsPending(false); 57 | } catch (e) { 58 | alert(e.message); 59 | setIsPending(false); 60 | } 61 | } 62 | 63 | const handleTransferClick = (nft) => { 64 | setNftToSend(nft); 65 | setVisibility(true); 66 | }; 67 | 68 | const handleChange = (e) => { 69 | setAmount(e.target.value); 70 | }; 71 | 72 | console.log("NFTBalances", NFTBalances); 73 | return ( 74 |
75 |

🖼 NFT Balances

76 |
77 | 78 | {NFTBalances?.result && 79 | NFTBalances.result.map((nft, index) => { 80 | //Verify Metadata 81 | nft = verifyMetadata(nft); 82 | return ( 83 | 87 | 89 | window.open( 90 | `${getExplorer(chainId)}address/${ 91 | nft.token_address 92 | }`, 93 | "_blank", 94 | ) 95 | } 96 | /> 97 | , 98 | 99 | handleTransferClick(nft)} /> 100 | , 101 | 102 | alert("OPENSEA INTEGRATION COMING!")} 104 | /> 105 | , 106 | ]} 107 | style={{ width: 240, border: "2px solid #e7eaf3" }} 108 | cover={ 109 | 116 | } 117 | key={index} 118 | > 119 | 120 | 121 | ); 122 | })} 123 | 124 |
125 | setVisibility(false)} 129 | onOk={() => transfer(nftToSend, amountToSend, receiverToSend)} 130 | confirmLoading={isPending} 131 | okText="Send" 132 | > 133 | 134 | {nftToSend && nftToSend.contract_type === "erc1155" && ( 135 | handleChange(e)} 138 | /> 139 | )} 140 | 141 |
142 | ); 143 | } 144 | 145 | export default NFTBalance; 146 | -------------------------------------------------------------------------------- /src/components/NativeBalance.jsx: -------------------------------------------------------------------------------- 1 | import { useMoralis, useNativeBalance } from "react-moralis"; 2 | 3 | function NativeBalance(props) { 4 | const { data: balance } = useNativeBalance(props); 5 | const { account, isAuthenticated } = useMoralis(); 6 | 7 | if (!account || !isAuthenticated) return null; 8 | 9 | return ( 10 |
11 | {balance.formatted} 12 |
13 | ); 14 | } 15 | 16 | export default NativeBalance; 17 | -------------------------------------------------------------------------------- /src/components/NativeTransactions/NativeTransactions.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useMoralis } from "react-moralis"; 3 | import { getEllipsisTxt } from "../../helpers/formatters"; 4 | import useNativeTransactions from "hooks/useNativeTransactions"; 5 | import "antd/dist/antd.css"; 6 | import { Skeleton, Table } from "antd"; 7 | import styles from "./styles"; 8 | 9 | function NativeTransactions() { 10 | const { nativeTransactions, chainId } = useNativeTransactions(); 11 | const { Moralis } = useMoralis(); 12 | useEffect(() => { 13 | console.log(nativeTransactions); 14 | }, [nativeTransactions]); 15 | const columns = [ 16 | { 17 | title: "From", 18 | dataIndex: "from_address", 19 | key: "from_address", 20 | render: (from) => getEllipsisTxt(from, 5), 21 | }, 22 | { 23 | title: "To", 24 | dataIndex: "to_address", 25 | key: "to_address", 26 | render: (to) => getEllipsisTxt(to, 5), 27 | }, 28 | { 29 | title: "Value", 30 | dataIndex: "value", 31 | key: "value", 32 | render: (value) => 33 | // missing second argument in FromWei, decimals 34 | parseFloat(Moralis.Units.FromWei(value)).toFixed(6), 35 | }, 36 | { 37 | title: "Hash", 38 | dataIndex: "hash", 39 | key: "hash", 40 | render: (hash) => ( 41 | 54 | View Transaction 55 | 56 | ), 57 | }, 58 | ]; 59 | 60 | let key = 0; 61 | return ( 62 |
63 |

💸Native Transactions

64 | 67 |
{ 71 | key++; 72 | return `${record.transaction_hash}-${key}`; 73 | }} 74 | /> 75 | 76 | 77 | ); 78 | } 79 | 80 | export default NativeTransactions; 81 | -------------------------------------------------------------------------------- /src/components/NativeTransactions/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./NativeTransactions"; 2 | -------------------------------------------------------------------------------- /src/components/NativeTransactions/styles.js: -------------------------------------------------------------------------------- 1 | const styles = { 2 | title: { 3 | fontSize: "30px", 4 | fontWeight: "700", 5 | }, 6 | card: { 7 | padding: "20px", 8 | display: "flex", 9 | background: "#FFFFFF", 10 | boxShadow: "0px 4px 10px rgba(0, 0, 0, 0.25)", 11 | border: "2px solid #e7eaf3", 12 | borderRadius: "15px", 13 | marginBottom: "20px", 14 | }, 15 | table: { 16 | tableLayout: "fixed", 17 | width: "100%", 18 | textAlign: "left", 19 | borderCollapse: "collapse", 20 | maxWidth: "100%", 21 | }, 22 | }; 23 | 24 | export default styles; 25 | -------------------------------------------------------------------------------- /src/components/QuickStart.jsx: -------------------------------------------------------------------------------- 1 | import { Card, Timeline, Typography } from "antd"; 2 | import React, { useMemo } from "react"; 3 | import { useMoralis } from "react-moralis"; 4 | 5 | const { Text } = Typography; 6 | 7 | const styles = { 8 | title: { 9 | fontSize: "20px", 10 | fontWeight: "700", 11 | }, 12 | text: { 13 | fontSize: "16px", 14 | }, 15 | card: { 16 | boxShadow: "0 0.5rem 1.2rem rgb(189 197 209 / 20%)", 17 | border: "1px solid #e7eaf3", 18 | borderRadius: "0.5rem", 19 | }, 20 | timeline: { 21 | marginBottom: "-45px", 22 | }, 23 | }; 24 | 25 | export default function QuickStart({ isServerInfo }) { 26 | const { Moralis } = useMoralis(); 27 | 28 | const isInchDex = useMemo( 29 | () => (Moralis.Plugins?.oneInch ? true : false), 30 | [Moralis.Plugins?.oneInch], 31 | ); 32 | 33 | return ( 34 |
35 | 39 | 📝 To-Do List 40 | 41 | } 42 | > 43 | 44 | 45 | 46 | Clone or fork{" "} 47 | 52 | ethereum-boilerplate 53 | {" "} 54 | 55 | 56 | 57 | 58 | 59 | Install all dependencies: npm install 60 | 61 | 62 | 63 | 64 | 65 | Sign up for a free account on{" "} 66 | 71 | Moralis 72 | 73 | 74 | 75 | 76 | 77 | 78 | Create a Moralis Server ( 79 | 84 | How to start Moralis Server 85 | 86 | ) 87 | 88 | 89 | 90 | 91 | 92 | Rename .env.example to .env{" "} 93 | and provide your appId and{" "} 94 | serverUrl from{" "} 95 | 100 | Moralis 101 | 102 | : 103 | 104 | 105 | REACT_APP_MORALIS_APPLICATION_ID = xxxxxxxxxxxx 106 | 107 | 108 | REACT_APP_MORALIS_SERVER_URL = 109 | https://xxxxxx.grandmoralis.com:2053/server 110 | 111 | 112 | 113 | 114 | 115 | Stop the app and start it again npm run start 116 | 117 | 118 | 119 | 120 | 121 | Install{" "} 122 | 127 | 1inch Moralis Plugin 128 | {" "} 129 | needed for the{""} component 130 | (optional) 131 | 132 | 133 | 134 | 135 | BUIDL!!! 136 | 137 | 138 | 139 |
140 | 144 | 💣 Starting Local Chain (optional) 145 | 146 | } 147 | > 148 | 149 | 150 | 151 | Install{" "} 152 | 157 | Truffle 158 | {" "} 159 | and{" "} 160 | 165 | ganache-cli 166 | {" "} 167 | npm install -g ganache-cli truffle 168 | 169 | 170 | 171 | 172 | Start you local devchain: npm run devchain on 173 | a new terminal 174 | 175 | 176 | 177 | 178 | Deploy test contract: npm run deploy on a new 179 | terminal 180 | 181 | 182 | 183 | 184 | Open the 📄 Contract tab 185 | 186 | 187 | 188 | 189 | 193 | 📡{" "} 194 | Connecting your Local Chain to the Moralis DB 195 | 196 | } 197 | > 198 | 199 | 200 | 201 | Download{" "} 202 | 207 | frpc 208 | {" "} 209 | and provide missing params in the .env file 210 | 211 | 212 | 213 | 214 | Connect your Moralis Database and Local Chain:{" "} 215 | npm run connect 216 | 217 | 218 | 219 | 220 | Add contract events you want to watch:{" "} 221 | npm run watch:events 222 | 223 | 224 | 225 | 226 |
227 |
228 | ); 229 | } 230 | -------------------------------------------------------------------------------- /src/components/Ramper.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { useMoralis } from "react-moralis"; 3 | 4 | function Ramper() { 5 | const [ramper, setRamper] = useState(); 6 | const { Moralis } = useMoralis(); 7 | useEffect(() => { 8 | if (!Moralis?.["Plugins"]?.["fiat"]) return null; 9 | async function initPlugin() { 10 | Moralis.Plugins.fiat 11 | .buy({}, { disableTriggers: true }) 12 | .then((data) => setRamper(data.data)); 13 | } 14 | initPlugin(); 15 | // eslint-disable-next-line react-hooks/exhaustive-deps 16 | }, [Moralis.Plugins]); 17 | 18 | return ( 19 |