Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
[
]
Welcome to the future of digital asset trading! Today, we are diving into the intricacies of a decentralized NFT marketplace built on the BitTorrent Chain (BTTC). This marketplace is designed to facilitate the trading of Non-Fungible Tokens (NFTs), integrating auction mechanisms, transaction fees, and robust security features. Whether you’re a creator, collector, or trader, this contract provides a secure and transparent environment for all your NFT transactions.
The MarketPlace contract is a comprehensive solution for managing NFT transactions. It supports the creation and management of sell orders, bidding on NFTs, and the execution of trades. Let’s break down the key components and functionalities of this contract.
The contract defines several state variables and data structures to manage orders, bids, and administrative settings:
using SafeERC20 for IERC20;
uint256 private _orderIds;
uint256 private _bidIds;address public _adminAddress = ””;
// To store commission percentage for each mint
uint8 private _adminCommissionPercentage = 25;
// Mapping from token to the current ask for the token
mapping(uint256 => IUtils.Order) private _orders;
// Mapping from token to the current ask for the token
mapping(uint256 => IUtils.Bid) private _bids;
mapping(address => bool) public approvedCurrency;
mapping(address => bool) public approvedNfts;
uint256 private constant EXPO = 1e18;
uint256 private constant BASE = 1000 * EXPO;
These functions allow the admin to manage various aspects of the marketplace:
function setAdminAddress(address _newAdminWallet) external override returns (bool) {
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Caller is not a admin");
require(_newAdminWallet != address(0), "Admin Wallet cannot be empty address");
emit UpdateAdminWallet(_adminAddress, _newAdminWallet);
_adminAddress = _newAdminWallet;
return true;
}
function setCommissionPercentage(uint8 _commissionPercentage) external override returns (bool) {
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Caller is not a admin");
_adminCommissionPercentage = _commissionPercentage;
emit CommissionUpdated(_adminCommissionPercentage);
return true;
}
function updateCurrency(address _tokenAddress, bool _status) external override returns (bool) {
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Caller is not a admin");
approvedCurrency[_tokenAddress] = _status;
return true;
}
function updateNFTContract(address _tokenAddress, bool _status) external override returns (bool) {
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Caller is not a admin");
approvedNfts[_tokenAddress] = _status;
return true;
}
These functions handle the creation, management, and execution of orders:
function setOrder(address _nftContract, uint256 _tokenId, address _currency, uint256 _askAmount, uint256 _expiryTime)
whenNotPaused
external
override
{
_orderIds += 1;require(approvedNfts[_nftContract], "NFT is not approved by admin");
require(approvedCurrency[_currency], "Currency is not approved by admin");
require(_askAmount > 0, "Ask Amount Cannot be Zero");
require(_expiryTime > block.timestamp, "Expiry Time cannot be in Past");
ERC721 nftContract = ERC721(_nftContract);
require(nftContract.ownerOf(_tokenId) == msg.sender, "You are not owner of Token Id");
bool isAllTokenApproved = nftContract.isApprovedForAll(_msgSender(), address(this));
address approvedSpenderOfToken = nftContract.getApproved(_tokenId);
require((isAllTokenApproved || approvedSpenderOfToken == address(this)), "Market Contract is not allowed to manage this Token ID");
uint256 currentOrderId = _orderIds;
IUtils.Order storage order = _orders[currentOrderId];
order.orderId = currentOrderId;
order.sender = _msgSender();
order.askAmount = _askAmount;
order.currency = _currency;
order.nftContract = _nftContract;
order.tokenId = _tokenId;
order.expiryTime = _expiryTime;
order.orderStatus = IUtils.OrderStatus.OPEN;
order.createdAt = block.timestamp;
order.updatedAt = block.timestamp;
emit OrderCreated(currentOrderId, order);
}
function getOrder(uint256 _orderId) external override view returns (IUtils.Order memory) {
return _orders[_orderId];
}
Cancel Order: Allows the order creator or an admin to cancel an open order.
function cancelOrder(uint256 _orderId) whenNotPaused external override returns (bool) {
IUtils.Order storage order = _orders[_orderId];require(order.sender != address(0), "Invalid Order Id");
require(order.orderStatus == IUtils.OrderStatus.OPEN, "Order status is not Open");
bool hasAdminRole = hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
require(order.sender == _msgSender() || hasAdminRole, "You Don't have right to cancel order");
order.orderStatus = IUtils.OrderStatus.CANCELED;
emit OrderRemoved(_orderId, order);
return true;
}
function completeOrder(uint256 _orderId) whenNotPaused external override returns (bool) {
IUtils.Order storage order = _orders[_orderId];require(order.sender != address(0), "Invalid Order Id");
require(order.orderStatus == IUtils.OrderStatus.OPEN, "Order status is not Open");
IERC20 token = IERC20(order.currency);
ERC721 nft = ERC721(order.nftContract);
require(block.timestamp <= order.expiryTime, "Order is expired");
require(token.balanceOf(_msgSender()) >= order.askAmount, "Not enough funds available to buy");
require(token.allowance(_msgSender(), address(this)) >= order.askAmount, "Please Approve Tokens Before You Buy");
uint256 _amountToDistribute = order.askAmount;
uint256 adminCommission = (_amountToDistribute * (_adminCommissionPercentage * EXPO)) / (BASE);
uint256 _amount = _amountToDistribute - adminCommission;
token.safeTransferFrom(_msgSender(), _adminAddress, adminCommission);
token.safeTransferFrom(_msgSender(), order.sender, _amount);
nft.transferFrom(order.sender, _msgSender(), order.tokenId);
order.orderStatus = IUtils.OrderStatus.COMPLETED;
order.recipient = _msgSender();
emit OrderCompleted(order.orderId, order);
return true;
}
These functions handle the creation, management, and execution of bids:
function addBid(address _nftContract, uint256 _tokenId, address _currency, uint256 _bidAmount, uint256 _expiryTime)
whenNotPaused
external
override
{
_bidIds += 1;require(approvedNfts[_nftContract], "NFT is not approved by admin");
require(approvedCurrency[_currency], "Currency is not approved by admin");
require(_bidAmount > 0, "Bid Amount Cannot be Zero");
require(_expiryTime > block.timestamp, "Expiry Time cannot be in Past");
ERC721 nft = ERC721(_nftContract);
require(nft.ownerOf(_tokenId) != msg.sender, "You Can't Bid on your Own Token");
IERC20 token = IERC20(_currency);
require(token.balanceOf(_msgSender()) >= _bidAmount, "Not enough funds available to add bid");
require(token.allowance(_msgSender(), address(this)) >= _bidAmount, "Please Approve Tokens Before You Bid");
uint256 currentBidId = _bidIds;
IUtils.Bid storage bid = _bids[currentBidId];
bid.bidId = currentBidId;
bid.sender = _msgSender();
bid.bidAmount = _bidAmount;
bid.currency = _currency;
bid.nftContract = _nftContract;
bid.tokenId = _tokenId;
bid.expiryTime = _expiryTime;
bid.bidStatus = IUtils.OrderStatus.OPEN;
bid.createdAt = block.timestamp;
bid.updatedAt = block.timestamp;
emit BidAdded(currentBidId, bid);
}
function cancelBid(uint256 _bidId) whenNotPaused external override returns (bool) {
IUtils.Bid storage bid = _bids[_bidId];require(bid.sender != address(0), "Invalid Bid Id");
require(bid.bidStatus == IUtils.OrderStatus.OPEN, "Bid status is not Open");
bool hasAdminRole = hasRole(DEFAULT_ADMIN_ROLE, _msgSender());
ERC721 nft = ERC721(bid.nftContract);
require(bid.sender == _msgSender() || nft.ownerOf(bid.tokenId) == _msgSender() || hasAdminRole, "You Don't have right to cancel bid");
bid.bidStatus = IUtils.OrderStatus.CANCELED;
emit BidRemoved(_bidId, bid);
return true;
}
function acceptBid(uint256 _bidId) whenNotPaused external override returns (bool) {
IUtils.Bid storage bid = _bids[_bidId];require(bid.sender != address(0), "Invalid Bid Id");
require(bid.bidStatus == IUtils.OrderStatus.OPEN, "Bid status is not Open");
require(block.timestamp <= bid.expiryTime, "Bid is expired");
IERC20 token = IERC20(bid.currency);
ERC721 nft = ERC721(bid.nftContract);
require(nft.ownerOf(bid.tokenId) == msg.sender, "You are not owner of Token Id");
require(token.balanceOf(bid.sender) >= bid.bidAmount, "Bidder doesn't have Enough Funds");
require(token.allowance(bid.sender, address(this)) >= bid.bidAmount, "Bidder has not Approved Tokens");
bool isAllTokenApproved = nft.isApprovedForAll(_msgSender(), address(this));
address approvedSpenderOfToken = nft.getApproved(bid.tokenId);
require((isAllTokenApproved || approvedSpenderOfToken == address(this)), "Market Contract is not allowed to manage this Token ID");
uint256 _amountToDistribute = bid.bidAmount;
uint256 adminCommission = (_amountToDistribute * (_adminCommissionPercentage * EXPO)) / (BASE);
uint256 _amount = _amountToDistribute - adminCommission;
nft.transferFrom(_msgSender(), bid.sender, bid.tokenId);
token.safeTransferFrom(bid.sender, _adminAddress, adminCommission);
token.safeTransferFrom(bid.sender, _msgSender(), _amount);
bid.bidStatus = IUtils.OrderStatus.COMPLETED;
bid.recipient = _msgSender();
emit BidAccepted(bid.bidId, bid);
return true;
}
The MarketPlace contract is a comprehensive solution for managing NFT transactions. By leveraging the power of smart contracts, it ensures transparency, security, and efficiency in the trading process. Whether you’re minting new NFTs, bidding on unique digital assets, or managing a marketplace, this contract provides the tools you need to succeed in the dynamic world of blockchain-based digital assets.
Github URL:
https://github.com/adeelch9/bttc-examples/tree/master/projects/nft-marketplace
[