// Contract: MagicHash
// Target function: function completeRound() public onlyOwner
//   ⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣾⣿⣿⣿⣿⣷⣶⣦⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀
//   ⠀⠀⠀⠀⠀⣠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⠀⠀⠀⠀⠀
//   ⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀
//   ⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⠟⠿⠿⡿⠀⢰⣿⠁⢈⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀
//   ⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣤⣄⠀⠀⠀⠈⠉⠀⠸⠿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀
//   ⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⢠⣶⣶⣤⡀⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⡆
//   ⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠼⣿⣿⡿⠃⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣷
//   ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⢀⣀⣀⠀⠀⠀⠀⢴⣿⣿⣿⣿⣿⣿⣿⣿⣿
//   ⢿⣿⣿⣿⣿⣿⣿⣿⢿⣿⠁⠀⠀⣼⣿⣿⣿⣦⠀⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⡿
//   ⠸⣿⣿⣿⣿⣿⣿⣏⠀⠀⠀⠀⠀⠛⠛⠿⠟⠋⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⠇
//   ⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⣤⡄⠀⣀⣀⣀⣀⣠⣾⣿⣿⣿⣿⣿⣿⣿⡟⠀
//   ⠀⠀⠻⣿⣿⣿⣿⣿⣿⣿⣄⣰⣿⠁⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀
//    ⠀⠀⠀⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀
//   ⠀⠀⠀⠀⠀⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⠀⠀⠀⠀⠀
//   ⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⢿⣿⣿⣿⣿⡿⠿⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
//
// Built By MagicByt3 - BitcoinTalk.org 
// MagicHash: Unite to Rent Hashpower and Mine Bitcoin Blocks Collectively
// 
// Pool your Ethereum to collectively rent hashpower aimed at solving Bitcoin blocks.
// Be part of a community-driven mining operation while maintaining transparency and trust.
// Each round has a predefined maximum limit and deposit size. Once the pool is full, the
// collected Ethereum is used to rent hashpower, targeting the hardcoded Bitcoin mining address.
// Block details are recorded for verification, and users specify their BTC payout addresses at time of deposit.
// Mining is conducted on the CKSolo pool https://solo.ckpool.org/ * This project is not operated in any way by the pool!
// Mining can be tracked at the following URL https://solo.ckpool.org/users/bc1qy7xdv25rv5ejkh4vkv4m8x7ctyzagma62ef0eh
// SPDX-License-Identifier: MIT - MagicByt3 2023
pragma solidity ^0.8.18;

// MagicHash Smart Contract
contract MagicHash {
    
    // State variables
    address public owner;  // Contract owner's address
    string public miningBTCAddress;  // Hardcoded BTC mining address
    
    // Struct to store user's deposited information
    struct UserInfo {
        uint256 ethDeposited;  // Amount of ETH deposited
        string btcPayoutAddress;  // User's BTC payout address
    }

    // Struct to store information about a found block
    struct BlockFoundInfo {
        string ipfsHash;  // IPFS hash containing additional info
        string transactionID;  // Transaction ID of the found block
        string blockHeight;  // Height of the found block
        string payoutAddress;  // BTC address for the mining reward
        uint256 timestamp;  // Timestamp when the block was found
        string blockHash;  // Hash of the found block
    }

    // Struct to store round information
    struct RoundInfo {
        uint256 maxLimit;  // Maximum limit of ETH for the round
        uint256 depositSize;  // Required deposit size for the round
        uint256 currentTotal;  // Current total ETH deposited in the round
        bool isComplete;  // Whether the round is complete
    }

    // Mappings and Arrays
    mapping(address => UserInfo) public userInfo;  // Mapping of user to their info
    BlockFoundInfo[] public blockFoundDetails;  // Array to store found block details
    RoundInfo[] public rounds;  // Array to store round details
    mapping(uint256 => address[]) public roundDepositors;  // Mapping of round to its depositors

    // Track the current round
    uint256 public currentRound;

    // Events
    event Deposited(address indexed user, uint256 amount, string btcPayoutAddress);
    event WithdrawnByOwner(uint256 amount);
    event BlockFound(string ipfsHash);
    event NewRoundConfigured(uint256 maxLimit, uint256 depositSize);
    event Refunded(address indexed user, uint256 amount);

    // Constructor to initialize contract
    constructor() {
        owner = msg.sender;
        miningBTCAddress = "bc1qy7xdv25rv5ejkh4vkv4m8x7ctyzagma62ef0eh";

        // Initialize the first round
        RoundInfo memory initialRound = RoundInfo({
            maxLimit: 1 ether,
            depositSize: 0.1 ether,
            currentTotal: 0,
            isComplete: false
        });
        rounds.push(initialRound);
        currentRound = 0;
    }

    // Modifier to restrict function to only owner
    modifier onlyOwner() {
        require(msg.sender == owner, "Not the owner");
        _;
    }

    // Function for users to deposit ETH
    function deposit(string memory btcPayoutAddress) public payable {
        require(!rounds[currentRound].isComplete, "Round is complete");
        require(msg.value == rounds[currentRound].depositSize, "Must deposit in specified size for the round");

        uint256 newTotal = rounds[currentRound].currentTotal + msg.value;
        require(newTotal <= rounds[currentRound].maxLimit, "Exceeds maximum limit for the round");

        userInfo[msg.sender].ethDeposited += msg.value;
        userInfo[msg.sender].btcPayoutAddress = btcPayoutAddress;

        rounds[currentRound].currentTotal = newTotal;

        roundDepositors[currentRound].push(msg.sender);

        emit Deposited(msg.sender, msg.value, btcPayoutAddress);
    }

    // Function for the owner to configure a new round
    function configureNewRound(uint256 maxLimit, uint256 depositSize) public onlyOwner {
        RoundInfo memory newRound = RoundInfo({
            maxLimit: maxLimit,
            depositSize: depositSize,
            currentTotal: 0,
            isComplete: false
        });
        rounds.push(newRound);
        currentRound++;

        emit NewRoundConfigured(maxLimit, depositSize);
    }