了解如何用hardhat,IPFS和Next js创建NFT市场
了解如何用hardhat,IPFS和Next js创建NFT市场
图片来源: shykhman
当用户出售 NFT 时,NFT 的所有权从创建者转移到市场合约。
当用户购买 NFT 时,购买的资金从买方转移到卖方,该 NFT 也将从市场转移到买方。
市场所有者可以设置用户出售 NFT 的服务费。这笔费用从卖方收取,并在每次交易完成后转移到合约所有者。市场合约所有者可以从市场进行的所有销售获得收入。
本文中,我们将在 Polygon 网络上部署一个市场合约。
Polygon是一个多层平台,其目标是通过大量的侧链来扩展以太坊,所有的侧链都旨在以高效且经济的方式疏通主平台。
Polygon 的主链是权益证明 (PoS) 侧链,参与者可以质押 MATIC 代币来验证交易并对网络升级进行投票。
npx create-next-app marketplace
npm install ethers hardhat ethereum-waffle chai @nomiclabs/hardhat-waffle @nomiclabs/hardhat-ethers web3modal @openzeppelin/contracts ipfs-http-client axios react-toastify
npx hardhat
如果 README.md 文件出现错误,删除并重试
require("@nomiclabs/hardhat-waffle");
const fs = require('fs');
module.exports = {
defaultNetwork: "hardhat",
networks: {
hardhat: {
chainId: 1337
},
// polygon testnet
mumbai: {
url: "https://rpc-mumbai.maticvigil.com",
accounts: [process.env.privateKey] // your wallet private key
},
//polygon mainnet
matic: {
url: "https://rpc-mainnet.maticvigil.com",
accounts: [process.env.privateKey]
}
},
solidity: {
version: "0.8.4",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
}
};
- hardhat.config.js -
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract NFTMarketplace is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
Counters.Counter private _itemsSold;
/* platform fee */
uint256 listingPrice = 0 ether;
address payable owner;
mapping(uint256 => MarketItem) private idToMarketItem;
struct MarketItem {
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
bool sold;
}
event MarketItemCreated (
uint256 indexed tokenId,
address seller,
address owner,
uint256 price,
bool sold
);
constructor() ERC721("Metaverse Tokens", "METT") {
owner = payable(msg.sender);
}
/* Updates the listing price of the contract */
function updateListingPrice(uint _listingPrice) public payable {
require(owner == msg.sender, "Only marketplace owner can update listing price.");
listingPrice = _listingPrice;
}
/* Returns the listing price of the contract */
function getListingPrice() public view returns (uint256) {
return listingPrice;
}
/* Mints a token and lists it in the marketplace */
function createToken(string memory tokenURI, uint256 price) public payable returns (uint) {
_tokenIds.increment();
uint256 newTokenId = _tokenIds.current();
_mint(msg.sender, newTokenId);
_setTokenURI(newTokenId, tokenURI);
createMarketItem(newTokenId, price);
return newTokenId;
}
function createMarketItem(
uint256 tokenId,
uint256 price
) private {
require(price > 0, "Price must be at least 1 wei");
require(msg.value == listingPrice, "Price must be equal to listing price");
idToMarketItem[tokenId] = MarketItem(
tokenId,
payable(msg.sender),
payable(address(this)),
price,
false
);
_transfer(msg.sender, address(this), tokenId);
emit MarketItemCreated(
tokenId,
msg.sender,
address(this),
price,
false
);
}
/* allows someone to resell a token they have purchased */
function resellToken(uint256 tokenId, uint256 price) public payable {
require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner can perform this operation");
require(msg.value == listingPrice, "Price must be equal to listing price");
idToMarketItem[tokenId].sold = false;
idToMarketItem[tokenId].price = price;
idToMarketItem[tokenId].seller = payable(msg.sender);
idToMarketItem[tokenId].owner = payable(address(this));
_itemsSold.decrement();
_transfer(msg.sender, address(this), tokenId);
}
/* Creates the sale of a marketplace item */
/* Transfers ownership of the item, as well as funds between parties */
function createMarketSale(
uint256 tokenId
) public payable {
uint price = idToMarketItem[tokenId].price;
address seller = idToMarketItem[tokenId].seller;
require(msg.value == price, "Please submit the asking price in order to complete the purchase");
idToMarketItem[tokenId].owner = payable(msg.sender);
idToMarketItem[tokenId].sold = true;
idToMarketItem[tokenId].seller = payable(address(0));
_itemsSold.increment();
_transfer(address(this), msg.sender, tokenId);
payable(owner).transfer(listingPrice);
payable(seller).transfer(msg.value);
}
/* Returns all unsold market items */
function fetchMarketItems() public view returns (MarketItem[] memory) {
uint itemCount = _tokenIds.current();
uint unsoldItemCount = _tokenIds.current() - _itemsSold.current();
uint currentIndex = 0;
MarketItem[] memory items = new MarketItem[](unsoldItemCount);
for (uint i = 0; i < itemCount; i++) {
if (idToMarketItem[i + 1].owner == address(this)) {
uint currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
/* Returns only items that a user has purchased */
function fetchMyNFTs() public view returns (MarketItem[] memory) {
uint totalItemCount = _tokenIds.current();
uint itemCount = 0;
uint currentIndex = 0;
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
uint currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
/* Returns only items a user has listed */
function fetchItemsListed() public view returns (MarketItem[] memory) {
uint totalItemCount = _tokenIds.current();
uint itemCount = 0;
uint currentIndex = 0;
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].seller == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].seller == msg.sender) {
uint currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
}
- NFTMarketplace.sol -
const hre = require("hardhat");
const fs = require('fs');
async function main() {
const NFTMarketplace = await hre.ethers.getContractFactory("NFTMarketplace");
const nftMarketplace = await NFTMarketplace.deploy();
await nftMarketplace.deployed();
console.log("nftMarketplace deployed to:", nftMarketplace.address);
fs.writeFileSync('./config.js', `
export const marketplaceAddress = "${nftMarketplace.address}"
`)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
- deploy.js -
config.js
文件npx hardhat run scripts/deploy.js --network mumbai
部署后,就可以看到市场合约地址
如果你在这里没有请求,必须在你的帐户中测试 Matic 才能成功部署合约
在这一部分中,我们将看到如何将部署的合约与下一个 js 前端关联起来。
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init -p
tailwind.config.js
配置路径module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
styles/globals.css
中的代码并且按下面更新:@tailwind base;
@tailwind components;
@tailwind utilities;
.js
文件create.js
、myNft.js
, dashboard.js
和resellNft.js
。_app.js
并如下编辑:import '../styles/globals.css'
import Link from 'next/link'
function MyApp({ Component, pageProps }) {
return (
<div>
<nav className="border-b p-6">
<p className="text-4xl font-bold">Metaverse Marketplace</p>
<div className="flex mt-4">
<Link href="/">
<a className="mr-4">
Home
</a>
</Link>
<Link href="/create">
<a className="mr-6">
Create NFT
</a>
</Link>
<Link href="/nftowns">
<a className="mr-6">
My NFTs
</a>
</Link>
<Link href="/dashboard">
<a className="mr-6">
Dashboard
</a>
</Link>
</div>
</nav>
<Component {...pageProps} />
</div>
)
}
export default MyApp
- _app.js -
index.js
并如下编辑:import { ethers } from 'ethers'
import { useEffect, useState } from 'react'
import axios from 'axios'
import Web3Modal from 'web3modal'
import {
marketplaceAddress
} from '../config'
import NFTMarketplace from '../artifacts/contracts/NFTMarketplace.sol/NFTMarketplace.json'
export default function Home() {
const [nfts, setNfts] = useState([])
const [loadingState, setLoadingState] = useState('not-loaded')
useEffect(() => {
loadNFTs()
}, [])
/*
* map over items returned from smart contract and format
* them as well as fetch their token metadata
*/
async function loadNFTs() {
/* create a generic provider and query for unsold market items */
const provider = new ethers.providers.JsonRpcProvider("https://rpc-mumbai.maticvigil.com")
//console.log('1.1. provider------Success', provider)
//console.log('1.02. marketplaceAddress, NFTMarketplace.abi, provider----', marketplaceAddress, NFTMarketplace.abi, provider)
const contract = new ethers.Contract(marketplaceAddress, NFTMarketplace.abi, provider)
//console.log('1.2. contract------Success', contract)
let data = null
try {
data = await contract.fetchMarketItems()
//console.log('2.1. contract.fetchMarketItems------Success', data)
} catch (error) {
//console.log('2.2. contract.fetchMarketItems------failed', error)
return toast.error(error || 'Error contract.fetchMarketItems')
}
/*
* map over items returned from smart contract and format
* them as well as fetch their token metadata
*/
try {
const items = await Promise.all(data.map(async (i) => {
const tokenUri = await contract.tokenURI(i.tokenId)
const meta = await axios.get(tokenUri)
const price = ethers.utils.formatUnits(i.price.toString(), 'ether')
const item = {
price,
tokenId: i.tokenId.toNumber(),
seller: i.seller,
owner: i.owner,
image: meta.data.image,
name: meta.data.name,
description: meta.data.description,
}
return item
}))
setNfts(items)
setLoadingState('loaded')
//console.log('3.1. get NFT List-----------Success', items)
} catch (error) {
//console.log('3.2. Error get NFT List-----------', error)
setLoadingState('loaded')
return toast.error(error || 'Error get NFT List')
}
}
async function buyNft(nft) {
/* needs the user to sign the transaction, so will use Web3Provider and sign it */
const web3Modal = new Web3Modal()
let connection = null
try {
connection = await web3Modal.connect()
//console.log('1.1. Connection-----------Success', connection)
} catch (error) {
//console.log('1.2. Connection-----------Error', error)
return toast.error(error || 'Error Connection')
}
const provider = new ethers.providers.Web3Provider(connection)
//console.log('2. provider-----------Success', provider)
const signer = provider.getSigner()
//console.log('3. signer-----------Success', signer)
//console.log('4.01. marketplaceAddress, NFTMarketplace.abi, signer----', marketplaceAddress, NFTMarketplace.abi, signer)
const contract = new ethers.Contract(marketplaceAddress, NFTMarketplace.abi, signer)
//console.log('4.2. contract------Success', contract)
/* user will be prompted to pay the asking proces to complete the transaction */
const price = ethers.utils.parseUnits(nft.price.toString(), 'ether')
//console.log('5. price------Success', price)
let transaction = null
try {
transaction = await contract.createMarketSale(nft.tokenId, {
value: price
})
//console.log('6.1. transaction-----------Success', transaction)
} catch (error) {
//console.log('6.2. transaction-----------Error', error)
return toast.error(error || 'Error transaction')
}
try {
await transaction.wait()
loadNFTs()
//console.log('7.1. transaction.wait-----------Success', transaction)
} catch (error) {
//console.log('7.2. transaction.wait-----------Error', error)
return toast.error(error || 'Error transaction.wait')
}
}
if (loadingState === 'loaded' && !nfts.length) return (<h1 className="px-20 py-10 text-3xl">No items in marketplace</h1>)
return (
<div className="flex justify-center">
<div className="px-4" style={{ maxWidth: '1600px' }}>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4">
{
nfts.map((nft, i) => (
<div key={i} className="border shadow rounded-xl overflow-hidden">
<img src={nft.image} />
<div className="p-4">
<p style={{ height: '64px' }} className="text-2xl font-semibold">{nft.name}</p>
<div style={{ height: '70px', overflow: 'hidden' }}>
<p className="text-gray-400">{nft.description}</p>
</div>
</div>
<div className="p-4 bg-black">
<p className="text-2xl font-bold text-white">{nft.price} ETH</p>
<button className="mt-4 w-full bg-pink-500 text-white font-bold py-2 px-12 rounded" onClick={() => buyNft(nft)}>Buy</button>
</div>
</div>
))
}
</div>
</div>
</div>
)
}
- index.js -
create.js
创建 NFT :import { useState } from 'react'
import { ethers } from 'ethers'
import { create as ipfsHttpClient } from 'ipfs-http-client'
import { useRouter } from 'next/router'
import Web3Modal from 'web3modal'
import { toast } from 'react-toastify'
import {
marketplaceAddress
} from '../config'
import NFTMarketplace from '../artifacts/contracts/NFTMarketplace.sol/NFTMarketplace.json'
export default function CreateItem() {
const [fileUrl, setFileUrl] = useState('')
const [formInput, updateFormInput] = useState({ price: '', name: '', description: '' })
const router = useRouter()
const client = ipfsHttpClient({ host: 'ipfs.infura.io', port: 5001, protocol: 'https', apiPath: 'api/v0' })
// convert image to URL
async function onChange(e) {
const file = e.target.files[0]
try {
const added = await client.add(
file,
// {
// progress: (prog) => //console.log(`received: ${prog}`)
// }
)
const url = `https://ipfs.infura.io/ipfs/${added.path}`
setFileUrl(url)
} catch (error) {
//console.log('Error uploading file: ', error)
toast.error(error || 'Error on Onchange File')
}
}
// upload to ipfs and return ipfs url
async function uploadToIPFS() {
const { name, description, price } = formInput
if (!name || !description || !price || !fileUrl) return
/* first, upload to IPFS */
const data = JSON.stringify({
name, description, image: fileUrl
})
try {
const added = await client.add(data)
const url = `https://ipfs.infura.io/ipfs/${added.path}`
/* after file is uploaded to IPFS, return the URL to use it in the transaction */
return url
} catch (error) {
//console.log('Error uploading file: ', error)
toast.error(error || 'Error on uploadToIPFS')
}
}
async function listNFTForSale() {
const url = await uploadToIPFS()
//console.log('1. uploadToIPFS Success------', url)
const web3Modal = new Web3Modal()
//console.log('2. Web3Modal------', web3Modal)
let connection = null
try {
connection = await web3Modal.connect()
//console.log('3.1. connection------success', connection)
} catch (error) {
//console.log('3.2. connection------failed', error)
toast.error(error || 'Error on web3Modal Connect')
}
if (!connection) return
const provider = new ethers.providers.Web3Provider(connection)
//console.log('4. Provider ------success', provider)
const signer = provider.getSigner()
//console.log('5. signer ------success', signer)
/* next, create the item */
if (!formInput.price) return toast.error('Please enter price')
const price = ethers.utils.parseUnits(formInput.price, 'ether')
//console.log('6. price ------success', price)
//console.log('00.7. marketplaceAddress ------NFTMarketplace.abi, ---signer', marketplaceAddress, NFTMarketplace.abi, signer)
const contract = new ethers.Contract(
marketplaceAddress,
NFTMarketplace.abi,
signer
)
//console.log('7. contract ------success', contract)
let listingPrice = null
try {
listingPrice = await contract.getListingPrice()
listingPrice = listingPrice.toString()
//console.log('8.1. listingPrice------success', listingPrice)
} catch (error) {
//console.log('8.2. listingPrice------error', error)
toast.error(error || 'Error on getListingPrice')
}
if (!listingPrice) return
let transaction = null
try {
transaction = await contract.createToken(url, price, { value: listingPrice })
//console.log('9.1. contract.createToken------success', transaction)
} catch (error) {
//console.log('9.2. contract.createToken------error', error)
toast.error(error?.data?.message || 'Error while creating token')
}
if (!transaction) return
try {
await transaction.wait()
//console.log('10.1 transaction.wait------success')
} catch (error) {
//console.log('10.2 transaction.wait------error', error)
toast.error(error || 'Error while transaction.wait')
}
//console.log(transaction);
}
return (
<div className="flex justify-center">
<div className="w-1/2 flex flex-col pb-12">
<input
placeholder="Asset Name"
className="mt-8 border rounded p-4"
onChange={e => updateFormInput({ ...formInput, name: e.target.value })}
/>
<textarea
placeholder="Asset Description"
className="mt-2 border rounded p-4"
onChange={e => updateFormInput({ ...formInput, description: e.target.value })}
/>
<input
placeholder="Asset Price in Eth"
className="mt-2 border rounded p-4"
onChange={e => updateFormInput({ ...formInput, price: e.target.value })}
/>
<input
type="file"
name="Asset"
className="p-4 w-80 rounded"
onChange={onChange}
/>
{
fileUrl && (
<div className="text-black">File Url: {fileUrl}</div>
)
}
<button onClick={listNFTForSale} className="font-bold mt-4 bg-gray-500 text-white rounded p-4 shadow-lg">
Create NFT
</button>
</div>
</div>
)
}
- create.js -
myNft.js
:import { ethers } from 'ethers'
import { useEffect, useState } from 'react'
import axios from 'axios'
import Web3Modal from 'web3modal'
import { useRouter } from 'next/router'
import {
marketplaceAddress
} from '../config'
import NFTMarketplace from '../artifacts/contracts/NFTMarketplace.sol/NFTMarketplace.json'
export default function MyAssets() {
const [nfts, setNfts] = useState([])
const [loadingState, setLoadingState] = useState('not-loaded')
const router = useRouter()
useEffect(() => {
loadNFTs()
}, [])
async function loadNFTs() {
const web3Modal = new Web3Modal({
network: "mainnet",
cacheProvider: true,
})
// console.log('1. web3Modal-------------success', web3Modal)
let connection = null
try {
connection = await web3Modal.connect()
// console.log('2.1. connection-------------success', connection)
} catch (error) {
// console.log('2.2. connection-------------error', error)
return toast.error(error || 'Error web3Modal.connect')
}
const provider = new ethers.providers.Web3Provider(connection)
// console.log('3. provider-------------success', provider)
const signer = provider.getSigner()
// console.log('4. signer-------------success', signer)
// console.log('5.01. marketplaceAddress, NFTMarketplace.abi, signer----', marketplaceAddress, NFTMarketplace.abi, signer)
const marketplaceContract = new ethers.Contract(marketplaceAddress, NFTMarketplace.abi, signer)
// console.log('5.2. marketplaceContract----------Success', marketplaceContract)
let data = null
try {
data = await marketplaceContract.fetchMyNFTs()
// console.log('6.1. marketplaceContract.fetchMyNFTs-------------success', data)
} catch (error) {
// console.log('6.2. marketplaceContract.fetchMyNFTs-------------error', error)
return toast.error(error || 'Error marketplaceContract.fetchMyNFTs')
}
try {
const items = await Promise.all(data.map(async (i) => {
const tokenURI = await marketplaceContract.tokenURI(i.tokenId)
const meta = await axios.get(tokenURI)
const price = ethers.utils.formatUnits(i.price.toString(), 'ether')
const item = {
price,
tokenId: i.tokenId.toNumber(),
seller: i.seller,
owner: i.owner,
image: meta.data.image,
tokenURI
}
return item
}))
setNfts(items)
setLoadingState('loaded')
// console.log('7.1. get NFT List-----------Success', items)
} catch (error) {
// console.log('7.2. Error get NFT List-----------', error)
setLoadingState('loaded')
return toast.error(error || 'Error get NFT List')
}
}
function listNFT(nft) {
// console.log('nft:', nft)
router.push(`/nft-demo/resell-nft?id=${nft.tokenId}&tokenURI=${nft.tokenURI}`)
}
if (loadingState === 'loaded' && !nfts.length) return (<h1 className="py-10 px-20 text-3xl">No NFTs owned</h1>)
return (
<div className="flex justify-center">
<div className="p-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4">
{
nfts.map((nft, i) => (
<div key={i} className="border shadow rounded-xl overflow-hidden">
<img src={nft.image} className="rounded" />
<div className="p-4 bg-black">
<p className="text-2xl font-bold text-white">Price - {nft.price} Eth</p>
<button className="mt-4 w-full bg-pink-500 text-white font-bold py-2 px-12 rounded" onClick={() => listNFT(nft)}>List</button>
</div>
</div>
))
}
</div>
</div>
</div>
)
}
- myNft.js -
dashboard.js
:import { ethers } from 'ethers'
import { useEffect, useState } from 'react'
import axios from 'axios'
import Web3Modal from 'web3modal'
import {
marketplaceAddress
} from '../config'
import NFTMarketplace from '../artifacts/contracts/NFTMarketplace.sol/NFTMarketplace.json'
export default function CreatorDashboard() {
const [nfts, setNfts] = useState([])
const [loadingState, setLoadingState] = useState('not-loaded')
useEffect(() => {
loadNFTs()
}, [])
async function loadNFTs() {
const web3Modal = new Web3Modal({
network: 'mainnet',
cacheProvider: true,
})
//console.log('1. web3Modal------success', web3Modal)
let connection = null
try {
connection = await web3Modal.connect()
//console.log('2.1. connection------success', connection)
} catch (error) {
//console.log('2.2. connection------failed', error)
return toast.error(error || 'Error on web3Modal Connect')
}
const provider = new ethers.providers.Web3Provider(connection)
//console.log('3. Provider ------success', provider)
const signer = provider.getSigner()
//console.log('4. signer ------success', signer)
//console.log('005. marketplaceAddress ------NFTMarketplace.abi, ---signer', marketplaceAddress, NFTMarketplace.abi, signer)
const contract = new ethers.Contract(marketplaceAddress, NFTMarketplace.abi, signer)
//console.log('5. contract ------success', contract)
let data = null
try {
data = await contract.fetchItemsListed()
//console.log('6.1. contract fetchItemsListed------success', data)
} catch (error) {
//console.log('6.1. contract fetchItemsListed------success', error)
return toast.error(error || 'Error contract fetchItemsListed')
}
try {
const items = await Promise.all(data.map(async (i) => {
const tokenUri = await contract.tokenURI(i.tokenId)
const meta = await axios.get(tokenUri)
const price = ethers.utils.formatUnits(i.price.toString(), 'ether')
const item = {
price,
tokenId: i.tokenId.toNumber(),
seller: i.seller,
owner: i.owner,
image: meta.data.image,
}
return item
}))
//console.log('7.1. get Token List-----------Success', items)
setNfts(items)
setLoadingState('loaded')
} catch (error) {
//console.log('7.2. Error get List-----------', error)
setLoadingState('loaded')
return toast.error(error || 'Error get List')
}
}
if (loadingState === 'loaded' && !nfts.length) return (
<h1 className="text-xl p-4 w-96 my-10 mx-auto">No NFTs listed</h1>
)
return (
<div>
<div className="p-4">
<h2 className="text-2xl py-2">Items Listed</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4">
{
nfts.map((nft, i) => (
<div key={i} className="border shadow rounded-xl overflow-hidden">
<img src={nft.image} className="rounded" />
<div className="p-4 bg-black">
<p className="text-2xl font-bold text-white">Price - {nft.price} Eth</p>
</div>
</div>
))
}
</div>
</div>
</div>
)
}
- dashboard.js -
resellNft.js
:import { ethers } from 'ethers'
import { useEffect, useState } from 'react'
import axios from 'axios'
import Web3Modal from 'web3modal'
import { useRouter } from 'next/router'
import {
marketplaceAddress
} from '../config'
import NFTMarketplace from '../artifacts/contracts/NFTMarketplace.sol/NFTMarketplace.json'
export default function MyAssets() {
const [nfts, setNfts] = useState([])
const [loadingState, setLoadingState] = useState('not-loaded')
const router = useRouter()
useEffect(() => {
loadNFTs()
}, [])
async function loadNFTs() {
const web3Modal = new Web3Modal({
network: "mainnet",
cacheProvider: true,
})
// console.log('1. web3Modal-------------success', web3Modal)
let connection = null
try {
connection = await web3Modal.connect()
// console.log('2.1. connection-------------success', connection)
} catch (error) {
// console.log('2.2. connection-------------error', error)
return toast.error(error || 'Error web3Modal.connect')
}
const provider = new ethers.providers.Web3Provider(connection)
// console.log('3. provider-------------success', provider)
const signer = provider.getSigner()
// console.log('4. signer-------------success', signer)
// console.log('5.01. marketplaceAddress, NFTMarketplace.abi, signer----', marketplaceAddress, NFTMarketplace.abi, signer)
const marketplaceContract = new ethers.Contract(marketplaceAddress, NFTMarketplace.abi, signer)
// console.log('5.2. marketplaceContract----------Success', marketplaceContract)
let data = null
try {
data = await marketplaceContract.fetchMyNFTs()
// console.log('6.1. marketplaceContract.fetchMyNFTs-------------success', data)
} catch (error) {
// console.log('6.2. marketplaceContract.fetchMyNFTs-------------error', error)
return toast.error(error || 'Error marketplaceContract.fetchMyNFTs')
}
try {
const items = await Promise.all(data.map(async (i) => {
const tokenURI = await marketplaceContract.tokenURI(i.tokenId)
const meta = await axios.get(tokenURI)
const price = ethers.utils.formatUnits(i.price.toString(), 'ether')
const item = {
price,
tokenId: i.tokenId.toNumber(),
seller: i.seller,
owner: i.owner,
image: meta.data.image,
tokenURI
}
return item
}))
setNfts(items)
setLoadingState('loaded')
// console.log('7.1. get NFT List-----------Success', items)
} catch (error) {
// console.log('7.2. Error get NFT List-----------', error)
setLoadingState('loaded')
return toast.error(error || 'Error get NFT List')
}
}
function listNFT(nft) {
// console.log('nft:', nft)
router.push(`/nft-demo/resell-nft?id=${nft.tokenId}&tokenURI=${nft.tokenURI}`)
}
if (loadingState === 'loaded' && !nfts.length) return (<h1 className="py-10 px-20 text-3xl">No NFTs owned</h1>)
return (
<div className="flex justify-center">
<div className="p-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4">
{
nfts.map((nft, i) => (
<div key={i} className="border shadow rounded-xl overflow-hidden">
<img src={nft.image} className="rounded" />
<div className="p-4 bg-black">
<p className="text-2xl font-bold text-white">Price - {nft.price} Eth</p>
<button className="mt-4 w-full bg-pink-500 text-white font-bold py-2 px-12 rounded" onClick={() => listNFT(nft)}>List</button>
</div>
</div>
))
}
</div>
</div>
</div>
)
}
- resellNft.js -
现在我们可以测试app了
运行命令:
npm run dev
原文链接:https://betterprogramming.pub/create-a-full-stack-nft-marketplace-on-the-polygon-network-20176b3a9e33?source=user_profile---------1-------------------------------
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!