ETH Price: $2,074.77 (+11.99%)

Contract Diff Checker

Contract Name:
ETHCMiningPool

Contract Source Code:

File 1 of 1 : ETHCMiningPool

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;


abstract contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor(address owner_) {
        _transferOwnership(owner_);
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _checkOwner() internal view virtual {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

interface IETHC {

    struct Block {
        address[] miners;
        address selectedMiner;
        uint256 miningReward;
    }

    function mine(uint256 mineCount) external payable;
    function futureMine(uint256 mineCount, uint256 blockCounts) external payable;
    function revealSelectedMiner(uint256 targetBlock) external;

    function selectedMinerOfBlock(uint256 _blockNumber) external view returns (address);
    function minersOfBlockCount(uint256 _blockNumber) external view returns (uint256);
    function blockNumber() external view returns (uint256);
    function mineCost() external view returns (uint256);
    function blocks(uint256 blockNumber) external view returns (Block memory);
    function transfer(address to, uint value) external returns (bool);
    function balanceOf(address owner) external view returns (uint);
}


contract ETHCMiningPool is Ownable {
    
    IETHC public ETHC;
    uint256 contributionDenominator;
    mapping(uint256 => uint256) public totalBlockContribution;
    mapping(address => mapping(uint256 => uint256)) public minerContributionPerBlock;
    mapping(uint256 => uint8) public successfullyMined;
    mapping(uint256 => uint256) public miningReward;
    
    uint256 feesPayable;
    address feeCollector;

    // Fees set to 2% to start
    uint256 feeNumerator = 20;
    uint256 feeDenominator = 1000;

    bool _locked;

    modifier Lock {
        require(!_locked);
        _locked = true;
        _;
        _locked = false;
    }

    constructor(
        address tokenAddress,
        address feeCollector_
    ) Ownable(msg.sender) {
        ETHC = IETHC(tokenAddress);
        feeCollector = feeCollector_;
    }

    function mine(uint256 mineCount) public payable Lock {
        uint256 blockNumber = ETHC.blockNumber();
        minerContributionPerBlock[msg.sender][blockNumber] += mineCount;
        totalBlockContribution[blockNumber] += mineCount;
        ETHC.mine{value: msg.value}(mineCount);
    }

    function futureMine(uint256 mineCount, uint256 blockCounts) external payable Lock {
        uint256 blockNumber = ETHC.blockNumber();
        for (uint256 i=0; i<blockCounts; i++) {
            blockNumber += 1;
            minerContributionPerBlock[msg.sender][blockNumber] += mineCount;
            totalBlockContribution[blockNumber] += mineCount;
        }
        ETHC.futureMine{value: msg.value}(mineCount, blockCounts);
    }

    function resolveBlocks(uint256[] memory blockNumbers) external Lock {
        for (uint256 i=0; i<blockNumbers.length; i++) {
            uint256 blockNumber = blockNumbers[i];
            if (successfullyMined[blockNumber] != 0) { 
                continue;
            }

            address selectedMiner = ETHC.selectedMinerOfBlock(blockNumber);
            if (selectedMiner == address(0)) {
                continue;
            } else if (selectedMiner == address(this)) {
                successfullyMined[blockNumber] = 1;
                IETHC.Block memory blockData = ETHC.blocks(blockNumber);
                uint256 fees = blockData.miningReward * feeNumerator / feeDenominator;
                feesPayable += fees;
                miningReward[blockNumber] = blockData.miningReward - fees;
            } else {
                successfullyMined[blockNumber] = 2;
            }
        }
    }

    function collectBlocksRewards(uint256[] memory blockNumbers) external Lock {

        uint256 rewards = 0;

        for (uint256 i=0; i<blockNumbers.length; i++) {
            uint256 blockNumber = blockNumbers[i];
            // Case: succesfully mined unset
            if (successfullyMined[blockNumber] == 0) {
                address selectedMiner = ETHC.selectedMinerOfBlock(blockNumber);

                // Case: Still not mined
                if (selectedMiner == address(0)) {
                    continue;

                // Case: mined and the pool was selected
                } else if (selectedMiner == address(this)) {
                    successfullyMined[blockNumber] = 1;
                    IETHC.Block memory blockData = ETHC.blocks(blockNumber);
                    uint256 fees = blockData.miningReward * feeNumerator / feeDenominator;
                    feesPayable += fees;
                    miningReward[blockNumber] = blockData.miningReward - fees;

                // Case: mined and the pool was not selected
                } else {
                    successfullyMined[blockNumber] = 2;
                    continue;
                }

            // Case: we have already determined the pool was not selected
            } else if (successfullyMined[blockNumber] == 2) {
                continue;
            }

            rewards += miningReward[blockNumber] * minerContributionPerBlock[msg.sender][blockNumber] / totalBlockContribution[blockNumber];
            totalBlockContribution[blockNumber] -= minerContributionPerBlock[msg.sender][blockNumber];
            delete minerContributionPerBlock[msg.sender][blockNumber];
        }

        if (rewards > 0) {
            ETHC.transfer(msg.sender, rewards);
        }
    }

    function checkRewardsForBlocks(uint256[] memory blockNumbersToCheck) external view returns (uint256 totalRewards) {
        for (uint256 i; i<blockNumbersToCheck.length; i++) {
            uint256 blockNumber = blockNumbersToCheck[i];
            uint256 blockReward = 0;

            // Case: succesfully mined unset
            if (successfullyMined[blockNumber] == 0) {
                address selectedMiner = ETHC.selectedMinerOfBlock(blockNumber);

                // Case: Still not mined
                if (selectedMiner == address(0)) {
                    continue;

                // Case: mined and the pool was selected
                } else if (selectedMiner == address(this)) {
                    IETHC.Block memory blockData = ETHC.blocks(blockNumber);
                    uint256 fees = blockData.miningReward * feeNumerator / feeDenominator;
                    blockReward = blockData.miningReward - fees;
                // Case: mined and the pool was not selected
                } else {
                    continue;
                }
            // Case: we have already determined the pool was not selected
            } else if (successfullyMined[blockNumber] == 2) {
                continue;
            }

            totalRewards += blockReward * minerContributionPerBlock[msg.sender][blockNumber] / totalBlockContribution[blockNumber];
        }
    }

    function collectFee(uint256 amount) external onlyOwner {
        require(amount <= feesPayable);
        if (feesPayable > 0 && feeCollector != address(0)) {
            ETHC.transfer(feeCollector, amount == 0 ? feesPayable : amount);
        }
    }

    function setFeeCollector(address newFeeCollector) external onlyOwner {
        feeCollector = newFeeCollector;
    }

    function setFeeNumerator(uint256 newFeeNumerator) external onlyOwner {
        require(newFeeNumerator < feeNumerator);
        feeNumerator = newFeeNumerator;
    }

    function rescueRewards(uint256 amount) external onlyOwner {
        ETHC.transfer(msg.sender, amount);
    }

    receive() external payable Lock {
        uint256 mineCost = ETHC.mineCost();
        uint256 mineCount = msg.value / mineCost;
        uint256 totalCost = mineCost * mineCount;
        if (totalCost < address(this).balance) {
            msg.sender.call{value: address(this).balance - totalCost}("");
        }

        if (mineCount > 0) {
            mine(mineCount);
        }
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):