Skip to main content
PulseScanner.io

Address

0x08e5df3efbfe92fd6eb566f04e4c68ada0bbe9bf
Current Holdings
$0.00
TXs sent
not counted
First Active
2025-11-20
block 25,072,437
Last Active
258 days ago
block 25,426,894
Funded By
not identified

Net worth historyi

148 snapshots · to block 27,455,299coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchFlareXLotterysolc 0.8.29+commit.ab55807cruntime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.29;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title FlareX Holder Lottery
 * @notice Hourly lottery system that rewards random FLX holders
 * @dev Receives liquidity tax from FlareX token and distributes 30% to random eligible holders
 * 
 * Features:
 * - Hourly lottery draws (every 1 hour)
 * - Minimum 0.2% supply holding requirement (20,000 FLX)
 * - 30% of accumulated tokens distributed to winner
 * - Previous winners cannot win again
 * - Owner can withdraw remaining tokens
 * - Verifiable random winner selection
 */
contract FlareXLottery is Ownable {
    // Constants
    uint256 private constant TOTAL_SUPPLY = 10_000_000 * 10**18;
    uint256 public constant MIN_HOLDER_PERCENT = 20; // 0.2% = 20/10000
    uint256 public constant REWARD_PERCENT = 30; // 30% of pool
    uint256 public constant LOTTERY_INTERVAL = 1 hours;
    
    // State variables
    IERC20 public flxToken;
    uint256 public lastLotteryTime;
    uint256 public totalDraws;
    uint256 public totalRewardsDistributed;
    
    // Track previous winners
    mapping(address => bool) public hasWon;
    address[] public allWinners;
    
    // Lottery history
    struct LotteryDraw {
        uint256 drawNumber;
        uint256 timestamp;
        address winner;
        uint256 rewardAmount;
        uint256 eligibleHolders;
    }
    
    mapping(uint256 => LotteryDraw) public lotteryHistory;
    
    // Events
    event LotteryDrawn(
        uint256 indexed drawNumber,
        address indexed winner,
        uint256 rewardAmount,
        uint256 eligibleHolders,
        uint256 timestamp
    );
    event TokensWithdrawn(address indexed owner, uint256 amount);
    event LotteryIntervalUpdated(uint256 newInterval);
    
    /**
     * @notice Constructor - Initialize lottery contract
     * @param _flxToken Address of FlareX token contract
     */
    constructor(address _flxToken) Ownable(msg.sender) {
        require(_flxToken != address(0), "Invalid token address");
        flxToken = IERC20(_flxToken);
        lastLotteryTime = block.timestamp;
    }
    
    /**
     * @notice Calculate minimum FLX tokens required to be eligible
     * @return Minimum token amount (20,000 FLX = 0.2% of 10M supply)
     */
    function getMinimumHolding() public pure returns (uint256) {
        return (TOTAL_SUPPLY * MIN_HOLDER_PERCENT) / 10000; // 20,000 FLX
    }
    
    /**
     * @notice Check if address is eligible for lottery
     * @param holder Address to check
     * @return True if holder has minimum required balance and has not won before
     */
    function isEligible(address holder) public view returns (bool) {
        return flxToken.balanceOf(holder) >= getMinimumHolding() && !hasWon[holder];
    }
    
    /**
     * @notice Check if address has won before
     * @param holder Address to check
     * @return True if holder has won before
     */
    function hasPreviouslyWon(address holder) public view returns (bool) {
        return hasWon[holder];
    }
    
    /**
     * @notice Get total number of unique winners
     * @return Number of addresses that have won
     */
    function getTotalWinners() public view returns (uint256) {
        return allWinners.length;
    }
    
    /**
     * @notice Get all previous winners
     * @return Array of all winner addresses
     */
    function getAllWinners() public view returns (address[] memory) {
        return allWinners;
    }
    
    /**
     * @notice Get current lottery pool balance
     * @return Current FLX balance in contract
     */
    function getPoolBalance() public view returns (uint256) {
        return flxToken.balanceOf(address(this));
    }
    
    /**
     * @notice Calculate reward amount for next draw
     * @return 30% of current pool balance
     */
    function getNextRewardAmount() public view returns (uint256) {
        uint256 poolBalance = getPoolBalance();
        return (poolBalance * REWARD_PERCENT) / 100;
    }
    
    /**
     * @notice Check if lottery can be drawn
     * @return True if 1 hour has passed since last draw
     */
    function canDrawLottery() public view returns (bool) {
        return block.timestamp >= lastLotteryTime + LOTTERY_INTERVAL;
    }
    
    /**
     * @notice Get time remaining until next lottery
     * @return Seconds until next draw is available
     */
    function getTimeUntilNextDraw() public view returns (uint256) {
        if (canDrawLottery()) return 0;
        return (lastLotteryTime + LOTTERY_INTERVAL) - block.timestamp;
    }
    
    /**
     * @notice Draw lottery and select random winner
     * @param eligibleHolders Array of addresses that meet minimum holding requirement
     * @dev Anyone can call this function, but must provide eligible holders list
     */
    function drawLottery(address[] calldata eligibleHolders) external {
        require(canDrawLottery(), "Lottery interval not reached");
        require(eligibleHolders.length > 0, "No eligible holders provided");
        
        uint256 poolBalance = getPoolBalance();
        require(poolBalance > 0, "No tokens in pool");
        
        // Verify all provided addresses are eligible (have balance AND have not won before)
        for (uint256 i = 0; i < eligibleHolders.length; i++) {
            require(isEligible(eligibleHolders[i]), "Holder not eligible or already won");
            require(eligibleHolders[i] != address(0), "Invalid address");
        }
        
        // Select random winner using pseudo-random method
        uint256 randomIndex = _generateRandomNumber(eligibleHolders.length);
        address winner = eligibleHolders[randomIndex];
        
        // Calculate reward (30% of pool)
        uint256 rewardAmount = getNextRewardAmount();
        
        // Transfer reward to winner
        require(flxToken.transfer(winner, rewardAmount), "Transfer failed");
        
        // Mark winner as having won
        hasWon[winner] = true;
        allWinners.push(winner);
        
        // Update state
        totalDraws++;
        totalRewardsDistributed += rewardAmount;
        lastLotteryTime = block.timestamp;
        
        // Record lottery history
        lotteryHistory[totalDraws] = LotteryDraw({
            drawNumber: totalDraws,
            timestamp: block.timestamp,
            winner: winner,
            rewardAmount: rewardAmount,
            eligibleHolders: eligibleHolders.length
        });
        
        emit LotteryDrawn(
            totalDraws,
            winner,
            rewardAmount,
            eligibleHolders.length,
            block.timestamp
        );
    }
    
    /**
     * @notice Generate pseudo-random number for winner selection
     * @param max Maximum value (array length)
     * @return Random index
     * @dev Uses block data for randomness - suitable for low-stakes lottery
     */
    function _generateRandomNumber(uint256 max) private view returns (uint256) {
        uint256 random = uint256(
            keccak256(
                abi.encodePacked(
                    block.timestamp,
                    block.prevrandao,
                    msg.sender,
                    totalDraws,
                    getPoolBalance()
                )
            )
        );
        return random % max;
    }
    
    /**
     * @notice Owner withdraws tokens from contract
     * @param amount Amount to withdraw (0 = withdraw all)
     */
    function withdrawTokens(uint256 amount) external onlyOwner {
        uint256 balance = getPoolBalance();
        require(balance > 0, "No tokens to withdraw");
        
        uint256 withdrawAmount = amount == 0 ? balance : amount;
        require(withdrawAmount <= balance, "Insufficient balance");
        
        require(flxToken.transfer(msg.sender, withdrawAmount), "Transfer failed");
        
        emit TokensWithdrawn(msg.sender, withdrawAmount);
    }
    
    /**
     * @notice Get lottery draw details by draw number
     * @param drawNumber Draw number to query
     * @return Lottery draw details
     */
    function getLotteryDraw(uint256 drawNumber) external view returns (LotteryDraw memory) {
        require(drawNumber > 0 && drawNumber <= totalDraws, "Invalid draw number");
        return lotteryHistory[drawNumber];
    }
    
    /**
     * @notice Get recent lottery draws
     * @param count Number of recent draws to return
     * @return Array of recent lottery draws
     */
    function getRecentDraws(uint256 count) external view returns (LotteryDraw[] memory) {
        if (totalDraws == 0) {
            return new LotteryDraw[](0);
        }
        
        uint256 returnCount = count > totalDraws ? totalDraws : count;
        LotteryDraw[] memory draws = new LotteryDraw[](returnCount);
        
        for (uint256 i = 0; i < returnCount; i++) {
            draws[i] = lotteryHistory[totalDraws - i];
        }
        
        return draws;
    }
    
    /**
     * @notice Get lottery statistics
     * @return totalDrawsCount Total number of draws
     * @return totalRewards Total rewards distributed
     * @return currentPool Current pool balance
     * @return nextReward Next reward amount
     * @return timeUntilNext Time until next draw
     */
    function getLotteryStats() external view returns (
        uint256 totalDrawsCount,
        uint256 totalRewards,
        uint256 currentPool,
        uint256 nextReward,
        uint256 timeUntilNext
    ) {
        return (
            totalDraws,
            totalRewardsDistributed,
            getPoolBalance(),
            getNextRewardAmount(),
            getTimeUntilNextDraw()
        );
    }
}