You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
4.4 KiB

// SPDX-License-Identifier: MIT OR Apache-2.0
//mostly done
pragma solidity ^0.8.14;
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./interfaces/ITreasury.sol";
contract Marketplace is Initializable {
//variables
uint256 currentSaleId;
uint256 fee;
ITreasury treasury;
IERC721Upgradeable nft;
IERC20Upgradeable BoM;
struct Sale {
address payable seller;
uint256 tokenId;
uint256 price;
bool bought;
bool cancelled;
}
mapping(uint256 => Sale) saleIdToSale;
//events
event SaleCreated(
uint256 indexed saleId,
address indexed seller,
uint256 price,
uint256 indexed tokenId
);
event SaleCancelled(uint256 indexed saleId);
event SaleUpdated(
uint256 indexed saleId,
uint256 oldPrice,
uint256 newPrice
);
event TokenBought(
uint256 indexed saleId,
address indexed buyer,
uint256 indexed tokenId,
uint256 price
);
event FeesChanged(address indexed admin, uint256 oldFee, uint256 newFee);
//modifiers
modifier isExistingSale(uint256 saleId) {
require(saleIdToSale[saleId].price != 0, "!exists");
_;
}
modifier onlySaleOwner(uint256 saleId) {
require(saleIdToSale[saleId].seller == msg.sender, "!seller");
_;
}
modifier onlyValidPrice(uint256 price) {
require(price > 0, "!price");
_;
}
modifier onlyAdmin() {
require(treasury.isAdmin(msg.sender), "!admin");
_;
}
// constructor(
// uint256 _fee,
// ITreasury _treasury,
// IERC721Upgradeable _nft,
// IERC20Upgradeable token
// ) {
// fee = _fee;
// treasury = _treasury;
// nft = _nft;
// BoM = token;
// }
function initialize(
uint256 _fee,
ITreasury _treasury,
IERC721Upgradeable _nft,
IERC20Upgradeable token
) public initializer {
fee = _fee;
treasury = _treasury;
nft = _nft;
BoM = token;
}
//internal functions
function _distributeFunds(uint256 amount, address seller) internal {
uint256 _fee = (amount * fee) / 10000;
uint256 goesToSeller = amount - _fee;
BoM.transferFrom(msg.sender, address(this), _fee);
BoM.transferFrom(msg.sender, seller, goesToSeller);
}
//external functions
function createSale(uint256 tokenId, uint256 price)
public
onlyValidPrice(price)
{
currentSaleId++;
Sale storage sale = saleIdToSale[currentSaleId];
sale.seller = payable(msg.sender);
sale.price = price;
sale.tokenId = tokenId;
nft.transferFrom(msg.sender, address(this), tokenId);
emit SaleCreated(currentSaleId, msg.sender, price, tokenId);
}
function cancelSale(uint256 saleId) public onlySaleOwner(saleId) {
Sale storage sale = saleIdToSale[saleId];
require(!sale.bought, "bought");
require(!sale.cancelled, "cancelled");
nft.transferFrom(address(this), msg.sender, sale.tokenId);
sale.cancelled = true;
emit SaleCancelled(saleId);
}
function updateSale(uint256 saleId, uint256 price)
public
onlySaleOwner(saleId)
onlyValidPrice(price)
isExistingSale(saleId)
{
Sale storage sale = saleIdToSale[saleId];
require(!sale.bought, "bought");
require(!sale.cancelled, "cancelled");
uint256 oldPrice = sale.price;
sale.price = price;
emit SaleUpdated(saleId, oldPrice, price);
}
function buyToken(uint256 saleId) public isExistingSale(saleId) {
Sale storage sale = saleIdToSale[saleId];
require(!sale.bought, "bought");
require(!sale.cancelled, "cancelled");
nft.transferFrom(address(this), msg.sender, sale.tokenId);
_distributeFunds(sale.price, sale.seller);
sale.bought = true;
emit TokenBought(saleId, msg.sender, sale.tokenId, sale.price);
}
//admin functions
function changeFees(uint256 _fee) public onlyAdmin {
require(_fee > 0 && _fee < 2000, "wrong arg");
emit FeesChanged(msg.sender, fee, _fee);
fee = _fee;
}
}