NFT交易市场-后端开发

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>NFT Market</title>
</head>

<body>
  <h1>Upload file to IPFS</h1>
  <form action="/upload" method="POST" enctype="multipart/form-data">
    <label>Title</label>
    <input type="text" name="title">
    <br><br>
    <label>Description</label>
    <input type="text" name="description">
    <br><br>
    <input type="file" name="file">
    <br><br>
    <input type="submit" name="Submit">
  </form>
</body>

</html>
  • 在package.json文件中添加如下代码
  • app.js代码如下
import express from 'express';
import bodyParser from 'body-parser';
import fileUpload from 'express-fileupload';

const app = express();

//配置模板引擎,express框架将会自动查找以'.ejs'为扩展名的文件作为视图模板,并将数据填充到这些模板中,最终生成HTML页面返回给客户端
app.set('view engine', 'ejs');
//配置中间件
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload());

app.get('/', (req, res) => {
  //res.render()方法是Express框架中应用于渲染试图模板的方法,将指定的视图模板渲染成HTML页面然后作为响应发送给客户端
  res.render("home");
});

app.post('/upload', (req, res) => {
  //注意:req.body后面的属性是和home.ejs里面的name属性相对应
  const title = req.body.title;
  const description = req.body.description;
  console.log(req.files);

  //将用户上传的文件保存在我们的files文件夹内
  const file = req.files.file;
  const filename = file.name;
  const filePath = "files/" + filename;
  file.mv(filePath, (err) => {
    if (err) {
      console.log(err);
      res.status(500).send("error occured");
    }
  })

  res.json(
    {
      message: "file upload successful!"
    }
  )
});

app.listen(3000, () => {
  console.log('Example app listening on port 3000!');
});
  • 新建files文件夹存放图片

  • 在终端运行node app.js命令启动我们的服务器,然后在网页上输入localhost:3000打开我们的网页,输入相应值,传一张图片,然后我们可以在我们的files文件夹目录下找到该图片
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 新建ipfs-uploader.js文件用来上传图片到 ipfs,代码如下

import { create } from 'kubo-rpc-client';
import fs from 'fs';

// 使用 IPv4 地址连接到 IPFS 节点
const ipfs = create('http://127.0.0.1:5001');

async function uploadFileToIPFS(filePath) {
  const file = fs.readFileSync(filePath);
  const result = await ipfs.add({ path: filePath, content: file });
  console.log(result);
  return result;
}

uploadFileToIPFS("files/qkl.png");

  • 输入node ipfs-uploader.js命令运行,返回一串CID,我们可以通过该CID在网页上查看我们上传的图片127.0.0.1:8080/ipfs/CID,注意:同时要运行本地的 ipfs节点,我是在WSL终端运行ipfs节点,在vscode终端运行命令,具体看自己想怎么操作。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 修改ipfs-uploader.js文件代码如下,尝试上传一个json文件到IPFS
import { create } from 'kubo-rpc-client';
import fs from 'fs';

// 使用 IPv4 地址连接到 IPFS 节点
const ipfs = create('http://127.0.0.1:5001');

async function uploadFileToIPFS(filePath) {
  const file = fs.readFileSync(filePath);
  const result = await ipfs.add({ path: filePath, content: file });
  console.log(result);
  return result;
}

async function uploadJSONToIPFS(json) {
  const result = await ipfs.add(JSON.stringify(json));
  console.log(result);
  return result;
}

uploadJSONToIPFS({ name: "test" });

运行该代码返回值如下
在这里插入图片描述
在网页上 查看如下
在这里插入图片描述

  • 最后再修改我们的代码,在app.js中引入ipfs-uploader.js文件中的上传功能,用到了node.js中的export功能,我在Node.js章节中解释过,修改后的完整代码如下
  • app.js代码 如下:
import express from 'express';
import bodyParser from 'body-parser';
import fileUpload from 'express-fileupload';
import { uploadFileToIPFS, uploadJSONToIPFS } from './ipfs-uploader.js';

const app = express();

//配置模板引擎,express框架将会自动查找以'.ejs'为扩展名的文件作为视图模板,并将数据填充到这些模板中,最终生成HTML页面返回给客户端
app.set('view engine', 'ejs');
//配置中间件
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload());

app.get('/', (req, res) => {
  //res.render()方法是Express框架中应用于渲染试图模板的方法,将指定的视图模板渲染成HTML页面然后作为响应发送给客户端
  res.render("home");
});

app.post('/upload', (req, res) => {
  //注意:req.body后面的属性是和home.ejs里面的name属性相对应
  const title = req.body.title;
  const description = req.body.description;

  //将用户上传的文件保存在我们的files文件夹内
  const file = req.files.file;
  const filename = file.name;
  const filePath = "files/" + filename;

  file.mv(filePath, async (err) => {
    if (err) {
      console.log(err);
      res.status(500).send("error occured");
    }

    //上传图片到IPFS
    const fileResult = await uploadFileToIPFS(filePath);
    //拿到上传图片的CID
    const fileCid = fileResult.cid.toString();

    const metadata = {
      title: title,
      description: description,
      image: 'http://127.0.0.1:8080/ipfs/' + fileCid
    }

    //返回信息给用户
    res.json({
      message: "file uploaded successfully",
      metadata: metadata
    });
  })

});

app.listen(3000, () => {
  console.log('Example app listening on port 3000!');
});

  • ipfs-uploader.js文件代码如下:
import { create } from 'kubo-rpc-client';
import fs from 'fs';

// 使用 IPv4 地址连接到 IPFS 节点
const ipfs = create('http://127.0.0.1:5001');

//上传图片到ipfs
export async function uploadFileToIPFS(filePath) {
  const file = fs.readFileSync(filePath);
  const result = await ipfs.add({ path: filePath, content: file });
  console.log(result);
  return result;
}

//上传json格式文件到ipfs
export async function uploadJSONToIPFS(json) {
  const result = await ipfs.add(JSON.stringify(json));
  return result;
}
  • 然后要实现mint NFT给用户,首先我们需要将我们之前的NFT合约连接到remix上面,这个之前有详细讲过如何连接哈
    在这里插入图片描述
    在这里插入图片描述
  • 然后选择ERC721合约进行相应操作,注意期间要启动hardhat节点,否则连接不上Remix - Hardhat Provider,sorry,今天测试的时候发现之前的ERC721合约 少写了uri功能,因此修改了该合约,修改ERC721合约代码如下
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyNFT is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
    uint256 private _nextTokenId;

    constructor() ERC721("MyNFT", "NFT") Ownable(msg.sender) {}

    function safeMint(address to, string memory uri) public onlyOwner {
        uint256 tokenId = _nextTokenId++;
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);
    }

    // The following functions are overrides required by Solidity.

    function _update(
        address to,
        uint256 tokenId,
        address auth
    ) internal override(ERC721, ERC721Enumerable) returns (address) {
        return super._update(to, tokenId, auth);
    }

    function _increaseBalance(
        address account,
        uint128 value
    ) internal override(ERC721, ERC721Enumerable) {
        super._increaseBalance(account, value);
    }

    function tokenURI(
        uint256 tokenId
    ) public view override(ERC721, ERC721URIStorage) returns (string memory) {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(
        bytes4 interfaceId
    )
        public
        view
        override(ERC721, ERC721Enumerable, ERC721URIStorage)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

启动hardhat节点

在这里插入图片描述
在这里插入图片描述

  • 然后我们需要实现当用户成功上传一个图片到IPFS以后,合约自动挖一个NFT给用户,这里用到了ethers库。在终端输入npm install ethers安装ethers库。
  • 新建一个abis文件夹,文件夹里面新建一个myNFT.json的文件,正常编译部署完ERC721合约后,我们可以在remix编译界面上直接找到该合约的abi,复制即可,然后粘贴到myNFT.json文件中
    在这里插入图片描述
  • 创建一个名为nft-minter.js的文件 用来实现挖NFT给用户的功能,若是直接打印result, console.log(result);,我们可以看到完整信息,我们也可以简化信息console.log(result.hash);,完整代码如下,注意替换地址
import { ethers, JsonRpcProvider } from "ethers";
import fs from 'fs';

//挖一个NFT
async function mint(to, uri) {
  const provider = new JsonRpcProvider("http://127.0.0.1:8545");
  const signer = await provider.getSigner();
  //改成自己的ERC721合约地址,在remix上面复制合约地址
  const contractAddress = "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9";
  const abi = JSON.parse(fs.readFileSync("./abis/myNFT.json"));
  const contract = new ethers.Contract(contractAddress, abi, signer);
  const result = await contract.safeMint(to, uri);
  console.log(result.hash);
}

//测试一下,这里的地址是你想给他mint NFT的地址
mint('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', 'https://sdcsdc.com');

这是完整信息界面
在这里插入图片描述
这是简化后的输出

然后我们查看remix上面该地址拥有的NFT可以发现,mint过去了,因为我测试了三次,所以该地址拥有的NFT现在有三个啦
在这里插入图片描述

  • 测试成功之后我们就可以删除掉最后一行测试代码啦
    在这里插入图片描述
  • 然后 再把该功能export出去,在app.js中import进来
    在这里插入图片描述
    在这里插入图片描述
  • app.js修改后的完整代码如下
import express from 'express';
import bodyParser from 'body-parser';
import fileUpload from 'express-fileupload';
import { uploadFileToIPFS, uploadJSONToIPFS } from './ipfs-uploader.js';
import { mint } from './nft-minter.js';

const app = express();

//配置模板引擎,express框架将会自动查找以'.ejs'为扩展名的文件作为视图模板,并将数据填充到这些模板中,最终生成HTML页面返回给客户端
app.set('view engine', 'ejs');
//配置中间件
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload());

app.get('/', (req, res) => {
  //res.render()方法是Express框架中应用于渲染试图模板的方法,将指定的视图模板渲染成HTML页面然后作为响应发送给客户端
  res.render("home");
});

app.post('/upload', (req, res) => {
  //注意:req.body后面的属性是和home.ejs里面的name属性相对应
  const title = req.body.title;
  const description = req.body.description;

  //将用户上传的文件保存在我们的files文件夹内
  const file = req.files.file;
  const filename = file.name;
  const filePath = "files/" + filename;

  file.mv(filePath, async (err) => {
    if (err) {
      console.log(err);
      res.status(500).send("error occured");
    }

    //上传图片到IPFS
    const fileResult = await uploadFileToIPFS(filePath);
    //拿到上传图片的CID
    const fileCid = fileResult.cid.toString();

    const metadata = {
      title: title,
      description: description,
      image: 'http://127.0.0.1:8080/ipfs/' + fileCid
    }

    const metadataResult = await uploadFileToIPFS(metadata);
    const metadataCid = metadataResult.cid.toString();
    console.log(metadataCid);

    //这里的地址我暂时放的我开始mint NFT的地址
    await mint("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 'http://127.0.0.1:8080/ipfs/' + metadataCid);

    //返回信息给用户
    res.json({
      message: "file uploaded successfully",
      metadata: metadata
    });
  })

});

app.listen(3000, () => {
  console.log('Example app listening on port 3000!');
});
  • 然后我们打开网页测试一下是否成功,注意要开启ipfs节点哈
    在这里插入图片描述
  • 我们可以发现remix上面该地址的NFT增加了一个
    在这里插入图片描述
    在这里插入图片描述
    测试成功!!!😊
  • 因为在代码中有很多写死的变量,如果我们后期去修改,找起来很麻烦,因此我们可以使用dotenv这个库,只需要在.env文件中修改变量即可,就方便亿点点,关于去查询这些库的用法可以在https://www.npmjs.com/网站上查询
    在这里插入图片描述
  • 首先在终端输入npm install dotenv --save命令安装库
  • 新建.env文件
  • 在需要用到.env的文件中导入库并读取该文件
    在这里插入图片描述
  • 使用如下的替换格式,具体要替换哪些看你们自己啦
    在这里插入图片描述
    这是.env文件的内容
    在这里插入图片描述
    在这里插入图片描述
  • 最后可以再保存然后打开网页上传一下文件,看下是否给地址mint了一个NFT,我这里是成功了哈,注意别替换错了。
  • 未完待续~😀(有什么问题欢迎提问哈)

相关推荐

  1. 开发辅助

    2024-03-24 05:38:03       21 阅读
  2. 开发教程

    2024-03-24 05:38:03       14 阅读
  3. 开发大纲

    2024-03-24 05:38:03       19 阅读
  4. 开发面试题

    2024-03-24 05:38:03       41 阅读
  5. 开发笔记20240106

    2024-03-24 05:38:03       32 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-24 05:38:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-24 05:38:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-24 05:38:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-24 05:38:03       20 阅读

热门阅读

  1. 数据仓库——维度表更新

    2024-03-24 05:38:03       19 阅读
  2. C#中const与readonly关键字区别

    2024-03-24 05:38:03       18 阅读
  3. 数据分析-Pandas类别的排序和顺序

    2024-03-24 05:38:03       18 阅读
  4. 最常考的设计模式之一---单例模式

    2024-03-24 05:38:03       17 阅读
  5. 设计模式之单例模式

    2024-03-24 05:38:03       17 阅读
  6. 面试宝典:MySQL-深度分析如何避免幻读

    2024-03-24 05:38:03       18 阅读
  7. 第4周 Python程序流程控制刷题(循环结构)

    2024-03-24 05:38:03       17 阅读
  8. Gin简介(Go web基础知识)

    2024-03-24 05:38:03       20 阅读
  9. oracle ADG主备切换

    2024-03-24 05:38:03       20 阅读
  10. Spring设计模式-实战篇之策略模式 + 工厂模式

    2024-03-24 05:38:03       21 阅读
  11. Android studio 简单入门程序

    2024-03-24 05:38:03       17 阅读