设计逻辑实现一个简易版的NFT721代币,这个代币可以在opensea查看到,通过这个代币来实现一个交易NFT的合约。卖家:出售NFT的一方,可以挂单list、撤单revoke、修改价格update。买家:购买NFT的一方,可以购买purchase。订单:卖家发布的NFT链
<!--StartFragment-->
实现一个简易版的NFT721代币,这个代币可以在opensea查看到,通过这个代币来实现一个交易NFT的合约。
卖家:出售NFT
的一方,可以挂单list
、撤单revoke
、修改价格update
。
买家:购买NFT
的一方,可以购买purchase
。
订单:卖家发布的NFT
链上订单,一个系列的同一tokenId
最多存在一个订单,其中包含挂单价格price
和持有人owner
信息。当一个订单交易完成或被撤单后,其中信息清零。
<!--EndFragment-->
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract WQQNFT is ERC721URIStorage {
using Counters for Counters.Counter ;
Counters.Counter private counter;
// 构造函数
constructor ()ERC721("wuqingqing","wuqingqing"){
}
// 可以是批量的操作元数据"ipfs://QmQkm9LsS*******BbA4E4kLrY8EGMKQTaBK/"为元数据的CID值
function _baseURI() internal pure override returns (string memory) {
return "ipfs://QmQkm9LsS*******BbA4E4kLrY8EGMKQTaBK/";
}
// 铸造函数
function mint(address to, string memory tokenURI)external {
uint tokenId = counter.current();
_setTokenURI(tokenId, tokenURI);
_mint(to, tokenId);
counter.increment();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
contract NFTSwap{
// 挂单
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 Update(
address indexed seller,
address indexed nftAddr,
uint256 indexed tokenId,
uint256 price
);
// 撤单
event Revoke(
address indexed seller,
address indexed nftAddr,
uint256 indexed tokenId
);
struct Order{
// 持有人信息
address owner;
// 挂单价格
uint256 price;
}
// nft order映射
mapping (address=>mapping (uint256=>Order)) public nftList;
receive() external payable { }
fallback() external payable { }
// 卖家上架nft 合约地址为_nftAddr,tokenId为_tokenId,价格_price为以太坊(单位是wei)
function list(address _nftAddress, uint256 _tokenId, uint256 _price)public {
IERC721 _nft = IERC721(_nftAddress);
require(_nft.getApproved(_tokenId)==address(this), "Need Approved");// 合约得到授权
require(_price>0);// 价格大于0
Order storage _order =nftList[_nftAddress][_tokenId]; // 设置NFT持有人和价格
_order.owner = msg.sender;
_order.price = _price;
// 将NFT转账到合约
_nft.safeTransferFrom(msg.sender, address(this), _tokenId);
emit List(msg.sender, _nftAddress, _tokenId, _price);
}
// 买家购买NFT,合约为_nftAddress,tokenId为_tokenId,调用函数时要附带ETH
function purchase(address _nftAddress, uint256 _tokenId) public payable {
Order storage _order =nftList[_nftAddress][_tokenId]; // 取得Order
require(_order.price>0 ,"Invaild price");// 价格必须大于0
require(msg.value>=_order.price,"Invaild price"); // 购买价格大于上架价格
// 声明IERC721接口合约
IERC721 _nft = IERC721(_nftAddress);
require(_nft.ownerOf(_tokenId)==address(this), "Invalid Order"); // tokenId的主人是当前合约
// 将合约拥有的NFT转给买家
_nft.safeTransferFrom(address(this), msg.sender, _tokenId);
// 将EHT转给Order.owner
payable (_order.owner).transfer(_order.price);
//多余的ETH退回给买家
if (msg.value>_order.price){
payable (msg.sender).transfer(msg.value-_order.price);
}
emit Purchase(msg.sender, _nftAddress, _tokenId, _order.price);
delete nftList[_nftAddress][_tokenId]; // 删除上架的order
}
// 撤单卖家取消订单
function revoke(address _nftAddress, uint256 _tokenId)public {
Order storage _order =nftList[_nftAddress][_tokenId]; // 取得Order
require(_order.owner==msg.sender, "Not Owner");// 必须是持有人发起
// 声明IERC721接口合约
IERC721 _nft = IERC721(_nftAddress);
require(_nft.ownerOf(_tokenId)==address(this), "Invalid Order"); // tokenId的主人是当前合约
// 将NFT 转移给卖家
_nft.safeTransferFrom(address(this), msg.sender, _tokenId);
delete nftList[_nftAddress][_tokenId];
emit Revoke(msg.sender, _nftAddress, _tokenId);
}
// 调整价格卖家调整挂单价格
function update(
address _nftAddress,
uint256 _tokenId,
uint256 _newPrice
)public {
require(_newPrice>0, "Invaild Price");
Order storage _order =nftList[_nftAddress][_tokenId]; // 取得Order
require(_order.owner==msg.sender, "Not Owner");// 必须是持有人发起
// 声明IERC721接口合约
IERC721 _nft = IERC721(_nftAddress);
require(_nft.ownerOf(_tokenId)==address(this), "Invalid Order"); // tokenId的主人是当前合约
_order.price = _newPrice;
emit Update(msg.sender, _nftAddress, _tokenId, _newPrice);
}
// 实现{IERC721Receiver}的onERC721Received,能够接收ERC721代币
function onERC721Received(
address operator,
address from,
uint tokenId,
bytes calldata data
) external returns (bytes4){
return IERC721Receiver.onERC721Received.selector;
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!