NFT交易市场-后端开发

  • 首先我们需要配置好我们的ipfs,参考官方文档

    • 1.https://docs.ipfs.tech/install/command-line/#system-requirements
    • https://docs.ipfs.tech/how-to/command-line-quick-start/#initialize-the-repository
  • 首先新建一个文件夹

  • 然后在终端输入npm init -y命令进行初始化
    在这里插入图片描述

  • npm install express安装 express
    在这里插入图片描述

  • npm install ejs安装ejs模板引擎

  • npm install body-parser安装body-parser模块

  • npm install express-fileupload安装express-fileupload模块

  • npm install kubo-rpc-client

  • 新建一个views文件夹,里面新建一个home.ejs文件
    文件中输入以下代码

<!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");}//上传图片到IPFSconst fileResult = await uploadFileToIPFS(filePath);//拿到上传图片的CIDconst 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)publicviewoverride(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");}//上传图片到IPFSconst fileResult = await uploadFileToIPFS(filePath);//拿到上传图片的CIDconst 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,我这里是成功了哈,注意别替换错了。
  • 未完待续~😀(有什么问题欢迎提问哈)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/284041.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AI】发现一款运行成本较低的SelfHosting语言模型

【背景】 作为一个想构建局域网AI服务的屌丝,一直苦恼的自然是有限的资源下有没有对Spec要求低一点的SelfHosting的AI服务框架了。今天给大家介绍这款听起来有点希望,但是我也还没试验过,感兴趣的可以去尝试看看。 【介绍】 大模型生成式AI与别的技术不同,由于资源要求高…

分布式之网关介绍

一、网关简介 1、网关背景 由于微服务“各自为政的特性”使微服务的使用非常麻烦。通常公司会有一个“前台小姐姐”作为统一入口&#xff0c;这就是网关 2、网关作用 统一入口&#xff1a;为服务提供一个唯一的入口&#xff0c;网关起到外部和内部隔离的作用&#xff0c; 保…

演讲嘉宾公布 | 智能家居与会议系统专题论坛将于3月28日举办

一、智能家居与会议系统专题论坛 智能家居通过集成先进的技术和设备&#xff0c;为人们提供了更安全、舒适、高效、便捷且多彩的生活体验。智能会议系统它通过先进的技术手段&#xff0c;提高了会议效率&#xff0c;降低了沟通成本&#xff0c;提升了参会者的会议体验。对于现代…

iOS模拟器 Unable to boot the Simulator —— Ficow笔记

本文首发于 Ficow Shen’s Blog&#xff0c;原文地址&#xff1a; iOS模拟器 Unable to boot the Simulator —— Ficow笔记。 内容概览 前言终结模拟器进程命令行改权限清除模拟器缓存总结 前言 iOS模拟器和Xcode一样不靠谱&#xff0c;问题也不少。&#x1f602; 那就有病治…

设计数据库之外部模式:数据库的应用

Chapter5&#xff1a;设计数据库之外部模式&#xff1a;数据库的应用 笔记来源&#xff1a;《漫画数据库》—科学出版社 设计数据库的步骤&#xff1a; 概念模式 概念模式(conceptual schema)是指将现实世界模型化的阶段进而&#xff0c;是确定数据库理论结构的阶段。 概念模…

分布式搜索引擎-DSL查询文档

分布式搜索引擎-DSL查询文档 文章目录 分布式搜索引擎-DSL查询文档1、DSL Query的分类1.1、全文检索查询1.2、精确查询1.3、地理查询1.4、复合查询1.5、Function Score Query1.6、复合查询Boolean Query 2、搜索结果处理2.1、排序2.2、分页2.3、深度分页2.4、高亮 1、DSL Query…

优化选址问题 | 基于鹈鹕算法求解基站选址问题含Matlab源码

目录 问题代码问题 鹈鹕算法(Pelican Optimization Algorithm, POA)是一种相对较新的启发式优化算法,模拟了鹈鹕鸟觅食的行为。这种算法通常用于解决复杂的优化问题,如函数优化、路径规划、调度问题等。基站选址问题通常是一个复杂的优化问题,需要考虑覆盖范围、干扰、成…

java设计模式(2)---六大原则

设计模式之六大原则 这篇博客非常有意义&#xff0c;希望自己能够理解的基础上&#xff0c;在实际开发中融入这些思想&#xff0c;运用里面的精髓。 先列出六大原则&#xff1a;单一职责原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特原则、开闭原则。 一、单一职…

STM32 使用gcc编译介绍

文章目录 前言1. keil5下的默认编译工具链用的是哪个2. Arm编译工具链和GCC编译工具链有什么区别吗&#xff1f;3. Gcc交叉编译工具链的命名规范4. 怎么下载gcc-arm编译工具链参考资料 前言 我们在STM32上进行开发时&#xff0c;一般都是基于Keil5进行编译下载&#xff0c;Kei…

docker 数据卷 (二)

1&#xff0c;为什么使用数据卷 卷是在一个或多个容器内被选定的目录&#xff0c;为docker提供持久化数据或共享数据&#xff0c;是docker存储容器生成和使用的数据的首选机制。对卷的修改会直接生效&#xff0c;当提交或创建镜像时&#xff0c;卷不被包括在镜像中。 总结为两…

FileZilla 链接服务器提示 20 秒连接超时

FileZilla 有个默认设置是如果 20 秒没有数据的话会自动中断链接。 Command: Pass: **************** Error: Connection timed out after 20 seconds of inactivity Error: Could not connect to server修改配置 这个配置是可以修改的&#xff0c;修改的步骤为&#xff1a; …

PostgreSQL中控制文件的解析与恢复

最近遇到有人问起PG中控制文件的一些使用问题,总结了一下。 1、PG控制文件简介 1.1、存储的位置 它的路径位于: 相关信息,可以用命令pg_controldata得到: [10:41:27-postgres@centos2:/var/lib/pgsql/14/data/global]$ pg_controldata -D $PGDATA pg_control version …

【LabVIEW FPGA入门】FPGA寄存器(Register)

当您需要从多个时钟域或设计的不同部分访问数据&#xff0c;并且需要编写可重复使用的代码时&#xff0c;可使用寄存器项来存储数据。与 FIFO 相比&#xff0c;寄存器项消耗的 FPGA 逻辑资源更少&#xff0c;而且不消耗块存储器&#xff0c;而块存储器是最有限的 FPGA 资源类型…

java数据结构与算法基础-----字符串------正则表达式---持续补充中

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 目前校招的面试&#xff0c;经常会遇到各种各样的有关字符串处理的算法。掌…

综合知识篇20-基于中间件的开发新技术考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

基于python+vue电影院订票信息管理系统flask-django-php-nodejs

根据此问题&#xff0c;研发一套电影院订票信息管理系统&#xff0c;既能够大大提高信息的检索、变更与维护的工作效率&#xff0c;也能够方便信息系统的管理运用&#xff0c;从而减少信息管理成本&#xff0c;提高效率。 该电影院订票信息管理系统采用B/S架构、前后端分离以及…

家用路由器和企业路由器的区别?

一、家用路由器 家用路由器路由器交换机 它只有一个WAN口和一个LAN口&#xff0c;WAN口接公网一个地址&#xff0c;LAN口接你电脑一个IP地址&#xff0c;完全符合路由器的设计&#xff0c;而因为家里如果用了&#xff0c;说明要接多个电脑&#xff0c;那么如果还需要对每个接口…

MySQL 8.0-索引- 不可见索引(invisible indexes)

概述 MySQL 8.0引入了不可见索引(invisible index)&#xff0c;这个在实际工作用还是用的到的&#xff0c;我觉得可以了解下。 在介绍不可见索引之前&#xff0c;我先来看下invisible index是个什么或者定义。 我们依然使用拆开来看&#xff0c;然后再把拆出来的词放到MySQL…

LLM漫谈(五)| 从q star视角解密OpenAI 2027年实现AGI计划

最近&#xff0c;网上疯传OpenAI2027年关于AGI的计划。在本文&#xff0c;我们将针对部分细节以第一人称进行分享。​ 摘要&#xff1a;OpenAI于2022年8月开始训练一个125万亿参数的多模态模型。第一个阶段是Arrakis&#xff0c;也叫Q*&#xff0c;该模型于2023年12月完成训练&…

【小沐学Python】Python实现Web图表功能(Lux)

文章目录 1、简介2、安装3、测试3.1 入门示例3.2 入门示例2 结语 1、简介 https://github.com/lux-org/lux 用于智能可视化发现的 Python API Lux 是一个 Python 库&#xff0c;通过自动化可视化和数据分析过程来促进快速简便的数据探索。通过简单地在 Jupyter 笔记本中打印出…