Use-It-Or-Lose-It Slot Auction

use-it-or-lose-it-slot-auction · auction-allocation · 2011 B runtime · funds-movement

scores

source

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

contract SlotAuction {
    address payable public beneficiary;
    uint256 public deadline;
    uint256 public timeout;
    uint256 public penalty;
    address payable public highestBidder;
    uint256 public highestBid;
    bool public executed;
    bool public forfeited;

    event BidPlaced(address indexed bidder, uint256 amount);
    event Refunded(address indexed bidder, uint256 amount);
    event Executed(address indexed winner, uint256 amount);
    event Forfeited(address indexed winner, uint256 refund);

    constructor(
        address payable _beneficiary,
        uint256 _deadline,
        uint256 _timeoutDuration,
        uint256 _penalty
    ) {
        beneficiary = _beneficiary;
        deadline = _deadline;
        timeout = _deadline + _timeoutDuration;
        penalty = _penalty;
    }

    function bid() external payable {
        require(block.timestamp < deadline, "bidding closed");
        require(msg.value > highestBid, "bid too low");

        address payable previousBidder = highestBidder;
        uint256 previousBid = highestBid;

        highestBidder = payable(msg.sender);
        highestBid = msg.value;

        if (previousBidder != address(0)) {
            (bool ok, ) = previousBidder.call{value: previousBid}("");
            require(ok, "refund failed");
            emit Refunded(previousBidder, previousBid);
        }
        emit BidPlaced(msg.sender, msg.value);
    }

    function execute() external {
        require(!executed && !forfeited, "already closed");
        require(block.timestamp >= deadline && block.timestamp < timeout, "not in window");
        require(msg.sender == highestBidder, "not winner");

        executed = true;
        (bool ok, ) = beneficiary.call{value: highestBid}("");
        require(ok, "beneficiary transfer failed");
        emit Executed(msg.sender, highestBid);
    }

    function forfeit() external {
        require(!executed && !forfeited, "already closed");
        require(block.timestamp >= timeout, "too early");
        require(msg.sender == highestBidder, "not winner");
        require(highestBid >= penalty, "penalty too high");

        forfeited = true;
        uint256 refund = highestBid - penalty;
        (bool ok, ) = payable(msg.sender).call{value: refund}("");
        require(ok, "refund failed");
        emit Forfeited(msg.sender, refund);
    }
}