• 全国 [切换]
  • 二维码
    展会联盟

    手机WAP版

    手机也能谈生意,信息同步6大终端平台!
    当前位置: 首页 » 行业新闻 » 热点新闻 » 正文

    实现一个简洁的NFT交易所

    放大字体  缩小字体 发布日期:2025-01-02 05:36:04   浏览次数:9  发布人:7163****  IP:124.223.189***  评论:0
    导读

    前言本文实现一个简单版的NFT交易所,主要包含上架、下架、更新价格、购买NFT等相关功能NFT合约说明 关于NFT合约的开发、测试、部署具体实现,可以查看另一篇:快速实现一个标准的NFT合约(实操篇) NFT交易所合约 合约说明具备上架、下架、更新价格、购买NFT // SPDX-License-Identifier: MIT // Compatible with OpenZeppelin Con

    前言

    本文实现一个简单版的NFT交易所,主要包含上架、下架、更新价格、购买NFT等相关功能

    NFT合约说明

    关于NFT合约的开发、测试、部署具体实现,可以查看另一篇:快速实现一个标准的NFT合约(实操篇)

    NFT交易所合约

    合约说明具备上架、下架、更新价格、购买NFT

    // SPDX-License-Identifier: MIT // Compatible with OpenZeppelin Contracts ^5.0.0 pragma solidity ^0.8.22; import "hardhat/console.sol"; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import "./NFT.sol";//实现的nft的合约 contract NFTSwap is IERC721Receiver { event List( address indexed seller, address indexed nftAddr, uint256 indexed tokenId, uint256 price ); event Purchase( address indexed buyer, address indexed nftAddr, uint256 indexed tokenId, uint256 price ); event Revoke( address indexed seller, address indexed nftAddr, uint256 indexed tokenId ); event Update( address indexed seller, address indexed nftAddr, uint256 indexed tokenId, uint256 newPrice ); receive() external payable {}//解决没有接受函数的问题 // 定义order结构体 struct Order { address owner; uint256 price; } // NFT Order映射 mapping(address => mapping(uint256 => Order)) public nftList; fallback() external payable {} // 挂单: 卖家上架NFT,合约地址为_nftAddr,tokenId为_tokenId,价格_price为以太坊(单位是wei) function list(address _nftAddr, uint256 _tokenId, uint256 _price) public { IERC721 _nft = IERC721(_nftAddr); // 声明IERC721接口合约变量 require(_nft.getApproved(_tokenId) == address(this), "Need Approval"); // 合约得到授权 require(_price > 0); // 价格大于0 Order storage _order = nftList[_nftAddr][_tokenId]; //设置NFT持有人和价格 _order.owner = msg.sender; _order.price = _price; // 将NFT转账到合约 _nft.safeTransferFrom(msg.sender, address(this), _tokenId); // 释放List事件 emit List(msg.sender, _nftAddr, _tokenId, _price); } // 购买: 买家购买NFT,合约为_nftAddr,tokenId为_tokenId,调用函数时要附带ETH function purchase(address _nftAddr, uint256 _tokenId) public payable { Order storage _order = nftList[_nftAddr][_tokenId]; // 取得Order require(_order.price > 0, "Invalid Price"); // NFT价格大于0 require(msg.value >= _order.price, "Increase price"); // 购买价格大于标价 // 声明IERC721接口合约变量 IERC721 _nft = IERC721(_nftAddr); require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中 // 将NFT转给买家 _nft.safeTransferFrom(address(this), msg.sender, _tokenId); // 将ETH转给卖家 payable(_order.owner).transfer(_order.price); // 多余ETH给买家退款 if (msg.value > _order.price) { payable(msg.sender).transfer(msg.value - _order.price); } // 释放Purchase事件 emit Purchase(msg.sender, _nftAddr, _tokenId, _order.price); delete nftList[_nftAddr][_tokenId]; // 删除order } // 撤单: 卖家取消挂单 function revoke(address _nftAddr, uint256 _tokenId) public { Order storage _order = nftList[_nftAddr][_tokenId]; // 取得Order require(_order.owner == msg.sender, "Not Owner"); // 必须由持有人发起 // 声明IERC721接口合约变量 IERC721 _nft = IERC721(_nftAddr); require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中 // 将NFT转给卖家 _nft.safeTransferFrom(address(this), msg.sender, _tokenId); delete nftList[_nftAddr][_tokenId]; // 删除order // 释放Revoke事件 emit Revoke(msg.sender, _nftAddr, _tokenId); } // 调整价格: 卖家调整挂单价格 function update( address _nftAddr, uint256 _tokenId, uint256 _newPrice ) public { require(_newPrice > 0, "Invalid Price"); // NFT价格大于0 Order storage _order = nftList[_nftAddr][_tokenId]; // 取得Order require(_order.owner == msg.sender, "Not Owner"); // 必须由持有人发起 // 声明IERC721接口合约变量 IERC721 _nft = IERC721(_nftAddr); require(_nft.ownerOf(_tokenId) == address(this), "Invalid Order"); // NFT在合约中 // 调整NFT价格 _order.price = _newPrice; // 释放Update事件 emit Update(msg.sender, _nftAddr, _tokenId, _newPrice); } // 实现{IERC721Receiver}的onERC721Received,能够接收ERC721代币 function onERC721Received( address operator, address from, uint tokenId, bytes calldata data ) external override returns (bytes4) { return IERC721Receiver.onERC721Received.selector; } }

    NFT交易所测试

    const {ethers,getNamedAccounts,deployments} = require("hardhat"); const { assert,expect } = require("chai"); describe("NFTSwap",function(){ let nft;//合约 let nftswap;//合约 let addr1; let addr2; let firstAccount//第一个账户 let secondAccount//第二个账户 let mekadata='ipfs://QmQT8VpmWQVhUhoDCEK1mdHXaFaJ3KawkRxHm96GUhrXLB';//mekadata关于说明nft相关描述,属性的json文件 let mekadata1="ipfs://QmXzbsbjpWpbSGJkgGzmk6r6HLz1nvjpEtjFR6bVhMh3U9";//同上 beforeEach(async function(){ await deployments.fixture(["nft","nftswap"]);//部署nft和nft交易所 [addr1,addr2]=await ethers.getSigners();//获取账号(说明:这样获取的账号支持签名操作,例如:如果使用secondAccount就会报错VoidSigner cannot sign transactions) firstAccount=(await getNamedAccounts()).firstAccount; secondAccount=(await getNamedAccounts()).secondAccount; const nftDeployment = await deployments.get("BoykaNFT"); nft = await ethers.getContractAt("BoykaNFT",nftDeployment.address);//已经部署的合约交互 const nftswapDeployment = await deployments.get("NFTSwap"); nftswap = await ethers.getContractAt("NFTSwap",nftswapDeployment.address);//已经部署的合约交互 }) describe("nftswap",function(){ it("把nft授权给交易所swap",async ()=>{ //铸造两个nft await nft.safeMint(firstAccount,mekadata); console.log(await nft.ownerOf(0))//查看持有者 await nft.safeMint(firstAccount,mekadata1); console.log(await nft.ownerOf(1))//同上 //把铸造的nft授权给nft交易所 await nft.approve(nftswap.address,0); await nft.approve(nftswap.address,1); //上架nft //把nft放到交易所 参数说明:nft的合约地址 ,nftid,nft的价格 await nftswap.list(nft.address,0,ethers.utils.parseEther("1")); await nftswap.list(nft.address,1,ethers.utils.parseEther("1")); //查看是否上架成功 console.log('上架成功',await nftswap.nftList(nft.address,0)) //如果不存在的nft会返回owner: '0x0000000000000000000000000000000000000000', console.log("查看不存在的nft",await nftswap.nftList(nft.address,3))//不存在的nft //更新nft的价格 await nftswap.update(nft.address,0,ethers.utils.parseEther("2"));//把nft的价格改成2eth console.log("查看更新的价格",await nftswap.nftList(nft.address,0)) await nftswap.update(nft.address,1,ethers.utils.parseEther("23"));//同上 console.log("查看更新的价格",await nftswap.nftList(nft.address,1)) //下架 //把nftid为1的nft下架 await nftswap.revoke(nft.address,1); //返回owner为0x0000000000000000000000000000000000000000说明下架成功 console.log('下架成功',await nftswap.nftList(nft.address,1)) //购买nft console.log(secondAccount) //切换账号到addr2使用await ethers.getSigners() 添加ether足够的值 //说明参数:1.nft合约地址2.nft的id3.addr2的msg.value的eth,要大于nft的价格当前addr2的值为3 await nftswap.connect(addr2).purchase(nft.address,0,{value:ethers.utils.parseEther("3")}); console.log('所有权时addr2',await nft.ownerOf(0));//返回的账号地址时addr2说明addr2购买成功了 }) }) }) # 测试指令 # npx hardhat test ./test/xxx.js

    NFT交易所部署

    module.exports = async function ({getNamedAccounts,deployments}) { const firstAccount= (await getNamedAccounts()).firstAccount; const {deploy,log} = deployments; const NftSwap=await deploy("NFTSwap",{ from:firstAccount, args: [],//参数 log: true, }) console.log("nftswap合约",NftSwap.address) } module.exports.tags = ["all","nftswap"]; # 部署指令 # npx hardhat deploy

    总结

    以上就是简洁版NFT交易所的整个实现过程,此交易所具备上架、下架、改价、购买的功能和一些验证的方法。

     
    (文/匿名(若涉版权问题请联系我们核实发布者) / 非法信息举报 / 删稿)
    打赏
    免责声明
    • 
    本文为昵称为 7163**** 发布的作品,本文仅代表发布者个人观点,本站未对其内容进行核实,请读者仅做参考,如若文中涉及有违公德、触犯法律的内容,一经发现,立即删除,发布者需自行承担相应责任。涉及到版权或其他问题,请及时联系我们154208694@qq.com删除,我们积极做(权利人与发布者之间的调停者)中立处理。郑重说明:不 违规举报 视为放弃权利,本站不承担任何责任!
    有个别老鼠屎以营利为目的遇到侵权情况但不联系本站或自己发布违规信息然后直接向本站索取高额赔偿等情况,本站一概以诈骗报警处理,曾经有1例诈骗分子已经绳之以法,本站本着公平公正的原则,若遇 违规举报 我们100%在3个工作日内处理!
    0相关评论
     

    (c)2008-现在 nm0.com All Rights Reserved.