112 lines
3.9 KiB
Solidity
112 lines
3.9 KiB
Solidity
// SPDX-License-Identifier: Proprietary
|
|
|
|
pragma solidity ^0.7.2;
|
|
|
|
library LibAuctionable {
|
|
bytes32 constant AUCTIONABLE_STORAGE_POSITION = keccak256("gallery.token.nft.LibAuctionable");
|
|
|
|
enum PaymentType { Coin, Token }
|
|
|
|
struct Auction {
|
|
address payable beneficiary; // person who gets paid when auction wins (owner usually)
|
|
uint256[] itemIds; // NFT ids up for auction
|
|
uint256 endTime; // absolute time in seconds
|
|
address payable highestBidder;
|
|
uint256 highestBid;
|
|
PaymentType paymentType;
|
|
bool ended;
|
|
bool finalized; // ownership of nfts transferred
|
|
}
|
|
|
|
struct AuctionableStore {
|
|
uint256 auctionId; //nonce for auction ids
|
|
mapping (uint256 => Auction) auctions;
|
|
mapping (uint256 => mapping(address => uint256)) pendingReturns;
|
|
mapping (uint256 => uint256) nftId2AuctionId;
|
|
}
|
|
|
|
function store() internal pure returns (AuctionableStore storage aus) {
|
|
bytes32 position = AUCTIONABLE_STORAGE_POSITION;
|
|
assembly {
|
|
aus.slot := position
|
|
}
|
|
}
|
|
|
|
event AuctionStarted(uint256 indexed id, address from);
|
|
event HighBid(uint256 indexed id, address indexed bidder, uint256 amount);
|
|
event AuctionEnded(uint256 indexed id, address indexed winner, uint256 amount);
|
|
|
|
function getNewAuctionId() internal returns(uint256) {
|
|
uint256 newAuctionId = store().auctionId;
|
|
store().auctionId++;
|
|
return newAuctionId;
|
|
}
|
|
|
|
/**
|
|
This just creates the auction, it's not responsible for changing the NFT's state.
|
|
*/
|
|
function createNewAuction(PaymentType _paymentType, uint256 _endTime, uint256[] memory _nftIds) internal returns (uint256) {
|
|
uint256 newAuctionId = getNewAuctionId();
|
|
Auction storage newAuction = store().auctions[newAuctionId];
|
|
newAuction.beneficiary = msg.sender;
|
|
newAuction.itemIds = _nftIds;
|
|
newAuction.endTime = _endTime;
|
|
newAuction.paymentType = _paymentType;
|
|
|
|
for (uint i = 0; i < _nftIds.length; ++i) {
|
|
store().nftId2AuctionId[_nftIds[i]] = newAuctionId;
|
|
}
|
|
|
|
emit AuctionStarted(newAuctionId, msg.sender);
|
|
return newAuctionId;
|
|
}
|
|
|
|
/**
|
|
This just ends the auction, it doesn't transfer the NFTs or pay the winner.
|
|
*/
|
|
function endAuction(uint256 _auctionId) internal {
|
|
Auction storage auction = store().auctions[_auctionId];
|
|
require(!auction.ended, "Auction already ended");
|
|
require(block.timestamp >= auction.endTime, "Not time to end auction");
|
|
auction.ended = true;
|
|
emit AuctionEnded(_auctionId, auction.highestBidder, auction.highestBid);
|
|
}
|
|
|
|
/**
|
|
Dissociates NFTs from auction. This MUST be called, and ONLY AFTER NFTs are transferred
|
|
*/
|
|
function postAuctionCleanup(uint256 _auctionId) internal {
|
|
Auction storage auction = store().auctions[_auctionId];
|
|
require(auction.ended, "Auction must be ended");
|
|
require(!auction.finalized, "Auction must not be finalized");
|
|
auction.finalized = true;
|
|
for (uint i = 0; i < auction.itemIds.length; ++i) {
|
|
delete store().nftId2AuctionId[ auction.itemIds[i] ];
|
|
}
|
|
}
|
|
|
|
/**
|
|
This is needed to facilitate NFT transfer after auction conclusion.
|
|
*/
|
|
function getAuctionForNft(uint256 _nftId) internal view returns (uint256) {
|
|
return store().nftId2AuctionId[_nftId];
|
|
}
|
|
|
|
/**
|
|
Used to approve transfer of NFT when auction successfully concludes.
|
|
*/
|
|
function validAuctionTransfer(address _from, address _to, uint256 _nftId) internal view returns (bool) {
|
|
uint256 auctionId = getAuctionForNft(_nftId);
|
|
if (auctionId == 0) return false;
|
|
|
|
Auction storage auction = store().auctions[auctionId];
|
|
|
|
return
|
|
auction.ended &&
|
|
!auction.finalized &&
|
|
_from == auction.beneficiary &&
|
|
_to == auction.highestBidder
|
|
;
|
|
}
|
|
}
|