├── .dockerignore
├── .gitignore
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── assets
├── NftViz.png
├── Search.png
├── arrow.png
├── creator1.png
├── creator10.jpg
├── creator2.png
├── creator3.png
├── creator4.png
├── creator5.png
├── creator6.png
├── creator7.png
├── creator8.png
├── creator9.png
├── cross.png
├── discord.png
├── github.png
├── heart-outline.png
├── heart.png
├── index.js
├── instagram.png
├── left.png
├── loader.gif
├── loader1.gif
├── logo02.png
├── menu.png
├── right.png
├── telegram.png
├── tick.png
├── twitter.png
├── up.png
├── upload.png
└── youtube.png
├── components
├── ActionButtons.jsx
├── Banner.jsx
├── Button.jsx
├── CreatorCard.jsx
├── Footer.jsx
├── Input.jsx
├── Loader.jsx
├── Modal.jsx
├── NFTCard.jsx
├── Navbar.jsx
├── SearchBar.jsx
├── index.js
└── withTransition.jsx
├── context
├── NFTContext.js
├── NFTMarketplace.json
└── constants.js
├── contracts
├── NFTMarketplace.json
└── NFTMarketplace.sol
├── docker-compose.yml
├── hardhat.config.js
├── next.config.js
├── package-lock.json
├── package.json
├── pages
├── _app.js
├── create-nft.js
├── index.js
├── listed-nfts.js
├── my-nfts.js
├── nft-details.js
└── resell-nft.js
├── postcss.config.js
├── public
├── favicon.ico
└── vercel.svg
├── scripts
└── deploy.js
├── styles
└── globals.css
├── tailwind.config.js
├── test
└── sample-test.js
└── utils
└── index.js
/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | .dockerignore
3 | .gitignore
4 | node_modules
5 | npm-debug.log
6 | README.md
7 | .next
8 | .git
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | # next.js
4 | /.next/
5 | /out/
6 |
7 | # production
8 | /build
9 |
10 | # local env files
11 | .secret
12 | .env
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | # vercel
19 | .vercel
20 |
21 | #Hardhat files
22 | cache
23 | artifacts
24 |
25 | #vscode
26 | .vscode
27 |
28 | node_modules
29 | .env
30 | coverage
31 | coverage.json
32 | typechain
33 |
34 | #Hardhat files
35 | cache
36 | artifacts
37 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Specify the base image to use for the container
2 | FROM node:18-alpine
3 |
4 | # Set the working directory to /app in the container
5 | WORKDIR /app
6 |
7 | # Copy all files from the current directory to the /app directory in the container
8 | COPY . /app
9 |
10 | # Copy the package.json and package-lock.json files from the current directory to the /app directory in the container
11 | COPY package.json package-lock.json ./
12 |
13 | # Install dependencies using npm
14 | RUN npm install
15 |
16 | # Copy the next.config.js file from the current directory to the /app directory in the container
17 | COPY next.config.js ./next.config.js
18 |
19 | # Expose port 3000 for the container
20 | EXPOSE 3000
21 |
22 | # Start the development server using npm when the container is run
23 | CMD ["npm", "run", "dev"]
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Kai Everdream
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 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .DEFAULT_GOAL := help
2 |
3 | MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
4 | CURRENT_DIR := $(dir $(MKFILE_PATH))
5 |
6 |
7 | DAPP_CONTAINER := polyplace
8 |
9 | .PHONY: help
10 | help:
11 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
12 |
13 | .PHONY: build-dev
14 | build-dev: ## Makes the static files and adds them to the project
15 | @docker rmi ${DAPP_CONTAINER} || true
16 | @docker build -t ${DAPP_CONTAINER} -f Dockerfile .
17 |
18 | .PHONY: run-dev
19 | run-dev: clean-dev ## Cleans, builds and runs the software on the DEVELOPMENT environment
20 | @docker-compose -p ${DAPP_CONTAINER} up --build -d
21 |
22 | .PHONY: recreate-dev
23 | recreate-dev: clean-dev ## Cleans & recreates everything on the DEVELOPMENT environment
24 | @docker-compose -p ${DAPP_CONTAINER} up --force-recreate -d
25 |
26 | .PHONY: clean-dev
27 | clean-dev: ## Cleans the software from the DEVELOPMENT environment
28 | @docker-compose -p ${DAPP_CONTAINER} down || true
29 |
30 | .PHONY: logs-dev
31 | logs-dev: ## Shows the logs of the DEVELOPMENT environment; CTRL+C to exit
32 | @docker-compose -p ${DAPP_CONTAINER} logs -f
33 |
34 | .PHONY: clean-dev
35 | clean-sso-dev: ## Cleans the software from the DEVELOPMENT environment
36 | @docker stop ${DAPP_CONTAINER} || true
37 | @docker rm ${DAPP_CONTAINER} || true
38 |
39 | .PHONY: purge
40 | purge: ## WARNING! Use this with care. It will stop and remove all containers, volumes, networks, etc
41 | @docker stop $(docker ps -aq) || true
42 | @docker rm $(docker ps -aq) || true
43 | @docker system prune -f && docker volume prune -f && docker network prune -f
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | # Polyplace
8 |
9 | An open decentralized NFT Marketplace built with Solidity and Next.js, powered by Polygon Technologies. It basically is an open platform where users can mint and trade their own NFTs.
10 |
11 |
12 | ## Table of Contents
13 |
14 | - [The Project](#the-project)
15 | - [Developers](#developers)
16 | - [Resources](#resources)
17 |
18 |
19 | ## The Project
20 |
21 | An open platform where users can mint their own NFTs and list them on a Marketplace or buy NFTs from others. It includes:
22 |
23 | - A smart contract which represents a collection of NFTs by following the ERC-721 standard.
24 | - A smart contract which represents the NFT Marketplace and contains all the logic to make offers, execute offers...
25 | - A Next.js front-end application as a user interface.
26 |
27 | `NFTMarketplace` Polygon(Mumbai Testnet) smart contract address:
28 |
29 | https://mumbai.polygonscan.com/address/0xF5f6B924332C350E3Fcd3A50Fc94db822f0B760f
30 |
31 | ### Demo video
32 |
33 | https://www.youtube.com/watch?v=kVIb7MGJ53k&t=36s
34 |
35 | ### Project details
36 |
37 | Users can access the application via web-browser, and must have the Metamask wallet installed. The interface, built with Next.js, relies on the ethers.js library to communicate with the smart contracts through Metamask. This means that the data reflected on the front-end application is fetched from the Polygon blockchain. Each action performed by the user (mint an NFT, sell NFT, buy NFT...) creates a transaction on Polygon, which will require Metamask confirmation and a small fee, and this transaction will permanently modify the state of the NFTMarketplace smart contracts. On top of it, user's NFT Metadata will be uploaded to the IPFS, generating a hash which will be permanently recorded on the blockchain to prove ownership.
38 |
39 | ### Features
40 |
41 | Users can perform the following actions on the NFT Marketplace:
42 |
43 | #### Mint
44 |
45 | Input a name, description and upload a file (image) to mint an NFT. Once minted, a representation of this NFT will be displayed in the marketplace and it will be owned by its creator. This is open for everyone, meaning everyone can participate in this NFT creation through this platform.
46 |
47 | #### Buy NFT
48 |
49 | A user can buy NFTs which someone else offered. This will require paying the requested price and a small fee.
50 |
51 | #### Sell NFT
52 |
53 | Users can sell their NFT by specifying its price (in MATIC). If someone fulfills this offer, then the NFT and its ownership is transferred to the new owner.
54 |
55 | ### Smart Contract Visualization
56 |
57 | Below you can view the current's smart contract functions (and its interactions).
58 |
59 |
60 |
61 |
62 |
63 |
64 | ## Developers
65 |
66 | These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.
67 |
68 | ### Connect to Mumbai Testnet
69 |
70 | First, it is required to install Metamask wallet browser extension: https://metamask.io/
71 |
72 | Next, you need to configure Metamask to connect to the desired blockchain by using the following link: https://chainlist.org/ and add the network of your choice (Mumbai Testnet for now), by simply connecting your wallet from a test address.
73 |
74 | ### Getting test MATIC
75 |
76 | You can get up to 2 test MATIC / day by pasting your address here: https://mumbaifaucet.com/.
77 |
78 | ### Install locally
79 |
80 | First, you will need to `clone` or `fork` the repository into your Github account:
81 |
82 | ```shell
83 | git clone https://github.com/chrisstef/polyplace.git
84 | ```
85 |
86 | Run the following command in your terminal after cloning the main repo:
87 |
88 | ```shell
89 | npm install
90 | ```
91 |
92 | At this point you will be able to run the frontend with:
93 |
94 | ```shell
95 | npm run dev
96 | ```
97 |
98 | ### Install & Run in Docker Environment
99 |
100 | Before you begin, you'll need to have Docker installed on your machine. If you haven't already installed it, you can follow the installation instructions for your operating system on the official Docker website: https://docs.docker.com/get-docker/
101 |
102 | To run the app in a Docker environment, follow these steps:
103 |
104 | - Clone the repository to your local machine.
105 | - Navigate to the root directory of the project in your terminal.
106 | - Run the following command:
107 |
108 | ```sh
109 | docker-compose up --force-recreate
110 | ```
111 |
112 | The `docker-compose up --force-recreate` command starts the container defined in the `docker-compose.yml` file. The `--force-recreate` flag forces recreation of containers even if their configuration appears to be unchanged. This is useful when you want to make sure you are running the latest version of the container.
113 |
114 | This command will start the container and map port `3000` on the container to port `3000` on your local machine. You can access the app by opening http://localhost:3000 in your web browser.
115 |
116 | To stop the container, use `Ctrl + C` in your terminal and run the following command:
117 |
118 | ```sh
119 | docker-compose down
120 | ```
121 |
122 | ### Run with Makefile (Optional)
123 |
124 | `Makefile` provides convenient shortcuts for common tasks(docker instructions in our case). It is a way of automating software building procedure and other complex tasks with dependencies. Make sure you have `Makefile` installed and proceed with the following commands:
125 |
126 | ```shell
127 | ## Cleans, builds and runs the dapp on the DEVELOPMENT environment
128 | make run-dev
129 | ```
130 |
131 | ```shell
132 | ## Cleans & recreates everything on the DEVELOPMENT environment
133 | make recreate-dev
134 | ```
135 |
136 | ```shell
137 | ## Cleans the dapp from the DEVELOPMENT environment
138 | make clean-dev
139 | ```
140 |
141 | To see the list of all the available commands:
142 |
143 | ```shell
144 | make help
145 | ```
146 |
147 | That's it! You now have the `Next.js` app running in a Docker container. You can make changes to the app by modifying the files in the pages directory, and the changes will be automatically reflected in the running container.
148 |
149 | ### Smart Contract development
150 |
151 | Make sure to go through the official Docs: https://hardhat.org/hardhat-runner/docs/getting-started#overview.
152 |
153 | Initialize hardhat by running the following command:
154 |
155 | ```
156 | npx hardhat
157 | ```
158 |
159 | First, you will have to set up a local network by running the following command:
160 |
161 | ```
162 | npx hardhat node
163 | ```
164 |
165 | After you are happy with your changes in `NFTMarketplace.sol` file, compile the smart contract:
166 |
167 | ```
168 | npx hardhat compile
169 | ```
170 |
171 | ### Deployment on Local Blockchain
172 |
173 | Deploy the contracts on your local hardhat network by running the following command:
174 |
175 | ```
176 | npx hardhat run scripts/deploy.js --network localhost
177 | ```
178 |
179 | If all goes well, a new smart contract address refering the NFT Marketplace will be generated. Paste this address in the `constants.js` file.
180 |
181 | Next, remove the argument provided in the `JsonRpcProvider` which is located in the __line 111__ of the `NFTContext.js` file.
182 |
183 | Finally, run the frontend on a new terminal to open the User Interface:
184 |
185 | ```
186 | npm run dev
187 | ```
188 |
189 | A local instance of Polyplace will be up and running on your local environment.
190 |
191 |
192 | ### Tech stack
193 |
194 | - `Solidity`
195 | - `Next.js`
196 | - `hardhat`
197 | - `ethers.js`
198 | - `node.js`
199 | - `Metamask`
200 | - `IPFS`
201 | - `Infura`
202 | - `Alchemy`
203 |
204 | ### Future Ideas
205 |
206 | - Clear deploy on Polygon Mainnet.
207 | - Auction features.
208 | - Bulk upload of NFTs as collections.
209 | - Creator details page.
210 |
211 |
212 | ## Resources
213 |
214 | - [polygon.technology](https://polygon.technology/)
215 | - [Solidity](https://docs.soliditylang.org/en/v0.8.15/)
216 | - [node.js](https://nodejs.org/)
217 | - [ethers.js](https://docs.ethers.io/v5/)
218 | - [next.js](https://nextjs.org/)
219 | - [IPFS](https://ipfs.io/)
220 | - [Infura](https://infura.io/)
221 | - [Alchemy](https://www.alchemy.com/)
222 | - [Vercel](https://vercel.com/docs)
223 |
--------------------------------------------------------------------------------
/assets/NftViz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/NftViz.png
--------------------------------------------------------------------------------
/assets/Search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/Search.png
--------------------------------------------------------------------------------
/assets/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/arrow.png
--------------------------------------------------------------------------------
/assets/creator1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator1.png
--------------------------------------------------------------------------------
/assets/creator10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator10.jpg
--------------------------------------------------------------------------------
/assets/creator2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator2.png
--------------------------------------------------------------------------------
/assets/creator3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator3.png
--------------------------------------------------------------------------------
/assets/creator4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator4.png
--------------------------------------------------------------------------------
/assets/creator5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator5.png
--------------------------------------------------------------------------------
/assets/creator6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator6.png
--------------------------------------------------------------------------------
/assets/creator7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator7.png
--------------------------------------------------------------------------------
/assets/creator8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator8.png
--------------------------------------------------------------------------------
/assets/creator9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/creator9.png
--------------------------------------------------------------------------------
/assets/cross.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/cross.png
--------------------------------------------------------------------------------
/assets/discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/discord.png
--------------------------------------------------------------------------------
/assets/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/github.png
--------------------------------------------------------------------------------
/assets/heart-outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/heart-outline.png
--------------------------------------------------------------------------------
/assets/heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/heart.png
--------------------------------------------------------------------------------
/assets/index.js:
--------------------------------------------------------------------------------
1 | import heartOutline from './heart-outline.png';
2 | import heart from './heart.png';
3 | import search from './Search.png';
4 | import tick from './tick.png';
5 | import cross from './cross.png';
6 | import logo02 from './logo02.png';
7 | import menu from './menu.png';
8 | import discord from './discord.png';
9 | import github from './github.png';
10 | import telegram from './telegram.png';
11 | import twitter from './twitter.png';
12 | import upload from './upload.png';
13 | import creator1 from './creator1.png';
14 | import creator2 from './creator2.png';
15 | import creator3 from './creator3.png';
16 | import creator4 from './creator4.png';
17 | import creator5 from './creator5.png';
18 | import creator6 from './creator6.png';
19 | import creator7 from './creator7.png';
20 | import creator8 from './creator8.png';
21 | import creator9 from './creator9.png';
22 | import creator10 from './creator10.jpg';
23 | import right from './right.png';
24 | import left from './left.png';
25 | import loader from './loader.gif';
26 | import arrow from './arrow.png';
27 | import youtube from './youtube.png';
28 | import up from './up.png';
29 |
30 | export default {
31 | heartOutline,
32 | heart,
33 | search,
34 | tick,
35 | cross,
36 | logo02,
37 | menu,
38 | discord,
39 | github,
40 | telegram,
41 | twitter,
42 | upload,
43 | creator1,
44 | creator2,
45 | creator3,
46 | creator4,
47 | creator5,
48 | creator6,
49 | creator7,
50 | creator8,
51 | creator9,
52 | creator10,
53 | right,
54 | left,
55 | loader,
56 | arrow,
57 | youtube,
58 | up
59 | };
60 |
--------------------------------------------------------------------------------
/assets/instagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/instagram.png
--------------------------------------------------------------------------------
/assets/left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/left.png
--------------------------------------------------------------------------------
/assets/loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/loader.gif
--------------------------------------------------------------------------------
/assets/loader1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/loader1.gif
--------------------------------------------------------------------------------
/assets/logo02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/logo02.png
--------------------------------------------------------------------------------
/assets/menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/menu.png
--------------------------------------------------------------------------------
/assets/right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/right.png
--------------------------------------------------------------------------------
/assets/telegram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/telegram.png
--------------------------------------------------------------------------------
/assets/tick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/tick.png
--------------------------------------------------------------------------------
/assets/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/twitter.png
--------------------------------------------------------------------------------
/assets/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/up.png
--------------------------------------------------------------------------------
/assets/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/upload.png
--------------------------------------------------------------------------------
/assets/youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/assets/youtube.png
--------------------------------------------------------------------------------
/components/ActionButtons.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { BiRefresh, BiLinkExternal, BiCopy } from 'react-icons/bi';
3 | import { MdMoreVert } from 'react-icons/md';
4 |
5 | import { MarketAddress } from '../context/constants';
6 |
7 | const ActionButtons = () => {
8 | const [tooltipText, setTooltipText] = useState('');
9 |
10 | const handleRefresh = () => {
11 | window.location.reload();
12 | setTooltipText('Refreshing...');
13 | };
14 |
15 | const handleExternalLink = () => {
16 | const nftURL = `https://mumbai.polygonscan.com/token/${MarketAddress}?a=121`;
17 | window.open(nftURL, '_blank');
18 | setTooltipText('Redirecting...');
19 | };
20 |
21 | const handleCopyURL = () => {
22 | const currentURL = window.location.href;
23 | navigator.clipboard.writeText(currentURL);
24 | setTooltipText('URL copied!');
25 | };
26 |
27 | const handleMouseLeave = () => {
28 | setTooltipText(''); // Reset the tooltip text when the mouse leaves
29 | };
30 |
31 | const actionItems = [
32 | { icon: , name: "Refresh" },
33 | { icon: , name: "External" },
34 | { icon: , name: "Copy" },
35 | { icon: , name: "More" },
36 | ];
37 |
38 | const iconClassName = 'h-6 w-6 text-gray-500 dark:text-gray-400';
39 |
40 | return (
41 |
42 | {actionItems.map((item) => (
43 |
48 | {React.cloneElement(item.icon, {
49 | className: iconClassName,
50 | onClick: item.icon.props.onClick,
51 | })}
52 |
53 | {tooltipText || item.name}
54 |
55 |
56 | ))}
57 |
58 | );
59 | };
60 |
61 | export default ActionButtons;
62 |
--------------------------------------------------------------------------------
/components/Banner.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Banner = ({ name, childStyles, parentStyles }) => (
4 |
7 | );
8 |
9 | export default Banner;
10 |
--------------------------------------------------------------------------------
/components/Button.jsx:
--------------------------------------------------------------------------------
1 | const Button = ({ btnName, classStyles, handleClick }) => (
2 |
7 | {btnName}
8 |
9 | );
10 |
11 | export default Button;
12 |
--------------------------------------------------------------------------------
/components/CreatorCard.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { motion } from 'framer-motion';
3 | import Image from 'next/image';
4 | import images from '../assets';
5 | import { NFTContext } from '../context/NFTContext';
6 |
7 | const CreatorCard = ({ rank, creatorImage, creatorName, creatorEths }) => {
8 | const { nftCurrency } = useContext(NFTContext);
9 |
10 | const shouldRender = rank <= 10;
11 |
12 | return shouldRender ? (
13 |
19 |
22 |
23 |
29 |
30 | {creatorImage && (
31 |
38 | )}
39 |
40 | {images.tick && (
41 |
47 | )}
48 |
49 |
50 |
51 |
52 |
53 |
54 | {creatorName}
55 |
56 |
57 | {creatorEths.toFixed(2)} {nftCurrency}
58 |
59 |
60 |
61 | ) : null;
62 | };
63 |
64 | export default CreatorCard;
65 |
--------------------------------------------------------------------------------
/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image';
2 | import Link from 'next/link';
3 | import { useTheme } from 'next-themes';
4 |
5 | import images from '../assets';
6 | import Button from './Button';
7 |
8 | const Footer = () => {
9 | const { theme } = useTheme();
10 |
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
Polyplace
21 |
22 |
Get the latest updates
23 |
33 |
34 |
64 |
65 |
66 |
67 |
Polyplace Inc. All Rights Reserved.
68 |
84 |
85 |
86 |
87 | );
88 | };
89 |
90 | export default Footer;
91 |
--------------------------------------------------------------------------------
/components/Input.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 |
3 | import { NFTContext } from '../context/NFTContext';
4 |
5 | const Input = ({ inputType, title, placeholder, handleClick }) => {
6 | const { nftCurrency } = useContext(NFTContext);
7 |
8 | return (
9 |
10 |
{title}
11 |
12 | {inputType === 'number' ? (
13 |
14 |
20 |
{nftCurrency}
21 |
22 | ) : inputType === 'textarea' ? (
23 |
29 | ) : (
30 |
35 | )}
36 |
37 | );
38 | };
39 |
40 | export default Input;
41 |
--------------------------------------------------------------------------------
/components/Loader.jsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image';
2 |
3 | import images from '../assets';
4 |
5 | const Loader = () => (
6 |
7 |
8 |
9 | );
10 |
11 | export default Loader;
12 |
--------------------------------------------------------------------------------
/components/Modal.jsx:
--------------------------------------------------------------------------------
1 | import { useRef } from 'react';
2 | import Image from 'next/image';
3 | import { useTheme } from 'next-themes';
4 |
5 | import images from '../assets';
6 |
7 | const Modal = ({ header, body, footer, handleClose }) => {
8 | const modalRef = useRef(null);
9 | const { theme } = useTheme();
10 |
11 | const handleClickOutside = (e) => {
12 | if (modalRef.current && !modalRef.current.contains(e.target)) {
13 | handleClose();
14 | }
15 | };
16 |
17 | return (
18 |
19 |
20 |
25 |
26 |
{header}
27 |
28 |
29 | {body}
30 |
31 |
32 | {footer}
33 |
34 |
35 |
36 | );
37 | };
38 |
39 | export default Modal;
40 |
--------------------------------------------------------------------------------
/components/NFTCard.jsx:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | import Image from 'next/image';
3 | import Link from 'next/link';
4 | import { NFTContext } from '../context/NFTContext';
5 | import { motion } from 'framer-motion';
6 |
7 | import images from '../assets';
8 | import { shortenAddress } from '../utils/index';
9 | import { shortenPrice } from '../utils/index';
10 | import { shortenName } from '../utils/index';
11 |
12 | const NFTCard = ({ nft, onProfilePage }) => {
13 | const { nftCurrency } = useContext(NFTContext);
14 |
15 | return (
16 |
17 | { }}
20 | onHoverEnd={e => { }}
21 | whileInView={{ opacity: [0, 1] }}
22 | transition={{ duration: 0.2 }}
23 | className="flex-1 min-w-215 max-w-max xs:max-w-none sm:w-full sm:min-w-155 minmd:min-w-256 minlg:min-w-327 dark:bg-nft-black-3 bg-white rounded-2xl p-4 m-4 minlg:m-8 sm:my-2 sm:mx-2 cursor-pointer shadow-md hover:shadow-lg duration-500"
24 | >
25 |
26 |
33 |
34 |
35 |
36 | {nft.name.length > 14 ? shortenName(nft.name) : nft.name}
37 |
38 |
39 |
{nft.price > 100000 ? shortenPrice(nft.price) : nft.price} {nftCurrency}
40 |
{shortenAddress(onProfilePage ? nft.owner : nft.seller)}
41 |
42 |
43 |
44 |
45 | );
46 | };
47 |
48 | export default NFTCard;
49 |
--------------------------------------------------------------------------------
/components/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext } from 'react';
2 |
3 | import { useRouter } from 'next/router';
4 | import { useTheme } from 'next-themes';
5 | import Image from 'next/image';
6 | import Link from 'next/link';
7 |
8 | import { NFTContext } from '../context/NFTContext';
9 |
10 | import images from '../assets';
11 |
12 | import Button from './Button';
13 |
14 | const MenuItems = ({ isMobile, active, setActive, setIsOpen }) => {
15 | const generateLink = (i) => {
16 | switch (i) {
17 | case 0: return '/';
18 | case 1: return '/listed-nfts';
19 | case 2: return '/my-nfts';
20 | default:
21 | break;
22 | }
23 | };
24 |
25 | return (
26 |
27 | {['Explore NFTs', 'Listed NFTs', 'My NFTs'].map((item, i) => (
28 | {
31 | setActive(item);
32 |
33 | if (isMobile) setIsOpen(false);
34 | }}
35 | className={`flex flex-row items-center font-poppins font-semibold text-base dark:hover:text-white hover:text-nft-dark mx-3 transition duration-500
36 | ${active === item
37 | ? 'dark:text-white text-nft-black-1'
38 | : 'dark:text-nft-gray-3 text-nft-gray-2'}
39 | `}
40 | >
41 | {item}
42 |
43 | ))}
44 |
45 | );
46 | };
47 |
48 | const ButtonGroup = ({ setActive, router, setIsOpen }) => {
49 | const { connectWallet, currentAccount } = useContext(NFTContext);
50 |
51 | return currentAccount ? (
52 | {
56 | setActive('');
57 | setIsOpen(false);
58 |
59 | router.push('/create-nft');
60 | }}
61 | />
62 | ) : (
63 |
68 | );
69 | };
70 |
71 | const checkActive = (active, setActive, router) => {
72 | switch (router.pathname) {
73 | case '/':
74 | if (active !== 'Explore NFTs') setActive('Explore NFTs');
75 | break;
76 | case '/listed-nfts':
77 | if (active !== 'Listed NFTs') setActive('Listed NFTs');
78 | break;
79 | case '/my-nfts':
80 | if (active !== 'My NFTs') setActive('My NFTs');
81 | break;
82 | case '/create-nft':
83 | setActive('');
84 | break;
85 |
86 | default:
87 | setActive('');
88 | }
89 | };
90 |
91 | const Navbar = () => {
92 | const { theme, setTheme } = useTheme();
93 | const router = useRouter();
94 | const [active, setActive] = useState('Explore NFTs');
95 | const [isOpen, setIsOpen] = useState(false);
96 |
97 | useEffect(() => {
98 | setTheme('dark');
99 | }, []);
100 |
101 | useEffect(() => {
102 | checkActive(active, setActive, router);
103 | }, [router.pathname]);
104 |
105 | return (
106 |
107 |
108 |
109 |
{
112 | setActive('Explore NFTs');
113 | }}
114 | >
115 |
116 |
Polyplace
117 |
118 |
119 |
120 |
{
123 | setActive('Explore NFTs');
124 | setIsOpen(false);
125 | }}
126 | >
127 |
128 |
129 |
130 |
131 |
132 |
133 |
setTheme(theme === 'light' ? 'dark' : 'light')}
138 | />
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | {isOpen
156 | ? (
157 |
setIsOpen(false)}
164 | className={theme === 'light' ? 'filter invert' : ''}
165 | />
166 | ) : (
167 | setIsOpen(true)}
174 | className={theme === 'light' ? 'filter invert' : ''}
175 | />
176 | )}
177 |
178 | {isOpen && (
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 | )}
188 |
189 |
190 |
191 | );
192 | };
193 |
194 | export default Navbar;
195 |
--------------------------------------------------------------------------------
/components/SearchBar.jsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import Image from 'next/image';
3 |
4 | import { useTheme } from 'next-themes';
5 |
6 | import images from '../assets';
7 |
8 | const SearchBar = ({ activeSelect, setActiveSelect, handleSearch, clearSearch }) => {
9 | const [search, setSearch] = useState('');
10 | const [debouncedSearch, setDebouncedSearch] = useState(search);
11 | const [toggle, setToggle] = useState(false);
12 | const { theme } = useTheme();
13 |
14 | useEffect(() => {
15 | const timer = setTimeout(() => {
16 | setSearch(debouncedSearch);
17 | }, 1000);
18 |
19 | return () => clearTimeout(timer);
20 | }, [debouncedSearch]);
21 |
22 | useEffect(() => {
23 | if (search) {
24 | handleSearch(search);
25 | } else {
26 | clearSearch();
27 | }
28 | }, [search]);
29 |
30 | return (
31 | <>
32 |
33 |
41 | setDebouncedSearch(e.target.value)}
46 | value={debouncedSearch}
47 | />
48 |
49 | setToggle((prevToggle) => !prevToggle)} className="relative flexBetween ml-4 sm:ml-0 sm:mt-2 min-w-190 cursor-pointer dark:bg-nft-black-2 bg-white border dark:border-nft-black-2 border-nft-gray-2 py-3 px-4 rounded-md">
50 |
{activeSelect}
51 |
59 | {toggle && (
60 |
61 | {['Recently Added', 'Price (low to high)', 'Price (high to low)'].map((item) => (
62 |
setActiveSelect(item)}
65 | key={item}
66 | >
67 | {item}
68 |
69 | ))}
70 |
71 | )}
72 |
73 |
74 | >
75 | );
76 | };
77 |
78 | export default SearchBar;
79 |
--------------------------------------------------------------------------------
/components/index.js:
--------------------------------------------------------------------------------
1 | import Navbar from './Navbar';
2 | import Footer from './Footer';
3 | import Button from './Button';
4 | import Banner from './Banner';
5 | import CreatorCard from './CreatorCard';
6 | import NFTCard from './NFTCard';
7 | import Input from './Input';
8 | import Loader from './Loader';
9 | import Modal from './Modal';
10 | import SearchBar from './SearchBar';
11 | import withTransition from './withTransition';
12 | import ActionButtons from './ActionButtons';
13 |
14 | export { Navbar, Footer, Button, Banner, CreatorCard, NFTCard, Input, Loader, Modal, SearchBar, withTransition, ActionButtons };
15 |
--------------------------------------------------------------------------------
/components/withTransition.jsx:
--------------------------------------------------------------------------------
1 | import { motion } from 'framer-motion';
2 |
3 | export default function withTransition(Component) {
4 | return (props) => (
5 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/context/NFTContext.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import Web3Modal from 'web3modal';
3 | import { ethers } from 'ethers';
4 | import axios from 'axios';
5 | import { create as ipfsHttpClient } from 'ipfs-http-client';
6 |
7 | import { MarketAddress, MarketAddressABI } from './constants';
8 |
9 | const subdomainName = 'polyplace';
10 |
11 | const projectId = process.env.NEXT_PUBLIC_IPFS_PROJECT_ID;
12 | const projectSecret = process.env.NEXT_PUBLIC_API_KEY_SECRET;
13 | const auth = `Basic ${Buffer.from(`${projectId}:${projectSecret}`).toString(
14 | 'base64',
15 | )}`;
16 |
17 | const endpointBasePath = `https://${subdomainName}.infura-ipfs.io/ipfs/`;
18 |
19 | const client = ipfsHttpClient({
20 | host: 'ipfs.infura.io',
21 | port: 5001,
22 | protocol: 'https',
23 | headers: {
24 | authorization: auth,
25 | },
26 | });
27 |
28 | const fetchContract = (signerOrProvider) => new ethers.Contract(MarketAddress, MarketAddressABI, signerOrProvider);
29 |
30 | export const NFTContext = React.createContext();
31 |
32 | export const NFTProvider = ({ children }) => {
33 | const nftCurrency = 'MATIC';
34 | const [currentAccount, setCurrentAccount] = useState('');
35 | const [isLoadingNFT, setIsLoadingNFT] = useState(false);
36 |
37 | const checkIfWalletIsConnect = async () => {
38 | if (!window.ethereum) return alert('Please install MetaMask.');
39 |
40 | const accounts = await window.ethereum.request({ method: 'eth_accounts' });
41 | if (accounts.length) {
42 | setCurrentAccount(accounts[0]);
43 | } else {
44 | console.log('No accounts found');
45 | }
46 | };
47 |
48 | useEffect(() => {
49 | checkIfWalletIsConnect();
50 | }, []);
51 |
52 | const connectWallet = async () => {
53 | if (!window.ethereum) return alert('Please install MetaMask.');
54 |
55 | const accounts = await window.ethereum.request({
56 | method: 'eth_requestAccounts',
57 | });
58 |
59 | setCurrentAccount(accounts[0]);
60 | window.location.reload();
61 | };
62 |
63 | const uploadToIPFS = async (file) => {
64 | try {
65 | const added = await client.add({ content: file });
66 |
67 | const url = `${endpointBasePath}/${added.path}`;
68 |
69 | console.log(`Upload to IPFS url: ${url}`);
70 |
71 | return url;
72 | } catch (error) {
73 | console.log('error uploading file');
74 | }
75 | };
76 |
77 | const createSale = async (url, formInputPrice, isReselling, id) => {
78 | const web3Modal = new Web3Modal();
79 | const connection = await web3Modal.connect();
80 | const provider = new ethers.providers.Web3Provider(connection);
81 | const signer = provider.getSigner();
82 |
83 | const price = ethers.utils.parseUnits(formInputPrice, 'ether');
84 | const contract = fetchContract(signer);
85 | const listingPrice = await contract.getListingPrice();
86 |
87 | const transaction = !isReselling
88 | ? await contract.createToken(url, price, {
89 | value: listingPrice.toString(),
90 | })
91 | : await contract.resellToken(id, price, {
92 | value: listingPrice.toString(),
93 | });
94 |
95 | setIsLoadingNFT(true);
96 | await transaction.wait();
97 | };
98 |
99 | const createNFT = async (formInput, fileUrl, router) => {
100 | const { name, description, price } = formInput;
101 |
102 | if (!name || !description || !price || !fileUrl) return;
103 |
104 | const data = JSON.stringify({ name, description, image: fileUrl });
105 |
106 | try {
107 | const added = await client.add(data);
108 | const url = endpointBasePath + added.path;
109 |
110 | console.log(`Created NFT url: ${url}`);
111 |
112 | await createSale(url, price);
113 |
114 | router.push('/');
115 | } catch (error) {
116 | console.log('error uploading file');
117 | }
118 | };
119 |
120 | const fetchNFTs = async () => {
121 | setIsLoadingNFT(false);
122 | const provider = new ethers.providers.AlchemyProvider(
123 | 'maticmum',
124 | process.env.NEXT_PUBLIC_API_KEY,
125 | );
126 | const contract = fetchContract(provider);
127 | const data = await contract.fetchMarketItems();
128 |
129 | const items = await Promise.all(
130 | data.map(async ({ tokenId, seller, owner, price: unformattedPrice }) => {
131 | const tokenURI = await contract.tokenURI(tokenId);
132 | console.log('data', tokenURI);
133 | try {
134 | const { data: { image, name, description } } = await axios.get(tokenURI);
135 | const price = ethers.utils.formatUnits(unformattedPrice.toString(), 'ether');
136 |
137 | // return an object with relevant properties
138 | return {
139 | price,
140 | tokenId: tokenId.toNumber(),
141 | seller,
142 | owner,
143 | image,
144 | name,
145 | description,
146 | tokenURI,
147 | };
148 | } catch (error) {
149 | if (error.response && error.response.status === 404) {
150 | // handle 404 error here
151 | console.log('Token URI not found.');
152 | return null;
153 | }
154 | // handle other errors here
155 | console.error(error);
156 | return null;
157 | }
158 | }),
159 | );
160 |
161 | return items;
162 | };
163 |
164 | const fetchMyNFTsOrListedNFTs = async (type) => {
165 | setIsLoadingNFT(false);
166 | const web3Modal = new Web3Modal();
167 | const connection = await web3Modal.connect();
168 | const provider = new ethers.providers.Web3Provider(connection);
169 | const signer = provider.getSigner();
170 |
171 | const contract = fetchContract(signer);
172 | const data = type === 'fetchItemsListed'
173 | ? await contract.fetchItemsListed()
174 | : await contract.fetchMyNFTs();
175 |
176 | const items = await Promise.all(
177 | data.map(async ({ tokenId, seller, owner, price: unformattedPrice }) => {
178 | const tokenURI = await contract.tokenURI(tokenId);
179 | const {
180 | data: { image, name, description },
181 | } = await axios.get(tokenURI);
182 | const price = ethers.utils.formatUnits(
183 | unformattedPrice.toString(),
184 | 'ether',
185 | );
186 |
187 | return {
188 | price,
189 | tokenId: tokenId.toNumber(),
190 | seller,
191 | owner,
192 | image,
193 | name,
194 | description,
195 | tokenURI,
196 | };
197 | }),
198 | );
199 | return items;
200 | };
201 |
202 | const buyNft = async (nft) => {
203 | const web3Modal = new Web3Modal();
204 | const connection = await web3Modal.connect();
205 | const provider = new ethers.providers.Web3Provider(connection);
206 | const signer = provider.getSigner();
207 | const contract = new ethers.Contract(
208 | MarketAddress,
209 | MarketAddressABI,
210 | signer,
211 | );
212 |
213 | const price = ethers.utils.parseUnits(nft.price.toString(), 'ether');
214 | const transaction = await contract.createMarketSale(nft.tokenId, {
215 | value: price,
216 | });
217 |
218 | setIsLoadingNFT(true);
219 | await transaction.wait();
220 | setIsLoadingNFT(false);
221 | };
222 |
223 | return (
224 |
238 | {children}
239 |
240 | );
241 | };
242 |
--------------------------------------------------------------------------------
/context/NFTMarketplace.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "NFTMarketplace",
4 | "sourceName": "contracts/NFTMarketplace.sol",
5 | "abi": [
6 | {
7 | "inputs": [],
8 | "stateMutability": "nonpayable",
9 | "type": "constructor"
10 | },
11 | {
12 | "anonymous": false,
13 | "inputs": [
14 | {
15 | "indexed": true,
16 | "internalType": "address",
17 | "name": "owner",
18 | "type": "address"
19 | },
20 | {
21 | "indexed": true,
22 | "internalType": "address",
23 | "name": "approved",
24 | "type": "address"
25 | },
26 | {
27 | "indexed": true,
28 | "internalType": "uint256",
29 | "name": "tokenId",
30 | "type": "uint256"
31 | }
32 | ],
33 | "name": "Approval",
34 | "type": "event"
35 | },
36 | {
37 | "anonymous": false,
38 | "inputs": [
39 | {
40 | "indexed": true,
41 | "internalType": "address",
42 | "name": "owner",
43 | "type": "address"
44 | },
45 | {
46 | "indexed": true,
47 | "internalType": "address",
48 | "name": "operator",
49 | "type": "address"
50 | },
51 | {
52 | "indexed": false,
53 | "internalType": "bool",
54 | "name": "approved",
55 | "type": "bool"
56 | }
57 | ],
58 | "name": "ApprovalForAll",
59 | "type": "event"
60 | },
61 | {
62 | "anonymous": false,
63 | "inputs": [
64 | {
65 | "indexed": true,
66 | "internalType": "uint256",
67 | "name": "tokenId",
68 | "type": "uint256"
69 | },
70 | {
71 | "indexed": false,
72 | "internalType": "address",
73 | "name": "seller",
74 | "type": "address"
75 | },
76 | {
77 | "indexed": false,
78 | "internalType": "address",
79 | "name": "owner",
80 | "type": "address"
81 | },
82 | {
83 | "indexed": false,
84 | "internalType": "uint256",
85 | "name": "price",
86 | "type": "uint256"
87 | },
88 | {
89 | "indexed": false,
90 | "internalType": "bool",
91 | "name": "sold",
92 | "type": "bool"
93 | }
94 | ],
95 | "name": "MarketItemCreated",
96 | "type": "event"
97 | },
98 | {
99 | "anonymous": false,
100 | "inputs": [
101 | {
102 | "indexed": true,
103 | "internalType": "address",
104 | "name": "from",
105 | "type": "address"
106 | },
107 | {
108 | "indexed": true,
109 | "internalType": "address",
110 | "name": "to",
111 | "type": "address"
112 | },
113 | {
114 | "indexed": true,
115 | "internalType": "uint256",
116 | "name": "tokenId",
117 | "type": "uint256"
118 | }
119 | ],
120 | "name": "Transfer",
121 | "type": "event"
122 | },
123 | {
124 | "inputs": [
125 | {
126 | "internalType": "address",
127 | "name": "to",
128 | "type": "address"
129 | },
130 | {
131 | "internalType": "uint256",
132 | "name": "tokenId",
133 | "type": "uint256"
134 | }
135 | ],
136 | "name": "approve",
137 | "outputs": [],
138 | "stateMutability": "nonpayable",
139 | "type": "function"
140 | },
141 | {
142 | "inputs": [
143 | {
144 | "internalType": "address",
145 | "name": "owner",
146 | "type": "address"
147 | }
148 | ],
149 | "name": "balanceOf",
150 | "outputs": [
151 | {
152 | "internalType": "uint256",
153 | "name": "",
154 | "type": "uint256"
155 | }
156 | ],
157 | "stateMutability": "view",
158 | "type": "function"
159 | },
160 | {
161 | "inputs": [
162 | {
163 | "internalType": "uint256",
164 | "name": "tokenId",
165 | "type": "uint256"
166 | }
167 | ],
168 | "name": "createMarketSale",
169 | "outputs": [],
170 | "stateMutability": "payable",
171 | "type": "function"
172 | },
173 | {
174 | "inputs": [
175 | {
176 | "internalType": "string",
177 | "name": "tokenURI",
178 | "type": "string"
179 | },
180 | {
181 | "internalType": "uint256",
182 | "name": "price",
183 | "type": "uint256"
184 | }
185 | ],
186 | "name": "createToken",
187 | "outputs": [
188 | {
189 | "internalType": "uint256",
190 | "name": "",
191 | "type": "uint256"
192 | }
193 | ],
194 | "stateMutability": "payable",
195 | "type": "function"
196 | },
197 | {
198 | "inputs": [],
199 | "name": "fetchItemsListed",
200 | "outputs": [
201 | {
202 | "components": [
203 | {
204 | "internalType": "uint256",
205 | "name": "tokenId",
206 | "type": "uint256"
207 | },
208 | {
209 | "internalType": "address payable",
210 | "name": "seller",
211 | "type": "address"
212 | },
213 | {
214 | "internalType": "address payable",
215 | "name": "owner",
216 | "type": "address"
217 | },
218 | {
219 | "internalType": "uint256",
220 | "name": "price",
221 | "type": "uint256"
222 | },
223 | {
224 | "internalType": "bool",
225 | "name": "sold",
226 | "type": "bool"
227 | }
228 | ],
229 | "internalType": "struct NFTMarketplace.MarketItem[]",
230 | "name": "",
231 | "type": "tuple[]"
232 | }
233 | ],
234 | "stateMutability": "view",
235 | "type": "function"
236 | },
237 | {
238 | "inputs": [],
239 | "name": "fetchMarketItems",
240 | "outputs": [
241 | {
242 | "components": [
243 | {
244 | "internalType": "uint256",
245 | "name": "tokenId",
246 | "type": "uint256"
247 | },
248 | {
249 | "internalType": "address payable",
250 | "name": "seller",
251 | "type": "address"
252 | },
253 | {
254 | "internalType": "address payable",
255 | "name": "owner",
256 | "type": "address"
257 | },
258 | {
259 | "internalType": "uint256",
260 | "name": "price",
261 | "type": "uint256"
262 | },
263 | {
264 | "internalType": "bool",
265 | "name": "sold",
266 | "type": "bool"
267 | }
268 | ],
269 | "internalType": "struct NFTMarketplace.MarketItem[]",
270 | "name": "",
271 | "type": "tuple[]"
272 | }
273 | ],
274 | "stateMutability": "view",
275 | "type": "function"
276 | },
277 | {
278 | "inputs": [],
279 | "name": "fetchMyNFTs",
280 | "outputs": [
281 | {
282 | "components": [
283 | {
284 | "internalType": "uint256",
285 | "name": "tokenId",
286 | "type": "uint256"
287 | },
288 | {
289 | "internalType": "address payable",
290 | "name": "seller",
291 | "type": "address"
292 | },
293 | {
294 | "internalType": "address payable",
295 | "name": "owner",
296 | "type": "address"
297 | },
298 | {
299 | "internalType": "uint256",
300 | "name": "price",
301 | "type": "uint256"
302 | },
303 | {
304 | "internalType": "bool",
305 | "name": "sold",
306 | "type": "bool"
307 | }
308 | ],
309 | "internalType": "struct NFTMarketplace.MarketItem[]",
310 | "name": "",
311 | "type": "tuple[]"
312 | }
313 | ],
314 | "stateMutability": "view",
315 | "type": "function"
316 | },
317 | {
318 | "inputs": [
319 | {
320 | "internalType": "uint256",
321 | "name": "tokenId",
322 | "type": "uint256"
323 | }
324 | ],
325 | "name": "getApproved",
326 | "outputs": [
327 | {
328 | "internalType": "address",
329 | "name": "",
330 | "type": "address"
331 | }
332 | ],
333 | "stateMutability": "view",
334 | "type": "function"
335 | },
336 | {
337 | "inputs": [],
338 | "name": "getListingPrice",
339 | "outputs": [
340 | {
341 | "internalType": "uint256",
342 | "name": "",
343 | "type": "uint256"
344 | }
345 | ],
346 | "stateMutability": "view",
347 | "type": "function"
348 | },
349 | {
350 | "inputs": [
351 | {
352 | "internalType": "address",
353 | "name": "owner",
354 | "type": "address"
355 | },
356 | {
357 | "internalType": "address",
358 | "name": "operator",
359 | "type": "address"
360 | }
361 | ],
362 | "name": "isApprovedForAll",
363 | "outputs": [
364 | {
365 | "internalType": "bool",
366 | "name": "",
367 | "type": "bool"
368 | }
369 | ],
370 | "stateMutability": "view",
371 | "type": "function"
372 | },
373 | {
374 | "inputs": [],
375 | "name": "name",
376 | "outputs": [
377 | {
378 | "internalType": "string",
379 | "name": "",
380 | "type": "string"
381 | }
382 | ],
383 | "stateMutability": "view",
384 | "type": "function"
385 | },
386 | {
387 | "inputs": [
388 | {
389 | "internalType": "uint256",
390 | "name": "tokenId",
391 | "type": "uint256"
392 | }
393 | ],
394 | "name": "ownerOf",
395 | "outputs": [
396 | {
397 | "internalType": "address",
398 | "name": "",
399 | "type": "address"
400 | }
401 | ],
402 | "stateMutability": "view",
403 | "type": "function"
404 | },
405 | {
406 | "inputs": [
407 | {
408 | "internalType": "uint256",
409 | "name": "tokenId",
410 | "type": "uint256"
411 | },
412 | {
413 | "internalType": "uint256",
414 | "name": "price",
415 | "type": "uint256"
416 | }
417 | ],
418 | "name": "resellToken",
419 | "outputs": [],
420 | "stateMutability": "payable",
421 | "type": "function"
422 | },
423 | {
424 | "inputs": [
425 | {
426 | "internalType": "address",
427 | "name": "from",
428 | "type": "address"
429 | },
430 | {
431 | "internalType": "address",
432 | "name": "to",
433 | "type": "address"
434 | },
435 | {
436 | "internalType": "uint256",
437 | "name": "tokenId",
438 | "type": "uint256"
439 | }
440 | ],
441 | "name": "safeTransferFrom",
442 | "outputs": [],
443 | "stateMutability": "nonpayable",
444 | "type": "function"
445 | },
446 | {
447 | "inputs": [
448 | {
449 | "internalType": "address",
450 | "name": "from",
451 | "type": "address"
452 | },
453 | {
454 | "internalType": "address",
455 | "name": "to",
456 | "type": "address"
457 | },
458 | {
459 | "internalType": "uint256",
460 | "name": "tokenId",
461 | "type": "uint256"
462 | },
463 | {
464 | "internalType": "bytes",
465 | "name": "_data",
466 | "type": "bytes"
467 | }
468 | ],
469 | "name": "safeTransferFrom",
470 | "outputs": [],
471 | "stateMutability": "nonpayable",
472 | "type": "function"
473 | },
474 | {
475 | "inputs": [
476 | {
477 | "internalType": "address",
478 | "name": "operator",
479 | "type": "address"
480 | },
481 | {
482 | "internalType": "bool",
483 | "name": "approved",
484 | "type": "bool"
485 | }
486 | ],
487 | "name": "setApprovalForAll",
488 | "outputs": [],
489 | "stateMutability": "nonpayable",
490 | "type": "function"
491 | },
492 | {
493 | "inputs": [
494 | {
495 | "internalType": "bytes4",
496 | "name": "interfaceId",
497 | "type": "bytes4"
498 | }
499 | ],
500 | "name": "supportsInterface",
501 | "outputs": [
502 | {
503 | "internalType": "bool",
504 | "name": "",
505 | "type": "bool"
506 | }
507 | ],
508 | "stateMutability": "view",
509 | "type": "function"
510 | },
511 | {
512 | "inputs": [],
513 | "name": "symbol",
514 | "outputs": [
515 | {
516 | "internalType": "string",
517 | "name": "",
518 | "type": "string"
519 | }
520 | ],
521 | "stateMutability": "view",
522 | "type": "function"
523 | },
524 | {
525 | "inputs": [
526 | {
527 | "internalType": "uint256",
528 | "name": "tokenId",
529 | "type": "uint256"
530 | }
531 | ],
532 | "name": "tokenURI",
533 | "outputs": [
534 | {
535 | "internalType": "string",
536 | "name": "",
537 | "type": "string"
538 | }
539 | ],
540 | "stateMutability": "view",
541 | "type": "function"
542 | },
543 | {
544 | "inputs": [
545 | {
546 | "internalType": "address",
547 | "name": "from",
548 | "type": "address"
549 | },
550 | {
551 | "internalType": "address",
552 | "name": "to",
553 | "type": "address"
554 | },
555 | {
556 | "internalType": "uint256",
557 | "name": "tokenId",
558 | "type": "uint256"
559 | }
560 | ],
561 | "name": "transferFrom",
562 | "outputs": [],
563 | "stateMutability": "nonpayable",
564 | "type": "function"
565 | },
566 | {
567 | "inputs": [
568 | {
569 | "internalType": "uint256",
570 | "name": "_listingPrice",
571 | "type": "uint256"
572 | }
573 | ],
574 | "name": "updateListingPrice",
575 | "outputs": [],
576 | "stateMutability": "payable",
577 | "type": "function"
578 | }
579 | ],
580 | "bytecode": "0x60806040526658d15e176280006009553480156200001c57600080fd5b506040518060400160405280600d81526020017f506f6c79706c61636520496e63000000000000000000000000000000000000008152506040518060400160405280600481526020017f504f4c59000000000000000000000000000000000000000000000000000000008152508160009080519060200190620000a192919062000104565b508060019080519060200190620000ba92919062000104565b50505033600a60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555062000219565b8280546200011290620001b4565b90600052602060002090601f01602090048101928262000136576000855562000182565b82601f106200015157805160ff191683800117855562000182565b8280016001018555821562000182579182015b828111156200018157825182559160200191906001019062000164565b5b50905062000191919062000195565b5090565b5b80821115620001b057600081600090555060010162000196565b5090565b60006002820490506001821680620001cd57607f821691505b60208210811415620001e457620001e3620001ea565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b61435c80620002296000396000f3fe60806040526004361061012a5760003560e01c80636352211e116100ab578063ae677aa31161006f578063ae677aa3146103f9578063b88d4fde14610415578063be9af5361461043e578063c87b56dd1461045a578063e219fc7514610497578063e985e9c5146104b35761012a565b80636352211e146102fb57806370a082311461033857806372b3b6201461037557806395d89b41146103a5578063a22cb465146103d05761012a565b806312e85585116100f257806312e8558514610228578063202e37401461025357806323b872dd1461027e57806342842e0e146102a757806345f8fa80146102d05761012a565b806301ffc9a71461012f57806306fdde031461016c578063081812fc14610197578063095ea7b3146101d45780630f08efe0146101fd575b600080fd5b34801561013b57600080fd5b5061015660048036038101906101519190612e9c565b6104f0565b6040516101639190613576565b60405180910390f35b34801561017857600080fd5b506101816105d2565b60405161018e9190613591565b60405180910390f35b3480156101a357600080fd5b506101be60048036038101906101b99190612f42565b610664565b6040516101cb91906134a8565b60405180910390f35b3480156101e057600080fd5b506101fb60048036038101906101f69190612e60565b6106e9565b005b34801561020957600080fd5b50610212610801565b60405161021f9190613554565b60405180910390f35b34801561023457600080fd5b5061023d610ab6565b60405161024a9190613873565b60405180910390f35b34801561025f57600080fd5b50610268610ac0565b6040516102759190613554565b60405180910390f35b34801561028a57600080fd5b506102a560048036038101906102a09190612d5a565b610dfa565b005b3480156102b357600080fd5b506102ce60048036038101906102c99190612d5a565b610e5a565b005b3480156102dc57600080fd5b506102e5610e7a565b6040516102f29190613554565b60405180910390f35b34801561030757600080fd5b50610322600480360381019061031d9190612f42565b6111b4565b60405161032f91906134a8565b60405180910390f35b34801561034457600080fd5b5061035f600480360381019061035a9190612cf5565b611266565b60405161036c9190613873565b60405180910390f35b61038f600480360381019061038a9190612eee565b61131e565b60405161039c9190613873565b60405180910390f35b3480156103b157600080fd5b506103ba611360565b6040516103c79190613591565b60405180910390f35b3480156103dc57600080fd5b506103f760048036038101906103f29190612e24565b6113f2565b005b610413600480360381019061040e9190612f42565b611408565b005b34801561042157600080fd5b5061043c60048036038101906104379190612da9565b6114a2565b005b61045860048036038101906104539190612f42565b611504565b005b34801561046657600080fd5b50610481600480360381019061047c9190612f42565b61173c565b60405161048e9190613591565b60405180910390f35b6104b160048036038101906104ac9190612f6b565b61188e565b005b3480156104bf57600080fd5b506104da60048036038101906104d59190612d1e565b611a83565b6040516104e79190613576565b60405180910390f35b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806105bb57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806105cb57506105ca82611b17565b5b9050919050565b6060600080546105e190613b14565b80601f016020809104026020016040519081016040528092919081815260200182805461060d90613b14565b801561065a5780601f1061062f5761010080835404028352916020019161065a565b820191906000526020600020905b81548152906001019060200180831161063d57829003601f168201915b5050505050905090565b600061066f82611b81565b6106ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a590613793565b60405180910390fd5b6004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006106f4826111b4565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161075c906137d3565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610784611bed565b73ffffffffffffffffffffffffffffffffffffffff1614806107b357506107b2816107ad611bed565b611a83565b5b6107f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e990613693565b60405180910390fd5b6107fc8383611bf5565b505050565b6060600061080f6007611cae565b9050600061081d6008611cae565b6108276007611cae565b6108319190613a18565b90506000808267ffffffffffffffff811115610876577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156108af57816020015b61089c612abc565b8152602001906001900390816108945790505b50905060005b84811015610aab573073ffffffffffffffffffffffffffffffffffffffff16600b60006001846108e59190613991565b815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610a985760006001826109429190613991565b90506000600b60008381526020019081526020016000209050806040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820160009054906101000a900460ff161515151581525050848681518110610a7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250600185610a939190613991565b945050505b8080610aa390613b77565b9150506108b5565b508094505050505090565b6000600954905090565b60606000610ace6007611cae565b905060008060005b83811015610b77573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610b069190613991565b815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610b6457600183610b619190613991565b92505b8080610b6f90613b77565b915050610ad6565b5060008267ffffffffffffffff811115610bba577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610bf357816020015b610be0612abc565b815260200190600190039081610bd85790505b50905060005b84811015610def573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610c299190613991565b815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610ddc576000600182610c869190613991565b90506000600b60008381526020019081526020016000209050806040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820160009054906101000a900460ff161515151581525050848681518110610dbf577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250600185610dd79190613991565b945050505b8080610de790613b77565b915050610bf9565b508094505050505090565b610e0b610e05611bed565b82611cbc565b610e4a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4190613813565b60405180910390fd5b610e55838383611d9a565b505050565b610e75838383604051806020016040528060008152506114a2565b505050565b60606000610e886007611cae565b905060008060005b83811015610f31573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610ec09190613991565b815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610f1e57600183610f1b9190613991565b92505b8080610f2990613b77565b915050610e90565b5060008267ffffffffffffffff811115610f74577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610fad57816020015b610f9a612abc565b815260200190600190039081610f925790505b50905060005b848110156111a9573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610fe39190613991565b815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156111965760006001826110409190613991565b90506000600b60008381526020019081526020016000209050806040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820160009054906101000a900460ff161515151581525050848681518110611179577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101819052506001856111919190613991565b945050505b80806111a190613b77565b915050610fb3565b508094505050505090565b6000806002600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561125d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611254906136d3565b60405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156112d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ce906136b3565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600061132a6007612001565b60006113366007611cae565b90506113423382612017565b61134c81856121f1565b6113568184612265565b8091505092915050565b60606001805461136f90613b14565b80601f016020809104026020016040519081016040528092919081815260200182805461139b90613b14565b80156113e85780601f106113bd576101008083540402835291602001916113e8565b820191906000526020600020905b8154815290600101906020018083116113cb57829003601f168201915b5050505050905090565b6114046113fd611bed565b8383612468565b5050565b3373ffffffffffffffffffffffffffffffffffffffff16600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161148f90613833565b60405180910390fd5b8060098190555050565b6114b36114ad611bed565b83611cbc565b6114f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e990613813565b60405180910390fd5b6114fe848484846125d5565b50505050565b6000600b6000838152602001908152602001600020600301549050803414611561576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155890613713565b60405180910390fd5b33600b600084815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600b600084815260200190815260200160002060040160006101000a81548160ff0219169083151502179055506000600b600084815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506116456008612001565b611650303384611d9a565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc6009549081150290604051600060405180830381858888f193505050501580156116ba573d6000803e3d6000fd5b50600b600083815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015611737573d6000803e3d6000fd5b505050565b606061174782611b81565b611786576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177d90613753565b60405180910390fd5b60006006600084815260200190815260200160002080546117a690613b14565b80601f01602080910402602001604051908101604052809291908181526020018280546117d290613b14565b801561181f5780601f106117f45761010080835404028352916020019161181f565b820191906000526020600020905b81548152906001019060200180831161180257829003601f168201915b505050505090506000611830612631565b9050600081511415611846578192505050611889565b60008251111561187b578082604051602001611863929190613484565b60405160208183030381529060405292505050611889565b61188484612648565b925050505b919050565b3373ffffffffffffffffffffffffffffffffffffffff16600b600084815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611932576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161192990613773565b60405180910390fd5b6009543414611976576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161196d906137f3565b60405180910390fd5b6000600b600084815260200190815260200160002060040160006101000a81548160ff02191690831515021790555080600b60008481526020019081526020016000206003018190555033600b600084815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555030600b600084815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611a7460086126ef565b611a7f333084611d9a565b5050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60008073ffffffffffffffffffffffffffffffffffffffff166002600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614159050919050565b600033905090565b816004600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16611c68836111b4565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600081600001549050919050565b6000611cc782611b81565b611d06576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cfd90613673565b60405180910390fd5b6000611d11836111b4565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611d8057508373ffffffffffffffffffffffffffffffffffffffff16611d6884610664565b73ffffffffffffffffffffffffffffffffffffffff16145b80611d915750611d908185611a83565b5b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff16611dba826111b4565b73ffffffffffffffffffffffffffffffffffffffff1614611e10576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e07906135f3565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611e80576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e7790613633565b60405180910390fd5b611e8b83838361274b565b611e96600082611bf5565b6001600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611ee69190613a18565b925050819055506001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611f3d9190613991565b92505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4611ffc838383612750565b505050565b6001816000016000828254019250508190555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612087576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161207e90613733565b60405180910390fd5b61209081611b81565b156120d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c790613613565b60405180910390fd5b6120dc6000838361274b565b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461212c9190613991565b92505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46121ed60008383612750565b5050565b6121fa82611b81565b612239576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612230906136f3565b60405180910390fd5b80600660008481526020019081526020016000209080519060200190612260929190612b19565b505050565b600081116122a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229f90613853565b60405180910390fd5b60095434146122ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122e3906137f3565b60405180910390fd5b6040518060a001604052808381526020013373ffffffffffffffffffffffffffffffffffffffff1681526020013073ffffffffffffffffffffffffffffffffffffffff16815260200182815260200160001515815250600b60008481526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506060820151816003015560808201518160040160006101000a81548160ff021916908315150217905550905050612425333084611d9a565b817fb640004f1d14576d0c209e240cad0410e0d8c0c33a09375861fbadae2588a98d333084600060405161245c94939291906134c3565b60405180910390a25050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156124d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ce90613653565b60405180910390fd5b80600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516125c89190613576565b60405180910390a3505050565b6125e0848484611d9a565b6125ec84848484612755565b61262b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612622906135d3565b60405180910390fd5b50505050565b606060405180602001604052806000815250905090565b606061265382611b81565b612692576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612689906137b3565b60405180910390fd5b600061269c612631565b905060008151116126bc57604051806020016040528060008152506126e7565b806126c6846128ec565b6040516020016126d7929190613484565b6040516020818303038152906040525b915050919050565b6000816000015490506000811161273b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612732906135b3565b60405180910390fd5b6001810382600001819055505050565b505050565b505050565b60006127768473ffffffffffffffffffffffffffffffffffffffff16612a99565b156128df578373ffffffffffffffffffffffffffffffffffffffff1663150b7a0261279f611bed565b8786866040518563ffffffff1660e01b81526004016127c19493929190613508565b602060405180830381600087803b1580156127db57600080fd5b505af192505050801561280c57506040513d601f19601f820116820180604052508101906128099190612ec5565b60015b61288f573d806000811461283c576040519150601f19603f3d011682016040523d82523d6000602084013e612841565b606091505b50600081511415612887576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161287e906135d3565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150506128e4565b600190505b949350505050565b60606000821415612934576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050612a94565b600082905060005b6000821461296657808061294f90613b77565b915050600a8261295f91906139e7565b915061293c565b60008167ffffffffffffffff8111156129a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f1916602001820160405280156129da5781602001600182028036833780820191505090505b5090505b60008514612a8d576001826129f39190613a18565b9150600a85612a029190613bc0565b6030612a0e9190613991565b60f81b818381518110612a4a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a85612a8691906139e7565b94506129de565b8093505050505b919050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6040518060a0016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000151581525090565b828054612b2590613b14565b90600052602060002090601f016020900481019282612b475760008555612b8e565b82601f10612b6057805160ff1916838001178555612b8e565b82800160010185558215612b8e579182015b82811115612b8d578251825591602001919060010190612b72565b5b509050612b9b9190612b9f565b5090565b5b80821115612bb8576000816000905550600101612ba0565b5090565b6000612bcf612bca846138b3565b61388e565b905082815260208101848484011115612be757600080fd5b612bf2848285613ad2565b509392505050565b6000612c0d612c08846138e4565b61388e565b905082815260208101848484011115612c2557600080fd5b612c30848285613ad2565b509392505050565b600081359050612c47816142ca565b92915050565b600081359050612c5c816142e1565b92915050565b600081359050612c71816142f8565b92915050565b600081519050612c86816142f8565b92915050565b600082601f830112612c9d57600080fd5b8135612cad848260208601612bbc565b91505092915050565b600082601f830112612cc757600080fd5b8135612cd7848260208601612bfa565b91505092915050565b600081359050612cef8161430f565b92915050565b600060208284031215612d0757600080fd5b6000612d1584828501612c38565b91505092915050565b60008060408385031215612d3157600080fd5b6000612d3f85828601612c38565b9250506020612d5085828601612c38565b9150509250929050565b600080600060608486031215612d6f57600080fd5b6000612d7d86828701612c38565b9350506020612d8e86828701612c38565b9250506040612d9f86828701612ce0565b9150509250925092565b60008060008060808587031215612dbf57600080fd5b6000612dcd87828801612c38565b9450506020612dde87828801612c38565b9350506040612def87828801612ce0565b925050606085013567ffffffffffffffff811115612e0c57600080fd5b612e1887828801612c8c565b91505092959194509250565b60008060408385031215612e3757600080fd5b6000612e4585828601612c38565b9250506020612e5685828601612c4d565b9150509250929050565b60008060408385031215612e7357600080fd5b6000612e8185828601612c38565b9250506020612e9285828601612ce0565b9150509250929050565b600060208284031215612eae57600080fd5b6000612ebc84828501612c62565b91505092915050565b600060208284031215612ed757600080fd5b6000612ee584828501612c77565b91505092915050565b60008060408385031215612f0157600080fd5b600083013567ffffffffffffffff811115612f1b57600080fd5b612f2785828601612cb6565b9250506020612f3885828601612ce0565b9150509250929050565b600060208284031215612f5457600080fd5b6000612f6284828501612ce0565b91505092915050565b60008060408385031215612f7e57600080fd5b6000612f8c85828601612ce0565b9250506020612f9d85828601612ce0565b9150509250929050565b6000612fb383836133fe565b60a08301905092915050565b612fc881613a5e565b82525050565b612fd781613a4c565b82525050565b6000612fe882613925565b612ff28185613953565b9350612ffd83613915565b8060005b8381101561302e5781516130158882612fa7565b975061302083613946565b925050600181019050613001565b5085935050505092915050565b61304481613a70565b82525050565b61305381613a70565b82525050565b600061306482613930565b61306e8185613964565b935061307e818560208601613ae1565b61308781613cad565b840191505092915050565b600061309d8261393b565b6130a78185613975565b93506130b7818560208601613ae1565b6130c081613cad565b840191505092915050565b60006130d68261393b565b6130e08185613986565b93506130f0818560208601613ae1565b80840191505092915050565b6000613109601b83613975565b915061311482613cbe565b602082019050919050565b600061312c603283613975565b915061313782613ce7565b604082019050919050565b600061314f602583613975565b915061315a82613d36565b604082019050919050565b6000613172601c83613975565b915061317d82613d85565b602082019050919050565b6000613195602483613975565b91506131a082613dae565b604082019050919050565b60006131b8601983613975565b91506131c382613dfd565b602082019050919050565b60006131db602c83613975565b91506131e682613e26565b604082019050919050565b60006131fe603883613975565b915061320982613e75565b604082019050919050565b6000613221602a83613975565b915061322c82613ec4565b604082019050919050565b6000613244602983613975565b915061324f82613f13565b604082019050919050565b6000613267602e83613975565b915061327282613f62565b604082019050919050565b600061328a604083613975565b915061329582613fb1565b604082019050919050565b60006132ad602083613975565b91506132b882614000565b602082019050919050565b60006132d0603183613975565b91506132db82614029565b604082019050919050565b60006132f3602a83613975565b91506132fe82614078565b604082019050919050565b6000613316602c83613975565b9150613321826140c7565b604082019050919050565b6000613339602f83613975565b915061334482614116565b604082019050919050565b600061335c602183613975565b915061336782614165565b604082019050919050565b600061337f602483613975565b915061338a826141b4565b604082019050919050565b60006133a2603183613975565b91506133ad82614203565b604082019050919050565b60006133c5603083613975565b91506133d082614252565b604082019050919050565b60006133e8601c83613975565b91506133f3826142a1565b602082019050919050565b60a0820160008201516134146000850182613466565b5060208201516134276020850182612fbf565b50604082015161343a6040850182612fbf565b50606082015161344d6060850182613466565b506080820151613460608085018261303b565b50505050565b61346f81613ac8565b82525050565b61347e81613ac8565b82525050565b600061349082856130cb565b915061349c82846130cb565b91508190509392505050565b60006020820190506134bd6000830184612fce565b92915050565b60006080820190506134d86000830187612fce565b6134e56020830186612fce565b6134f26040830185613475565b6134ff606083018461304a565b95945050505050565b600060808201905061351d6000830187612fce565b61352a6020830186612fce565b6135376040830185613475565b81810360608301526135498184613059565b905095945050505050565b6000602082019050818103600083015261356e8184612fdd565b905092915050565b600060208201905061358b600083018461304a565b92915050565b600060208201905081810360008301526135ab8184613092565b905092915050565b600060208201905081810360008301526135cc816130fc565b9050919050565b600060208201905081810360008301526135ec8161311f565b9050919050565b6000602082019050818103600083015261360c81613142565b9050919050565b6000602082019050818103600083015261362c81613165565b9050919050565b6000602082019050818103600083015261364c81613188565b9050919050565b6000602082019050818103600083015261366c816131ab565b9050919050565b6000602082019050818103600083015261368c816131ce565b9050919050565b600060208201905081810360008301526136ac816131f1565b9050919050565b600060208201905081810360008301526136cc81613214565b9050919050565b600060208201905081810360008301526136ec81613237565b9050919050565b6000602082019050818103600083015261370c8161325a565b9050919050565b6000602082019050818103600083015261372c8161327d565b9050919050565b6000602082019050818103600083015261374c816132a0565b9050919050565b6000602082019050818103600083015261376c816132c3565b9050919050565b6000602082019050818103600083015261378c816132e6565b9050919050565b600060208201905081810360008301526137ac81613309565b9050919050565b600060208201905081810360008301526137cc8161332c565b9050919050565b600060208201905081810360008301526137ec8161334f565b9050919050565b6000602082019050818103600083015261380c81613372565b9050919050565b6000602082019050818103600083015261382c81613395565b9050919050565b6000602082019050818103600083015261384c816133b8565b9050919050565b6000602082019050818103600083015261386c816133db565b9050919050565b60006020820190506138886000830184613475565b92915050565b60006138986138a9565b90506138a48282613b46565b919050565b6000604051905090565b600067ffffffffffffffff8211156138ce576138cd613c7e565b5b6138d782613cad565b9050602081019050919050565b600067ffffffffffffffff8211156138ff576138fe613c7e565b5b61390882613cad565b9050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600061399c82613ac8565b91506139a783613ac8565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156139dc576139db613bf1565b5b828201905092915050565b60006139f282613ac8565b91506139fd83613ac8565b925082613a0d57613a0c613c20565b5b828204905092915050565b6000613a2382613ac8565b9150613a2e83613ac8565b925082821015613a4157613a40613bf1565b5b828203905092915050565b6000613a5782613aa8565b9050919050565b6000613a6982613aa8565b9050919050565b60008115159050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015613aff578082015181840152602081019050613ae4565b83811115613b0e576000848401525b50505050565b60006002820490506001821680613b2c57607f821691505b60208210811415613b4057613b3f613c4f565b5b50919050565b613b4f82613cad565b810181811067ffffffffffffffff82111715613b6e57613b6d613c7e565b5b80604052505050565b6000613b8282613ac8565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613bb557613bb4613bf1565b5b600182019050919050565b6000613bcb82613ac8565b9150613bd683613ac8565b925082613be657613be5613c20565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f436f756e7465723a2064656372656d656e74206f766572666c6f770000000000600082015250565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b7f4552433732313a207472616e736665722066726f6d20696e636f72726563742060008201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b7f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000600082015250565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b7f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860008201527f697374656e7420746f6b656e0000000000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760008201527f6e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000602082015250565b7f4552433732313a2062616c616e636520717565727920666f7220746865207a6560008201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b7f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460008201527f656e7420746f6b656e0000000000000000000000000000000000000000000000602082015250565b7f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60008201527f6578697374656e7420746f6b656e000000000000000000000000000000000000602082015250565b7f506c65617365207375626d6974207468652061736b696e67207072696365206960008201527f6e206f7264657220746f20636f6d706c65746520746865207075726368617365602082015250565b7f4552433732313a206d696e7420746f20746865207a65726f2061646472657373600082015250565b7f45524337323155524953746f726167653a2055524920717565727920666f722060008201527f6e6f6e6578697374656e7420746f6b656e000000000000000000000000000000602082015250565b7f4f6e6c79206974656d206f776e65722063616e20706572666f726d207468697360008201527f206f7065726174696f6e00000000000000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860008201527f697374656e7420746f6b656e0000000000000000000000000000000000000000602082015250565b7f4552433732314d657461646174613a2055524920717565727920666f72206e6f60008201527f6e6578697374656e7420746f6b656e0000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b7f5072696365206d75737420626520657175616c20746f206c697374696e67207060008201527f7269636500000000000000000000000000000000000000000000000000000000602082015250565b7f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60008201527f776e6572206e6f7220617070726f766564000000000000000000000000000000602082015250565b7f4f6e6c79206d61726b6574706c616365206f776e65722063616e20757064617460008201527f65206c697374696e672070726963652e00000000000000000000000000000000602082015250565b7f5072696365206d757374206265206174206c6561737420312077656900000000600082015250565b6142d381613a4c565b81146142de57600080fd5b50565b6142ea81613a70565b81146142f557600080fd5b50565b61430181613a7c565b811461430c57600080fd5b50565b61431881613ac8565b811461432357600080fd5b5056fea2646970667358221220e5c1422ac547d22d62c18b4337400beea2ba6a3309c89601d141e5cad0f5171d64736f6c63430008040033",
581 | "deployedBytecode": "0x60806040526004361061012a5760003560e01c80636352211e116100ab578063ae677aa31161006f578063ae677aa3146103f9578063b88d4fde14610415578063be9af5361461043e578063c87b56dd1461045a578063e219fc7514610497578063e985e9c5146104b35761012a565b80636352211e146102fb57806370a082311461033857806372b3b6201461037557806395d89b41146103a5578063a22cb465146103d05761012a565b806312e85585116100f257806312e8558514610228578063202e37401461025357806323b872dd1461027e57806342842e0e146102a757806345f8fa80146102d05761012a565b806301ffc9a71461012f57806306fdde031461016c578063081812fc14610197578063095ea7b3146101d45780630f08efe0146101fd575b600080fd5b34801561013b57600080fd5b5061015660048036038101906101519190612e9c565b6104f0565b6040516101639190613576565b60405180910390f35b34801561017857600080fd5b506101816105d2565b60405161018e9190613591565b60405180910390f35b3480156101a357600080fd5b506101be60048036038101906101b99190612f42565b610664565b6040516101cb91906134a8565b60405180910390f35b3480156101e057600080fd5b506101fb60048036038101906101f69190612e60565b6106e9565b005b34801561020957600080fd5b50610212610801565b60405161021f9190613554565b60405180910390f35b34801561023457600080fd5b5061023d610ab6565b60405161024a9190613873565b60405180910390f35b34801561025f57600080fd5b50610268610ac0565b6040516102759190613554565b60405180910390f35b34801561028a57600080fd5b506102a560048036038101906102a09190612d5a565b610dfa565b005b3480156102b357600080fd5b506102ce60048036038101906102c99190612d5a565b610e5a565b005b3480156102dc57600080fd5b506102e5610e7a565b6040516102f29190613554565b60405180910390f35b34801561030757600080fd5b50610322600480360381019061031d9190612f42565b6111b4565b60405161032f91906134a8565b60405180910390f35b34801561034457600080fd5b5061035f600480360381019061035a9190612cf5565b611266565b60405161036c9190613873565b60405180910390f35b61038f600480360381019061038a9190612eee565b61131e565b60405161039c9190613873565b60405180910390f35b3480156103b157600080fd5b506103ba611360565b6040516103c79190613591565b60405180910390f35b3480156103dc57600080fd5b506103f760048036038101906103f29190612e24565b6113f2565b005b610413600480360381019061040e9190612f42565b611408565b005b34801561042157600080fd5b5061043c60048036038101906104379190612da9565b6114a2565b005b61045860048036038101906104539190612f42565b611504565b005b34801561046657600080fd5b50610481600480360381019061047c9190612f42565b61173c565b60405161048e9190613591565b60405180910390f35b6104b160048036038101906104ac9190612f6b565b61188e565b005b3480156104bf57600080fd5b506104da60048036038101906104d59190612d1e565b611a83565b6040516104e79190613576565b60405180910390f35b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806105bb57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806105cb57506105ca82611b17565b5b9050919050565b6060600080546105e190613b14565b80601f016020809104026020016040519081016040528092919081815260200182805461060d90613b14565b801561065a5780601f1061062f5761010080835404028352916020019161065a565b820191906000526020600020905b81548152906001019060200180831161063d57829003601f168201915b5050505050905090565b600061066f82611b81565b6106ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106a590613793565b60405180910390fd5b6004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006106f4826111b4565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161075c906137d3565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610784611bed565b73ffffffffffffffffffffffffffffffffffffffff1614806107b357506107b2816107ad611bed565b611a83565b5b6107f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107e990613693565b60405180910390fd5b6107fc8383611bf5565b505050565b6060600061080f6007611cae565b9050600061081d6008611cae565b6108276007611cae565b6108319190613a18565b90506000808267ffffffffffffffff811115610876577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280602002602001820160405280156108af57816020015b61089c612abc565b8152602001906001900390816108945790505b50905060005b84811015610aab573073ffffffffffffffffffffffffffffffffffffffff16600b60006001846108e59190613991565b815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610a985760006001826109429190613991565b90506000600b60008381526020019081526020016000209050806040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820160009054906101000a900460ff161515151581525050848681518110610a7b577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250600185610a939190613991565b945050505b8080610aa390613b77565b9150506108b5565b508094505050505090565b6000600954905090565b60606000610ace6007611cae565b905060008060005b83811015610b77573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610b069190613991565b815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610b6457600183610b619190613991565b92505b8080610b6f90613b77565b915050610ad6565b5060008267ffffffffffffffff811115610bba577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610bf357816020015b610be0612abc565b815260200190600190039081610bd85790505b50905060005b84811015610def573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610c299190613991565b815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610ddc576000600182610c869190613991565b90506000600b60008381526020019081526020016000209050806040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820160009054906101000a900460ff161515151581525050848681518110610dbf577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6020026020010181905250600185610dd79190613991565b945050505b8080610de790613b77565b915050610bf9565b508094505050505090565b610e0b610e05611bed565b82611cbc565b610e4a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e4190613813565b60405180910390fd5b610e55838383611d9a565b505050565b610e75838383604051806020016040528060008152506114a2565b505050565b60606000610e886007611cae565b905060008060005b83811015610f31573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610ec09190613991565b815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610f1e57600183610f1b9190613991565b92505b8080610f2990613b77565b915050610e90565b5060008267ffffffffffffffff811115610f74577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051908082528060200260200182016040528015610fad57816020015b610f9a612abc565b815260200190600190039081610f925790505b50905060005b848110156111a9573373ffffffffffffffffffffffffffffffffffffffff16600b6000600184610fe39190613991565b815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156111965760006001826110409190613991565b90506000600b60008381526020019081526020016000209050806040518060a0016040529081600082015481526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600382015481526020016004820160009054906101000a900460ff161515151581525050848681518110611179577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200260200101819052506001856111919190613991565b945050505b80806111a190613b77565b915050610fb3565b508094505050505090565b6000806002600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561125d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611254906136d3565b60405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156112d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112ce906136b3565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600061132a6007612001565b60006113366007611cae565b90506113423382612017565b61134c81856121f1565b6113568184612265565b8091505092915050565b60606001805461136f90613b14565b80601f016020809104026020016040519081016040528092919081815260200182805461139b90613b14565b80156113e85780601f106113bd576101008083540402835291602001916113e8565b820191906000526020600020905b8154815290600101906020018083116113cb57829003601f168201915b5050505050905090565b6114046113fd611bed565b8383612468565b5050565b3373ffffffffffffffffffffffffffffffffffffffff16600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611498576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161148f90613833565b60405180910390fd5b8060098190555050565b6114b36114ad611bed565b83611cbc565b6114f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e990613813565b60405180910390fd5b6114fe848484846125d5565b50505050565b6000600b6000838152602001908152602001600020600301549050803414611561576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155890613713565b60405180910390fd5b33600b600084815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600b600084815260200190815260200160002060040160006101000a81548160ff0219169083151502179055506000600b600084815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506116456008612001565b611650303384611d9a565b600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc6009549081150290604051600060405180830381858888f193505050501580156116ba573d6000803e3d6000fd5b50600b600083815260200190815260200160002060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015611737573d6000803e3d6000fd5b505050565b606061174782611b81565b611786576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177d90613753565b60405180910390fd5b60006006600084815260200190815260200160002080546117a690613b14565b80601f01602080910402602001604051908101604052809291908181526020018280546117d290613b14565b801561181f5780601f106117f45761010080835404028352916020019161181f565b820191906000526020600020905b81548152906001019060200180831161180257829003601f168201915b505050505090506000611830612631565b9050600081511415611846578192505050611889565b60008251111561187b578082604051602001611863929190613484565b60405160208183030381529060405292505050611889565b61188484612648565b925050505b919050565b3373ffffffffffffffffffffffffffffffffffffffff16600b600084815260200190815260200160002060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611932576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161192990613773565b60405180910390fd5b6009543414611976576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161196d906137f3565b60405180910390fd5b6000600b600084815260200190815260200160002060040160006101000a81548160ff02191690831515021790555080600b60008481526020019081526020016000206003018190555033600b600084815260200190815260200160002060010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555030600b600084815260200190815260200160002060020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611a7460086126ef565b611a7f333084611d9a565b5050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60008073ffffffffffffffffffffffffffffffffffffffff166002600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614159050919050565b600033905090565b816004600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16611c68836111b4565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600081600001549050919050565b6000611cc782611b81565b611d06576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cfd90613673565b60405180910390fd5b6000611d11836111b4565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480611d8057508373ffffffffffffffffffffffffffffffffffffffff16611d6884610664565b73ffffffffffffffffffffffffffffffffffffffff16145b80611d915750611d908185611a83565b5b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff16611dba826111b4565b73ffffffffffffffffffffffffffffffffffffffff1614611e10576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e07906135f3565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611e80576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e7790613633565b60405180910390fd5b611e8b83838361274b565b611e96600082611bf5565b6001600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611ee69190613a18565b925050819055506001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611f3d9190613991565b92505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4611ffc838383612750565b505050565b6001816000016000828254019250508190555050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415612087576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161207e90613733565b60405180910390fd5b61209081611b81565b156120d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c790613613565b60405180910390fd5b6120dc6000838361274b565b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461212c9190613991565b92505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46121ed60008383612750565b5050565b6121fa82611b81565b612239576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612230906136f3565b60405180910390fd5b80600660008481526020019081526020016000209080519060200190612260929190612b19565b505050565b600081116122a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229f90613853565b60405180910390fd5b60095434146122ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122e3906137f3565b60405180910390fd5b6040518060a001604052808381526020013373ffffffffffffffffffffffffffffffffffffffff1681526020013073ffffffffffffffffffffffffffffffffffffffff16815260200182815260200160001515815250600b60008481526020019081526020016000206000820151816000015560208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506060820151816003015560808201518160040160006101000a81548160ff021916908315150217905550905050612425333084611d9a565b817fb640004f1d14576d0c209e240cad0410e0d8c0c33a09375861fbadae2588a98d333084600060405161245c94939291906134c3565b60405180910390a25050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156124d7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124ce90613653565b60405180910390fd5b80600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516125c89190613576565b60405180910390a3505050565b6125e0848484611d9a565b6125ec84848484612755565b61262b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612622906135d3565b60405180910390fd5b50505050565b606060405180602001604052806000815250905090565b606061265382611b81565b612692576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612689906137b3565b60405180910390fd5b600061269c612631565b905060008151116126bc57604051806020016040528060008152506126e7565b806126c6846128ec565b6040516020016126d7929190613484565b6040516020818303038152906040525b915050919050565b6000816000015490506000811161273b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612732906135b3565b60405180910390fd5b6001810382600001819055505050565b505050565b505050565b60006127768473ffffffffffffffffffffffffffffffffffffffff16612a99565b156128df578373ffffffffffffffffffffffffffffffffffffffff1663150b7a0261279f611bed565b8786866040518563ffffffff1660e01b81526004016127c19493929190613508565b602060405180830381600087803b1580156127db57600080fd5b505af192505050801561280c57506040513d601f19601f820116820180604052508101906128099190612ec5565b60015b61288f573d806000811461283c576040519150601f19603f3d011682016040523d82523d6000602084013e612841565b606091505b50600081511415612887576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161287e906135d3565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149150506128e4565b600190505b949350505050565b60606000821415612934576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050612a94565b600082905060005b6000821461296657808061294f90613b77565b915050600a8261295f91906139e7565b915061293c565b60008167ffffffffffffffff8111156129a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040519080825280601f01601f1916602001820160405280156129da5781602001600182028036833780820191505090505b5090505b60008514612a8d576001826129f39190613a18565b9150600a85612a029190613bc0565b6030612a0e9190613991565b60f81b818381518110612a4a577f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a85612a8691906139e7565b94506129de565b8093505050505b919050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6040518060a0016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000151581525090565b828054612b2590613b14565b90600052602060002090601f016020900481019282612b475760008555612b8e565b82601f10612b6057805160ff1916838001178555612b8e565b82800160010185558215612b8e579182015b82811115612b8d578251825591602001919060010190612b72565b5b509050612b9b9190612b9f565b5090565b5b80821115612bb8576000816000905550600101612ba0565b5090565b6000612bcf612bca846138b3565b61388e565b905082815260208101848484011115612be757600080fd5b612bf2848285613ad2565b509392505050565b6000612c0d612c08846138e4565b61388e565b905082815260208101848484011115612c2557600080fd5b612c30848285613ad2565b509392505050565b600081359050612c47816142ca565b92915050565b600081359050612c5c816142e1565b92915050565b600081359050612c71816142f8565b92915050565b600081519050612c86816142f8565b92915050565b600082601f830112612c9d57600080fd5b8135612cad848260208601612bbc565b91505092915050565b600082601f830112612cc757600080fd5b8135612cd7848260208601612bfa565b91505092915050565b600081359050612cef8161430f565b92915050565b600060208284031215612d0757600080fd5b6000612d1584828501612c38565b91505092915050565b60008060408385031215612d3157600080fd5b6000612d3f85828601612c38565b9250506020612d5085828601612c38565b9150509250929050565b600080600060608486031215612d6f57600080fd5b6000612d7d86828701612c38565b9350506020612d8e86828701612c38565b9250506040612d9f86828701612ce0565b9150509250925092565b60008060008060808587031215612dbf57600080fd5b6000612dcd87828801612c38565b9450506020612dde87828801612c38565b9350506040612def87828801612ce0565b925050606085013567ffffffffffffffff811115612e0c57600080fd5b612e1887828801612c8c565b91505092959194509250565b60008060408385031215612e3757600080fd5b6000612e4585828601612c38565b9250506020612e5685828601612c4d565b9150509250929050565b60008060408385031215612e7357600080fd5b6000612e8185828601612c38565b9250506020612e9285828601612ce0565b9150509250929050565b600060208284031215612eae57600080fd5b6000612ebc84828501612c62565b91505092915050565b600060208284031215612ed757600080fd5b6000612ee584828501612c77565b91505092915050565b60008060408385031215612f0157600080fd5b600083013567ffffffffffffffff811115612f1b57600080fd5b612f2785828601612cb6565b9250506020612f3885828601612ce0565b9150509250929050565b600060208284031215612f5457600080fd5b6000612f6284828501612ce0565b91505092915050565b60008060408385031215612f7e57600080fd5b6000612f8c85828601612ce0565b9250506020612f9d85828601612ce0565b9150509250929050565b6000612fb383836133fe565b60a08301905092915050565b612fc881613a5e565b82525050565b612fd781613a4c565b82525050565b6000612fe882613925565b612ff28185613953565b9350612ffd83613915565b8060005b8381101561302e5781516130158882612fa7565b975061302083613946565b925050600181019050613001565b5085935050505092915050565b61304481613a70565b82525050565b61305381613a70565b82525050565b600061306482613930565b61306e8185613964565b935061307e818560208601613ae1565b61308781613cad565b840191505092915050565b600061309d8261393b565b6130a78185613975565b93506130b7818560208601613ae1565b6130c081613cad565b840191505092915050565b60006130d68261393b565b6130e08185613986565b93506130f0818560208601613ae1565b80840191505092915050565b6000613109601b83613975565b915061311482613cbe565b602082019050919050565b600061312c603283613975565b915061313782613ce7565b604082019050919050565b600061314f602583613975565b915061315a82613d36565b604082019050919050565b6000613172601c83613975565b915061317d82613d85565b602082019050919050565b6000613195602483613975565b91506131a082613dae565b604082019050919050565b60006131b8601983613975565b91506131c382613dfd565b602082019050919050565b60006131db602c83613975565b91506131e682613e26565b604082019050919050565b60006131fe603883613975565b915061320982613e75565b604082019050919050565b6000613221602a83613975565b915061322c82613ec4565b604082019050919050565b6000613244602983613975565b915061324f82613f13565b604082019050919050565b6000613267602e83613975565b915061327282613f62565b604082019050919050565b600061328a604083613975565b915061329582613fb1565b604082019050919050565b60006132ad602083613975565b91506132b882614000565b602082019050919050565b60006132d0603183613975565b91506132db82614029565b604082019050919050565b60006132f3602a83613975565b91506132fe82614078565b604082019050919050565b6000613316602c83613975565b9150613321826140c7565b604082019050919050565b6000613339602f83613975565b915061334482614116565b604082019050919050565b600061335c602183613975565b915061336782614165565b604082019050919050565b600061337f602483613975565b915061338a826141b4565b604082019050919050565b60006133a2603183613975565b91506133ad82614203565b604082019050919050565b60006133c5603083613975565b91506133d082614252565b604082019050919050565b60006133e8601c83613975565b91506133f3826142a1565b602082019050919050565b60a0820160008201516134146000850182613466565b5060208201516134276020850182612fbf565b50604082015161343a6040850182612fbf565b50606082015161344d6060850182613466565b506080820151613460608085018261303b565b50505050565b61346f81613ac8565b82525050565b61347e81613ac8565b82525050565b600061349082856130cb565b915061349c82846130cb565b91508190509392505050565b60006020820190506134bd6000830184612fce565b92915050565b60006080820190506134d86000830187612fce565b6134e56020830186612fce565b6134f26040830185613475565b6134ff606083018461304a565b95945050505050565b600060808201905061351d6000830187612fce565b61352a6020830186612fce565b6135376040830185613475565b81810360608301526135498184613059565b905095945050505050565b6000602082019050818103600083015261356e8184612fdd565b905092915050565b600060208201905061358b600083018461304a565b92915050565b600060208201905081810360008301526135ab8184613092565b905092915050565b600060208201905081810360008301526135cc816130fc565b9050919050565b600060208201905081810360008301526135ec8161311f565b9050919050565b6000602082019050818103600083015261360c81613142565b9050919050565b6000602082019050818103600083015261362c81613165565b9050919050565b6000602082019050818103600083015261364c81613188565b9050919050565b6000602082019050818103600083015261366c816131ab565b9050919050565b6000602082019050818103600083015261368c816131ce565b9050919050565b600060208201905081810360008301526136ac816131f1565b9050919050565b600060208201905081810360008301526136cc81613214565b9050919050565b600060208201905081810360008301526136ec81613237565b9050919050565b6000602082019050818103600083015261370c8161325a565b9050919050565b6000602082019050818103600083015261372c8161327d565b9050919050565b6000602082019050818103600083015261374c816132a0565b9050919050565b6000602082019050818103600083015261376c816132c3565b9050919050565b6000602082019050818103600083015261378c816132e6565b9050919050565b600060208201905081810360008301526137ac81613309565b9050919050565b600060208201905081810360008301526137cc8161332c565b9050919050565b600060208201905081810360008301526137ec8161334f565b9050919050565b6000602082019050818103600083015261380c81613372565b9050919050565b6000602082019050818103600083015261382c81613395565b9050919050565b6000602082019050818103600083015261384c816133b8565b9050919050565b6000602082019050818103600083015261386c816133db565b9050919050565b60006020820190506138886000830184613475565b92915050565b60006138986138a9565b90506138a48282613b46565b919050565b6000604051905090565b600067ffffffffffffffff8211156138ce576138cd613c7e565b5b6138d782613cad565b9050602081019050919050565b600067ffffffffffffffff8211156138ff576138fe613c7e565b5b61390882613cad565b9050602081019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600061399c82613ac8565b91506139a783613ac8565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156139dc576139db613bf1565b5b828201905092915050565b60006139f282613ac8565b91506139fd83613ac8565b925082613a0d57613a0c613c20565b5b828204905092915050565b6000613a2382613ac8565b9150613a2e83613ac8565b925082821015613a4157613a40613bf1565b5b828203905092915050565b6000613a5782613aa8565b9050919050565b6000613a6982613aa8565b9050919050565b60008115159050919050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015613aff578082015181840152602081019050613ae4565b83811115613b0e576000848401525b50505050565b60006002820490506001821680613b2c57607f821691505b60208210811415613b4057613b3f613c4f565b5b50919050565b613b4f82613cad565b810181811067ffffffffffffffff82111715613b6e57613b6d613c7e565b5b80604052505050565b6000613b8282613ac8565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613bb557613bb4613bf1565b5b600182019050919050565b6000613bcb82613ac8565b9150613bd683613ac8565b925082613be657613be5613c20565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000601f19601f8301169050919050565b7f436f756e7465723a2064656372656d656e74206f766572666c6f770000000000600082015250565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b7f4552433732313a207472616e736665722066726f6d20696e636f72726563742060008201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b7f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000600082015250565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b7f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860008201527f697374656e7420746f6b656e0000000000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760008201527f6e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000602082015250565b7f4552433732313a2062616c616e636520717565727920666f7220746865207a6560008201527f726f206164647265737300000000000000000000000000000000000000000000602082015250565b7f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460008201527f656e7420746f6b656e0000000000000000000000000000000000000000000000602082015250565b7f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60008201527f6578697374656e7420746f6b656e000000000000000000000000000000000000602082015250565b7f506c65617365207375626d6974207468652061736b696e67207072696365206960008201527f6e206f7264657220746f20636f6d706c65746520746865207075726368617365602082015250565b7f4552433732313a206d696e7420746f20746865207a65726f2061646472657373600082015250565b7f45524337323155524953746f726167653a2055524920717565727920666f722060008201527f6e6f6e6578697374656e7420746f6b656e000000000000000000000000000000602082015250565b7f4f6e6c79206974656d206f776e65722063616e20706572666f726d207468697360008201527f206f7065726174696f6e00000000000000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860008201527f697374656e7420746f6b656e0000000000000000000000000000000000000000602082015250565b7f4552433732314d657461646174613a2055524920717565727920666f72206e6f60008201527f6e6578697374656e7420746f6b656e0000000000000000000000000000000000602082015250565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b7f5072696365206d75737420626520657175616c20746f206c697374696e67207060008201527f7269636500000000000000000000000000000000000000000000000000000000602082015250565b7f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60008201527f776e6572206e6f7220617070726f766564000000000000000000000000000000602082015250565b7f4f6e6c79206d61726b6574706c616365206f776e65722063616e20757064617460008201527f65206c697374696e672070726963652e00000000000000000000000000000000602082015250565b7f5072696365206d757374206265206174206c6561737420312077656900000000600082015250565b6142d381613a4c565b81146142de57600080fd5b50565b6142ea81613a70565b81146142f557600080fd5b50565b61430181613a7c565b811461430c57600080fd5b50565b61431881613ac8565b811461432357600080fd5b5056fea2646970667358221220e5c1422ac547d22d62c18b4337400beea2ba6a3309c89601d141e5cad0f5171d64736f6c63430008040033",
582 | "linkReferences": {},
583 | "deployedLinkReferences": {}
584 | }
585 |
--------------------------------------------------------------------------------
/context/constants.js:
--------------------------------------------------------------------------------
1 | import marketAbi from './NFTMarketplace.json';
2 |
3 | export const MarketAddress = '0xF5f6B924332C350E3Fcd3A50Fc94db822f0B760f';
4 | export const MarketAddressABI = marketAbi.abi;
5 |
--------------------------------------------------------------------------------
/contracts/NFTMarketplace.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.4;
3 |
4 | import "@openzeppelin/contracts/utils/Counters.sol";
5 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
6 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
7 |
8 | import "hardhat/console.sol";
9 |
10 | contract NFTMarketplace is ERC721URIStorage {
11 | using Counters for Counters.Counter;
12 | Counters.Counter private _tokenIds;
13 | Counters.Counter private _itemsSold;
14 |
15 | uint256 listingPrice = 0.025 ether;
16 | address payable owner;
17 |
18 | mapping(uint256 => MarketItem) private idToMarketItem;
19 |
20 | struct MarketItem {
21 | uint256 tokenId;
22 | address payable seller;
23 | address payable owner;
24 | uint256 price;
25 | bool sold;
26 | }
27 |
28 | event MarketItemCreated (
29 | uint256 indexed tokenId,
30 | address seller,
31 | address owner,
32 | uint256 price,
33 | bool sold
34 | );
35 |
36 | constructor() ERC721("Polyplace Inc.", "PLY") {
37 | owner = payable(msg.sender);
38 | }
39 |
40 | /* Updates the listing price of the contract */
41 | function updateListingPrice(uint _listingPrice) public payable {
42 | require(owner == msg.sender, "Only marketplace owner can update listing price.");
43 | listingPrice = _listingPrice;
44 | }
45 |
46 | /* Returns the listing price of the contract */
47 | function getListingPrice() public view returns (uint256) {
48 | return listingPrice;
49 | }
50 |
51 | /* Mints a token and lists it in the marketplace */
52 | function createToken(string memory tokenURI, uint256 price) public payable returns (uint) {
53 | _tokenIds.increment();
54 | uint256 newTokenId = _tokenIds.current();
55 |
56 | _mint(msg.sender, newTokenId);
57 | _setTokenURI(newTokenId, tokenURI);
58 | createMarketItem(newTokenId, price);
59 | return newTokenId;
60 | }
61 |
62 | function createMarketItem(
63 | uint256 tokenId,
64 | uint256 price
65 | ) private {
66 | require(price > 0, "Price must be at least 1 wei");
67 | require(msg.value == listingPrice, "Price must be equal to listing price");
68 |
69 | idToMarketItem[tokenId] = MarketItem(
70 | tokenId,
71 | payable(msg.sender),
72 | payable(address(this)),
73 | price,
74 | false
75 | );
76 |
77 | _transfer(msg.sender, address(this), tokenId);
78 | emit MarketItemCreated(
79 | tokenId,
80 | msg.sender,
81 | address(this),
82 | price,
83 | false
84 | );
85 | }
86 |
87 | /* allows someone to resell a token they have purchased */
88 | function resellToken(uint256 tokenId, uint256 price) public payable {
89 | require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner can perform this operation");
90 | require(msg.value == listingPrice, "Price must be equal to listing price");
91 | idToMarketItem[tokenId].sold = false;
92 | idToMarketItem[tokenId].price = price;
93 | idToMarketItem[tokenId].seller = payable(msg.sender);
94 | idToMarketItem[tokenId].owner = payable(address(this));
95 | _itemsSold.decrement();
96 |
97 | _transfer(msg.sender, address(this), tokenId);
98 | }
99 |
100 | /* Creates the sale of a marketplace item */
101 | /* Transfers ownership of the item, as well as funds between parties */
102 | function createMarketSale(
103 | uint256 tokenId
104 | ) public payable {
105 | uint price = idToMarketItem[tokenId].price;
106 | address payable creator = idToMarketItem[tokenId].seller;
107 | require(msg.value == price, "Please submit the asking price in order to complete the purchase");
108 | idToMarketItem[tokenId].owner = payable(msg.sender);
109 | idToMarketItem[tokenId].sold = true;
110 | idToMarketItem[tokenId].seller = payable(address(0));
111 | _itemsSold.increment();
112 | _transfer(address(this), msg.sender, tokenId);
113 | payable(owner).transfer(listingPrice);
114 | payable(creator).transfer(msg.value);
115 | }
116 |
117 | /* Returns all unsold market items */
118 | function fetchMarketItems() public view returns (MarketItem[] memory) {
119 | uint itemCount = _tokenIds.current();
120 | uint unsoldItemCount = _tokenIds.current() - _itemsSold.current();
121 | uint currentIndex = 0;
122 |
123 | MarketItem[] memory items = new MarketItem[](unsoldItemCount);
124 | for (uint i = 0; i < itemCount; i++) {
125 | if (idToMarketItem[i + 1].owner == address(this)) {
126 | uint currentId = i + 1;
127 | MarketItem storage currentItem = idToMarketItem[currentId];
128 | items[currentIndex] = currentItem;
129 | currentIndex += 1;
130 | }
131 | }
132 | return items;
133 | }
134 |
135 | /* Returns only items that a user has purchased */
136 | function fetchMyNFTs() public view returns (MarketItem[] memory) {
137 | uint totalItemCount = _tokenIds.current();
138 | uint itemCount = 0;
139 | uint currentIndex = 0;
140 |
141 | for (uint i = 0; i < totalItemCount; i++) {
142 | if (idToMarketItem[i + 1].owner == msg.sender) {
143 | itemCount += 1;
144 | }
145 | }
146 |
147 | MarketItem[] memory items = new MarketItem[](itemCount);
148 | for (uint i = 0; i < totalItemCount; i++) {
149 | if (idToMarketItem[i + 1].owner == msg.sender) {
150 | uint currentId = i + 1;
151 | MarketItem storage currentItem = idToMarketItem[currentId];
152 | items[currentIndex] = currentItem;
153 | currentIndex += 1;
154 | }
155 | }
156 | return items;
157 | }
158 |
159 | /* Returns only items a user has listed */
160 | function fetchItemsListed() public view returns (MarketItem[] memory) {
161 | uint totalItemCount = _tokenIds.current();
162 | uint itemCount = 0;
163 | uint currentIndex = 0;
164 |
165 | for (uint i = 0; i < totalItemCount; i++) {
166 | if (idToMarketItem[i + 1].seller == msg.sender) {
167 | itemCount += 1;
168 | }
169 | }
170 |
171 | MarketItem[] memory items = new MarketItem[](itemCount);
172 | for (uint i = 0; i < totalItemCount; i++) {
173 | if (idToMarketItem[i + 1].seller == msg.sender) {
174 | uint currentId = i + 1;
175 | MarketItem storage currentItem = idToMarketItem[currentId];
176 | items[currentIndex] = currentItem;
177 | currentIndex += 1;
178 | }
179 | }
180 | return items;
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | dapp:
5 | build:
6 | context: .
7 | dockerfile: Dockerfile
8 | container_name: dapp
9 | restart: always
10 | volumes:
11 | - ./:/app
12 | - /app/node_modules
13 | - /app/.next
14 | ports:
15 | - 3000:3000
16 |
--------------------------------------------------------------------------------
/hardhat.config.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | require('@nomiclabs/hardhat-waffle');
4 |
5 | const privateKey = fs.readFileSync('.secret').toString().trim();
6 |
7 | module.exports = {
8 | networks: {
9 | hardhat: {
10 | chainId: 1337,
11 | },
12 | matic: {
13 | url: 'https://rpc-mumbai.maticvigil.com',
14 | accounts: [privateKey],
15 | },
16 | },
17 | solidity: '0.8.4',
18 | };
19 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 |
3 | const nextConfig = {
4 | reactStrictMode: true,
5 | webpackDevMiddleware: (config) => {
6 | config.watchOptions = {
7 | poll: 1000,
8 | aggregateTimeout: 300,
9 | };
10 | return config;
11 | },
12 | images: {
13 | domains: ['polyplace.infura-ipfs.io'],
14 | },
15 | };
16 |
17 | module.exports = nextConfig;
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nft_marketplace",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@nomiclabs/hardhat-ethers": "2.0.5",
13 | "@nomiclabs/hardhat-waffle": "^2.0.5",
14 | "@openzeppelin/contracts": "^4.7.3",
15 | "@vercel/analytics": "^0.1.1",
16 | "axios": "0.26.0",
17 | "dotenv": "^16.0.3",
18 | "ethers": "^5.5.4",
19 | "framer-motion": "^6.5.1",
20 | "hardhat": "^2.12.0",
21 | "ipfs-http-client": "^56.0.1",
22 | "next": "12.1.0",
23 | "next-themes": "0.1.1",
24 | "react": "17.0.2",
25 | "react-dom": "17.0.2",
26 | "react-dropzone": "12.0.4",
27 | "react-icons": "^4.4.0",
28 | "web3modal": "1.9.5"
29 | },
30 | "devDependencies": {
31 | "autoprefixer": "10.4.2",
32 | "eslint": "^8.16.0",
33 | "eslint-config-airbnb": "^19.0.4",
34 | "eslint-config-next": "12.1.0",
35 | "eslint-plugin-import": "^2.26.0",
36 | "eslint-plugin-jsx-a11y": "^6.5.1",
37 | "eslint-plugin-react": "^7.30.0",
38 | "eslint-plugin-react-hooks": "^4.5.0",
39 | "postcss": "8.4.7",
40 | "tailwindcss": "3.0.23"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import Script from 'next/script';
2 | import { ThemeProvider } from 'next-themes';
3 | import Head from 'next/head';
4 |
5 | import { Navbar, Footer } from '../components';
6 |
7 | import { NFTProvider } from '../context/NFTContext';
8 | import '../styles/globals.css';
9 |
10 | const MyApp = ({ Component, pageProps }) => (
11 |
12 |
13 |
14 |
15 |
Polyplace
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | );
29 |
30 | export default MyApp;
31 |
--------------------------------------------------------------------------------
/pages/create-nft.js:
--------------------------------------------------------------------------------
1 | import { useState, useMemo, useCallback, useContext } from 'react';
2 |
3 | import { useRouter } from 'next/router';
4 | import { useDropzone } from 'react-dropzone';
5 | import Image from 'next/image';
6 | import { useTheme } from 'next-themes';
7 |
8 | import withTransition from '../components/withTransition';
9 |
10 | import { NFTContext } from '../context/NFTContext';
11 | import { Button, Input, Loader } from '../components';
12 |
13 | import images from '../assets';
14 |
15 | const CreateNFT = () => {
16 | const [fileUrl, setFileUrl] = useState(null);
17 | const [formInput, setFormInput] = useState({ price: '', name: '', description: '' });
18 | const { theme } = useTheme();
19 | const { isLoadingNFT, uploadToIPFS, createNFT } = useContext(NFTContext);
20 | const router = useRouter();
21 |
22 | const onDrop = useCallback(async (acceptedFile) => {
23 | const url = await uploadToIPFS(acceptedFile[0]);
24 |
25 | setFileUrl(url);
26 | }, []);
27 |
28 | const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
29 | onDrop,
30 | accept: 'image/*',
31 | maxSize: 5000000,
32 | });
33 |
34 | const fileStyle = useMemo(() => (
35 | `dark:bg-nft-black-1 bg-white border dark:border-white border-nft-gray-2 flex flex-col items-center p-5 rounded-sm border-dashed
36 | ${isDragActive && ' border-file-active'}
37 | ${isDragAccept && ' border-file-accept'}
38 | ${isDragReject && ' border-file-reject'}
39 | `
40 | ), [isDragActive, isDragAccept, isDragReject]);
41 |
42 | if (isLoadingNFT) {
43 | return (
44 |
45 |
46 |
47 | );
48 | }
49 |
50 | return (
51 |
52 |
53 |
54 | Create a new NFT
55 |
56 |
57 |
Upload File
58 |
59 |
60 |
61 |
62 |
63 | JPG, PNG, GIF, SVG, WEBM Max 100mb.
64 |
65 |
66 |
74 |
75 |
76 | Drag and Drop File,
77 |
78 |
79 | or Browse media on your device.
80 |
81 |
82 |
83 | {fileUrl && (
84 |
85 |
86 |
87 |
88 |
89 | )}
90 |
91 |
92 |
setFormInput({ ...formInput, name: e.target.value })}
97 | />
98 |
setFormInput({ ...formInput, description: e.target.value })}
103 | />
104 |
setFormInput({ ...formInput, price: e.target.value })}
109 | />
110 |
111 | createNFT(formInput, fileUrl, router)}
115 | />
116 |
117 |
118 |
119 | );
120 | };
121 |
122 | export default withTransition(CreateNFT);
123 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useRef, useContext } from 'react';
2 | import Image from 'next/image';
3 | import { useTheme } from 'next-themes';
4 |
5 | import { NFTContext } from '../context/NFTContext';
6 |
7 | import { Banner, CreatorCard, Loader, NFTCard, SearchBar, withTransition } from '../components';
8 |
9 | import images from '../assets';
10 | import { getCreators } from '../utils/index';
11 | import { shortenAddress } from '../utils/index';
12 |
13 | const Home = () => {
14 | const { fetchNFTs } = useContext(NFTContext);
15 | const [hideButtons, setHideButtons] = useState(false);
16 | const [nfts, setNfts] = useState([]);
17 | const [nftsCopy, setNftsCopy] = useState([]);
18 | const { theme } = useTheme();
19 | const [activeSelect, setActiveSelect] = useState('Recently Added');
20 | const [isLoading, setIsLoading] = useState(true);
21 | const [showMore, setShowMore] = useState(false);
22 | const [showScrollButton, setShowScrollButton] = useState(false);
23 |
24 | const parentRef = useRef(null);
25 | const scrollRef = useRef(null);
26 |
27 | useEffect(() => {
28 | fetchNFTs()
29 | .then((items) => {
30 | const finalitems = items.filter((v) => v !== null);
31 | setNfts(finalitems);
32 | setNftsCopy(finalitems);
33 | setIsLoading(false);
34 | });
35 | }, []);
36 |
37 | useEffect(() => {
38 | const sortedNfts = [...nfts];
39 |
40 | switch (activeSelect) {
41 | case 'Price (low to high)':
42 | setNfts(sortedNfts.sort((a, b) => a.price - b.price));
43 | break;
44 | case 'Price (high to low)':
45 | setNfts(sortedNfts.sort((a, b) => b.price - a.price));
46 | break;
47 | case 'Recently Added':
48 | setNfts(sortedNfts.sort((a, b) => b.tokenId - a.tokenId));
49 | break;
50 | default:
51 | setNfts(nfts);
52 | break;
53 | }
54 | }, [activeSelect]);
55 |
56 | const onHandleSearch = (value) => {
57 | const filteredNfts = nfts.filter(({ name }) => name.toLowerCase().includes(value.toLowerCase()));
58 |
59 | if (filteredNfts.length) {
60 | setNfts(filteredNfts);
61 | } else {
62 | setNfts(nftsCopy);
63 | }
64 | };
65 |
66 | const onClearSearch = () => {
67 | if (nfts.length && nftsCopy.length) {
68 | setNfts(nftsCopy);
69 | }
70 | };
71 |
72 | const handleScroll = (direction) => {
73 | const { current } = scrollRef;
74 |
75 | const scrollAmount = window.innerWidth > 1800 ? 270 : 210;
76 |
77 | if (direction === 'left') {
78 | current.scrollLeft -= scrollAmount;
79 | } else {
80 | current.scrollLeft += scrollAmount;
81 | }
82 | };
83 |
84 | const isScrollable = () => {
85 | const { current } = scrollRef;
86 | const { current: parent } = parentRef;
87 |
88 | if (current?.scrollWidth >= parent?.offsetWidth) {
89 | setHideButtons(false);
90 | } else {
91 | setHideButtons(true);
92 | }
93 | };
94 |
95 | useEffect(() => {
96 | isScrollable();
97 |
98 | window.addEventListener('resize', isScrollable);
99 |
100 | return () => {
101 | window.removeEventListener('resize', isScrollable);
102 | };
103 | });
104 |
105 | useEffect(() => {
106 | const handleScrollButtonVisibility = () => {
107 | window.scrollY > 1000 ? setShowScrollButton(true) : setShowScrollButton(false);
108 | };
109 |
110 | window.addEventListener('scroll', handleScrollButtonVisibility);
111 |
112 | return () => {
113 | window.removeEventListener('scroll', handleScrollButtonVisibility);
114 | };
115 | });
116 |
117 | const handleScrollToTop = () => {
118 | window.scrollTo({ top: 0, behavior: 'smooth' });
119 | };
120 |
121 | const topCreators = getCreators(nftsCopy);
122 |
123 | return (
124 |
125 |
126 |
127 |
132 |
133 | {!isLoading && !nfts.length ? (
134 |
The marketplace is empty.
135 | ) : isLoading ?
: (
136 | <>
137 |
138 |
139 | ⭐ Top Creators
140 |
141 |
142 |
143 | {topCreators.map((creator, i) => (
144 |
151 | ))}
152 | {!hideButtons && (
153 | <>
154 |
handleScroll('left')} className="absolute w-8 h-8 minlg:w-12 minlg:h-12 top-45 cursor-pointer left-0">
155 |
162 |
163 |
handleScroll('right')} className="absolute w-8 h-8 minlg:w-12 minlg:h-12 top-45 cursor-pointer right-0">
164 |
171 |
172 | >
173 | )}
174 |
175 |
176 |
177 |
178 |
179 |
180 |
🔥 Hot NFTs
181 |
182 |
188 |
189 |
190 | {showMore ? (
191 |
192 | {nfts.map((nft) => )}
193 |
194 | ) : (
195 |
196 | {nfts.slice(0, 12).map((nft) => )}
197 |
198 | )}
199 | {!showMore && (
200 |
201 | setShowMore(true)}>Show More
202 |
203 | )}
204 |
205 | >
206 | )}
207 |
208 | {
209 | showScrollButton && (
210 |
211 |
217 |
224 |
225 |
226 | )
227 | }
228 |
229 |
230 | );
231 | };
232 |
233 | export default withTransition(Home);
234 |
--------------------------------------------------------------------------------
/pages/listed-nfts.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext } from 'react';
2 |
3 | import withTransition from '../components/withTransition';
4 |
5 | import { NFTContext } from '../context/NFTContext';
6 | import { Loader, NFTCard } from '../components';
7 |
8 | const ListedNFTs = () => {
9 | const { fetchMyNFTsOrListedNFTs } = useContext(NFTContext);
10 | const [nfts, setNfts] = useState([]);
11 | const [isLoading, setIsLoading] = useState(true);
12 |
13 | useEffect(() => {
14 | fetchMyNFTsOrListedNFTs('fetchItemsListed')
15 | .then((items) => {
16 | setNfts(items);
17 | setIsLoading(false);
18 | });
19 | }, []);
20 |
21 | if (isLoading) {
22 | return (
23 |
24 |
25 |
26 | );
27 | }
28 |
29 | if (!isLoading && nfts.length === 0) {
30 | return (
31 |
32 |
No NFTs Listed for Sale!
33 |
34 | );
35 | }
36 |
37 | return (
38 |
39 |
40 |
41 |
Listed NFTs for Sale
42 |
43 | {nfts.map((nft) => )}
44 |
45 |
46 |
47 |
48 | );
49 | };
50 |
51 | export default withTransition(ListedNFTs);
52 |
--------------------------------------------------------------------------------
/pages/my-nfts.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext } from 'react';
2 |
3 | import Image from 'next/image';
4 |
5 | import withTransition from '../components/withTransition';
6 |
7 | import { NFTContext } from '../context/NFTContext';
8 | import { Loader, NFTCard, Banner, SearchBar } from '../components';
9 | import images from '../assets';
10 | import { shortenAddress } from '../utils/index';
11 |
12 | const MyNFTs = () => {
13 | const { fetchMyNFTsOrListedNFTs, currentAccount } = useContext(NFTContext);
14 | const [nfts, setNfts] = useState([]);
15 | const [nftsCopy, setNftsCopy] = useState([]);
16 | const [isLoading, setIsLoading] = useState(false);
17 | const [activeSelect, setActiveSelect] = useState('Recently Added');
18 |
19 | useEffect(() => {
20 | fetchMyNFTsOrListedNFTs()
21 | .then((items) => {
22 | setNfts(items);
23 | setNftsCopy(items);
24 | setIsLoading(false);
25 | });
26 | }, []);
27 |
28 | useEffect(() => {
29 | const sortedNfts = [...nfts];
30 |
31 | switch (activeSelect) {
32 | case 'Price (low to high)':
33 | setNfts(sortedNfts.sort((a, b) => a.price - b.price));
34 | break;
35 | case 'Price (high to low)':
36 | setNfts(sortedNfts.sort((a, b) => b.price - a.price));
37 | break;
38 | case 'Recently Added':
39 | setNfts(sortedNfts.sort((a, b) => b.tokenId - a.tokenId));
40 | break;
41 | default:
42 | setNfts(nfts);
43 | break;
44 | }
45 | }, [activeSelect]);
46 |
47 | if (isLoading) {
48 | return (
49 |
50 |
51 |
52 | );
53 | }
54 |
55 | const onHandleSearch = (value) => {
56 | const filteredNfts = nfts.filter(({ name }) => name.toLowerCase().includes(value.toLowerCase()));
57 |
58 | if (filteredNfts.length) {
59 | setNfts(filteredNfts);
60 | } else {
61 | setNfts(nftsCopy);
62 | }
63 | };
64 |
65 | const onClearSearch = () => {
66 | if (nfts.length && nftsCopy.length) {
67 | setNfts(nftsCopy);
68 | }
69 | };
70 |
71 | return (
72 |
73 |
74 |
80 |
81 |
82 |
83 |
88 |
89 |
{shortenAddress(currentAccount)}
90 |
91 |
92 |
93 | {!isLoading && !nfts.length && !nftsCopy.length ? (
94 |
95 |
No NFTs Owned!
96 |
97 | ) : (
98 |
99 |
100 |
106 |
107 |
108 | {nfts.map((nft) => (
109 |
114 | ))}
115 |
116 |
117 | )}
118 |
119 | );
120 | };
121 |
122 | export default withTransition(MyNFTs);
123 |
--------------------------------------------------------------------------------
/pages/nft-details.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useContext } from 'react';
2 | import { useRouter } from 'next/router';
3 | import Image from 'next/image';
4 |
5 | import withTransition from '../components/withTransition';
6 | import { shortenName, shortenAddress } from '../utils/index';
7 | import { NFTContext } from '../context/NFTContext';
8 | import { ActionButtons, Button, Loader, Modal } from '../components';
9 | import images from '../assets';
10 |
11 | const PaymentBodyCmp = ({ nft, nftCurrency }) => (
12 |
13 |
14 |
Item
15 |
Subtotal
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
{shortenAddress(nft.seller)}
25 |
{nft.name}
26 |
27 |
28 |
29 |
30 |
{nft.price} {nftCurrency}
31 |
32 |
33 |
34 |
35 |
Total
36 |
{nft.price} {nftCurrency}
37 |
38 |
39 | );
40 |
41 | const AssetDetails = () => {
42 | const { nftCurrency, buyNft, currentAccount, isLoadingNFT } = useContext(NFTContext);
43 | const [nft, setNft] = useState({ image: '', itemId: '', name: '', owner: '', price: '', seller: '' });
44 | const [paymentModal, setPaymentModal] = useState(false);
45 | const [successModal, setSuccessModal] = useState(false);
46 | const [isLoading, setIsLoading] = useState(true);
47 | const router = useRouter();
48 |
49 | useEffect(() => {
50 | // disable body scroll when navbar is open
51 | if (paymentModal || successModal) {
52 | document.body.style.overflow = 'hidden';
53 | } else {
54 | document.body.style.overflow = 'visible';
55 | }
56 | }, [paymentModal, successModal]);
57 |
58 | useEffect(() => {
59 | if (!router.isReady) return;
60 |
61 | setNft(router.query);
62 |
63 | setIsLoading(false);
64 | }, [router.isReady]);
65 |
66 | const checkout = async () => {
67 | await buyNft(nft);
68 |
69 | setPaymentModal(false);
70 | setSuccessModal(true);
71 | };
72 |
73 | if (isLoading) return ;
74 |
75 | return (
76 |
77 |
82 |
83 |
84 |
85 |
{nft.name.length > 18 ? shortenName(nft.name) : nft.name}
86 |
87 |
88 |
89 |
90 |
Owned by
91 |
92 |
93 |
94 |
95 |
{nft.seller === '0x0000000000000000000000000000000000000000' ? shortenAddress(currentAccount) : shortenAddress(nft.seller)}
96 |
97 |
98 |
99 |
100 |
101 |
102 |
105 |
106 |
107 | {nft.description}
108 |
109 |
110 |
111 |
112 | {currentAccount === nft.seller.toLowerCase()
113 | ? (
114 |
115 | You cannot buy your own NFT
116 |
117 | )
118 | : currentAccount === nft.owner.toLowerCase()
119 | ? (
120 |
router.push(`/resell-nft?id=${nft.tokenId}&tokenURI=${nft.tokenURI}`)}
125 | />
126 | )
127 | : (
128 | setPaymentModal(true)}
133 | />
134 | )}
135 |
136 |
137 |
138 | {paymentModal && (
139 |
}
142 | footer={(
143 |
144 |
150 | setPaymentModal(false)}
155 | />
156 |
157 | )}
158 | handleClose={() => setPaymentModal(false)}
159 | />
160 | )}
161 |
162 | {isLoadingNFT && (
163 |
167 |
168 |
169 |
170 |
171 | )}
172 | handleClose={() => setSuccessModal(false)}
173 | />
174 | )}
175 |
176 | {successModal && (
177 | setSuccessModal(false)}>
181 |
182 |
183 |
184 | You successfully purchased {nft.name} from {shortenAddress(nft.seller)} .
185 |
186 | )}
187 | footer={(
188 |
189 | router.push('/my-nfts')}
194 | />
195 |
196 | )}
197 | handleClose={() => setSuccessModal(false)}
198 | />
199 | )}
200 |
201 | );
202 | };
203 |
204 | export default withTransition(AssetDetails);
205 |
--------------------------------------------------------------------------------
/pages/resell-nft.js:
--------------------------------------------------------------------------------
1 | import { useEffect, useState, useContext } from 'react';
2 | import { useRouter } from 'next/router';
3 |
4 | import axios from 'axios';
5 | import withTransition from '../components/withTransition';
6 |
7 | import { NFTContext } from '../context/NFTContext';
8 | import { Button, Input, Loader } from '../components';
9 |
10 | const ResellNFT = () => {
11 | const { createSale, isLoadingNFT } = useContext(NFTContext);
12 | const [price, setPrice] = useState('');
13 | const [image, setImage] = useState('');
14 | const router = useRouter();
15 | const { id, tokenURI } = router.query;
16 |
17 | const fetchNFT = async () => {
18 | if (!tokenURI) return;
19 |
20 | const { data } = await axios.get(tokenURI);
21 |
22 | setPrice(data.price);
23 | setImage(data.image);
24 | };
25 |
26 | useEffect(() => {
27 | fetchNFT();
28 | }, [id]);
29 |
30 | const resell = async () => {
31 | await createSale(tokenURI, price, true, id);
32 |
33 | router.push('/');
34 | };
35 |
36 | if (isLoadingNFT) {
37 | return (
38 |
39 |
40 |
41 | );
42 | }
43 |
44 | return (
45 |
46 |
47 |
Resell NFT
48 |
49 |
setPrice(e.target.value)}
54 | />
55 |
56 | {image &&
}
57 |
58 |
59 |
65 |
66 |
67 |
68 | );
69 | };
70 |
71 | export default withTransition(ResellNFT);
72 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisstef/polyplace/ce5592cbe936751c3048522ee70314e34a3223b2/public/favicon.ico
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/scripts/deploy.js:
--------------------------------------------------------------------------------
1 |
2 | const hre = require('hardhat');
3 |
4 | async function main() {
5 | const NFTMarketplace = await hre.ethers.getContractFactory('NFTMarketplace');
6 | const nftMarketplace = await NFTMarketplace.deploy();
7 |
8 | await nftMarketplace.deployed();
9 |
10 | console.log('NFTMarketplace deployed to:', nftMarketplace.address);
11 | }
12 |
13 | main()
14 | .then(() => process.exit(0))
15 | .catch((error) => {
16 | console.error(error);
17 | process.exit(1);
18 | });
19 |
20 | /*
21 | CODE EXPLANATION:
22 | This script deploys a contract named "NFTMarketplace" using the Hardhat environment. The deployed contract's address is logged in the console.
23 | In case of an error during deployment, an error message is logged in the console and the script exits with a status code of 1.
24 | */
25 |
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap");
2 |
3 | /* ./styles/globals.css */
4 | @tailwind base;
5 | @tailwind components;
6 | @tailwind utilities;
7 |
8 | .nft-gradient {
9 | background: linear-gradient(
10 | 101.12deg,
11 | #7B3FE4 27.35%,
12 | #9D5DFF 99.99%,
13 | #c81cc5 100%,
14 | #c81cc5 100%
15 | );
16 | }
17 |
18 | .white-bg {
19 | background: rgba(255, 255, 255, 0.2);
20 | }
21 |
22 | .nav-h {
23 | height: calc(100vh - 66px);
24 | }
25 |
26 | /* Hide scrollbar for Chrome, Safari and Opera */
27 | .no-scrollbar::-webkit-scrollbar {
28 | display: none;
29 | }
30 |
31 | /* Hide scrollbar for IE, Edge and Firefox */
32 | .no-scrollbar {
33 | scroll-behavior: smooth;
34 | -ms-overflow-style: none; /* IE and Edge */
35 | scrollbar-width: none; /* Firefox */
36 | }
37 |
38 | .checkbox {
39 | opacity: 0;
40 | position: absolute;
41 | }
42 |
43 | .label {
44 | transform: scale(1.5);
45 | }
46 |
47 | .ball {
48 | top: 2px;
49 | left: 2px;
50 | transition: transform 0.2s linear;
51 | }
52 |
53 | /* target the elemenent after the label*/
54 | .checkbox:checked + .label .ball {
55 | transform: translateX(16px);
56 | }
57 |
58 | .fa-moon {
59 | color: pink;
60 | font-size: 9px;
61 | }
62 |
63 | .fa-sun {
64 | color: yellow;
65 | font-size: 9px;
66 | }
67 |
68 | .animated {
69 | -webkit-animation-duration: 1s;
70 | animation-duration: 1s;
71 | -webkit-animation-fill-mode: both;
72 | animation-fill-mode: both;
73 | -webkit-animation-duration: 500ms;
74 | animation-duration: 500ms;
75 | }
76 |
77 | .fadeIn {
78 | -webkit-animation-name: fadeIn;
79 | animation-name: fadeIn;
80 | }
81 |
82 | .flexCenter {
83 | display: flex;
84 | justify-content: center;
85 | align-items: center;
86 | }
87 |
88 | .flexBetween {
89 | display: flex;
90 | justify-content: space-between;
91 | align-items: center;
92 | }
93 |
94 | .flexStart {
95 | display: flex;
96 | justify-content: flex-start;
97 | align-items: flex-start;
98 | }
99 |
100 | .flexStartCenter {
101 | display: flex;
102 | justify-content: flex-start;
103 | align-items: center;
104 | }
105 |
106 | .flexBetweenStart {
107 | display: flex;
108 | justify-content: space-between;
109 | align-items: flex-start;
110 | }
111 |
112 | .flexCenterStart {
113 | display: flex;
114 | justify-content: center;
115 | align-items: flex-start;
116 | }
117 |
118 | @keyframes fadeIn {
119 | from {
120 | opacity: 0;
121 | }
122 |
123 | to {
124 | opacity: 1;
125 | }
126 | }
127 |
128 | @layer components {
129 | .action-icon {
130 | @apply flex items-center justify-center p-2;
131 | }
132 |
133 | .action-tooltip {
134 | @apply absolute w-auto p-2 m-2 min-w-max top-10 rounded-md shadow-md font-poppins dark:text-white text-nft-black-1 text-sm minlg:text-lg font-semibold dark:bg-nft-black-1 bg-white scale-0
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: [
3 | './pages/**/*.{js,ts,jsx,tsx}',
4 | './components/**/*.{js,ts,jsx,tsx}',
5 | ],
6 | darkMode: 'class',
7 | theme: {
8 | extend: {
9 | colors: {
10 | 'regal-blue': '#243c5a',
11 | 'nft-dark': '#24252D',
12 | 'nft-gray-1': '#E3E1E3',
13 | 'nft-gray-2': '#888888',
14 | 'nft-gray-3': '#4F4F4F',
15 | 'nft-black-1': '#2D2E36',
16 | 'nft-black-2': '#1B1A21',
17 | 'nft-black-3': '#2A2D3A',
18 | 'nft-black-4': '#24252D',
19 | 'nft-red-violet': '#7B3FE4',
20 | 'file-active': '#2196f3',
21 | 'file-accept': '#00e676',
22 | 'file-reject': '#ff1744',
23 | 'overlay-black': 'rgba(0, 0, 0, 0.8)',
24 | },
25 | width: {
26 | 215: '215px',
27 | 357: '357px',
28 | 557: '557px',
29 | },
30 | minWidth: {
31 | 155: '155px',
32 | 190: '190px',
33 | 215: '215px',
34 | 240: '240px',
35 | 256: '256px',
36 | 327: '327px',
37 | },
38 | height: {
39 | 300: '300px',
40 | 557: '557px',
41 | },
42 | inset: {
43 | 45: '45%',
44 | 65: '65px',
45 | },
46 | spacing: {
47 | 65: '65px',
48 | },
49 | flex: {
50 | 2: '2 2 0%',
51 | },
52 | lineHeight: {
53 | 70: '70px',
54 | },
55 | zIndex: {
56 | '-5': '-5',
57 | 0: '0',
58 | },
59 | },
60 | screens: {
61 | lg: { max: '1800px' },
62 | md: { max: '990px' },
63 | sm: { max: '600px' },
64 | xs: { max: '400px' },
65 | minmd: '1700px',
66 | minlg: '2100px',
67 | },
68 | fontFamily: {
69 | poppins: ['Poppins', 'sans-serif'],
70 | },
71 | },
72 | variants: {
73 | extend: {},
74 | },
75 | plugins: [],
76 | };
77 |
--------------------------------------------------------------------------------
/test/sample-test.js:
--------------------------------------------------------------------------------
1 | const { expect } = require('chai');
2 | const { ethers } = require('hardhat');
3 |
4 | describe('Greeter', () => {
5 | it("Should return the new greeting once it's changed", async () => {
6 | const Greeter = await ethers.getContractFactory('Greeter');
7 | const greeter = await Greeter.deploy('Hello, world!');
8 | await greeter.deployed();
9 |
10 | expect(await greeter.greet()).to.equal('Hello, world!');
11 |
12 | const setGreetingTx = await greeter.setGreeting('Hola, mundo!');
13 |
14 | // wait until the transaction is mined
15 | await setGreetingTx.wait();
16 |
17 | expect(await greeter.greet()).to.equal('Hola, mundo!');
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/utils/index.js:
--------------------------------------------------------------------------------
1 | export const getCreators = (nfts) => {
2 | const creators = nfts.reduce((creatorObject, nft) => {
3 | (creatorObject[nft.seller] = creatorObject[nft.seller] || []).push(nft);
4 |
5 | return creatorObject;
6 | }, {});
7 |
8 | return Object.entries(creators).map((creator) => {
9 | const seller = creator[0];
10 | const sum = creator[1].map((item) => Number(item.price)).reduce((prev, curr) => prev + curr, 0);
11 |
12 | return ({ seller, sum });
13 | });
14 | };
15 |
16 |
17 | // A useful function to create unique blockchain addresses.
18 |
19 | export const makeId = (length) => {
20 | let result = '';
21 |
22 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
23 | const charactersLength = characters.length;
24 |
25 | for (let i = 0; i < length; i += 1) {
26 | result += characters.charAt(Math.floor(Math.random() * charactersLength));
27 | }
28 |
29 | return result;
30 | };
31 |
32 |
33 | export const shortenAddress = (address) => (
34 | `${address.slice(0, 5)}...${address.slice(address.length - 4)}`
35 | );
36 |
37 | export const shortenName = (name) => (
38 | `${name.slice(0, 14)}...`
39 | );
40 |
41 | export const shortenPrice = () => (
42 | 'A lot of'
43 | );
44 |
45 |
--------------------------------------------------------------------------------