NFT đang được sử dụngtrong nhiều lĩnh vực như Nghệ thuật, Gaming, Metaverse, Collectible,… Cùng vớitiềm năng của NFT là nhu cầu tìm kiếm một nền tảng để có thể sở hữu, mua bán các sản ph
Trang 1ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN
KHOA KHOA HỌC VÀ KỸ THUẬT THÔNG TIN
BÁO CÁO ĐỒ ÁN CUỐI KỲ
Trang 3CHƯƠNG 5: PHÂN TÍCH TRANG WEB 17
Trang 4LỜI MỞ ĐẦU
NFT (Non-fungible token) là một tài sản số sử dụng công nghệ blockchain
Làn sóng NFT phát triển mạnh mẽ trong thời gian gần đây và trở thành một trongnhững nền tảng quan trọng của nền kinh tế tiền mã hóa NFT đang được sử dụngtrong nhiều lĩnh vực như Nghệ thuật, Gaming, Metaverse, Collectible,… Cùng vớitiềm năng của NFT là nhu cầu tìm kiếm một nền tảng để có thể sở hữu, mua bán các
sản phẩm NFT với nhiều mục đích khác nhau được gọi là NFT Marketplace.
Trước nhu cầu đó, cùng với yêu cầu môn học, nhóm chúng em quyết định chọn đềtài Xây dựng NFT Marketplace
Với đề tài và môn học này, nhóm xin chân thành cảm ơn sự giúp đỡ tận tìnhcủa Thầy Võ Tấn Khoa Song, do còn nhiều hạn chế đề tài nhóm xây dựng khôngtránh khỏi những thiếu sót Rất mong được thầy cô và các bạn đóng góp ý kiến đểchương trình ngày càng được hoàn thiện
Trân trọng cảm ơn!
Trang 5CHƯƠNG 1: TỔNG QUAN VỀ ĐỀ TÀI 1.1 Lý do chọn đề tài
NFT là tài sản mật mã được tạo trên công nghệ blockchain có mã nhận dạng duynhất và siêu dữ liệu, giúp chúng có thể phân biệt, khác biệt và hoàn toàn duy nhất.NFT là tài sản kỹ thuật số đại diện cho các tài sản trong thế giới thực như nghệthuật, âm nhạc, vật phẩm trong trò chơi và video được liên kết với bằng chứngquyền sở hữu
Vì vậy NFT Marketplace ra đời để có thể người dùng có thể tạo, mua hoặc bánNFT Thị trường này cũng được sử dụng để lưu trữ, hiển thị hoặc hiển thị giao dịch
và tạo mã thông báo NFT hoặc bất kỳ tài sản kỹ thuật số nào Đối với người dùng,trải nghiệm thị trường NFT thuận tiện như một sàn giao dịch tiền điện tử
1.2 Yêu cầu của đề tài
- Nắm được các kiến thức cơ bản về smart contract, cách deploy một smartcontract,
-Tạo ra một sàn giao dịch NFT có các chức năng cơ bản như:cửa sổ mua sắm,
ví, đăng ký tài khoản, tìm kiếm,
1.3 Đối tượng
1.3.1 Guest:
- Khách viếng thăm
- Xem thông tin sản phẩm cũng như các tin tức khác
- Đăng ký để kết nối với ví Metamask
Website được thiết kế với
- Giao diện hài hoà, thân thiện, giúp người dùng dễ dàng sử dụng
- Trang chủ sẽ hiển thị danh sách các sản phẩm được bán
- Khách hàng có thể dễ dàng tìm thấy thông tin chi tiết các sản phẩm mà họquan tâm
- Khách hàng có thể tìm kiếm sản phẩm
- Có chức năng đăng ký và liên kết với ví Metamask
Trang 61.6 Các module
1.6.1 Module sản phẩm
Các NFT được liệt kê trên thị trường phải hiển thị tất cả thông tin quantrọng theo cách tối ưu hóa nhất: tên, giá, mô tả, chủ sở hữu, phương thứcthanh toán, v.v
1.7 Công cụ triển khai
- IDE: Visual Studio Code
- Quản lý code: Github
- Quản lý công việc: Excel
- Trao đổi, liên lạc: Microsoft Team, Facebook
Trang 7CHƯƠNG 2: CƠ SỞ LÝ THUYẾT Tech stack:
● Programing Language - Solidity
● Blockchain Platform - Polygon (MATIC)
● NFT Standards EERC-721
● Front-end Frameworks
● Web application framework - Next.js
● CSS framework - CSS Tailwind
● Storage Platforms - IPFS
● Ethereum Web Client Library - Ethers.js
2.1 Ngôn ngữ lập trình Solidity
Solidity được biết đến là một ngôn ngữ lập trình hướng contract, được sử dụnghầu hết trong smart contract (nâng cấp và tạo lập) thuộc hệ sinh thái Ethereum.Solidity có các cú pháp và câu lệnh gần giống với các ngôn ngữ lập trình phổ biếnhiện nay (Java, C++, C# ) Ngôn ngữ Solidity có những ứng dụng vô cùng quantrọng đối với công nghệ Blockchain Một ví dụ điển hình của công nghệ Blockchainhiện nay chính là tiền điện tử Nhờ có sự ra đời của ngôn ngữ lập trình Solidity, cácnhà lập trình có thể dễ dàng ứng dụng công nghệ Blockchain này vào các lĩnh vựckinh tế và đời sống
2.2 Nền tảng Blockchain – Polygon (MATIC)
- Polygon (MATIC) là một platform hỗ trợ phát triển cơ sở hạ tầng vàgiúp Ethereum mở rộng quy mô hay còn gọi là layer 2 Polygon (MATIC) hỗ trợtất cả các công cụ Ethereum hiện có cùng với các giao dịch nhanh hơn và rẻ hơn.Polygon (MATIC) cố gắng giải quyết các vấn đề về khả năng mở rộng và khảnăng sử dụng trong khi không ảnh hưởng đến phân quyền, bảo mật và tận dụngcộng đồng nhà phát triển, hệ sinh thái hiện có Polygon là một giải pháp mở rộngoff/side chain cho các nền tảng hiện có để cung cấp khả năng mở rộng và trảinghiệm người dùng vượt trội cho DApps/ chức năng người dùng
- Tính năng chính và điểm nổi bật:
- Khả năng mở rộng: giao dịch nhanh, chi phí thấp và an toàn trên cácsidechain Polygon với độ chính xác đạt được trên chuỗi chính và Ethereum làlayer 1 base chain tương thích đầu tiên
- Thông lượng cao: đạt được lên đến 10.000 TPS trên một singlesidechain trên testnet nội bộ Nhiều chuỗi sẽ được thêm vào để mở rộng quy môtheo chiều ngang
Trang 8- Trải nghiệm người dùng: mượt mà và dễ sử dụng từ chain chính đếnPolygon, ứng dụng di động gốc và SDK có hỗ trợ Wallet Connect
- Bảo mật: những người vận hành Polygon chain, chính họ là những
người đóng vai trò quan trọng trong hệ thống PoS
- Public Sidechains: Polygon sidechain về bản chất là công khai (so vớichuỗi DApp riêng lẻ), không được phép và có khả năng hỗ trợ nhiều giao thức
● Môi trường thực thi (triển khai máy ảo có thể cắm được)
● Logic thực thi (chức năng chuyển đổi trạng thái của mạng Polygon,thường được viết dưới dạng hợp đồng thông minh Ethereum)
- Polygon networks layer
Một tập hợp của các mạng blockchain có chủ quyền Mỗi mạng phục vụcộng đồng tương ứng của nó, duy trì các chức năng như:
● Đối chiếu giao dịch
● Sự đồng thuận của nội bộ
● Sản xuất khối
Trang 9Các mạng có thể sử dụng giao thức Polygon (MATIC) để kết nối với nhau vàtrao đổi thông tin tùy ý
- Security layer
Một layer chuyên biệt, không bắt buộc phải quản lý một tập hợp các trìnhxác thực và có thể kiểm tra định kỳ tính hợp lệ của bất kỳ chuỗi Polygon(MATIC) nào với một khoản phí Lớp này có thể được triển khai như một siêublockchain chạy song song với Ethereum, phụ trách các chức năng như:
● Quản lý trình xác thực (đăng ký/ hủy đăng ký, phần thưởng…)
● Xác thực Polygon Chain
Lớp bảo mật là fully abstract và có thể có nhiều trường hợp, được thực hiệnbởi các thực thể khác nhau, có các đặc điểm khác nhau Nó cũng có thể đượcthực hiện trực tiếp trên Ethereum, trong trường hợp đó, các thợ đào Ethereumthực hiện việc xác nhận
- Ethereum layer
Polygon chain có thể sử dụng Ethereum, blockchain lập trình an toàn nhấttrên thế giới, để lưu trữ và thực hiện bất kỳ thành phần quan trọng nào tronglogic của chúng Layer này được triển khai dưới dạng một tập hợp các hợp đồngthông minh Ethereum, phụ trách các chức năng như:
● Tính chất cuối cùng/điểm kiểm tra
● Staking
● Giải quyết tranh chấp
● Chuyển tiếp thông tin
2.3 Tiêu chuẩn ERC-721
Tiêu chuẩn non-fungible token ERC-721 được viết bằng ngôn ngữ Solidity trênchuỗi khối Ethereum và nó cho phép các nhà phát triển mã hóa quyền sở hữu bất kỳ
dữ liệu tùy ý nào. Đặc biệt, tiêu chuẩn này nhằm mục đích tạo ra các mã thông báo
có thể hoán đổi cho nhau. Một ví dụ về hợp đồng ER-721 là của OpenZeppelin, cho
phép các nhà phát triển theo dõi các vật phẩm trong trò chơi của họ
Trang 10Hình 2.2 Mã thông báo ERC-721
2.4 Frontend Frameworks
2.4.1 Next.js
- Next.js là một framework dùng để phát triển các ứng dụng React.React là một framework của javascript để xây dựng frontend với nhiều ưu điểmnhư chia nhỏ các phần của web, module hoá css, xử lý sự kiện…Tuy nhiên,react chỉ phù hợp để render dữ liệu phía client, việc này ảnh hưởng rất lớn đếnSEO của website khi mà hầu hết những data mà google đánh index đều phảiđược render ở server
- Phân biệt giữa Serverside Rendering và Clientside Rendering
Serverside Rendering Clientside Rendering
Server trả về cho browser file
HTML của trang đã được
rendered
CSR trả về file HTML gần như trống cùng vớilink tới file JS
Nội dung file HTML đã hoàn
chỉnh và được hiển thị ngay khi
nó được load về máy
Đối với CSR, ta sẽ cần chờ tới khi tất cả các quátrình xây dựng Virtual DOM và gắn các sự kiệnhoàn thành đến khi Virtual DOM được chuyểnvào browser DOM để website có thể xem được
Bảng 2.1 So sánh Serverside rendering và Clientside rendering
Trang 11- Để hỗ trợ việc render ở phía server cho React, các nhà phát triển đã tạo raNext.js Next.js tích hợp nhiều tính năng như:
- Pre-rendering, cả static generation (SSG) và server-side rendering (SSR),
- Tách mã tự động để tải trang nhanh hơn, mỗi page chỉ load những gì cầnthiết cho page đó Ví dụ khi render trang chủ thì những page khác sẽ khôngđược khởi tạo, như vậy trang chủ sẽ được load nhanh cho dù website của bạn
sử dụng
2.5 Ethereum Development Environment – Hardhat
- Hardhat là một môi trường để biên dịch, triển khai, test và debug dappethereum được phát triển trên nền tảng javascript
- Một số điểm tính năng nổi bật của Hardhat
- Tích hợp mạng local Hardhat, dễ dàng chạy và debug code ngay trên local
- Debug dễ dàng hơn: Với Hardhat, chúng ta có thể debug code Solidity dễdàng hơn khi có thể console.log ra các biến (Solidity vốn ko hỗ trợ console.log)
- Hệ thống plugin: Giúp developer có thể bổ sung chức năng, tùy vào từng dự
án cụ thể
- Hỗ trợ TypeScript
- So sánh Hardhat và Truffle
Tài liệu hướng dẫn rõ ràng và được cấu
trúc tốt, phù hợp cho người mới Có tài liệu hướng dẫn rõ ràng, nhiều tàiliệu tham khảo trên các web, blog,
youtube…
Hardhat có một cộng đồng rất sôi nổi
bao gồm các nhà phát triển blockchain
và các thành viên cốt lõi của
framework
Truffle có cộng đồng hùng mạnh và sôinổi nhờ ra đời sớm hơn
Hardhat có rất nhiều thư viện và plugin,
người dùng có thể tự tạo plugin cho
mình
Truffle cũng có plugin hoặc thư viện gọi
là Box, người dùng cũng có thể tự tạoBox cho mình nhưng cách dùng phức tạphơn
Trang 12Môi trường thử nghiệm linh hoạt hơn do
có thể tương tác trực tiếp với smart
contract
Thử nghiệm không thể tương tác vớicontract
Bảng 2.2 So sánh Truffle và Hardhat
2.6 Storage Platforms - IPFS
- IPFS là viết tắt của từ Interplanetary File System, một hệ thống tập tin phântán ngang hàng kết nối tất cả các thiết bị máy tính với nhau Cụ thể hơn, nó sẽphân phối dữ liệu được lưu trữ theo hình thức P2P, hay còn gọi là mạng nganghàng
- Trong đó, các hoạt động của IPFS chủ yếu dựa vào khả năng tính toán băngthông của tất cả các máy tham gia chứ không tập trung vào một phần nhỏ cácmáy chủ trung tâm như giao thức HTTP
- IPFS là mạng lưới chuyển phát nội dung hoàn toàn phi tập trung cho phépquản lý và lưu trữ dữ liệu một cách linh hoạt Mỗi máy tính tham gia trong mạnglưới đảm nhận nhiệm vụ download và upload dữ liệu mà không cần sự can thiệpcủa máy chủ trung tâm
- Đầu tiên mọi dữ liệu sẽ được mã hoá và được lưu dưới dạng mã hash (còngọi là đối tượng IPFS) Ý tưởng chủ đạo là nếu trình duyệt của bạn muốn truycập một trang nào đó trên IPFS thì chỉ cần đưa ra mã hash rồi mạng sẽ tìm máy
có lưu trữ dữ liệu khớp với mã hash và sau đó tải dữ liệu, trang đó về từ máytính đấy về cho bạn
- Mỗi máy tính tham gia trong mạng lưới của nó sẽ đảm nhận cả việcdownload lẫn upload dữ liệu mà không cần có sự có mặt của một máy chủ trungtâm Tổng quan, cách hoạt động của IPFS sẽ có 2 phần chính:
- Xác định tệp có địa chỉ nội dung (giá trị hash của tệp đó)
- Tìm dữ liệu được lưu trữ và tải xuống: khi bạn có đoạn hash của file haytrang cần tải, mạng sẽ tìm và connect tới máy tốt nhất để tải dữ liệu xuốngcho bạn
2.7 Ethereum Web Client Library - Ethers.js
Ethers.js là một thư viện được viết bằng javascript giúp dapp tương tác được vớimạng Ethereum Blockchain
Các tính năng nổi bật Ethers.js gồm có:
- Giữ private key ở client một cách an toàn
- Import và export JSON wallets
- Import và export ví theo chuẩn BIP 39
- Hỗ trợ ABI, ABIv2 và Human-Readable ABI
Trang 13- Kết nối với Ethereum nodes thông qua nhiều provider như JSON-RPC,INFURA, Etherscan, Alchemy, Cloudflare, MetaMask
- Siêu dữ liệu NFT là mô tả của tài sản kỹ thuật số được bán dưới dạng NFT,
cụ thể là tên, ngày tạo, thuộc tính, chủ sở hữu, v.v
- IPFS là một hệ thống lưu trữ dữ liệu tránh tiêu tốn điện năng lưu trữ tài sản
kỹ thuật số với siêu dữ liệu trên blockchain
- Hợp đồng thông minh tạo ra một số nhận dạng duy nhất cho mỗi NFT Cáchợp đồng thông minh cho thị trường NFT sử dụng tiêu chuẩn ERC-721 đểtạo các mã thông báo không thể thay thế, giúp phân biệt NFT với các mãthông báo tiền điện tử có thể thay thế
Trang 14- Blockchain là một cơ sở dữ liệu phân tán lưu trữ thông tin về các giao dịchNFT.
3.1.2 Công nghệ và dịch vụ của bên thứ ba
- Solidity là một ngôn ngữ lập trình cho các hợp đồng thông minh
- Infura.io là một dịch vụ cung cấp quyền truy cập vào chuỗi khối Ethereum
3.2 Các bước thực hiện
- Người dùng tải lên nội dung kỹ thuật số và điền vào siêu dữ liệu
- Siêu dữ liệu đã được xác minh và gửi tới bộ lưu trữ dữ liệu bên ngoài
- Một mã nhận dạng duy nhất được chỉ định cho nội dung và một NFT đượctạo ra
- NFT được thêm vào blockchain
Trang 15CHƯƠNG 4: CÀI ĐẶT MÔI TRƯỜNG 4.1 Tạo một ứng dụng Next.js
npx create-next-app nft-marketplace
4.2 Cài đặt các dependencies cho ứng dụng
cd nft-marketplace
npm install ethers hardhat @nomiclabs/hardhat-waffle /
ethereum-waffle chai @nomiclabs/hardhat-ethers /
web3modal @openzeppelin/contracts ipfs-http-client /
axios
4.3 Cài đặt framework Tailwind
Thiết lập dependencies
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
Tạo các tệp cấu hình cần thiết để Tailwind hoạt động với Next.js
Trang 16?Hardhat project root: <Choose default path>
(Lưu ý: Nếu gặp lỗi khi tham chiếu đến tệp README.md, xóa README.md
và chạy lại npx hardhat.)
Sau khi chạy lệnh, một số tệp và thư mục mới sẽ được thêm vào thư mục gốc
hardhat.config.js - Chứa toàn bộ thiết lập Hardhat của ứng dụng (cấu hình,
plugin và các tác vụ tùy chỉnh)
scripts - Một thư mục chứa một tập lệnh có tên là sample-script.js sẽ triển
khai hợp đồng thông minh khi ứng dụng được thực thi
test - Một thư mục chứa một tập lệnh thử nghiệm mẫu.
contracts - Một thư mục chứa một hợp đồng thông minh Solidity.
Cấu hình lại tệp hardhat.config.js
// kết nối với munbai testnet
// unused configuration commented out for now
Trang 18CHƯƠNG 5: PHÂN TÍCH TRANG WEB 5.1 Smart contract
contractNFTMarketplaceisERC721URIStorage {
using CountersforCounters.Counter;
Counters.Counter private _tokenIds;
Counters.Counter private _itemsSold;
uint256 listingPrice = 0.025ether;
address payable owner;
mapping(uint256 => MarketItem) private idToMarketItem;
struct MarketItem {
uint256 tokenId;
address payable seller;
address payable owner;
Trang 19constructor() ERC721("Metaverse Tokens", "METT") {
owner = payable(msg.sender);
}
/* Cập nhật giá niêm yết của hợp đồng*/
function updateListingPrice(uint_listingPrice) publicpayable {
require(owner == msg.sender, "Only marketplace owner can update listingprice.");
listingPrice = _listingPrice;
}
/* Trả về giá niêm yết của hợp đồng*/
function getListingPrice() publicviewreturns (uint256) {
return listingPrice;
}
/* Tạo Token và thêm nó vào marketplace */
function createToken(string memory tokenURI, uint256 price) public payable
returns (uint) {
_tokenIds.increment();
uint256 newTokenId = _tokenIds.current();
_mint(msg.sender, newTokenId);
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),
Trang 20payable(address(this)),
/* cho phép ai đó bán lại token mà họ đã mua*/
function resellToken(uint256tokenId, uint256price) publicpayable {
require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner canperform 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);
}
/* Tạo chức năng mua bán một marketplace item */
/* Chuyển quyền sở hữu item, cũng như tiền giữa các bên tham gia mua bán*/ function createMarketSale(
uint256tokenId
) publicpayable {
uint price = idToMarketItem[tokenId].price;
address seller = idToMarketItem[tokenId].seller;
require(msg.value == price, "Please submit the asking price in order to completethe purchase");
Trang 21idToMarketItem[tokenId].owner = payable(msg.sender);
/* Trả lại tất cả các item chưa bán được trên market*/
function fetchMarketItems() publicviewreturns (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)) {
/* Chỉ trả lại các item mà người dùng đã mua*/
function fetchMyNFTs() publicviewreturns (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;
}
}
Trang 22MarketItem[] memory items = new MarketItem[](itemCount);
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
/* Chỉ trả lại các item mà người dùng đã liệt kê*/
function fetchItemsListed() publicviewreturns (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) {
Trang 231 Infinity Marketplace Tên của trang
2 Thanh Navbar Điều hướng đến các trang: Home, Sell NFT, My
NFTs, Dashboard
3 Thông tin ví người
dùng Hiển thị số tiền và địa chỉ tài khoản người dùng
4 Danh sách sản phẩm Hiển thị những sản phẩm đang bán trên sàn
5 Nút Buy Mua và thanh toán sản phẩm thông qua ví metamask
6 Nút Detail Xem chi tiết thông tin sản phẩm
Bảng 5.1 Bảng chức năng trang chủ.
5.2.2 Code
/* pages/index.js */
import { ethers } from"ethers";
import { useEffect, useState } from"react";
importaxiosfrom"axios";
Trang 24import { useRouter } from"next/router";
import { marketplaceAddress } from" /config";
" /artifacts/contracts/NFTMarketplace.sol/NFTMarketplace.json";
exportdefaultfunction Home() {
const [searchTerm, setSearchTerm] = useState("");
const [nfts, setNfts] = useState([]);
const [loadingState, setLoadingState] = useState("not-loaded");
asyncfunction loadNFTs() {
/* tạo một nhà cung cấp chung và truy vấn các item chưa bán được trên market*/
const provider = newethers.providers.JsonRpcProvider(
* map over các item được trả về từ smart contract and format
* chúng được biết như là fetch token metadata
*/
const items = awaitPromise.all(
Trang 25data.map(async (i) => {
consttokenUri = awaitcontract.tokenURI(i tokenId);
constmeta = awaitaxios.get(tokenUri);
letprice = ethers.utils.formatUnits(iprice.toString(), "ether");
image:meta.data.image,
name:meta.data.name,
description:meta.data.description,
asyncfunction buyNft(nft) {
/* cần người dùng đăng ký vào giao dịch, vì vậy sẽ sử dụng Web3Provider vàđăng ký*/
const web3Modal = newWeb3Modal();
const connection = awaitweb3Modal.connect();
const provider = newethers.providers.Web3Provider(connection);
const signer = provider.getSigner();
const contract = newethers.Contract(
const price = ethers.utils.parseUnits(nft.price.toString(), "ether");
const transaction = awaitcontract.createMarketSale(nft.tokenId, {
value:price,
Trang 26if (loadingState === "loaded" && !nfts.length)
return <h1className="px-20 py-10 text-3xl">No items in marketplace</h1>; return (
<divclassName="flex">
<divclassName="px-4"style={{ maxWidth:"1600px" }}>
<h2className="text-2xl py-2">Marketplace</h2>
<divclassName="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 pt-4"> {nfts
Trang 27<divclassName="h-1/2 bg-cover">
<divstyle={{ height:"70px", overflow:"hidden" }}>
<pclassName="text-gray-400">{nft.description}</p>
</div>
</div>
<divclassName="h-1/4 p-4 bg-black">
<pclassName="text-2xl font-bold text-white">
Trang 28import { useState } from'react'
import { ethers } from'ethers'
Trang 29import { create asipfsHttpClient } from'ipfs-http-client'
import { useRouter } from'next/router'
importWeb3Modalfrom'web3modal'
constclient = ipfsHttpClient('https://ipfs.infura.io:5001/api/v0')
exportdefaultfunction CreateItem() {
const [fileUrl, setFileUrl] = useState(null)
const [formInput, updateFormInput] = useState({ price: '', name: '', description:
'' })
constrouter = useRouter()
asyncfunction onChange(e) {
/* tải image đến IPFS */
const file = e.target.files[0]
asyncfunction uploadToIPFS() {
const { name, description, price } = formInput
if (!name || !description || !price || !fileUrl) return
Trang 30/* đầu tiên, tải metadata đến IPFS */
const data = JSON.stringify({
name, description, image:fileUrl
})
try {
constadded = awaitclient.add(data)
consturl = `https://ipfs.infura.io/ipfs/${added.path}`
/* sau khi metadata được uploaded đến IPFS, trở về URL để sử dụng nó tronggiao dịch */
asyncfunction listNFTForSale() {
const url = await uploadToIPFS()
const web3Modal = newWeb3Modal()
const connection = awaitweb3Modal.connect()
const provider = newethers.providers.Web3Provider(connection)
const signer = provider.getSigner()
/* tạo NFT */
const price = ethers.utils.parseUnits(formInput.price, 'ether')
let contract = new ethers.Contract(marketplaceAddress, NFTMarketplace.abi,
signer)
let listingPrice = await contract.getListingPrice()
listingPrice = listingPrice.toString()
let transaction = awaitcontract.createToken(url, price, { value:listingPrice }) await transaction.wait()
router.push('/')
}
return (
<divclassName="flex justify-center">
<divclassName="w-1/2 flex flex-col pb-12">
<input
Trang 31placeholder="Asset Name"
className="mt-8 border rounded p-4"
onChange={ => updateFormInput({ formInput, name:e.target.value })} />
<textarea
placeholder="Asset Description"
className="mt-2 border rounded p-4"
onChange={ => updateFormInput({ .formInput, description:
e.target.value })}
/>
<input
placeholder="Asset Price in Eth"
className="mt-2 border rounded p-4"
onChange={ => updateFormInput({ formInput, price:e.target.value })} />
Trang 32Tìm kiếm NFT trong danh sách sở hữu
3 Nút List Chuyển đến trang Resell NFT để thực hiện bán lại NFT đang
sở hữu
4 Nút Detail Xem chi tiết thông tin sản phẩm
Bảng 5.3 Bảng chức năng trang Sell NFTs.
5.4.2 Code:
/* pages/my-nfts.js */
import { ethers } from'ethers'
import { useEffect, useState } from'react'
importaxiosfrom'axios'
importWeb3Modalfrom'web3modal'
import { useRouter } from'next/router'
import {
marketplaceAddress
} from' /config'