Priority Queue Ticket Auction
priority-queue-ticket-auction · auction-allocation · 3766 B runtime · funds-movement
scores
- usefulness: 68
- safety: 38
- liveness: 45
- authenticity: 40
- extensibility: 50
- bytecodeDiscipline: 78
- practical: 56
source
pragma solidity ^0.8.13;
interface IQueue {
function consumeSlot(address user) external;
}
contract PriorityQueueTicketAuction {
// ERC-721 state
mapping(uint256 => address) private _owners;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => uint256) private _balances;
// Auction state
address public queueContract;
address public beneficiary;
uint256 public endBlock;
uint256 public ticketId = 1;
address public highestBidder;
uint256 public highestBid;
bool public finalized;
event Bid(address indexed bidder, uint256 amount);
event Finalized(address indexed winner, uint256 amount);
event PriorityConsumed(address indexed user, uint256 ticketId);
constructor(address _queueContract, uint256 _endBlock) {
require(_queueContract != address(0), "Invalid queue");
require(_endBlock > block.number, "End block must be future");
queueContract = _queueContract;
beneficiary = msg.sender;
endBlock = _endBlock;
_mint(address(this), ticketId);
}
// --- ERC-721 ---
function balanceOf(address owner) external view returns (uint256) {
require(owner != address(0), "Ownership query for zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "Owner query for nonexistent token");
return owner;
}
function approve(address to, uint256 tokenId) external {
address owner = ownerOf(tokenId);
require(msg.sender == owner, "Not owner");
_tokenApprovals[tokenId] = to;
}
function getApproved(uint256 tokenId) public view returns (address) {
require(_exists(tokenId), "Approval query for nonexistent token");
return _tokenApprovals[tokenId];
}
function transferFrom(address from, address to, uint256 tokenId) public {
require(_isApprovedOrOwner(msg.sender, tokenId), "Not approved or owner");
_transfer(from, to, tokenId);
}
// --- Auction ---
function bid() external payable {
require(block.number < endBlock, "Auction ended");
require(msg.value > highestBid, "Bid too low");
uint256 minBid = (highestBid * 105) / 100;
require(msg.value >= minBid, "Bid increment 5% minimum");
address oldBidder = highestBidder;
uint256 oldBid = highestBid;
highestBidder = msg.sender;
highestBid = msg.value;
if (oldBidder != address(0)) {
(bool ok, ) = payable(oldBidder).call{value: oldBid}("");
require(ok, "Refund failed");
}
emit Bid(msg.sender, msg.value);
}
function finalize() external {
require(block.number >= endBlock, "Auction not ended");
require(!finalized, "Already finalized");
finalized = true;
if (highestBidder != address(0)) {
_transfer(address(this), highestBidder, ticketId);
emit Finalized(highestBidder, highestBid);
} else {
emit Finalized(address(0), 0);
}
}
function burnForPriority() external {
require(finalized, "Auction not finalized");
require(ownerOf(ticketId) == msg.sender, "Not ticket owner");
_burn(ticketId);
IQueue(queueContract).consumeSlot(msg.sender);
emit PriorityConsumed(msg.sender, ticketId);
}
function withdraw() external {
require(block.number >= endBlock, "Auction not ended");
require(msg.sender == beneficiary, "Only beneficiary");
uint256 amount = highestBid;
highestBid = 0;
(bool ok, ) = payable(beneficiary).call{value: amount}("");
require(ok, "Withdraw failed");
}
// --- Internal ERC-721 helpers ---
function _exists(uint256 tokenId) internal view returns (bool) {
return _owners[tokenId] != address(0);
}
function _mint(address to, uint256 tokenId) internal {
require(to != address(0), "Mint to zero address");
require(!_exists(tokenId), "Token already exists");
_balances[to] += 1;
_owners[tokenId] = to;
}
function _burn(uint256 tokenId) internal {
address owner = _owners[tokenId];
require(owner != address(0), "Burn nonexistent token");
_balances[owner] -= 1;
delete _owners[tokenId];
delete _tokenApprovals[tokenId];
}
function _transfer(address from, address to, uint256 tokenId) internal {
require(_owners[tokenId] == from, "Transfer from incorrect owner");
require(to != address(0), "Transfer to zero address");
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
delete _tokenApprovals[tokenId];
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
address owner = ownerOf(tokenId);
return (spender == owner || spender == getApproved(tokenId));
}
}