// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../DamnValuableNFT.sol"; /** * @title FreeRiderNFTMarketplace * @author Damn Vulnerable DeFi (https://damnvulnerabledefi.xyz) */ contract FreeRiderNFTMarketplace is ReentrancyGuard { using Address for address payable; DamnValuableNFT public token; uint256 public amountOfOffers; // tokenId -> price mapping(uint256 => uint256) private offers; event NFTOffered(address indexed offerer, uint256 tokenId, uint256 price); event NFTBought(address indexed buyer, uint256 tokenId, uint256 price); constructor(uint8 amountToMint) payable { require(amountToMint < 256, "Cannot mint that many tokens"); token = new DamnValuableNFT(); for(uint8 i = 0; i < amountToMint; i++) { token.safeMint(msg.sender); } } function offerMany(uint256[] calldata tokenIds, uint256[] calldata prices) external nonReentrant { require(tokenIds.length > 0 && tokenIds.length == prices.length); for (uint256 i = 0; i < tokenIds.length; i++) { _offerOne(tokenIds[i], prices[i]); } } function _offerOne(uint256 tokenId, uint256 price) private { require(price > 0, "Price must be greater than zero"); require( msg.sender == token.ownerOf(tokenId), "Account offering must be the owner" ); require( token.getApproved(tokenId) == address(this) || token.isApprovedForAll(msg.sender, address(this)), "Account offering must have approved transfer" ); offers[tokenId] = price; amountOfOffers++; emit NFTOffered(msg.sender, tokenId, price); } function buyMany(uint256[] calldata tokenIds) external payable nonReentrant { for (uint256 i = 0; i < tokenIds.length; i++) { _buyOne(tokenIds[i]); } } function _buyOne(uint256 tokenId) private { uint256 priceToPay = offers[tokenId]; require(priceToPay > 0, "Token is not being offered"); require(msg.value >= priceToPay, "Amount paid is not enough"); amountOfOffers--; // transfer from seller to buyer token.safeTransferFrom(token.ownerOf(tokenId), msg.sender, tokenId); // pay seller payable(token.ownerOf(tokenId)).sendValue(priceToPay); emit NFTBought(msg.sender, tokenId, priceToPay); } receive() external payable {} }