Created
November 17, 2024 16:49
-
-
Save KBPsystem777/648b22fb428ac704034d5c9a9082fcf5 to your computer and use it in GitHub Desktop.
ManageLife's Marketplace V2 Smart Contract
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.17; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
import "@openzeppelin/contracts/security/Pausable.sol"; | |
import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; | |
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import "./ManageLife.sol"; | |
contract Marketplace is ReentrancyGuard, Pausable, Ownable { | |
uint256 public constant PERCENTS_DIVIDER = 10000; | |
uint256 public adminPercent = 200; // 2% | |
uint256 public adminPending; | |
ManageLife public mLife; | |
bool public allowTrading = false; | |
struct Offer { | |
uint256 tokenId; | |
address seller; | |
uint256 price; | |
address offeredTo; | |
} | |
struct Bid { | |
address bidder; | |
uint256 value; | |
address paymentToken; // Payment token address | |
} | |
mapping(uint256 => Offer) public offers; | |
mapping(uint256 => Bid) public bids; | |
mapping(address => bool) public supportedTokens; // Supported tokens mapping | |
event Offered(uint256 indexed tokenId, uint256 price, address indexed toAddress); | |
event BidEntered(uint256 indexed tokenId, uint256 value, address indexed fromAddress, address paymentToken); | |
event BidCancelled(uint256 indexed tokenId, uint256 value, address indexed bidder); | |
event Bought(uint256 indexed tokenId, uint256 value, address indexed fromAddress, address indexed toAddress, bool isInstant, address paymentToken); | |
event BidWithdrawn(uint256 indexed tokenId, uint256 value); | |
event Cancelled(uint256 indexed tokenId); | |
event TradingStatus(bool _isTradingAllowed); | |
event SupportedTokenUpdated(address token, bool status); | |
event Received(address, uint); | |
error InvalidPercent(uint256 _percent, uint256 minimumPercent); | |
error UnsupportedPaymentToken(address token); | |
constructor() {} | |
modifier isTradingAllowed() { | |
require(allowTrading, "Trading is disabled at this moment"); | |
_; | |
} | |
function pause() external whenNotPaused onlyOwner { | |
_pause(); | |
} | |
function unpause() external whenPaused onlyOwner { | |
_unpause(); | |
} | |
function setTrading(bool _isTradingAllowed) external onlyOwner { | |
allowTrading = _isTradingAllowed; | |
emit TradingStatus(_isTradingAllowed); | |
} | |
function setNftContract(address nftAddress) external onlyOwner { | |
require(nftAddress != address(0x0), "Zero address"); | |
mLife = ManageLife(nftAddress); | |
} | |
function setAdminPercent(uint256 _percent) external onlyOwner { | |
if (_percent < 500) { | |
revert InvalidPercent({_percent: _percent, minimumPercent: 500}); | |
} | |
adminPercent = _percent; | |
} | |
function withdraw() external onlyOwner nonReentrant { | |
uint256 amount = adminPending; | |
adminPending = 0; | |
_safeTransferETH(owner(), amount); | |
} | |
function updateSupportedToken(address token, bool status) external onlyOwner { | |
supportedTokens[token] = status; | |
emit SupportedTokenUpdated(token, status); | |
} | |
function offerForSale(uint256 tokenId, uint256 minSalePrice) external whenNotPaused isTradingAllowed { | |
require(msg.sender == mLife.ownerOf(tokenId), "You do not own this MLRE"); | |
offers[tokenId] = Offer(tokenId, msg.sender, minSalePrice, address(0x0)); | |
emit Offered(tokenId, minSalePrice, address(0x0)); | |
} | |
function offerForSaleToAddress( | |
uint256 tokenId, | |
uint256 minSalePrice, | |
address toAddress | |
) external whenNotPaused isTradingAllowed { | |
require(msg.sender == mLife.ownerOf(tokenId), "You do not own this MLRE"); | |
offers[tokenId] = Offer(tokenId, msg.sender, minSalePrice, toAddress); | |
emit Offered(tokenId, minSalePrice, toAddress); | |
} | |
function buy(uint256 tokenId, address paymentToken) external payable whenNotPaused isTradingAllowed { | |
Offer memory offer = offers[tokenId]; | |
require(offer.offeredTo == address(0x0) || offer.offeredTo == msg.sender, "This offer is not for you"); | |
uint256 amount = offer.price; | |
require(amount > 0, "Invalid offer price"); | |
if (paymentToken == address(0)) { | |
require(msg.value == amount, "Incorrect ETH amount"); | |
} else { | |
require(supportedTokens[paymentToken], "Unsupported payment token"); | |
IERC20(paymentToken).transferFrom(msg.sender, address(this), amount); | |
} | |
address seller = offer.seller; | |
require(seller != msg.sender, "Seller == msg.sender"); | |
offers[tokenId] = Offer(tokenId, msg.sender, 0, address(0x0)); | |
mLife.transferFrom(seller, msg.sender, tokenId); | |
uint256 commission = (amount * adminPercent) / PERCENTS_DIVIDER; | |
adminPending += commission; | |
if (paymentToken == address(0)) { | |
_safeTransferETH(seller, amount - commission); | |
} else { | |
IERC20(paymentToken).transfer(seller, amount - commission); | |
} | |
emit Bought(tokenId, amount, seller, msg.sender, true, paymentToken); | |
} | |
receive() external payable { | |
emit Received(msg.sender, msg.value); | |
} | |
function _safeTransferETH(address to, uint256 value) internal { | |
(bool success, ) = to.call{value: value}(""); | |
require(success, "Transfer failed"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Summary
The updated marketplace is no longer just an ETH-based platform. By integrating token payments, we've created a more versatile and inclusive ecosystem. These enhancements ensure the platform remains competitive, attracts a broader audience, and strengthens the MLIFE token's role as a key asset in the ecosystem.