账户
0x55...0047
0x55...0047

0x55...0047

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.24+commit.e11b9ed9
语言
Solidity
合同源代码
文件 1 的 2:AdetSecmeli2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

// \\
// Created by Clodron
// If you want to create a new project, please contact me @
// info@clodron.com
// \\

contract FreeTimerOnChainWinMultipleWinners2 is ReentrancyGuard {
    address public owner;
    mapping(address => bool) public hasEntered;
    address[] public players;
    mapping(address => uint256) public playerIndexes;
    address[] public winnerAddresses;
    mapping(address => uint256) public winnerWins;
    bool public raffleStatus;
    uint256 public prizeAmount;
    uint256 public raffleEndTime;
    uint256 public ticketsSoldThisRound;
    uint256 public numberOfWinners;
    uint256 private raffleStartDuration;

    event NewEntry(address indexed player, uint256 numberOfEntries);
    event RaffleStarted(
        uint256 prizeAmount,
        uint256 endTime,
        uint256 numberOfWinners
    );
    event RaffleEnded();
    event WinnerSelected(address winner, uint256 prizeAmount);

    modifier onlyOwner() {
        require(msg.sender == owner, "Just owner.");
        _;
    }

    constructor() {
        owner = msg.sender;
        raffleStatus = false;
        ticketsSoldThisRound = 0;
    }

    function startRaffle(
        uint256 _prizeAmount,
        uint256 _duration,
        uint256 _numberOfWinners
    ) public onlyOwner {
        require(!raffleStatus, "Raffle already started.");
        require(_prizeAmount > 0, "Prize amount must be greater than 0!");
        require(_prizeAmount <= address(this).balance, "Not enough balance!");
        require(
            _numberOfWinners > 0,
            "Number of winners must be greater than 0."
        );

        prizeAmount = _prizeAmount;
        numberOfWinners = _numberOfWinners;
        raffleStatus = true;
        raffleEndTime = block.timestamp + (_duration * 1 minutes);
        raffleStartDuration = _duration;
        emit RaffleStarted(_prizeAmount, raffleEndTime, _numberOfWinners);
    }

    function getFreeTicket() public {
        require(raffleStatus, "Raffle is not started.");
        require(
            !hasEntered[msg.sender],
            "You have already claimed your free ticket."
        );

        players.push(msg.sender);
        hasEntered[msg.sender] = true;
        ticketsSoldThisRound += 1;
        emit NewEntry(msg.sender, ticketsSoldThisRound);

        if (getRemainingTimeSec() == 0 && players.length >= numberOfWinners) {
            selectWinners();
        }
    }

    function tryEndRaffle() public onlyOwner nonReentrant {
        require(raffleStatus, "Raffle is not started yet.");
        require(
            block.timestamp > raffleEndTime,
            "Raffle period has not ended yet!"
        );
        require(players.length > 0, "No players in raffle.");
        require(
            players.length >= numberOfWinners,
            "Not enough players to select winners."
        );

        selectWinners();
    }

    function selectWinners() private {
        uint256 prizePerWinner = prizeAmount / numberOfWinners;

        for (uint256 i = 0; i < numberOfWinners; i++) {
            uint256 winnerIndex = random() % players.length;
            address winner = players[winnerIndex];
            winnerAddresses.push(winner);
            payable(winner).transfer(prizePerWinner);
            winnerWins[winner] += 1;
            emit WinnerSelected(winner, prizePerWinner);
            removePlayer(winnerIndex);
        }

        endRaffle();
    }

    function removePlayer(uint256 index) private {
        if (index >= players.length) return;

        hasEntered[players[index]] = false;
        players[index] = players[players.length - 1];
        playerIndexes[players[index]] = index;
        players.pop();
    }

    function hardReset() public onlyOwner {
        endRaffle();
    }

    function endRaffle() private {
        raffleStatus = false;
        for (uint256 i = 0; i < players.length; i++) {
            hasEntered[players[i]] = false;
        }
        delete players;
        prizeAmount = 0;
        ticketsSoldThisRound = 0;
        emit RaffleEnded();
        delete winnerAddresses;
    }

    function random() private view returns (uint256) {
        return
            uint256(
                keccak256(
                    abi.encodePacked(
                        block.timestamp,
                        block.prevrandao,
                        players.length
                    )
                )
            );
    }

    function initialDeposit() public payable onlyOwner nonReentrant {
        require(msg.value > 0, "Deposit must be greater than 0");
    }

    function withdrawFunds() public payable onlyOwner nonReentrant {
        require(!raffleStatus, "Cannot withdraw before raffle has ended.");
        require(address(this).balance > 0, "No funds to withdraw");
        payable(owner).transfer(address(this).balance);
    }

    function getWinnerByIndex(
        uint256 index
    ) public view returns (address, uint256) {
        address winnerAddress = winnerAddresses[index];
        return (winnerAddress, winnerWins[winnerAddress]);
    }

    function getTotalWinners() public view returns (uint256) {
        return winnerAddresses.length;
    }

    function getRemainingTimeSec() public view returns (uint256) {
        if (block.timestamp >= raffleEndTime || !raffleStatus) {
            return 0;
        } else {
            return raffleEndTime - block.timestamp;
        }
    }

    function getRemainingTimeMin() public view returns (uint256) {
        if (block.timestamp >= raffleEndTime || !raffleStatus) {
            return 0;
        } else {
            uint256 remainingTimeInSeconds = raffleEndTime - block.timestamp;
            return remainingTimeInSeconds / 1 minutes;
        }
    }

    function getRemainingTimeHour() public view returns (uint256) {
        if (block.timestamp >= raffleEndTime || !raffleStatus) {
            return 0;
        } else {
            uint256 remainingTimeInSeconds = raffleEndTime - block.timestamp;
            return remainingTimeInSeconds / 1 hours;
        }
    }

    function getRaffleStartDuration() public view returns (uint256) {
        return raffleStartDuration;
    }

    function getContractBalance() public view returns (uint256) {
        return address(this).balance;
    }
}
合同源代码
文件 2 的 2:ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}
设置
{
  "compilationTarget": {
    "contracts/AdetSecmeli2.sol": "FreeTimerOnChainWinMultipleWinners2"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "remappings": []
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"numberOfEntries","type":"uint256"}],"name":"NewEntry","type":"event"},{"anonymous":false,"inputs":[],"name":"RaffleEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"numberOfWinners","type":"uint256"}],"name":"RaffleStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"prizeAmount","type":"uint256"}],"name":"WinnerSelected","type":"event"},{"inputs":[],"name":"getContractBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFreeTicket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRaffleStartDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTimeHour","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTimeMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingTimeSec","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalWinners","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getWinnerByIndex","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hardReset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasEntered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"numberOfWinners","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerIndexes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"players","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prizeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"raffleEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"raffleStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_prizeAmount","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_numberOfWinners","type":"uint256"}],"name":"startRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ticketsSoldThisRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tryEndRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"winnerAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"winnerWins","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFunds","outputs":[],"stateMutability":"payable","type":"function"}]