Block-Slot Reservation Auction

block-slot-reservation-auction · auction-allocation · 1400 B runtime · funds-movement

scores

source

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

contract BlockSlotReservationAuction {
    struct Reservation {
        address bidder;
        uint96 amount;
    }

    mapping(uint256 => Reservation) public reservations;
    mapping(uint256 => bool) public claimed;

    event BidPlaced(
        uint64 indexed targetBlock,
        uint128 indexed resourceId,
        address indexed bidder,
        uint256 amount,
        address previousBidder,
        uint256 previousAmount
    );
    event SlotClaimed(uint64 indexed targetBlock, uint128 indexed resourceId, address indexed bidder);

    function bid(uint128 resourceId, uint64 targetBlock) external payable {
        require(targetBlock >= block.number + 3);
        uint96 amount = uint96(msg.value);
        require(uint256(amount) == msg.value);

        uint256 key = _key(targetBlock, resourceId);
        Reservation storage r = reservations[key];

        if (r.amount != 0) {
            require(amount > r.amount);
            address previousBidder = r.bidder;
            uint96 previousAmount = r.amount;

            r.bidder = msg.sender;
            r.amount = amount;

            (bool ok, ) = payable(previousBidder).call{value: previousAmount}("");
            require(ok);

            emit BidPlaced(targetBlock, resourceId, msg.sender, amount, previousBidder, previousAmount);
        } else {
            r.bidder = msg.sender;
            r.amount = amount;
            emit BidPlaced(targetBlock, resourceId, msg.sender, amount, address(0), 0);
        }
    }

    function claimReservedSlot(uint128 resourceId, uint64 targetBlock) external {
        require(targetBlock == block.number);

        uint256 key = _key(targetBlock, resourceId);
        Reservation storage r = reservations[key];
        require(r.bidder == msg.sender);
        require(!claimed[key]);

        claimed[key] = true;
        emit SlotClaimed(targetBlock, resourceId, msg.sender);
    }

    function reservation(uint128 resourceId, uint64 targetBlock)
        external
        view
        returns (address bidder, uint256 amount, bool isClaimed)
    {
        uint256 key = _key(targetBlock, resourceId);
        Reservation storage r = reservations[key];
        return (r.bidder, r.amount, claimed[key]);
    }

    function _key(uint64 targetBlock, uint128 resourceId) internal pure returns (uint256) {
        return (uint256(targetBlock) << 128) | uint256(resourceId);
    }
}