Created
August 30, 2022 23:59
-
-
Save jplew/1f33c7a4e34608b94e7a93d3913d7814 to your computer and use it in GitHub Desktop.
on-chain market
This file contains 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
contract FlurksMarket is Context, ReentrancyGuard, Pausable, Ownable { | |
IERC721 flurksContract; // instance of the Flurks contract | |
struct Offer { | |
bool isForSale; | |
uint flurkID; | |
address seller; | |
uint minValue; // in ether | |
address onlySellTo; | |
} | |
struct Bid { | |
bool hasBid; | |
uint flurkID; | |
address bidder; | |
uint value; | |
} | |
// A record of flurks that are offered for sale at a specific minimum value, and perhaps to a specific person | |
mapping (uint => Offer) public flurkOffers; | |
// A record of the highest flurk bid | |
mapping (uint => Bid) public flurkBids; | |
// A record of pending ETH withdrawls by address | |
mapping (address => uint) public pendingWithdrawals; | |
event FlurkOfferCreated(uint indexed flurkID, uint minValue, address indexed Oferrer); | |
event FlurkOfferWithdrawn(uint indexed flurkID); | |
event FlurkBidCreated(uint indexed flurkID, uint value, address indexed fromAddress); | |
event FlurkBidWithdrawn(uint indexed flurkID, uint value, address indexed fromAddress); | |
event FlurkBought(uint indexed flurkID, uint value, address indexed fromAddress, address indexed toAddress); | |
// Initializes contract with an instance of Flurks contract, and sets deployer as owner | |
constructor(address initialFlurksAddress) { | |
flurksContract = IERC721(initialFlurksAddress); | |
} | |
function pause() public whenNotPaused onlyOwner { | |
_pause(); | |
} | |
function unpause() public whenPaused onlyOwner { | |
_unpause(); | |
} | |
modifier onlyHeckingCuteAndValidFlurk(uint flurkID) { | |
require(flurkID <= 4984, "flurk ID is not cute and valid"); | |
_; | |
} | |
modifier onlyFlurkOwner(uint flurkID) { | |
require(flurksContract.ownerOf(flurkID) == _msgSender(), "you are not the owner of this token"); | |
_; | |
} | |
// Allows the owner of a Flurks to stop offering it for sale | |
function WithdrawFlurk(uint flurkID) public | |
nonReentrant | |
onlyHeckingCuteAndValidFlurk(flurkID) | |
onlyFlurkOwner(flurkID) | |
{ | |
flurkOffers[flurkID] = Offer(false, flurkID, _msgSender(), 0, address(0x0)); | |
emit FlurkOfferWithdrawn(flurkID); | |
} | |
// Allows a CryptoFlurk owner to offer it for sale | |
function OfferFlurk(uint flurkID, uint minSalePriceInWei) public | |
whenNotPaused | |
nonReentrant | |
onlyHeckingCuteAndValidFlurk(flurkID) | |
onlyFlurkOwner(flurkID) | |
{ | |
flurkOffers[flurkID] = Offer(true, flurkID, _msgSender(), minSalePriceInWei, address(0x0)); | |
emit FlurkOfferCreated(flurkID, minSalePriceInWei, address(0x0)); | |
} | |
// Allows a CryptoFlurk owner to offer it for sale to a specific address | |
function OfferFlurkToAddress(uint flurkID, uint minSalePriceInWei, address toAddress) public | |
whenNotPaused | |
nonReentrant | |
onlyHeckingCuteAndValidFlurk(flurkID) | |
onlyFlurkOwner(flurkID) | |
{ | |
flurkOffers[flurkID] = Offer(true, flurkID, _msgSender(), minSalePriceInWei, toAddress); | |
emit FlurkOfferCreated(flurkID, minSalePriceInWei, toAddress); | |
} | |
// Allows users to buy a Flurk offered for sale | |
function BuyFlurk(uint flurkID) payable public | |
whenNotPaused | |
nonReentrant | |
onlyHeckingCuteAndValidFlurk(flurkID) | |
{ | |
Offer memory offer = flurkOffers[flurkID]; | |
require(offer.isForSale, "flurk is not for sale!"); | |
// Check if offer is valid for anyone or a specific address | |
require(offer.onlySellTo == address(0x0) || offer.onlySellTo == _msgSender(), "this offer is not for you"); | |
require(msg.value == offer.minValue, "not enough ether"); // Didn"t send enough ETH | |
address seller = offer.seller; | |
require(seller != _msgSender(), "seller cannot buy its own token"); | |
require(seller == flurksContract.ownerOf(flurkID), "seller no longer owner of flurk"); | |
flurkOffers[flurkID] = Offer(false, flurkID, _msgSender(), 0, address(0x0)); | |
flurksContract.safeTransferFrom(seller, _msgSender(), flurkID); | |
pendingWithdrawals[seller] += msg.value; | |
emit FlurkBought(flurkID, msg.value, seller, _msgSender()); | |
// Check for the case where there is a bid from the new owner and refund it. | |
// Any other bid can stay in place. | |
Bid memory bid = flurkBids[flurkID]; | |
if (bid.bidder == _msgSender()) { | |
// Kill bid and refund value | |
pendingWithdrawals[_msgSender()] += bid.value; | |
flurkBids[flurkID] = Bid(false, flurkID, address(0x0), 0); | |
} | |
} | |
// Allows users to enter bids for any Flurk | |
function BidFlurk(uint flurkID) payable public | |
whenNotPaused | |
nonReentrant | |
onlyHeckingCuteAndValidFlurk(flurkID) | |
{ | |
require(flurksContract.ownerOf(flurkID) != _msgSender(), "you already own this flurk"); | |
require(msg.value > 0, "cannot enter bid of zero"); | |
Bid memory existing = flurkBids[flurkID]; | |
require(msg.value > existing.value, "your bid is too low"); | |
if (existing.value > 0) { // Refund the failing bid | |
pendingWithdrawals[existing.bidder] += existing.value; | |
} | |
flurkBids[flurkID] = Bid(true, flurkID, _msgSender(), msg.value); | |
emit FlurkBidCreated(flurkID, msg.value, _msgSender()); | |
} | |
// Allows Flurk owners to accept bids for their Flurks | |
function AcceptFlurkBid(uint flurkID, uint minPrice) public | |
whenNotPaused | |
nonReentrant | |
onlyHeckingCuteAndValidFlurk(flurkID) | |
onlyFlurkOwner(flurkID) | |
{ | |
address seller = _msgSender(); | |
Bid memory bid = flurkBids[flurkID]; | |
require(bid.value > 0, "cannot enter bid of zero"); | |
require(bid.value > minPrice, "your bid is too low"); | |
require(seller != bid.bidder, "you already own this token"); | |
// remove flurk offer | |
flurkOffers[flurkID] = Offer(false, flurkID, bid.bidder, 0, address(0x0)); | |
// remove flurk bid | |
flurkBids[flurkID] = Bid(false, flurkID, address(0x0), 0); | |
// send the token to the bidder | |
flurksContract.safeTransferFrom(_msgSender(), bid.bidder, flurkID); | |
// pay the seller | |
pendingWithdrawals[seller] += bid.value; | |
emit FlurkBought(flurkID, bid.value, seller, bid.bidder); | |
} | |
// Allows bidders to withdraw their bids | |
function WithdrawFlurkBid(uint flurkID) public | |
nonReentrant | |
onlyHeckingCuteAndValidFlurk(flurkID) | |
{ | |
Bid memory bid = flurkBids[flurkID]; | |
require(bid.bidder == _msgSender(), "the bidder is not message sender"); | |
emit FlurkBidWithdrawn(flurkID, bid.value, _msgSender()); | |
uint amount = bid.value; | |
flurkBids[flurkID] = Bid(false, flurkID, address(0x0), 0); | |
// Refund the bid money | |
payable(_msgSender()).transfer(amount); | |
} | |
// Allows users to retrieve ETH from sales | |
function withdraw() public nonReentrant { | |
uint amount = pendingWithdrawals[_msgSender()]; | |
// Remember to zero the pending refund before | |
// sending to prevent re-entrancy attacks | |
pendingWithdrawals[_msgSender()] = 0; | |
payable(_msgSender()).transfer(amount); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment