├── .secret ├── .eslintrc.json ├── next.config.js ├── .config.js ├── styles ├── globals.css └── Home.module.css ├── public ├── favicon.ico └── vercel.svg ├── postcss.config.js ├── pages ├── api │ └── hello.js ├── _app.js ├── my-assets.js ├── creator-dashboard.js ├── index.js └── create-item.js ├── tailwind.config.js ├── hardhat.config.js ├── .gitignore ├── scripts └── deploy.js ├── contracts ├── NFT.sol └── NFTMarket.sol ├── package.json ├── README.md └── test └── sample-test.js /.secret: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reactStrictMode: true, 3 | } 4 | -------------------------------------------------------------------------------- /.config.js: -------------------------------------------------------------------------------- 1 | export const nftaddress = "" 2 | export const nftmarketaddress = "" -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwing utilities; -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EmanuelCampos/nft-marketplace/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(req, res) { 4 | res.status(200).json({ name: 'John Doe' }) 5 | } 6 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: [], 3 | darkMode: false, // or 'media' or 'class' 4 | theme: { 5 | extend: {}, 6 | }, 7 | variants: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } 12 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomiclabs/hardhat-waffle"); 2 | const fs = require("fs") 3 | 4 | const privateKey = fs.readFileSync(".secret").toString() 5 | const projectId = 6 | 7 | module.exports = { 8 | networks: { 9 | hardhat: { 10 | chainId: 1337 11 | }, 12 | mumbai: { 13 | url: `https://polygon-mumbai.infura.io/v3/${projectId}`, 14 | accounts: [privateKey] 15 | }, 16 | mainnet: { 17 | url: `https://mainnet.infura.io/v3/${projectId}`, 18 | accounts: [privateKey] 19 | } 20 | }, 21 | solidity: "0.8.4", 22 | }; 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | node_modules 37 | 38 | #Hardhat files 39 | cache 40 | artifacts 41 | -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | const hre = require("hardhat"); 2 | 3 | async function main() { 4 | const NFTMarket = await hre.ethers.getContractFactory("NFTMarket"); 5 | const nftMarket = await NFTMarket.deploy(); 6 | await nftMarket.deployed(); 7 | console.log("nftMarket deployed to:", nftMarket.address); 8 | 9 | const NFT = await hre.ethers.getContractFactory("NFT"); 10 | const nft = await NFT.deploy(nftMarket.address) 11 | await nft.deployed() 12 | console.log("nft deployed to:", nft.address); 13 | 14 | } 15 | 16 | // We recommend this pattern to be able to use async/await everywhere 17 | // and properly handle errors. 18 | main() 19 | .then(() => process.exit(0)) 20 | .catch((error) => { 21 | console.error(error); 22 | process.exit(1); 23 | }); 24 | -------------------------------------------------------------------------------- /contracts/NFT.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.4; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 5 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; 6 | import "@openzeppelin/contracts/utils/Counters.sol"; 7 | 8 | contract NFT is ERC721URIStorage { 9 | using Counters for Counters.Counter; 10 | Counters.Counter private _tokenIds; 11 | address contractAddress; 12 | 13 | constructor(address marketplaceAddress) ERC721("Metaverse Tokens", "METT") { 14 | contractAddress = marketplaceAddress; 15 | } 16 | 17 | function createToken(string memory tokenURI) public returns(uint) { 18 | _tokenIds.increment(); 19 | uint256 newItemId = _tokenIds.current(); 20 | 21 | _mint(msg.sender, newItemId); 22 | _setTokenURI(newItemId, tokenURI); 23 | setApprovalForAll(contractAddress, true); 24 | return newItemId; 25 | } 26 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "polygon-next", 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.2", 13 | "@nomiclabs/hardhat-waffle": "^2.0.1", 14 | "@openzeppelin/contracts": "^4.2.0", 15 | "axios": "^0.21.1", 16 | "chai": "^4.3.4", 17 | "ethereum-waffle": "^3.4.0", 18 | "ethers": "^5.4.1", 19 | "hardhat": "^2.4.1", 20 | "ipfs-http-client": "^50.1.2", 21 | "next": "11.0.1", 22 | "react": "17.0.2", 23 | "react-dom": "17.0.2", 24 | "web3modal": "^1.9.3" 25 | }, 26 | "devDependencies": { 27 | "autoprefixer": "^10.2.6", 28 | "eslint": "7.29.0", 29 | "eslint-config-next": "11.0.1", 30 | "postcss": "^8.3.5", 31 | "tailwindcss": "^2.2.4" 32 | } 33 | } -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import 'tailwindcss/tailwind.css' 2 | import Link from 'next/link' 3 | 4 | function MyApp({ Component, pageProps }) { 5 | return ( 6 |
7 | 32 | 33 |
34 | ) 35 | } 36 | 37 | export default MyApp 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /test/sample-test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require("chai"); 2 | 3 | describe("NFTMarket", function () { 4 | 5 | let owner 6 | 7 | beforeEach(async () => { 8 | const accs = await ethers.getSigners(); 9 | console.log(accs[0].address) 10 | 11 | owner = accs[0].address 12 | 13 | }); 14 | 15 | 16 | it("should create and execute market sales", async function () { 17 | 18 | const Market = await ethers.getContractFactory("NFTMarket") 19 | const market = await Market.deploy() 20 | await market.deployed() 21 | const marketAddress = market.address 22 | 23 | const NFT = await ethers.getContractFactory("NFT") 24 | const nft = await NFT.deploy(marketAddress) 25 | await nft.deployed() 26 | const nftContractAddress = nft.address 27 | 28 | let listingPrice = await market.getListingPrice() 29 | listingPrice = listingPrice.toString() 30 | 31 | const auctionPrice = ethers.utils.parseUnits("100", "ether") 32 | 33 | await nft.createToken("https://www.mytokenlocation.com") 34 | await nft.createToken("https://www.mytokenlocation2.com") 35 | 36 | await market.createMarketItem(nftContractAddress, 1, auctionPrice, { value: listingPrice }) 37 | await market.createMarketItem(nftContractAddress, 2, auctionPrice, { value: listingPrice }) 38 | 39 | const [_, buyerAddress] = await ethers.getSigners() 40 | 41 | await market.connect(buyerAddress).createMarketSale(nftContractAddress, 1, { value: auctionPrice }) 42 | 43 | let items = await market.fetchMarketItems() 44 | 45 | items = await Promise.all(items.map(async i => { 46 | const tokenUri = await nft.tokenURI(i.tokenId) 47 | let item = { 48 | price: i.price.toString(), 49 | tokenId: i.tokenId.toString(), 50 | seller: i.seller, 51 | owner: i.owner, 52 | tokenUri 53 | } 54 | return item 55 | 56 | 57 | })) 58 | 59 | console.log("items:", items) 60 | 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | min-height: 100vh; 3 | padding: 0 0.5rem; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | height: 100vh; 9 | } 10 | 11 | .main { 12 | padding: 5rem 0; 13 | flex: 1; 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: center; 17 | align-items: center; 18 | } 19 | 20 | .footer { 21 | width: 100%; 22 | height: 100px; 23 | border-top: 1px solid #eaeaea; 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | } 28 | 29 | .footer a { 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | flex-grow: 1; 34 | } 35 | 36 | .title a { 37 | color: #0070f3; 38 | text-decoration: none; 39 | } 40 | 41 | .title a:hover, 42 | .title a:focus, 43 | .title a:active { 44 | text-decoration: underline; 45 | } 46 | 47 | .title { 48 | margin: 0; 49 | line-height: 1.15; 50 | font-size: 4rem; 51 | } 52 | 53 | .title, 54 | .description { 55 | text-align: center; 56 | } 57 | 58 | .description { 59 | line-height: 1.5; 60 | font-size: 1.5rem; 61 | } 62 | 63 | .code { 64 | background: #fafafa; 65 | border-radius: 5px; 66 | padding: 0.75rem; 67 | font-size: 1.1rem; 68 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 69 | Bitstream Vera Sans Mono, Courier New, monospace; 70 | } 71 | 72 | .grid { 73 | display: flex; 74 | align-items: center; 75 | justify-content: center; 76 | flex-wrap: wrap; 77 | max-width: 800px; 78 | margin-top: 3rem; 79 | } 80 | 81 | .card { 82 | margin: 1rem; 83 | padding: 1.5rem; 84 | text-align: left; 85 | color: inherit; 86 | text-decoration: none; 87 | border: 1px solid #eaeaea; 88 | border-radius: 10px; 89 | transition: color 0.15s ease, border-color 0.15s ease; 90 | width: 45%; 91 | } 92 | 93 | .card:hover, 94 | .card:focus, 95 | .card:active { 96 | color: #0070f3; 97 | border-color: #0070f3; 98 | } 99 | 100 | .card h2 { 101 | margin: 0 0 1rem 0; 102 | font-size: 1.5rem; 103 | } 104 | 105 | .card p { 106 | margin: 0; 107 | font-size: 1.25rem; 108 | line-height: 1.5; 109 | } 110 | 111 | .logo { 112 | height: 1em; 113 | margin-left: 0.5rem; 114 | } 115 | 116 | @media (max-width: 600px) { 117 | .grid { 118 | width: 100%; 119 | flex-direction: column; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /pages/my-assets.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import { ethers } from 'ethers' 3 | import { useEffect, useState } from 'react' 4 | import axios from 'axios' 5 | import Web3Modal from 'web3modal' 6 | 7 | import { 8 | nftaddress, nftmarketaddress 9 | } from '../.config' 10 | 11 | import NFT from '../artifacts/contracts/NFT.sol/NFT.json' 12 | import Market from '../artifacts/contracts/NFTMarket.sol/NFTMarket.json' 13 | 14 | export default function MyAssets() { 15 | const [nfts, setNfts] = useState([]) 16 | const [loadingState, setLoadingState] = useState('not-loaded') 17 | 18 | useEffect(() => { 19 | loadNFTs() 20 | }, []) 21 | 22 | async function loadNFTs() { 23 | const web3Modal = new Web3Modal() 24 | const connection = await web3Modal.connect() 25 | const provider = new ethers.providers.Web3Provider(connection) 26 | const signer = provider.getSigner() 27 | 28 | const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, signer) 29 | const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider) 30 | const data = await marketContract.fetchMyNFTs() 31 | 32 | const items = await Promise.all(data.map(async i => { 33 | const tokenUri = await tokenContract.tokenURI(i.tokenId) 34 | const meta = await axios.get(tokenUri) 35 | let price = ethers.utils.formatUnits(i.price.toString(), 'ether') 36 | let item = { 37 | price, 38 | tokenId: i.tokenId.toNumber(), 39 | seller: i.seller, 40 | owner: i.owner, 41 | image: meta.data.image, 42 | } 43 | return item 44 | })) 45 | setNfts(items) 46 | setLoadingState('loaded') 47 | } 48 | 49 | if(loadingState === 'loaded' && !nfts.length) return ( 50 |

No assets owned

51 | ) 52 | 53 | return ( 54 |
55 |
56 |
57 | { 58 | nfts.map((nft, i) => ( 59 |
60 | {nft.name} 61 |
62 |

Price - {nft.price} Eth

63 |
64 |
65 | )) 66 | } 67 |
68 |
69 |
70 | ) 71 | 72 | 73 | } -------------------------------------------------------------------------------- /pages/creator-dashboard.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import { ethers } from 'ethers' 3 | import { useEffect, useState } from 'react' 4 | import axios from 'axios' 5 | import Web3Modal from 'web3modal' 6 | 7 | import { 8 | nftaddress, nftmarketaddress 9 | } from '../.config' 10 | 11 | import NFT from '../artifacts/contracts/NFT.sol/NFT.json' 12 | import Market from '../artifacts/contracts/NFTMarket.sol/NFTMarket.json' 13 | 14 | export default function CreatorDashboard() { 15 | const [nfts, setNfts] = useState([]) 16 | const [sold, setSold] = useState([]) 17 | const [loadingState, setLoadingState] = useState('not-loaded') 18 | 19 | useEffect(() => { 20 | loadNFTs() 21 | }, []) 22 | 23 | async function loadNFTs() { 24 | const web3Modal = new Web3Modal() 25 | const connection = await web3Modal.connect() 26 | const provider = new ethers.providers.Web3Provider(connection) 27 | const signer = provider.getSigner() 28 | 29 | const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, signer) 30 | const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider) 31 | const data = await marketContract.fetchItemsCreated() 32 | 33 | const items = await Promise.all(data.map(async i => { 34 | const tokenUri = await tokenContract.tokenURI(i.tokenId) 35 | const meta = await axios.get(tokenUri) 36 | let price = ethers.utils.formatUnits(i.price.toString(), 'ether') 37 | let item = { 38 | price, 39 | tokenId: i.tokenId.toNumber(), 40 | seller: i.seller, 41 | owner: i.owner, 42 | sold: i.sold, 43 | image: meta.data.image, 44 | } 45 | return item 46 | })) 47 | 48 | const soldItems = items.filter(i => i.sold) 49 | setSold(soldItems) 50 | setNfts(items) 51 | setLoadingState('loaded') 52 | } 53 | return( 54 |
55 |
56 |

Items Created

57 |
58 | { 59 | nfts.map((nft, i) => ( 60 |
61 | {nft.name} 62 |
63 |

Price - {nft.price} Eth

64 |
65 |
66 | )) 67 | } 68 |
69 |
70 |
71 | { 72 | Boolean(sold.length) && ( 73 |
74 |

Items Sold

75 |
76 | { 77 | sold.map((nft, i) => ( 78 |
79 | {nft.name} 80 |
81 |

Price - {nft.price} Eth

82 |
83 |
84 | )) 85 | } 86 |
87 |
88 | ) 89 | } 90 |
91 |
92 | ) 93 | } -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import { ethers} from 'ethers' 3 | import {useEffect, useState } from 'react' 4 | import axios from 'axios' 5 | import Web3Modal from 'web3modal' 6 | 7 | import { 8 | nftaddress, nftmarketaddress 9 | } from '../.config' 10 | 11 | import NFT from '../artifacts/contracts/NFT.sol/NFT.json' 12 | import Market from '../artifacts/contracts/NFTMarket.sol/NFTMarket.json' 13 | 14 | export default function Home() { 15 | const [nfts, setNfts] = useState([]) 16 | const [loadingState, setLoadingState] = useState('not-loaded') 17 | 18 | useEffect(() => { 19 | loadNFTs() 20 | }, []) 21 | 22 | async function loadNFTs() { 23 | const provider = new ethers.providers.JsonRpcProvider() 24 | const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider) 25 | const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, provider) 26 | 27 | const data = await marketContract.fetchMarketItems() 28 | 29 | const items = await Promise.all(data.map(async i => { 30 | const tokenUri = await tokenContract.tokenURI(i.tokenId) 31 | const meta = await axios.get(tokenUri) 32 | let price = ethers.utils.formatUnits(i.price.toString(), 'ether') 33 | let item = { 34 | price, 35 | tokenId: i.tokenId.toNumber(), 36 | seller: i.seller, 37 | owner: i.owner, 38 | image: meta.data.image, 39 | name: meta.data.name, 40 | description: meta.data.description, 41 | } 42 | return item 43 | })) 44 | setNfts(items) 45 | setLoadingState('loaded') 46 | } 47 | 48 | async function buyNft(nft) { 49 | const web3Modal = new Web3Modal() 50 | const connection = await web3Modal.connect() 51 | const provider = new ethers.providers.Web3Provider(connection) 52 | 53 | const signer = provider.getSigner() 54 | const contract = new ethers.Contract(nftmarketaddress, Market.abi, signer) 55 | 56 | const price = ethers.utils.parseUnits(nft.price.toString(), 'ether') 57 | 58 | const transaction = await contract.createMarketSale(nftaddress, nft.tokenId, { value: price }) 59 | 60 | await transaction.wait() 61 | loadNFTs() 62 | 63 | } 64 | 65 | if(loadingState === 'loaded' && !nfts.length) return ( 66 |

No items in marketplace

67 | ) 68 | 69 | return ( 70 |
71 |
72 |
73 | { 74 | nfts.map((nft, i) => ( 75 |
76 | {nft.name}/ 77 |
78 |

{nft.name}

79 |
80 |

{nft.description}

81 |
82 |
83 |
84 |

{nft.price} Matic

85 | 91 | 92 |
93 | 94 | 95 |
96 | )) 97 | } 98 |
99 |
100 |
101 | ) 102 | } 103 | -------------------------------------------------------------------------------- /pages/create-item.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | 3 | 4 | import { useState } from 'react' 5 | import { ethers } from 'ethers' 6 | import { create as ipfsHttpClient} from 'ipfs-http-client' 7 | import { useRouter } from 'next/router' 8 | import Web3Modal from 'web3modal' 9 | 10 | const client = ipfsHttpClient('https://ipfs.infura.io:5001/api/v0') 11 | 12 | import { 13 | nftaddress, nftmarketaddress 14 | } from '../.config' 15 | 16 | import NFT from '../artifacts/contracts/NFT.sol/NFT.json' 17 | import Market from '../artifacts/contracts/NFTMarket.sol/NFTMarket.json' 18 | 19 | export default function CreateItem() { 20 | const [fileUrl, setFileUrl] = useState(null) 21 | const [formInput, updateFormInput] = useState({ price: '', name: '', description: ''}) 22 | const router = useRouter() 23 | 24 | async function onChange(e) { 25 | const file = e.target.files[0] 26 | try { 27 | const added = await client.add( 28 | file, 29 | { 30 | progress: (prog) => console.log('received:' + prog) 31 | } 32 | ) 33 | const url = `https://ipfs.infura.io/ipfs/${added.path}` 34 | setFileUrl(url) 35 | } catch(e) { 36 | console.log(e) 37 | } 38 | } 39 | 40 | async function createItem() { 41 | const { name, description, price } = formInput 42 | 43 | if(!name || !description || !price || !fileUrl) return 44 | 45 | const data = JSON.stringify({ 46 | name, description, image: fileUrl 47 | }) 48 | 49 | try { 50 | const added = await client.add(data) 51 | const url = `https://ipfs.infura.io/ipfs/${added.path}` 52 | 53 | createSale(url) 54 | 55 | 56 | } catch(error) { 57 | console.log("Error uploading file:", error) 58 | } 59 | } 60 | 61 | async function createSale(url) { 62 | const web3Modal = new Web3Modal() 63 | const connection = await web3Modal.connect() 64 | const provider = new ethers.providers.Web3Provider(connection) 65 | const signer = provider.getSigner() 66 | 67 | let contract = new ethers.Contract(nftaddress, NFT.abi, signer) 68 | let transaction = await contract.createToken(url) 69 | let tx = await transaction.wait() 70 | 71 | let event = tx.events[0] 72 | let value = event.args[2] 73 | let tokenId = value.toNumber() 74 | 75 | const price = ethers.utils.parseUnits(formInput.price, 'ether') 76 | 77 | contract = new ethers.Contract(nftmarketaddress, Market.abi, signer) 78 | let listingPrice = await contract.getListingPrice() 79 | listingPrice = listingPrice.toString() 80 | 81 | transaction = await contract.createMarketItem(nftaddress, tokenId, price, { value: listingPrice}) 82 | 83 | await transaction.wait() 84 | router.push('/') 85 | } 86 | 87 | return ( 88 |
89 |
90 | updateFormInput({ ...formInput, name: e.target.value})} 94 | /> 95 |