EarlyAccess

Description:

Smart contract deployed on Ethereum.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

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

contract EarlyAccess {
    // Tracks prepaw selections: player => optionId => quantity selected
    mapping(address => mapping(uint256 => uint256)) public prepaws;
    
    // Track total selected per option
    mapping(uint256 => uint256) public totalPrePawsPerOption;
    
    // Track all unique players who purchased
    address[] public players;
    mapping(address => bool) public hasPrePawed;
    
    // Track all unique referrers (separate from players - can refer without buying)
    address[] public referrers;
    mapping(address => bool) public isReferrer;
    
    // Referral tracking: referrer => tier => count
    mapping(address => mapping(uint256 => uint256)) public referralsByTier;
    mapping(address => uint256) public totalReferrals;
    
    // Track WHO was referred by each referrer and WHICH tier they bought
    mapping(address => address[]) public referredPlayers;
    mapping(address => uint256[]) public referredPlayerTiers;
    
    // Option quantities
    uint256[4] public optionQuantities = [1, 3, 5, 10];
    
    // Max supply per tier
    uint256[4] public maxSupplyPerTier;
    
    // Price per unit in wei (0.025 ETH)
    uint256 public constant PRICE_PER_UNIT = 0.025 ether;
    
    address public owner;
    bool public paused;
    
    event PrePaw(address indexed player, uint256 indexed optionId, uint256 quantity, address indexed referrer);
    event Withdrawal(address indexed to, uint256 amount);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event Paused(address account);
    event Unpaused(address account);
    event MaxSupplyUpdated(uint256 indexed optionId, uint256 newMaxSupply);
    event Referral(address indexed referrer, address indexed player, uint256 indexed optionId);
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    modifier whenNotPaused() {
        require(!paused, "Presale is paused");
        _;
    }
    
    constructor() {
        owner = msg.sender;
        paused = false;
        
        // Set initial max supplies: [500, 200, 25, 10]
        maxSupplyPerTier[0] = 500;
        maxSupplyPerTier[1] = 200;
        maxSupplyPerTier[2] = 25;
        maxSupplyPerTier[3] = 10;
    }
    
    function prePaw(uint256 optionId, address referrer) external payable whenNotPaused {
        require(optionId < 4, "Invalid option");
        require(totalPrePawsPerOption[optionId] < maxSupplyPerTier[optionId], "Tier sold out");
        require(prepaws[msg.sender][optionId] == 0, "Already purchased this tier");
        require(referrer != msg.sender, "Cannot refer yourself");
        
        uint256 quantity = optionQuantities[optionId];
        uint256 cost = quantity * PRICE_PER_UNIT;
        
        require(msg.value == cost, "Incorrect payment");
        
        // Track first-time players
        if (!hasPrePawed[msg.sender]) {
            players.push(msg.sender);
            hasPrePawed[msg.sender] = true;
        }
        
        prepaws[msg.sender][optionId] += 1;
        totalPrePawsPerOption[optionId] += 1;
        
        // Track referral if valid referrer provided
        if (referrer != address(0)) {
            // Track first-time referrers
            if (!isReferrer[referrer]) {
                referrers.push(referrer);
                isReferrer[referrer] = true;
            }
            
            referralsByTier[referrer][optionId] += 1;
            totalReferrals[referrer] += 1;
            referredPlayers[referrer].push(msg.sender);
            referredPlayerTiers[referrer].push(optionId);
            emit Referral(referrer, msg.sender, optionId);
        }
        
        emit PrePaw(msg.sender, optionId, quantity, referrer);
    }
    
    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        require(balance > 0, "No funds");
        
        (bool success, ) = owner.call{value: balance}("");
        require(success, "Transfer failed");
        
        emit Withdrawal(owner, balance);
    }
    
    function emergencyWithdraw(address payable recipient) external onlyOwner {
        require(recipient != address(0), "Invalid recipient");
        uint256 balance = address(this).balance;
        require(balance > 0, "No funds");
        
        (bool success, ) = recipient.call{value: balance}("");
        require(success, "Transfer failed");
        
        emit Withdrawal(recipient, balance);
    }
    
    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "New owner is zero address");
        address oldOwner = owner;
        owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
    
    function pause() external onlyOwner {
        paused = true;
        emit Paused(msg.sender);
    }
    
    function unpause() external onlyOwner {
        paused = false;
        emit Unpaused(msg.sender);
    }
    
    function setMaxSupply(uint256 optionId, uint256 newMaxSupply) external onlyOwner {
        require(optionId < 4, "Invalid option");
        require(newMaxSupply >= totalPrePawsPerOption[optionId], "Cannot set below current sales");
        maxSupplyPerTier[optionId] = newMaxSupply;
        emit MaxSupplyUpdated(optionId, newMaxSupply);
    }
    
    function getAllPrePaws(address player) external view returns (uint256[4] memory) {
        return [
            prepaws[player][0],
            prepaws[player][1],
            prepaws[player][2],
            prepaws[player][3]
        ];
    }
    
    function getPrePaws(address player, uint256 optionId) external view returns (uint256) {
        return prepaws[player][optionId];
    }
    
    function getPrice(uint256 optionId) external view returns (uint256) {
        require(optionId < 4, "Invalid option");
        return optionQuantities[optionId] * PRICE_PER_UNIT;
    }
    
    function getBalance() external view returns (uint256) {
        return address(this).balance;
    }
    
    function getTotalPlayers() external view returns (uint256) {
        return players.length;
    }
    
    function getAllPlayers() external view returns (address[] memory) {
        return players;
    }
    
    function getPlayerAtIndex(uint256 index) external view returns (address) {
        require(index < players.length, "Index out of bounds");
        return players[index];
    }
    
    function getMaxSupply(uint256 optionId) external view returns (uint256) {
        require(optionId < 4, "Invalid option");
        return maxSupplyPerTier[optionId];
    }
    
    function getRemainingSupply(uint256 optionId) external view returns (uint256) {
        require(optionId < 4, "Invalid option");
        return maxSupplyPerTier[optionId] - totalPrePawsPerOption[optionId];
    }
    
    function getReferralsByTier(address referrer) external view returns (uint256[4] memory) {
        return [
            referralsByTier[referrer][0],
            referralsByTier[referrer][1],
            referralsByTier[referrer][2],
            referralsByTier[referrer][3]
        ];
    }
    
    function getTotalReferrals(address referrer) external view returns (uint256) {
        return totalReferrals[referrer];
    }
    
    function getReferralsForTier(address referrer, uint256 optionId) external view returns (uint256) {
        require(optionId < 4, "Invalid option");
        return referralsByTier[referrer][optionId];
    }
    
    function getTotalReferrers() external view returns (uint256) {
        return referrers.length;
    }
    
    // BATCH FUNCTIONS
    
    function getPlayerDataBatch(uint256 startIndex, uint256 count) 
        external 
        view 
        returns (
            address[] memory addresses,
            uint256[4][] memory purchases
        ) 
    {
        require(count <= 50, "Max 50 per batch");
        
        uint256 totalPlayers = players.length;
        if (startIndex >= totalPlayers) {
            return (new address[](0), new uint256[4][](0));
        }
        
        uint256 endIndex = startIndex + count;
        if (endIndex > totalPlayers) {
            endIndex = totalPlayers;
        }
        
        uint256 resultCount = endIndex - startIndex;
        addresses = new address[](resultCount);
        purchases = new uint256[4][](resultCount);
        
        for (uint256 i = 0; i < resultCount; i++) {
            address player = players[startIndex + i];
            addresses[i] = player;
            purchases[i] = [
                prepaws[player][0],
                prepaws[player][1],
                prepaws[player][2],
                prepaws[player][3]
            ];
        }
        
        return (addresses, purchases);
    }
    
    function getReferralDataBatch(uint256 startIndex, uint256 count)
        external
        view
        returns (
            address[] memory addresses,
            uint256[4][] memory referralsByTierData,
            uint256[] memory totalReferralsData
        )
    {
        require(count <= 50, "Max 50 per batch");
        
        uint256 totalReferrersCount = referrers.length;
        if (startIndex >= totalReferrersCount) {
            return (new address[](0), new uint256[4][](0), new uint256[](0));
        }
        
        uint256 endIndex = startIndex + count;
        if (endIndex > totalReferrersCount) {
            endIndex = totalReferrersCount;
        }
        
        uint256 resultCount = endIndex - startIndex;
        addresses = new address[](resultCount);
        referralsByTierData = new uint256[4][](resultCount);
        totalReferralsData = new uint256[](resultCount);
        
        for (uint256 i = 0; i < resultCount; i++) {
            address referrer = referrers[startIndex + i];
            addresses[i] = referrer;
            referralsByTierData[i] = [
                referralsByTier[referrer][0],
                referralsByTier[referrer][1],
                referralsByTier[referrer][2],
                referralsByTier[referrer][3]
            ];
            totalReferralsData[i] = totalReferrals[referrer];
        }
        
        return (addresses, referralsByTierData, totalReferralsData);
    }
    
    function getReferredPlayersBatch(address referrer, uint256 startIndex, uint256 count)
        external
        view
        returns (
            address[] memory referredAddresses,
            uint256[] memory tiers
        )
    {
        require(count <= 50, "Max 50 per batch");
        
        address[] storage referred = referredPlayers[referrer];
        uint256 totalReferred = referred.length;
        
        if (startIndex >= totalReferred) {
            return (new address[](0), new uint256[](0));
        }
        
        uint256 endIndex = startIndex + count;
        if (endIndex > totalReferred) {
            endIndex = totalReferred;
        }
        
        uint256 resultCount = endIndex - startIndex;
        referredAddresses = new address[](resultCount);
        tiers = new uint256[](resultCount);
        
        for (uint256 i = 0; i < resultCount; i++) {
            referredAddresses[i] = referredPlayers[referrer][startIndex + i];
            tiers[i] = referredPlayerTiers[referrer][startIndex + i];
        }
        
        return (referredAddresses, tiers);
    }
    
    function getTotalReferredPlayers(address referrer) external view returns (uint256) {
        return referredPlayers[referrer].length;
    }
}

Tags:
addr:0x95435066504872ad5b874f78433d81481125043d|verified:true|block:23699937|tx:0x438b9111bde160483d0342dad8055512a41150895f0d6b4f3e230117fd49a086|first_check:1761989099

Submitted on: 2025-11-01 10:24:59

Comments

Log in to comment.

No comments yet.