token-gallery-contracts/contracts/LibAuctionable.sol

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
;
}
}