NFT交易所开发源码搭建教程

NFT交易所开发源码搭建教程

使用 Polygon 在以太坊上构建全栈 NFT 市场

使用 Polygon、Next.js、Tailwind、Solidity、Hardhat、Ethers.js 和 IPFS 构建数字市场

要查看本教程的视频课程,请单击此处

在我上一篇端到端的以太坊教程中,全栈以太坊开发的完整指南中,我介绍了如何使用Hardhat和Ethers.js等现代工具在以太坊上构建基本应用程序。

在本指南中,您将学习如何在以太坊上构建、部署和测试全栈 NFT 市场。我们还将研究如何部署到 Polygon。

有一两件事,在过去的几个月中已变得很明显是多么地快,像复仇缩放解决方案多边形,Arbitrum和乐观势头渐强和采纳。这些技术使开发人员能够直接在以太坊上构建相同的应用程序,并具有更低的 gas 成本和更快的交易速度等额外好处。

由于这些解决方案提供的价值主张与现有内容的普遍缺乏相结合,我将使用这些不同的以太坊扩展解决方案为全栈应用程序构建各种示例项目和教程,从 Polygon 上的这个开始。

要查看此项目的最终源代码,请访问此 repo

先决条件

要在本指南中取得成功,您必须具备以下条件:

Node.js 安装在你的机器上作为浏览器扩展安装的 Metamask 钱包扩展

堆栈

在本指南中,我们将使用以下方法构建一个完整的堆栈应用程序:

Web 应用程序框架- Next.js Solidity

开发环境-安全帽

文件存储- IPFS

以太坊 Web 客户端库- Ethers.js

虽然它不是本指南的一部分(在单独的帖子中),但我们将研究如何使用图形协议构建更强大的 API 层,以绕过原生区块链层提供的数据访问模式的限制。

关于该项目

我们将要构建的项目将是Metaverse Marketplace——一个数字市场。

当用户出售物品时,物品的所有权将从创建者转移到市场。

当用户购买商品时,购买价格将从买家转移到卖家,商品从市场转移到买家。

市场所有者将能够设置上市费用。这笔费用将从卖方收取并在任何销售完成后转移给合同所有者,使市场所有者能够从市场上进行的任何销售中赚取经常性收入。

市场逻辑将由两个智能合约组成:

NFT 合约- 该合约允许用户铸造独特的数字资产。

市场合约- 该合约允许用户将他们的数字资产放在公开市场上出售。

我相信这是一个很好的项目,因为我们将使用的工具、技术和想法为这个堆栈上的许多其他类型的应用程序奠定了基础——在合同级别处理诸如支付、佣金和所有权转移之类的事情以及客户端应用程序如何使用此智能合约来构建高性能且美观的用户界面。

除了智能合约,我还将向您展示如何构建子图,以使智能合约中的数据查询更加灵活和高效。正如您将看到的,很难直接从智能合约中创建数据集视图并启用各种高性能数据访问模式。图表使这更容易。

关于多边形

从文档:

“Polygon 是一种协议和框架,用于构建和连接与以太坊兼容的区块链网络。在以太坊上聚合可扩展的解决方案,支持多链以太坊生态系统。”

Polygon 比以太坊快 10 倍左右,但交易成本却低 10 倍以上。

好吧,那是什么意思呢?

对我来说,这意味着我可以使用我在以太坊上构建应用程序时使用的相同知识、工具和技术来为用户构建更快、更便宜的应用程序,不仅提供更好的用户体验,还为许多人打开了大门直接在以太坊上构建是不可行的应用程序类型。

正如前面提到的,还有很多其他的复仇缩放解决方案,如Arbitrum和乐观,同时也是在类似的空间。这些扩展解决方案中的大多数都有技术差异,并且分为侧链、第 2 层和状态通道等不同类别。

Polygon最近从 Matic 更名,因此您还会看到Matic一词在指代其生态系统的各个部分时可以互换使用,因为该名称仍在各个地方使用,例如其代币和网络名称。

要了解有关 Polygon 的更多信息,请在此处查看这篇文章及其文档。

现在我们对项目和相关技术有了一个概述,让我们开始构建吧!

项目设置

首先,我们将创建一个新的 Next.js 应用程序。为此,请打开您的终端。创建或更改为新的空目录并运行以下命令:

npx create-next-app digital-marketplace

接下来,切换到新目录并安装依赖项:

cd digital-marketplace npm install ethers hardhat @nomiclabs/hardhat-waffle \ethereum-waffle chai @nomiclabs/hardhat-ethers \web3modal @openzeppelin/contracts ipfs-http-client@50.1.2 \axios

设置 Tailwind CSS

我们将使用Tailwind CSS进行样式设置,我们将在此步骤中进行设置。

Tailwind 是一个实用优先的 CSS 框架,它可以轻松添加样式并创建美观的网站,而无需进行大量工作。

接下来,安装 Tailwind 依赖项:

npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

接下来,我们将通过运行以下命令来创建 Tailwind 与 Next.js(tailwind.config.js和postcss.config.js)一起使用所需的配置文件:

npx tailwindcss init -p

最后,删除styles/globals.css 中的代码并使用以下内容更新它:

@tailwind base;@tailwind components;@tailwind utilities;

配置安全帽

接下来,从项目的根目录初始化一个新的 Hardhat 开发环境:

npx hardhat ? What do you want to do? Create a sample project ? Hardhat project root:

现在,您应该会在根目录中看到为您创建的以下文件和文件夹:

hardhat.config.js – 整个安全帽设置(即您的配置、插件和自定义任务)都包含在此文件中。

scripts – 包含名为 sample-script.js 的脚本的文件夹,该脚本将在执行

测试时部署您的智能合约- 包含示例测试脚本

合约的文件夹 – 包含示例 Solidity 智能合约的文件夹

接下来,使用以下内容更新hardhat.config.js 中的配置:

在此处查看要点

/* hardhat.config.js */require(“@nomiclabs/hardhat-waffle”)const fs = require(fs)const privateKey = fs.readFileSync(“.secret”).toString().trim() || “01234567890123456789”module.exports = { defaultNetwork: “hardhat”, networks: { hardhat: { chainId: 1337 }, mumbai: { url: “https://rpc-mumbai.matic.today

“, accounts: [privateKey] } }, solidity: { version: “0.8.4”, settings: { optimizer: { enabled: true, runs: 200 } } }}

在此配置中,我们配置了本地 Hardhat 开发环境以及Mumbai 测试网。

您可以在此处阅读有关这两个 Matic 网络的更多信息。

接下来,在项目的根目录创建一个名为.secret的文件。现在,我们将此文件留空。稍后,我们将使用一个测试钱包私钥填充它,该私钥将保存我们将从 Matic 测试网水龙头获得的一些 Matic 代币。

确保永远不要向 Git 提交任何私钥。为了更加安全,在使用包含真实代币的钱包时,请考虑将这些值存储在临时环境变量中。要从 Git 中省略,请将.secret添加到您的.gitignore文件中。

智能合约

接下来,我们将创建我们的智能合约!我们将从独特数字资产的 NFT 合约开始。

在合同目录中创建一个名为NFT.sol的新文件。在这里,添加以下代码:

在此处查看要点

// contracts/NFT.sol // SPDX-License-Identifier: MIT OR Apache-2.0pragma solidity ^0.8.3;import “@openzeppelin/contracts/utils/Counters.sol”;import “@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol”;import “@openzeppelin/contracts/token/ERC721/ERC721.sol”;import “hardhat/console.sol”;contract NFT is ERC721URIStorage { using Counters for Counters.Counter; Counters.Counter private _tokenIds; address contractAddress; constructor(address marketplaceAddress) ERC721(“Metaverse Tokens”, “METT”) { contractAddress = marketplaceAddress; } function createToken(string memory tokenURI) public returns (uint) { _tokenIds.increment(); uint256 newItemId = _tokenIds.current(); _mint(msg.sender, newItemId); _setTokenURI(newItemId, tokenURI); setApprovalForAll(contractAddress, true); return newItemId; }}

这是一个非常简单的 NFT 智能合约,允许用户铸造独特的数字资产并拥有它们的所有权。

在这份合同我们是从继承ERC721标准的实施OpenZepplin

接下来,我们将为市场创建合同。这是一个更大的智能合约。我已尽力记录每个函数的作用。

在名为Market.sol的合同目录中创建一个新文件:

在此处查看要点

// contracts/Market.sol // SPDX-License-Identifier: MIT OR Apache-2.0pragma solidity ^0.8.3;import “@openzeppelin/contracts/utils/Counters.sol”;import “@openzeppelin/contracts/security/ReentrancyGuard.sol”;import “@openzeppelin/contracts/token/ERC721/ERC721.sol”;import “hardhat/console.sol”;contract NFTMarket is ReentrancyGuard { using Counters for Counters.Counter; Counters.Counter private _itemIds; Counters.Counter private _itemsSold; address payable owner; uint256 listingPrice = 0.025 ether; constructor() { owner = payable(msg.sender); } struct MarketItem { uint itemId; address nftContract; uint256 tokenId; address payable seller; address payable owner; uint256 price; bool sold; } mapping(uint256 => MarketItem) private idToMarketItem; event MarketItemCreated ( uint indexed itemId, address indexed nftContract, uint256 indexed tokenId, address seller, address owner, uint256 price, bool sold ); /* Returns the listing price of the contract */ function getListingPrice() public view returns (uint256) { return listingPrice; } /* Places an item for sale on the marketplace */ function createMarketItem( address nftContract, uint256 tokenId, uint256 price ) public payable nonReentrant { require(price > 0, “Price must be at least 1 wei”); require(msg.value == listingPrice, “Price must be equal to listing price”); _itemIds.increment(); uint256 itemId = _itemIds.current(); idToMarketItem[itemId] = MarketItem( itemId, nftContract, tokenId, payable(msg.sender), payable(address(0)), price, false ); IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId); emit MarketItemCreated( itemId, nftContract, tokenId, msg.sender, address(0), price, false ); } /* Creates the sale of a marketplace item */ /* Transfers ownership of the item, as well as funds between parties */ function createMarketSale( address nftContract, uint256 itemId ) public payable nonReentrant { uint price = idToMarketItem[itemId].price; uint tokenId = idToMarketItem[itemId].tokenId; require(msg.value == price, “Please submit the asking price in order to complete the purchase”); idToMarketItem[itemId].seller.transfer(msg.value); IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId); idToMarketItem[itemId].owner = payable(msg.sender); idToMarketItem[itemId].sold = true; _itemsSold.increment(); payable(owner).transfer(listingPrice); } /* Returns all unsold market items */ function fetchMarketItems() public view returns (MarketItem[] memory) { uint itemCount = _itemIds.current(); uint unsoldItemCount = _itemIds.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(0)) { 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 = _itemIds.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 created */ function fetchItemsCreated() public view returns (MarketItem[] memory) { uint totalItemCount = _itemIds.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; }}

现在智能合约代码和环境已经完成,我们可以尝试测试一下。

为此,我们可以创建一个本地测试来运行大部分功能,例如铸造代币、将其出售、将其出售给用户以及查询代币。

要创建测试,请打开test/sample-test.js并使用以下代码更新它:

在此处查看要点

/* test/sample-test.js */describe(“NFTMarket”, function() { it(“Should create and execute market sales”, async function() { /* deploy the marketplace */ const Market = await ethers.getContractFactory(“NFTMarket”) const market = await Market.deploy() await market.deployed() const marketAddress = market.address /* deploy the NFT contract */ const NFT = await ethers.getContractFactory(“NFT”) const nft = await NFT.deploy(marketAddress) await nft.deployed() const nftContractAddress = nft.address let listingPrice = await market.getListingPrice() listingPrice = listingPrice.toString() const auctionPrice = ethers.utils.parseUnits(1, ether) /* create two tokens */ await nft.createToken(“https://www.mytokenlocation.com“) await nft.createToken(“https://www.mytokenlocation2.com

“) /* put both tokens for sale */ await market.createMarketItem(nftContractAddress, 1, auctionPrice, { value: listingPrice }) await market.createMarketItem(nftContractAddress, 2, auctionPrice, { value: listingPrice }) const [_, buyerAddress] = await ethers.getSigners() /* execute sale of token to another user */ await market.connect(buyerAddress).createMarketSale(nftContractAddress, 1, { value: auctionPrice}) /* query for and return the unsold items */ items = await market.fetchMarketItems() items = await Promise.all(items.map(async i => { const tokenUri = await nft.tokenURI(i.tokenId) let item = { price: i.price.toString(), tokenId: i.tokenId.toString(), seller: i.seller, owner: i.owner, tokenUri } return item })) console.log(items: , items) })})

要运行测试,npx hardhat test请从命令行运行:

如果测试成功运行,它应该注销包含单个市场项目的数组。

构建前端

现在智能合约正在运行并准备就绪,我们可以开始构建 UI。

我们可能会考虑的第一件事是设置布局,以便我们可以启用一些跨所有页面持续存在的导航。

要进行设置,请打开pages/_app.js并使用以下代码更新它:

在此处查看要点

/* pages/_app.js */import ../styles/globals.cssimport Link from next/linkfunction MyApp({ Component, pageProps }) { return (

)}export default MyApp

导航包含回家路线的链接以及用于出售数字资产、查看您购买的资产的页面,以及用于查看您创建的资产和出售的资产的创建者仪表板。

查询市场项目的合同

我们将更新的下一页是pages/index.js。这是应用程序的主要入口点,也是我们查询待售数字资产并将它们呈现到屏幕的视图。

在此处查看要点

/* pages/index.js */import { ethers } from ethersimport { useEffect, useState } from reactimport axios from axiosimport Web3Modal from “web3modal”import { nftaddress, nftmarketaddress} from ../configimport NFT from ../artifacts/contracts/NFT.sol/NFT.jsonimport Market from ../artifacts/contracts/Market.sol/NFTMarket.jsonexport default function Home() { const [nfts, setNfts] = useState([]) const [loadingState, setLoadingState] = useState(not-loaded) useEffect(() => { loadNFTs() }, []) async function loadNFTs() { /* create a generic provider and query for unsold market items */ const provider = new ethers.providers.JsonRpcProvider() const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider) const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, provider) const data = await marketContract.fetchMarketItems() /* * map over items returned from smart contract and format * them as well as fetch their token metadata */ const items = await Promise.all(data.map(async i => { const tokenUri = await tokenContract.tokenURI(i.tokenId) const meta = await axios.get(tokenUri) let price = ethers.utils.formatUnits(i.price.toString(), ether) let 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) } async function buyNft(nft) { /* needs the user to sign the transaction, so will use Web3Provider and sign it */ const web3Modal = new Web3Modal() const connection = await web3Modal.connect() const provider = new ethers.providers.Web3Provider(connection) const signer = provider.getSigner() const contract = new ethers.Contract(nftmarketaddress, Market.abi, signer) /* user will be prompted to pay the asking proces to complete the transaction */ const price = ethers.utils.parseUnits(nft.price.toString(), ether) const transaction = await contract.createMarketSale(nftaddress, nft.tokenId, { value: price }) await transaction.wait() loadNFTs() } if (loadingState === loaded && !nfts.length) return (

No items in marketplace

) return (
{ nfts.map((nft, i) => (

{nft.name}

{nft.description}

{nft.price} ETH

)) }
)}

当页面加载时,我们会在智能合约中查询任何仍在出售的物品,并将它们连同有关物品的元数据和用于购买它们的按钮一起呈现在屏幕上。

创建和列出数字项目

接下来,让我们创建允许用户创建和列出数字资产的页面。

此页面中发生了一些事情:

用户能够上传和保存文件到 IPFS用户能够创建一个新的独特的数字项目 (NFT)用户能够设置项目的元数据和价格,并在市场上出售

用户创建并列出商品后,他们将重新路由到主页以查看所有待售商品。

在此处查看要点

/* pages/create-item.js */import { useState } from reactimport { ethers } from ethersimport { create as ipfsHttpClient } from ipfs-http-clientimport { useRouter } from next/routerimport Web3Modal from web3modalconst client = ipfsHttpClient(https://ipfs.infura.io:5001/api/v0)import { nftaddress, nftmarketaddress} from ../configimport NFT from ../artifacts/contracts/NFT.sol/NFT.jsonimport Market from ../artifacts/contracts/Market.sol/NFTMarket.jsonexport default function CreateItem() { const [fileUrl, setFileUrl] = useState(null) const [formInput, updateFormInput] = useState({ price: , name: , description: }) const router = useRouter() 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) } } async function createMarket() { 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, pass the URL to save it on Polygon */ createSale(url) } catch (error) { console.log(Error uploading file: , error) } } async function createSale(url) { const web3Modal = new Web3Modal() const connection = await web3Modal.connect() const provider = new ethers.providers.Web3Provider(connection) const signer = provider.getSigner() /* next, create the item */ let contract = new ethers.Contract(nftaddress, NFT.abi, signer) let transaction = await contract.createToken(url) let tx = await transaction.wait() let event = tx.events[0] let value = event.args[2] let tokenId = value.toNumber() const price = ethers.utils.parseUnits(formInput.price, ether) /* then list the item for sale on the marketplace */ contract = new ethers.Contract(nftmarketaddress, Market.abi, signer) let listingPrice = await contract.getListingPrice() listingPrice = listingPrice.toString() transaction = await contract.createMarketItem(nftaddress, tokenId, price, { value: listingPrice }) await transaction.wait() router.push(/) } return (

updateFormInput({ …formInput, name: e.target.value })} />

仅查看用户购买的商品

在Market.sol智能合约中,我们创建了一个名为fetchMyNFTs仅返回用户拥有的项目的函数。

在pages/my-assets.js 中,我们将使用该函数来获取和呈现它们。

此功能与查询主页/index.js页面不同,因为我们需要向用户询问他们的地址并在合约中使用它,因此用户必须签署交易才能正确获取它们。

在此处查看要点

/* pages/my-assets.js */import { ethers } from ethersimport { useEffect, useState } from reactimport axios from axiosimport Web3Modal from “web3modal”import { nftmarketaddress, nftaddress} from ../configimport Market from ../artifacts/contracts/Market.sol/NFTMarket.jsonimport NFT from ../artifacts/contracts/NFT.sol/NFT.jsonexport default function MyAssets() { const [nfts, setNfts] = useState([]) const [loadingState, setLoadingState] = useState(not-loaded) useEffect(() => { loadNFTs() }, []) async function loadNFTs() { const web3Modal = new Web3Modal({ network: “mainnet”, cacheProvider: true, }) const connection = await web3Modal.connect() const provider = new ethers.providers.Web3Provider(connection) const signer = provider.getSigner() const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, signer) const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider) const data = await marketContract.fetchMyNFTs() const items = await Promise.all(data.map(async i => { const tokenUri = await tokenContract.tokenURI(i.tokenId) const meta = await axios.get(tokenUri) let price = ethers.utils.formatUnits(i.price.toString(), ether) let item = { price, tokenId: i.tokenId.toNumber(), seller: i.seller, owner: i.owner, image: meta.data.image, } return item })) setNfts(items) setLoadingState(loaded) } if (loadingState === loaded && !nfts.length) return (

No assets owned

) return (
{ nfts.map((nft, i) => (

Price – {nft.price} Eth

)) }
)}

创作者仪表板

我们将创建的最后一个页面是创建者仪表板,允许他们查看他们创建的所有项目以及他们出售的项目。

此页面将使用Market.sol智能合约中的fetchItemsCreated函数,该函数仅返回与调用函数的用户地址匹配的项目。

在客户端,我们使用sold布尔值将项目过滤到另一个单独的数组中,以仅向用户显示已售出的项目。

使用以下代码在pages目录中创建一个名为creator-dashboard.js的新文件:

在此处查看要点

/* pages/creator-dashboard.js */import { ethers } from ethersimport { useEffect, useState } from reactimport axios from axiosimport Web3Modal from “web3modal”import { nftmarketaddress, nftaddress} from ../configimport Market from ../artifacts/contracts/Market.sol/NFTMarket.jsonimport NFT from ../artifacts/contracts/NFT.sol/NFT.jsonexport default function CreatorDashboard() { const [nfts, setNfts] = useState([]) const [sold, setSold] = useState([]) const [loadingState, setLoadingState] = useState(not-loaded) useEffect(() => { loadNFTs() }, []) async function loadNFTs() { const web3Modal = new Web3Modal({ network: “mainnet”, cacheProvider: true, }) const connection = await web3Modal.connect() const provider = new ethers.providers.Web3Provider(connection) const signer = provider.getSigner() const marketContract = new ethers.Contract(nftmarketaddress, Market.abi, signer) const tokenContract = new ethers.Contract(nftaddress, NFT.abi, provider) const data = await marketContract.fetchItemsCreated() const items = await Promise.all(data.map(async i => { const tokenUri = await tokenContract.tokenURI(i.tokenId) const meta = await axios.get(tokenUri) let price = ethers.utils.formatUnits(i.price.toString(), ether) let item = { price, tokenId: i.tokenId.toNumber(), seller: i.seller, owner: i.owner, sold: i.sold, image: meta.data.image, } return item })) /* create a filtered array of items that have been sold */ const soldItems = items.filter(i => i.sold) setSold(soldItems) setNfts(items) setLoadingState(loaded) } if (loadingState === loaded && !nfts.length) return (

No assets created

) return (

Items Created

{ nfts.map((nft, i) => (

Price – {nft.price} Eth

)) }
{ Boolean(sold.length) && (

Items sold

{ sold.map((nft, i) => (

Price – {nft.price} Eth

)) }
) }
)}

运行项目

要运行该项目,我们需要有一个部署脚本来将智能合约部署到区块链网络。

将合约部署到本地网络

当我们创建项目时,Hardhat 在scripts/sample-script.js 中创建了一个示例部署脚本。

为了使这个脚本的目的更加明确,将scripts/sample-script.js的名称更新为scripts/deploy.js。

接下来,使用以下代码更新scripts/deploy.js 中的main函数:

async function main() { const NFTMarket = await hre.ethers.getContractFactory(“NFTMarket”); const nftMarket = await NFTMarket.deploy(); await nftMarket.deployed(); console.log(“nftMarket deployed to:”, nftMarket.address); const NFT = await hre.ethers.getContractFactory(“NFT”); const nft = await NFT.deploy(nftMarket.address); await nft.deployed(); console.log(“nft deployed to:”, nft.address);}

该脚本会将两个合约部署到区块链网络。

我们将首先在本地网络上进行测试,然后将其部署到孟买测试网。

要启动本地网络,请打开终端并运行以下命令:

npx hardhat node

这应该创建一个具有 19 个帐户的本地网络。

接下来,保持节点运行并打开一个单独的终端窗口来部署合约。

在单独的窗口中,运行以下命令:

npx hardhat run scripts/deploy.js –network localhost

部署完成后,CLI 应打印出已部署合约的地址:

文章转载http://www.wjyxt.net/

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注