Last Moment Auction
last-moment-auction · auction-allocation · 1944 B runtime · funds-movement
scores
- usefulness: 70
- safety: 60
- liveness: 50
- authenticity: 65
- extensibility: 50
- bytecodeDiscipline: 80
- practical: 64
source
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
contract LastMomentAuction {
uint32 public openBlock;
uint32 public closeBlock;
uint96 public totalPool;
struct BlockInfo {
uint32 bidCount;
uint96 bidSum;
}
struct BidderInfo {
uint32 blockNum;
bool claimed;
}
mapping(uint32 => BlockInfo) private blockInfos;
mapping(address => BidderInfo) private bidders;
event Bid(address indexed bidder, uint32 indexed blockNum, uint96 amount);
event Claim(address indexed bidder, uint96 amount);
constructor(uint32 open, uint32 close) {
require(close > open + 1, "invalid window");
openBlock = open;
closeBlock = close;
}
function bid() external payable {
uint32 blockNum = uint32(block.number);
require(blockNum >= openBlock && blockNum < closeBlock, "not in window");
require(msg.value > 0, "zero bid");
require(bidders[msg.sender].blockNum == 0, "already bid");
require(msg.value <= type(uint96).max, "value too high");
bidders[msg.sender].blockNum = blockNum;
blockInfos[blockNum].bidCount++;
blockInfos[blockNum].bidSum += uint96(msg.value);
totalPool += uint96(msg.value);
emit Bid(msg.sender, blockNum, uint96(msg.value));
}
function claim() external {
require(block.number >= closeBlock, "not closed");
BidderInfo memory info = bidders[msg.sender];
require(info.blockNum == closeBlock - 1, "not winner");
require(!info.claimed, "claimed");
BlockInfo memory win = blockInfos[info.blockNum];
require(win.bidCount > 0, "no winners");
uint96 share = totalPool / win.bidCount;
require(share > 0, "no share");
bidders[msg.sender].claimed = true;
(bool success, ) = payable(msg.sender).call{value: share}("");
require(success, "transfer failed");
emit Claim(msg.sender, share);
}
}