Created
September 6, 2021 05:55
-
-
Save M4cs/aee4eff4058c91c9d17e6012a8df885f to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.7+commit.e28d00a7.js&optimize=false&runs=200&gist=
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: UNLICENSED | |
pragma solidity ^0.8.0; | |
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | |
import "@openzeppelin/contracts/utils/math/SafeMath.sol"; | |
import "./LittleShartsAdmins.sol"; | |
contract LittleShartMarketplace is LittleShartsAdmins { | |
using SafeMath for uint256; | |
uint256 public _listingFee = 1; | |
address _nft; | |
address _token; | |
struct Listing { | |
address seller; | |
bool isActive; | |
uint price; | |
} | |
struct Bid { | |
address bidder; | |
bool isActive; | |
uint value; | |
} | |
// Treasury for sellers/bidders | |
mapping (uint256 => Listing) _listings; | |
mapping (uint256 => Bid) _bids; | |
mapping (address => uint256[]) _tokensListed; | |
// Locks up until listing is bought or refunds lister if cancelled | |
mapping (uint256 => uint256) _pendingFeeTreasury; | |
// Tracks tokenIds for sale for easy call access | |
uint256[] public _tokensForSale; | |
constructor ( | |
address _nftAddress, | |
address _tokenAddress, | |
address _masterAdmin | |
) { | |
_nft = _nftAddress; | |
_token = _tokenAddress; | |
masterAdmin = _masterAdmin; | |
admins = [_masterAdmin]; | |
} | |
function buyNow(uint256 tokenId) public payable { | |
Listing memory listing = _listings[tokenId]; | |
require(listing.isActive, "Listing is inactive!"); | |
require(listing.seller != msg.sender, "Cannot purchase your own listing!"); | |
require(msg.value == listing.price, "Value of TXN is not the same as listing price!"); | |
Bid memory bid = _bids[tokenId]; | |
uint256 bidValue = bid.value; | |
address bidder = bid.bidder; | |
if (bid.isActive && (bid.bidder == msg.sender)) { | |
// Buyer is current bidder, refund them their bid | |
payable(msg.sender).transfer(bidValue); | |
_bids[tokenId] = Bid(address(0), false, 0); | |
} | |
ERC721(_nft).approve(bidder, tokenId); | |
ERC721(_nft).transferFrom(address(this), bidder, tokenId); | |
require(ERC721(_nft).balanceOf(bid.bidder) == 1, "Transfer did not complete!"); | |
payable(listing.seller).transfer(msg.value); | |
payable(masterAdmin).transfer(_pendingFeeTreasury[tokenId]); | |
_removeFromSale(tokenId); | |
} | |
function acceptBid(uint256 tokenId) public { | |
Listing memory listing = _listings[tokenId]; | |
require(listing.seller == msg.sender, "Cannot accept bid on listing you do not own!"); | |
Bid memory bid = _bids[tokenId]; | |
require(bid.isActive, "No active bid to accept!"); | |
require(bid.value > 0, "Bid value is zero."); | |
ERC721(_nft).approve(bid.bidder, tokenId); | |
ERC721(_nft).transferFrom(address(this), bid.bidder, tokenId); | |
_bids[tokenId] = Bid(address(0), false, 0); | |
require(ERC721(_nft).balanceOf(bid.bidder) == 1, "Transfer did not complete!"); | |
payable(masterAdmin).transfer(_pendingFeeTreasury[tokenId]); | |
_removeFromSale(tokenId); | |
} | |
function cancelBid(uint256 tokenId) public { | |
Bid memory currentBid = _bids[tokenId]; | |
require(currentBid.isActive, "Bid is not active!"); | |
require(currentBid.bidder == msg.sender, "You are not owner of this bid!"); | |
uint refundAmnt = currentBid.value; | |
_bids[tokenId] = Bid(address(0), false, currentBid.value); | |
payable(msg.sender).transfer(refundAmnt); | |
} | |
function createBid(uint256 tokenId) public payable { | |
require(msg.value > 0, "Bid Price Cannot Be Negative!"); | |
Listing memory listing = _listings[tokenId]; | |
require(listing.isActive, "Listing Must Be Active To Bid!"); | |
require(listing.seller != msg.sender, "Cannot bid on your own listing!"); | |
Bid memory currentBid = _bids[tokenId]; | |
// Check if there is already a Bid | |
if (currentBid.isActive) { | |
// Make sure new bid is greater than old bid | |
require(msg.value > currentBid.value, "Too low to outbid current bid!"); | |
// Refund old bidder | |
payable(currentBid.bidder).transfer(currentBid.value); | |
} | |
_bids[tokenId] = Bid(msg.sender, true, msg.value); | |
} | |
function updateListing(uint256 tokenId, uint256 value) public payable { | |
require(value > 0, "Listing price cannot be negative!"); // Listing Cannot be Negatively Priced | |
Listing memory listing = _listings[tokenId]; | |
require(listing.seller==msg.sender, "Must be owner of token!"); // Must own the token trying to be updated | |
require(_listings[tokenId].isActive, "Listing is not active!"); // Listing must be active to update. List it first | |
uint256[2] memory amounts = _getFeeAmounts(_listingFee, value); | |
require(msg.value == amounts[1], "Value does not cover listing fee!"); | |
_pendingFeeTreasury[tokenId] += amounts[1]; | |
_listings[tokenId] = Listing(msg.sender, true, value); | |
} | |
function cancelListing(uint256 tokenId) public { | |
Listing memory listing = _listings[tokenId]; | |
require(listing.seller == msg.sender, "Must be owner of listing!"); | |
require(listing.isActive, "Listing must be active!"); | |
// At this point we know the sender is the seller. | |
// Lets refund and remove their Listing | |
payable(listing.seller).transfer(_pendingFeeTreasury[tokenId]); | |
_removeFromSale(tokenId); | |
} | |
function createListing(uint256 tokenId, uint256 value) public payable { | |
require(value > 0, "Listing price cannot be negative!"); // Listing Cannot be Negatively Priced | |
require(ERC721(_nft).ownerOf(tokenId)==msg.sender, "Must be owner of token!"); // Must own the token trying to be listed | |
require(!_listings[tokenId].isActive, "Listing is already active!"); // Listing must be inactive to start. Cancel or Update Otherwise | |
uint256[2] memory amounts = _getFeeAmounts(_listingFee, value); | |
require(msg.value == amounts[1], "Value does not cover listing fee!"); | |
// Contract Should Be Approved, Transfer to Contract | |
ERC721(_nft).transferFrom(msg.sender, address(this), tokenId); | |
require(ERC721(_nft).ownerOf(tokenId)==address(this), "Token Transfer Failed!"); | |
_pendingFeeTreasury[tokenId] = amounts[1]; | |
_tokensListed[msg.sender].push(tokenId); | |
_listings[tokenId] = Listing(msg.sender, true, value); | |
_tokensForSale.push(tokenId); | |
} | |
function getTokensForSale() public view returns (uint256[] memory) { | |
return _tokensForSale; | |
} | |
function getTokensListed() public view returns (uint256[] memory) { | |
return _tokensListed[msg.sender]; | |
} | |
function getTokensListed(address _owner) public view returns (uint256[] memory) { | |
return _tokensListed[_owner]; | |
} | |
function getFeeTreasuryAmountForListing(uint256 tokenId) public view onlyAdmin returns (uint256) { | |
return _pendingFeeTreasury[tokenId]; | |
} | |
function _removeFromSale(uint256 tokenId) internal { | |
uint256 tokenIndex; | |
for (uint i=0;i<_tokensForSale.length;i++) { | |
if (_tokensForSale[i] == tokenId) { | |
tokenIndex = i; | |
} | |
} | |
_tokensForSale[tokenIndex] = _tokensForSale[_tokensForSale.length-1]; | |
_tokensForSale.pop(); | |
_listings[tokenId] = Listing(msg.sender, false, 0); | |
_pendingFeeTreasury[tokenId] = 0; | |
uint256 listedIndex; | |
for (uint i=0;i<_tokensListed[msg.sender].length;i++) { | |
if (_tokensListed[msg.sender][i] == tokenId) { | |
listedIndex = i; | |
} | |
} | |
_tokensListed[msg.sender][listedIndex] = _tokensListed[msg.sender][_tokensListed[msg.sender].length-1]; | |
_tokensListed[msg.sender].pop(); | |
} | |
function _getFeeAmounts(uint256 fee, uint256 amount) internal pure returns (uint256[2] memory outAmounts) { | |
uint256 feeAmount = (amount / 100) * fee; | |
uint256 tOut = amount - feeAmount; | |
outAmounts[0] = tOut; | |
outAmounts[1] = feeAmount; | |
return outAmounts; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment