Skip to content

Commit

Permalink
Merge pull request #564 from Georgiafab/georgia
Browse files Browse the repository at this point in the history
task3: Georgiafab
  • Loading branch information
linghuccc authored Jul 4, 2024
2 parents e12e5a3 + b32c01f commit 7084cd6
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 0 deletions.
9 changes: 9 additions & 0 deletions members/Georgiafab/task3/ERC20Token.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MTK is ERC20 {
constructor(address owner) ERC20("MILKToken", "MTK") {
_mint(owner, 21000000 * 10 ** 18);
}
}
15 changes: 15 additions & 0 deletions members/Georgiafab/task3/ERC721Token.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract MILKNT is ERC721 {
uint256 private _nextId;

constructor() ERC721("MILKNFT", "MILKNT") {}

function saftMint(address to) public {
uint256 tokenId = _nextId++;
_safeMint(to, tokenId);
}
}
167 changes: 167 additions & 0 deletions members/Georgiafab/task3/NFTMarket.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.2 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

contract NFTMarket is ReentrancyGuard {
IERC20 public tokenContract;
using Math for uint256;

struct Listing {
uint256 tokenId; // NFT的Token ID
address seller; // 上架者地址
address nftContract; // NFT 合约地址
uint256 price; // 上架价格(使用ERC20代币)
bool active; // 上架状态
}

// 存储所有上架的NFT信息
mapping(address => mapping(uint256 => Listing)) public listings;

// 记录所有有上架NFT的合约地址
address[] private nftContracts;
// 记录每个合约地址对应的tokenId数组
mapping(address => uint256[]) private nftTokenIds;

// 上架NFT事件
event NFTListed(
uint256 indexed tokenId,
address indexed seller,
address indexed nftContract,
uint256 price
);

// 下架NFT事件
event NFTUnListed(uint256 indexed tokenId, address indexed seller);

// 购买NFT事件
event NFTSold(
uint256 tokenId,
address indexed buyer,
address indexed seller,
address nftContract,
uint256 price
);

// 合约构造函数,初始化ERC20代币合约地址
constructor(address _tokenContractAddress) {
tokenContract = IERC20(_tokenContractAddress);
}

function getTokenContract() external view returns (IERC20) {
return tokenContract;
}

// 上架NFT
function listNFT(
address _nftContract,
uint256 _tokenId,
uint256 _price
) external {
// 确保上架者是NFT的所有者
IERC721 nftContract = IERC721(_nftContract);
require(nftContract.ownerOf(_tokenId) == msg.sender, "Not token owner");
// 确保上架价格大于零
require(_price > 0, "Price must be greater than zero");

// 将NFT信息添加到上架列表中
listings[_nftContract][_tokenId] = Listing(
_tokenId,
msg.sender,
_nftContract,
_price,
true
);

// 如果该合约地址第一次上架NFT,则添加到nftContracts数组中
if (nftTokenIds[_nftContract].length == 0) {
nftContracts.push(_nftContract);
}

// 将tokenId添加到该合约地址对应的tokenId数组中
nftTokenIds[_nftContract].push(_tokenId);

// 触发上架NFT事件
emit NFTListed(_tokenId, msg.sender, _nftContract, _price);
}

// 下架NFT
function unListNFT(address _nftContract, uint256 _tokenId) external {
// 获取上架信息
Listing storage listing = listings[_nftContract][_tokenId];
// 确保上架状态为激活
require(listing.active, "Listing not active");
// 确保下架人是拥有者
require(listing.seller == msg.sender, "Not token owner");

// 修改上架状态为非激活
listing.active = false;

emit NFTUnListed(_tokenId, msg.sender);
}

// 购买NFT
function buyNFT(
address _nftContract,
uint256 _tokenId
) external nonReentrant {
Listing storage listing = listings[_nftContract][_tokenId];
require(listing.active, "Listing not active");

IERC721 nft = IERC721(_nftContract);
// 确保买家拥有足够的ERC20代币用于购买
require(
tokenContract.balanceOf(msg.sender) >= listing.price,
"Insufficient balance"
);
// 从买家转移ERC20代币给卖家
tokenContract.transferFrom(msg.sender, listing.seller, listing.price);
// 从卖家转移NFT给买家
nft.transferFrom(listing.seller, msg.sender, _tokenId);

// 修改上架状态为非激活
listing.active = false;

emit NFTSold(
_tokenId,
msg.sender,
listing.seller,
_nftContract,
listing.price
);
}

// 获取所有上架的NFT信息
function getAllListings() external view returns (Listing[] memory) {
uint256 totalListings = 0;

// 计算所有上架的NFT总数
for (uint i = 0; i < nftContracts.length; i++) {
address nftContract = nftContracts[i];
totalListings += nftTokenIds[nftContract].length;
}

// 创建一个数组来存储所有的上架信息
Listing[] memory allListings = new Listing[](totalListings);
uint256 currentIndex = 0;

// 填充数组
for (uint i = 0; i < nftContracts.length; i++) {
address nftContract = nftContracts[i];
uint256[] storage tokenIds = nftTokenIds[nftContract];
for (uint j = 0; j < tokenIds.length; j++) {
uint256 tokenId = tokenIds[j];
Listing storage listing = listings[nftContract][tokenId];
if (listing.active) {
allListings[currentIndex] = listing;
currentIndex++;
}
}
}

return allListings;
}
}
8 changes: 8 additions & 0 deletions members/Georgiafab/task3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## task3 介绍

1. 部署在 Sepolia 测试网上
![bind-wallet](./readme/deploy.png "deploy")
2. 提交全部合约文件(ERC20、ERC721、NFTMarket)
3. 提交上架 NFT、购买 NFT 的交易哈希
提交上架 NFT: 0xc940613d9297bcef090bb2252ef9e734dffb769d570b1eafc55931ca46d7f7cd
购买 NFT: 0xf937159ae007f8de3cd163752d66b33a8ad8897926f8e619c9b436c689d864e0
Binary file added members/Georgiafab/task3/readme/deploy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7084cd6

Please sign in to comment.