Bitmap Slot Auction

bitmap-slot-auction · auction-allocation · 1769 B runtime · funds-movement

scores

source

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract BitmapSlotAuction {
    address public immutable beneficiary;

    uint256[32] private bids;
    address[32] private bidders;
    uint8 public bidCount;
    bool public settled;

    address public winner;
    uint256 public winningBid;
    uint256 public price;
    uint8 public awardedSlot;

    event Bid(address indexed bidder, uint256 bidMask, uint8 indexed index);
    event Claimed(address indexed winner, uint8 indexed slot, uint256 price);

    constructor(address _beneficiary) {
        require(_beneficiary != address(0), "beneficiary zero");
        beneficiary = _beneficiary;
    }

    /// @notice Place a bid. `packed` is both the bid amount and the 256-bit mask.
    function bid(uint256 packed) external {
        require(!settled, "settled");
        require(bidCount < 32, "full");
        require(packed != 0, "zero");

        bids[bidCount] = packed;
        bidders[bidCount] = msg.sender;
        emit Bid(msg.sender, packed, bidCount);
        bidCount++;
    }

    /// @notice Settle: the highest bidder (first if tied) wins, pays the second-highest bid,
    ///         and receives the lowest set bit of their mask as the awarded slot.
    function claim() external payable {
        require(!settled, "settled");
        require(bidCount > 0, "empty");

        address topBidder;
        uint256 top;
        uint256 second;

        for (uint8 i = 0; i < bidCount; i++) {
            uint256 b = bids[i];
            if (b > top) {
                second = top;
                top = b;
                topBidder = bidders[i];
            } else if (b > second) {
                second = b;
            }
        }

        require(msg.sender == topBidder, "not winner");
        require(msg.value == second, "payment");

        settled = true;
        winner = topBidder;
        winningBid = top;
        price = second;
        awardedSlot = _lowestSetBit(top);

        if (second > 0) {
            (bool ok,) = beneficiary.call{value: second}("");
            require(ok, "transfer failed");
        }

        emit Claimed(msg.sender, awardedSlot, second);
    }

    function _lowestSetBit(uint256 x) internal pure returns (uint8 index) {
        while ((x & 1) == 0) {
            x >>= 1;
            index++;
        }
    }
}