Time-Slice State Auction

time-slice-state-auction · auction-allocation · 1627 B runtime · funds-movement

scores

source

pragma solidity ^0.8.13;

contract TimeSliceStateAuction {
    uint256 public constant SLICE_LENGTH = 100;
    uint256 public immutable genesis;
    address public immutable owner;

    bytes32 public state;

    struct Auction {
        uint96 highestBid;
        address payable highestBidder;
    }

    Auction internal auction;
    bytes32 public pendingValue;
    uint32 public auctionSlice;

    event Bid(address indexed bidder, uint256 amount, bytes32 value, uint32 indexed slice);
    event Transition(address indexed winner, uint256 amount, bytes32 value, uint32 indexed slice);

    constructor() {
        genesis = block.number;
        owner = msg.sender;
        auctionSlice = 1;
    }

    function currentSlice() public view returns (uint32) {
        return uint32((block.number - genesis) / SLICE_LENGTH);
    }

    function bid(bytes32 value) external payable {
        require(msg.value > 0, "no bid");
        require(msg.value <= type(uint96).max, "bid too large");
        require(currentSlice() + 1 == auctionSlice, "wrong slice");
        require(msg.value > auction.highestBid, "bid not higher");

        auction.highestBid = uint96(msg.value);
        auction.highestBidder = payable(msg.sender);
        pendingValue = value;

        emit Bid(msg.sender, msg.value, value, currentSlice());
    }

    function transition() external {
        uint32 s = currentSlice();
        require(s >= auctionSlice, "too early");

        uint96 winningBid = auction.highestBid;
        address winner = auction.highestBidder;
        bytes32 value = pendingValue;

        if (winningBid > 0) {
            state = value;
        }

        delete auction;
        pendingValue = bytes32(0);
        auctionSlice = s + 1;

        emit Transition(winner, winningBid, value, s);
    }

    function claimFees() external {
        require(msg.sender == owner, "not owner");
        payable(owner).transfer(address(this).balance);
    }
}