如何为 NFT 市场编写智能合约
介绍
本技术指南将为您提供使用 Solidity 和 Openzeppelin 构建完整 NFT 市场生态系统的全面指南。
我们的市场包含原生代币、可自定义版税的 NFT 创建以及安全的交易机制。
技术堆栈
- 坚固性^0.8.27
- OpenZeppelin 合约
- 安全帽开发环境
- TypeScript
- Ethers.js
合同结构
该项目由三个主要合同组成:
- 平台代币(NYWToken.sol)
- NFT合约(NYWNFT.sol)
- 市场合同(NYWMarketplace.sol)
1. 平台代币实现(NYWToken.sol)
我们的市场的基础始于实施平台的原生代币。
此 NYWToken 合约是一个简单的 ERC20 代币实现。
它继承自 OpenZeppelin ERC20 合约,并初始化代币供应量为 10 亿。
主要特点:
- 代币供应量:10亿枚
- 代币标准:符合 ERC20 标准
- 小数:18 位小数,最大可除性
- 初始分配:所有代币分配给合约部署者
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract NYWToken is ERC20 {
uint256 initialSupply = 10 ** 9;
constructor() ERC20("NYWToken", "NYW") {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}
2. NFT合约实现
NYWNFT 合约负责创建和销毁 NYW NFT 代币,以及管理其使用费。
该合约继承自 OpenZeppelin ERC721 合约,后者提供了创建和管理 NFT 所需的功能。
主要功能:
createNYW()
:创建具有可定制版税的新 NFTburnNYW()
:将 NFT 从流通中移除getCreator()
:更新元数据 URIgetRoyalty()
:退货版税配置
以下是NYWNFT合约的详细实现:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract NYWNFT is ERC721URIStorage, Ownable {
uint256 private _tokenId;
mapping(uint256 => address) public creators;
mapping(uint256 => uint256) public royalties;
event NYWTokenCreated(
address indexed creator,
uint256 tokenId,
uint256 royalty,
string tokenURI
);
event NYWTokenBurned(address indexed burner, uint256 tokenId);
constructor() ERC721("NYW NFT", "NYW") Ownable(msg.sender) {}
function createNYW(
string memory tokenURI,
uint256 royalty
) external returns (uint256) {
require(
royalty >= 0 && royalty <= 30,
"Royalty must be between 0 and 30"
);
_tokenId += 1;
creators[_tokenId] = msg.sender;
royalties[_tokenId] = royalty;
_safeMint(msg.sender, _tokenId);
_setTokenURI(_tokenId, tokenURI);
_setApprovalForAll(msg.sender, address(this), true);
emit NYWTokenCreated(msg.sender, _tokenId, royalty, tokenURI);
return _tokenId;
}
function burnNYW(uint256 tokenId) external {
require(
msg.sender == ownerOf(tokenId),
"Only the owner can burn the token"
);
_burn(tokenId);
delete creators[tokenId];
delete royalties[tokenId];
emit NYWTokenBurned(msg.sender, tokenId);
}
function getCreator(uint256 tokenId) external view returns (address) {
return creators[tokenId];
}
function getRoyalty(uint256 tokenId) external view returns (uint256) {
return royalties[tokenId];
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
3. 市场合同实施(NYWMarketplace.sol)
NYWMarketplace 合约负责管理 NFT 的上架、下架、购买以及资金提取:
主要功能:
listNFT(uint256 tokenId_, uint256 price_)
: 将新的 NFT 上架到市场进行销售delistNFT(uint256 tokenId_)
:从市场中移除 NFTbuyNFT(uint256 tokenId_)
:从市场购买 NFTwithdraw()
:从市场提取资金
function listNFT(uint256 tokenId_, uint256 price_) external {
// Check if the NFT is already listed
require(!isExisting[tokenId_], "NFT is already listed");
// Check if the NFT is owned by the caller
require(
nftContract.ownerOf(tokenId_) == msg.sender,
"You are not the owner of the NFT"
);
//Define new NFTMarketItem
NFTMarketItem memory newNFTMarketItem = NFTMarketItem(
tokenId_,
price_,
nywContract.getRoyalty(tokenId_),
payable(msg.sender),
nywContract.getCreator(tokenId_),
true
);
isExisting[tokenId_] = true;
listedNFTs.push(newNFTMarketItem);
tokenIdToNFTMarketItemId[tokenId_] = totalListedNFTs;
totalListedNFTs++;
emit NYWNFTListed(
tokenId_,
price_,
nywContract.getRoyalty(tokenId_),
nywContract.getCreator(tokenId_),
msg.sender
);
}
function delistNFT(uint256 tokenId_) external {
require(isExisting[tokenId_], "NFT is not listed");
uint256 nftMarketItemId = tokenIdToNFTMarketItemId[tokenId_];
require(
listedNFTs[nftMarketItemId].seller == msg.sender,
"Only the seller can delist the NFT"
);
deleteNFTfromArray(tokenId_);
emit NYWNFTDelisted(tokenId_);
}
function deleteNFTfromArray(uint256 tokenId_) public {
uint256 nftMarketItemId = tokenIdToNFTMarketItemId[tokenId_];
uint256 lastIndex = listedNFTs.length - 1;
listedNFTs[nftMarketItemId] = listedNFTs[lastIndex];
tokenIdToNFTMarketItemId[
listedNFTs[lastIndex].tokenId
] = nftMarketItemId;
listedNFTs.pop();
totalListedNFTs--;
delete tokenIdToNFTMarketItemId[tokenId_];
isExisting[tokenId_] = false;
}
function buyNFT(uint256 tokenId_) public payable {
require(isExisting[tokenId_], "NFT is not listed");
uint256 _nftMarketItemId = tokenIdToNFTMarketItemId[tokenId_];
NFTMarketItem memory _nftMarketItem = listedNFTs[_nftMarketItemId];
require(!_nftMarketItem.isSold, "NFT is already sold");
require(msg.value == _nftMarketItem.price, "Incorrect payment amount");
// Calculate royalty amount
uint256 _royaltyAmount = (_nftMarketItem.price *
_nftMarketItem.royalty) / deno;
// Calculate platform fee
uint256 _platformFeeAmount = (_nftMarketItem.price * platformFee) /
deno;
// Calculate seller amount
uint256 _sellerAmount = _nftMarketItem.price -
_royaltyAmount -
_platformFeeAmount;
// Transfer funds to the seller
payable(_nftMarketItem.seller).transfer(_sellerAmount);
// Transfer royalty amount to the creator
payable(_nftMarketItem.creator).transfer(_royaltyAmount);
// Transfer platform fee amount to the platform
payable(owner()).transfer(_platformFeeAmount);
//Transfer NFT to the buyer
nftContract.safeTransferFrom(
_nftMarketItem.seller,
msg.sender,
_nftMarketItem.tokenId
);
_nftMarketItem.isSold = true;
deleteNFTfromArray(tokenId_);
emit NYWNFTBought(
_nftMarketItem.tokenId,
msg.sender,
_nftMarketItem.seller,
_nftMarketItem.price
);
}
function withdraw() external onlyOwner {
uint256 balance = address(this).balance;
require(balance > 0, "No funds to withdraw");
payable(owner()).transfer(balance);
emit NYWNFTWithdrawn(balance);
}
结论
构建一个安全高效的 NFT 市场需要精心设计多个智能合约的协同工作。本指南涵盖了以下几个基本组件:平台代币、NFT 合约和市场功能。
鏂囩珷鏉ユ簮锛�https://dev.to/marksantiago02/how-to-write-smart-contract-for-nft-marketplace-5mg