搭建你的第一个NFTMarketplace以及智能合约管理系统

804 阅读8分钟

项目地址:github.com/yumao369/op…

前言

本文不会涉及太多理论,目的是教你搭建一个NFTMarketplace以及对应的合约管理系统,话不多说,让我们开始吧。

项目介绍

我们将会搭建一个简易的类似Opensea的nft交易平台,用户可以在上面创建或者购买nft。当用户a创建了一个nft并上架售卖时,这个nft的所有权将会从该用户转到NFTMarketplace这个合约上。当另用户b购买这个nft时,用户b需要向用户a支付该nft的价格,当交易完成时,nft的所有权从合约转到用户b。当这个过程完成时,合约的所有者将收到一笔上架费用,或者可以理解为交易手续费,这笔手续费是由用户a支付的。

当这个过程完成时,你可以去合约管理平台查看交易明细,合约所有者将有权重置上架费用。

项目启动

新建文件夹openseaClone,在文件夹下新建三个文件夹,client,smart_contract,contract_management,依次用于存放客户端代码,智能合约代码,合约管理平台代码

智能合约

  • cd smart_contract
  • npm init -y
  • 接下来安装项目依赖,npm i @nomiclabs/hardhat-ethers @nomiclabs/hardhat-waffle @openzeppelin/contracts chai ethereum-waffle ethers hardhat @nomicfoundation/hardhat-toolbox
  • npx hardhat

这时可以看到hardhat为我们初始化了一些列文件,现在你可以运行npx hardhat test,如果出现以下图片,则表示示例通过测试

7.PNG

接下来进入contracts文件,删除原有的文件,新建NFTMarketplace.sol文件,这个就是我们的只能合约代码,在文件中粘贴这个代码,之后打开test文件,删除原有文件,新建NFTMarketplace.js文件,在文件中粘贴这个代码,之后运行npx hardhat test,如果出现以下结果则说明测试通过

9.PNG 好了,我们现在准备好合约了,接下来去infura申请一个节点用于与以太坊交互,create new key->network选择Web3 api,输入项目名称->选择ropsten,复制url,并粘贴到下面代码的url后面。

现在,我们将把合约部署到ropsten network,你也可以部署到其他网络,或者你可以先到本地网络进行测试。打开hardhat.config.js,输入以下代码,你用于发布合约的钱包地址需要有一定的以太币,由于我们是在ropsten network发布合约,你可以去这个地址领取一定数量的币


/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.9",
  networks: {
    ropsten: {
      //the url you have created in infura,please place it here
      url: '',
      //private key of the wallet address that you need to deploy the contract
      accounts: ['']
    }
  }
};

接下来打开scripts/deploy.js,输入以下代码

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}"`)
}

const runMain = async () => {
  try {
    await main()
    process.exit(0)
  } catch (err) {
    console.error(err)
    process.exit(1)
  }
}

runMain()

在终端运行这条命令npx hardhat run scripts/deploy.js --network ropsten,如果你的终端输出以下结果,那么你的部署已经成功了,并且在smart_contract根目录下应该会生成一个新的文件config.js,里面保存了这个合约地址

10.PNG

目前为止,合约已经准备就绪,接下来我们开始搭建前端界面

用户界面

  • cd client
  • npm create vite@latest这里需要选择react项目,本项目用的是js版本,你也可以使用ts版本
  • 安装项目依赖npm i axios ethers ipfs-http-client react react-dom react-router-dom,npm i -D tailwindcss postcss autoprefixer
  • 启动项目npm run dev

接下来配置tailwindcss

  • npx tailwindcss init
  • 打开tailwind.config.cjs文件,粘贴下面的代码
module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
    "./components/*.jsx"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

  • 打开index.css,删除原有代码,粘贴以下代码
@tailwind base;
@tailwind components;
@tailwind utilities;

接下来可以按官网示例编写代码,测试是否配置成功。

现在在client根目录下新建utils/contants.js,以及utils/NFTMarketplace.json,将smart_contract/artifacts/contracts/NFTMarketplace.sol目录下的ABI文件NFTMarketplace.json中的内容复制到utils/NFTMarketplace.json里面,接下来,将以下代码粘贴到你的utils/contants.js文件中

import NFTMarketplaceAbi from './NFTMarketplace.json'

//this is the address of your contract in ropsten test network,please replace it
export const NFTMarketplaceAddress = '0x7356659757D92E06d50ee502Eb1e5f463E581b0d'
export const NFTMarketplaceABI = NFTMarketplaceAbi.abi

好了,一切就绪,可以编写前端代码了。前端总共有四个页面,marketcreateminemylisted ,分别用来展示上架的nft,创造你自己的nft,展示你已经拥有的nft,展示你上架的nft。我们先来看看效果。

image.png

image.png

image.png

image.png 首先我们连接上metamask钱包,可以看到,目前没有任何nft在售,接下来到create页面按要求创建你的nft,并等待区块确认,页面会自动跳转到market页

image.png

image.png 可以看到我们与以太坊的交互成功了,我成功创建了我的第一个nft,并上架销售。

现在我们回到代码,首先新建一个context/NFTMarketplaceContext.jsx文件,我们要用context传值,这样就不用一级一级传递props了,这个需要一定的react基础,在这个文件中粘贴这个代码,在这段代码中,我们首先检测是否安装了metamask客户端,接下来定义了一个connectwallet方法,用于连接当前用户,当然最重要的是实例化了合约。接下来我们就可以在各个页面获取这个合约实例了。现在我们可以输出一下这个合约实例。

image.png 可以看到里面有我们在NFTMarketplace.sol中定义的各个方法,还有从ERC720等合约中继承过来的方法。

接下来我们只需要在需要的地方使用这些方法即可,比如在market页面中,我们使用了fetchMarketItems这个方法,用法如下

    const data = await NFTMarketplaceContract.fetchMarketItems()
    console.log(data)

输出如下

image.png

可以看到,这就是我们之前上架的那个nft的信息。

到这一步,剩下的就是将取出的信息进行页面展示了,这里就不做介绍了,大家可以自己编写,或者直接复制我的代码,本文的目的是教大家搭建nftmarketplace,理论的东西大家可以后面慢慢摸索。

合约管理系统

作为合约的所有者,你可能想看到每一笔交易的详细信息,这个时候,我们就需要搭建一个合约管理系统,本文的合约管理系统只适用于当前合约,大家可以自己拓展。

合约管理系统的项目初始化和用户交互界面类似,这里就不多做介绍了。

首先让我们看看实现的效果

image.png

image.png

image.png

image.png 可以看到,我们已经可以拿到合约的信息了,比如第一页properties中显示ETH Balance为0.025,也就是合约的余额是0.025,因为用户上架nft需要向合约交一笔‘手续费’(listingprice),而这笔手续费就是0.025,并且你也可以看到目前我上架的nftfetchItemsListed,在售的nftfetchMarketItems,在call方法中,我们需要输入参数进行查询,比如tokenURI,我之前上架的tokenid是1,查询这个nft的uri,可以看到返回。

这里最重要的是,我们如何区分这四种方法,还记得我们之前输出的NFTMarketplaceContract实例吗,这些方法就是这个实例里面的。

const NFTMarketplaceContractInterface = new ethers.utils.Interface(NFTMarketplaceABI)
//get all the functions
const { functions } = NFTMarketplaceContractInterface
//get all the events
const { events } = NFTMarketplaceContractInterface

通过这段代码,我们可以区分functionsevents,但是properties,sendmethod,callmethod如何区分呢?

//properties
functions[item].constant === true && functions[item].inputs.length === 0
//call
functions[item].constant === true && functions[item].inputs.length > 0
//send
functions[item].constant === false

as you can see,we can distinguish them like that.好了,区分了这四种方法之后,接下来又是编写前端页面和合约进行交互了,这部分就不介绍了。

整体效果

上面我们以及上架了一个nft了,现在我们用另一个账号登录页面,可以看到,mylisted页面什么都没有

image.png

image.png 到market页面点击buy,签名,等待合约执行完成,可以看到一下变化,mine页面展示了刚刚购买的nft

image.png

image.png 回到之前那个账号,可以看到,mylisted已经什么都没有了

image.png 再来到我们的合约管理系统

image.png

image.png 我们可以查到详细信息。

让我们再试一下合约管理系统的send方法,比如我作为合约的拥有者想更改交易的手续费,我可以调用updateListingPrice,如下

image.png 我们再查看listingprice,可以看到,已经变成1ETH

image.png

现在我们可以通过交易哈希去ropsten test network Etherscan查看每一笔交易更加详细的的信息

image.png 这个是我点击购买的那个事件,可以看到里面详细记录了该nft从一个账户转到了另一个账户,交易了0.1Ether,这正好就是售卖者出售的价格,下面还有这笔交易所需的gas费

总结

以上就是本文的全部内容了,后面我会逐步完善github代码,以及添加注释。都看完了,给我的github一个小星星呀!