// SPDX-License-Identifier: MIT pragma solidity 0.8.30; /// @notice A finite ETH faucet. It does not mine ETH. One claim per address, /// not per person: creating new wallets can bypass the address limit. contract StockMineRewards { uint256 public constant REWARD = 0.000001 ether; uint256 public constant FUND_CAP = 0.03 ether; address public owner; bool public paused = true; uint256 public totalFunded; uint256 public totalPaid; mapping(address => bool) public claimed; bool private entered; error WrongNetwork(); error Unauthorized(); error IsPaused(); error AlreadyClaimed(); error EmptyFund(); error InvalidFunding(); error TransferFailed(); error ReentrantCall(); error MustPause(); event Funded(address indexed sender, uint256 amount); event Claimed(address indexed recipient, uint256 amount); event PauseChanged(bool paused); event ReturnedToOwner(uint256 amount); constructor() { if (block.chainid != 1) revert WrongNetwork(); owner = msg.sender; } modifier onlyOwner() { if (msg.sender != owner) revert Unauthorized(); _; } modifier nonReentrant() { if (entered) revert ReentrantCall(); entered = true; _; entered = false; } function fund() external payable onlyOwner { if (msg.value == 0 || totalFunded + msg.value > FUND_CAP) revert InvalidFunding(); totalFunded += msg.value; emit Funded(msg.sender, msg.value); } function setPaused(bool value) external onlyOwner { if (!value && address(this).balance < REWARD) revert EmptyFund(); paused = value; emit PauseChanged(value); } function claim() external nonReentrant { if (block.chainid != 1) revert WrongNetwork(); if (paused) revert IsPaused(); if (claimed[msg.sender]) revert AlreadyClaimed(); if (address(this).balance < REWARD) revert EmptyFund(); claimed[msg.sender] = true; totalPaid += REWARD; (bool success,) = payable(msg.sender).call{value: REWARD}(""); if (!success) revert TransferFailed(); emit Claimed(msg.sender, REWARD); } /// @notice Owner can recover unused funds only while claims are paused. function returnUnusedFunds() external onlyOwner nonReentrant { if (!paused) revert MustPause(); uint256 value = address(this).balance; if (value == 0) revert EmptyFund(); (bool success,) = payable(owner).call{value: value}(""); if (!success) revert TransferFailed(); emit ReturnedToOwner(value); } }