Main

0x5f623dcf224ea704d7cc840b37752f30efd8f110

Verification
Verified
v0.8.27+commit.40a35a09
Type
Contract
11,254 bytes
ABI entries
94
27 read · 24 write
License
mit

Contract information

Address
0x5f623dcf224ea704d7cc840b37752f30efd8f110
Chain
Robinhood Chain (4663)
Compiler
v0.8.27+commit.40a35a09
Optimization
Enabled
Creation tx
0xe0eda03aef…626b4558e4

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (27)

STARTER_FACILITY_INDEX()uint256
STARTER_MINER_INDEX()uint256
acquiredStarterMiner(address)bool
burnPct()uint256
cash()address
cooldown()uint256
facilities(uint256)uint256, uint256, uint256, bool, uint256, uint256
facilityCount()uint256
getPlayerMinersPaginated(address, uint256, uint256)tuple[]
getReferrals(address)address[]
initializedStarterFacility(address)bool
lastFacilityUpgradeTimestamp(address)uint256
lottery()address
minerSecondHandMarket(uint256)uint256
miners(uint256)uint256, uint256, uint256, uint256, uint256, uint256, uint256, bool
owner()address
ownerToFacility(address)uint256, uint256, uint256, uint256, uint256, uint256, uint256
playerHashrate(address)uint256
playerMinersId(uint256)uint256, uint256, uint256, uint256, uint256, uint256, uint256, bool
playerMinersOwned(address)uint256
playerOccupiedCoords(address, uint256, uint256)bool
referrals(address)address
referredUsers(address, uint256)address
robbersCorporation()address
timeUntilNextFacilityUpgrade(address)uint256
totalHashrate()uint256
uniqueMinerCount()uint256

Events (15)

FacilityBoughtFacilityCostChangedFacilityProductionToggledInitialFacilityPurchasedLotteryUpdatedMinerBoughtMinerCostChangedMinerProductionToggledMinerSecondaryMarketAddedMinerSoldNewFacilityAddedNewMinerAddedOwnershipTransferredPlayerHashrateDecreasedPlayerHashrateIncreased

ABI

[
  {
    "inputs": [],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "AlreadyAtMaxFacility",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "AlreadyPurchasedInitialFactory",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "CantBuyNewFacilityYet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "CantModifyStarterFacility",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "CantModifyStarterMiner",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "CorporationNotSet",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "FacilityDimensionsInvalid",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "FacilityInadequatePowerOutput",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "GreatDepression",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "IndexOutOfBounds",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidFacilityIndex",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidFee",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidMinerCoordinates",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidMinerIndex",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidPowerOutput",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidReferrer",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MinerNotInProduction",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NeedToInitializeFacility",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NewFacilityNotInProduction",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NonExistentFacility",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NonExistentMiner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PlayerDoesNotOwnMiner",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "StarterMinerAlreadyAcquired",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TooPoor",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "WithdrawFailed",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "player",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "facilityIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      }
    ],
    "name": "FacilityBought",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "facilityIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "newCost",
        "type": "uint256"
      }
    ],
    "name": "FacilityCostChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "facilityIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "name": "FacilityProductionToggled",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "player",
        "type": "address"
      }
    ],
    "name": "InitialFacilityPurchased",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "oldLottery",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newLottery",
        "type": "address"
      }
    ],
    "name": "LotteryUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "payer",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "player",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "minerId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "name": "MinerBought",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "newCost",
        "type": "uint256"
      }
    ],
    "name": "MinerCostChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "name": "MinerProductionToggled",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "price",
        "type": "uint256"
      }
    ],
    "name": "MinerSecondaryMarketAdded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "player",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "secondHandPrice",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "minerId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "name": "MinerSold",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "facilityIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "totalPowerOutput",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "name": "NewFacilityAdded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "hashRate",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "powerConsumption",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "name": "NewMinerAdded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "player",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "playerHashrate",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "playerPendingRewards",
        "type": "uint256"
      }
    ],
    "name": "PlayerHashrateDecreased",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "player",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "playerHashrate",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "playerPendingRewards",
        "type": "uint256"
      }
    ],
    "name": "PlayerHashrateIncreased",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "STARTER_FACILITY_INDEX",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "STARTER_MINER_INDEX",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "acquiredStarterMiner",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "maxMiners",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "totalPowerOutput",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      },
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "name": "addFacility",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "hashrate",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "powerConsumption",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "name": "addMiner",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "price",
        "type": "uint256"
      }
    ],
    "name": "addSecondaryMarketForMiner",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "burnPct",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "name": "buyMiner",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "_receiver",
        "type": "address"
      }
    ],
    "name": "buyMinerFor",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "buyNewFacility",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "cash",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "facilityIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "newCost",
        "type": "uint256"
      }
    ],
    "name": "changeFacilityCost",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "newCost",
        "type": "uint256"
      }
    ],
    "name": "changeMinerCost",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "cooldown",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "facilities",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "maxMiners",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "totalPowerOutput",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      },
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "facilityCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "name": "getFreeStarterMiner",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "player",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "startIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "size",
        "type": "uint256"
      }
    ],
    "name": "getPlayerMinersPaginated",
    "outputs": [
      {
        "components": [
          {
            "internalType": "uint256",
            "name": "minerIndex",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "id",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "x",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "y",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "hashrate",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "powerConsumption",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "cost",
            "type": "uint256"
          },
          {
            "internalType": "bool",
            "name": "inProduction",
            "type": "bool"
          }
        ],
        "internalType": "struct Miner[]",
        "name": "",
        "type": "tuple[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "referrer",
        "type": "address"
      }
    ],
    "name": "getReferrals",
    "outputs": [
      {
        "internalType": "address[]",
        "name": "",
        "type": "address[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "governanceRecoverUnsupported",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "initializedStarterFacility",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "lastFacilityUpgradeTimestamp",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lottery",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "minerSecondHandMarket",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "miners",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "hashrate",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "powerConsumption",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "ownerToFacility",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "facilityIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxMiners",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "currMiners",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "totalPowerOutput",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "currPowerOutput",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "playerHashrate",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "playerMinersId",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "x",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "y",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "hashrate",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "powerConsumption",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "cost",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "playerMinersOwned",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "_spacer",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "playerOccupiedCoords",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "referrer",
        "type": "address"
      }
    ],
    "name": "purchaseInitialFacility",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "referrals",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "referredUsers",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "robbersCorporation",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "minerId",
        "type": "uint256"
      }
    ],
    "name": "sellMiner",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "burn",
        "type": "uint256"
      }
    ],
    "name": "setBurnPct",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_cash",
        "type": "address"
      }
    ],
    "name": "setCash",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_robbersCorporation",
        "type": "address"
      }
    ],
    "name": "setCashersCorporation",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "_cooldown",
        "type": "uint256"
      }
    ],
    "name": "setCooldown",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_lottery",
        "type": "address"
      }
    ],
    "name": "setLottery",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "player",
        "type": "address"
      }
    ],
    "name": "syncPlayerHashrate",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "player",
        "type": "address"
      }
    ],
    "name": "timeUntilNextFacilityUpgrade",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "facilityIndex",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "name": "toggleFacilityProduction",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "minerIndex",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "inProduction",
        "type": "bool"
      }
    ],
    "name": "toggleMinerProduction",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalHashrate",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "uniqueMinerCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "withdraw",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "amt",
        "type": "uint256"
      }
    ],
    "name": "withdrawCash",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

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

import {Ownable} from "./openzeppelin/access/Ownable.sol";
import {EnumerableSetLib} from "./solady/utils/EnumerableSetLib.sol";
import {FixedPointMathLib} from "./solady/utils/FixedPointMathLib.sol";

import {ICash} from "./interfaces/ICash.sol";
import {ILotteryHashrate} from "./interfaces/ILotteryHashrate.sol";

import {Miner} from "./types/Miner.sol";
import {Facility} from "./types/Facility.sol";
import {NewFacility} from "./types/NewFacility.sol";

import {Errors} from "./libraries/Errors.sol";
import {Events} from "./libraries/Events.sol";

// Cash main program
contract Main is Ownable {
    using EnumerableSetLib for EnumerableSetLib.Uint256Set;

    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    //            STORAGE
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    /// @dev Cash token address.
    address public cash;

    /// @dev robbersCorporation fee recipient.
    address public robbersCorporation;
    
    /// @dev CASH lottery that receives exact player hashrate updates.
    address public lottery;

    // every miner has an id
    uint256 universalMinerId;

    /// @dev Total unique miners.
    uint256 public uniqueMinerCount;

    /// @dev Total facilities.
    uint256 public facilityCount;

    /// @dev Total network hashrate.
    uint256 public totalHashrate;

    /// @dev Initial cooldown time is 24H.
    uint256 public cooldown = 24 hours;

    /// @dev Initial burn is 75%.
    uint256 public burnPct = 0.75e18;

    /// @dev Players total hashrate.
    mapping(address => uint256) public playerHashrate;

    /// @dev Tracks different miners and its stats.
    mapping(uint256 => Miner) public miners;

    /// @dev Tracks different facilities and its stats.
    mapping(uint256 => NewFacility) public facilities;

    /// @dev Tracks how many of each miner a player has. Only tracks Id.
    mapping(address => EnumerableSetLib.Uint256Set) public playerMinersOwned;

    /// @dev Maps minerId to the actual miner struct
    mapping(uint256 => Miner) public playerMinersId;

    /// @dev Tracks players facility stats.
    mapping(address => Facility) public ownerToFacility;

    /// @dev Tracks new players initializing in the game.
    mapping(address => bool) public initializedStarterFacility;

    /// @dev Tracks if a player has acquired a free miner.
    mapping(address => bool) public acquiredStarterMiner;

    /// @dev Tracks if a there's a secondary market for a certain miner.
    mapping(uint256 => uint256) public minerSecondHandMarket;

    /// @dev Tracks each miners coords for a player
    mapping(address => mapping(uint256 => mapping(uint256 => bool))) public playerOccupiedCoords;

    mapping(address => uint256) public lastFacilityUpgradeTimestamp;

    /// @dev Tracks referrals.
    mapping(address => address) public referrals;

    /// @dev Tracks referred users.
    mapping(address => address[]) public referredUsers;

    /// @dev start miner and facility index (these will never change since every player starts with same facility).
    uint256 public immutable STARTER_MINER_INDEX;
    uint256 public immutable STARTER_FACILITY_INDEX;

    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    //          CONSTRUCTOR
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    constructor() Ownable(msg.sender) {
        STARTER_MINER_INDEX = ++uniqueMinerCount;

        // add starter free miner
        miners[STARTER_MINER_INDEX] = Miner(
            STARTER_MINER_INDEX,
            type(uint256).max,
            type(uint256).max,
            type(uint256).max,
            100,
            1,
            type(uint256).max, // this is the free starter miner, people cannot buy it
            false
        );

        // add starter facility
        facilities[++facilityCount] = NewFacility(
            4,
            28,
            type(uint256).max, // starter facility, people cannot buy it
            false,
            2,
            2
        );

        STARTER_FACILITY_INDEX = facilityCount;
    }

    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    //        USER FUNCTIONS
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    /**
     * @dev All new players claim the initial facility for free.
     * Players can only purchase upgrades after claiming the initial facility.
     */
    function purchaseInitialFacility(address referrer) external {
        if (initializedStarterFacility[msg.sender]) {
            revert Errors.AlreadyPurchasedInitialFactory();
        }

        if (referrer == msg.sender) {
            revert Errors.InvalidReferrer();
        }

        initializedStarterFacility[msg.sender] = true;

        if (referrer != address(0)) {
            referrals[msg.sender] = referrer;
            referredUsers[referrer].push(msg.sender);
        }

        NewFacility memory newFacility = facilities[STARTER_FACILITY_INDEX];
        Facility storage facility = ownerToFacility[msg.sender];

        // initialize players starter facility
        facility.facilityIndex = STARTER_FACILITY_INDEX;
        facility.maxMiners = newFacility.maxMiners;
        facility.totalPowerOutput = newFacility.totalPowerOutput;
        facility.x = newFacility.x;
        facility.y = newFacility.y;

        emit Events.InitialFacilityPurchased(msg.sender);
    }

    /**
     * @dev All new players can redeem 1 free miner.
     *
     * Players are not required to redeem a free miner.
     */
    function getFreeStarterMiner(uint256 x, uint256 y) external {
        if (acquiredStarterMiner[msg.sender]) {
            revert Errors.StarterMinerAlreadyAcquired();
        }

        acquiredStarterMiner[msg.sender] = true;

        Miner memory miner = miners[STARTER_MINER_INDEX];
        Facility storage facility = ownerToFacility[msg.sender];

        if (_isInvalidCoordinates(x, y, facility.x, facility.y)) {
            revert Errors.InvalidMinerCoordinates();
        }

        if (facility.currPowerOutput + miner.powerConsumption > facility.totalPowerOutput) {
            revert Errors.FacilityInadequatePowerOutput();
        }

        miner.x = x;
        miner.y = y;
        miner.id = ++universalMinerId;
        playerOccupiedCoords[msg.sender][x][y] = true;

        playerMinersOwned[msg.sender].add(universalMinerId);
        playerMinersId[universalMinerId] = miner;

        // increase facility miners
        facility.currMiners++;

        // increase power consumption from factory
        facility.currPowerOutput += miner.powerConsumption;

        // emit Events.FreeMinerRedeemed(msg.sender);
        emit Events.MinerBought(msg.sender, msg.sender, STARTER_MINER_INDEX, 0, universalMinerId, x, y);

        _increaseHashrate(msg.sender, miner.hashrate);
    }

    function buyMiner(uint256 minerIndex, uint256 x, uint256 y) external {
        _buyMiner(minerIndex, x, y, msg.sender);
    }

    function buyMinerFor(uint256 minerIndex, uint256 x, uint256 y, address _receiver) external {
        _buyMiner(minerIndex, x, y, _receiver);
    }

    /**
     * @dev Purchase new miners using cash.
     */
    function _buyMiner(uint256 minerIndex, uint256 x, uint256 y, address _receiver) internal {
        // check user has enough funds for miner and facility allows it
        Miner memory miner = miners[minerIndex];
        Facility storage facility = ownerToFacility[_receiver];

        if (_isInvalidCoordinates(x, y, facility.x, facility.y)) {
            revert Errors.InvalidMinerCoordinates();
        }

        // this case will cover if an index too large is passed in
        if (!miner.inProduction) revert Errors.MinerNotInProduction();

        if (ICash(cash).balanceOf(msg.sender) < miner.cost) {
            revert Errors.TooPoor();
        }

        if (facility.currPowerOutput + miner.powerConsumption > facility.totalPowerOutput) {
            revert Errors.FacilityInadequatePowerOutput();
        }

        // Transfer the price, burn the configured share, and route the remainder immediately.
        ICash(cash).transferFrom(msg.sender, address(this), miner.cost);
        _splitPurchasePayment(miner.cost);

        miner.x = x;
        miner.y = y;
        miner.id = ++universalMinerId;
        playerOccupiedCoords[_receiver][x][y] = true;

        playerMinersOwned[_receiver].add(universalMinerId);
        playerMinersId[universalMinerId] = miner;

        // increase facility miners
        facility.currMiners++;

        // increase power consumption from factory
        facility.currPowerOutput += miner.powerConsumption;

        emit Events.MinerBought(msg.sender, _receiver, minerIndex, miner.cost, universalMinerId, x, y);

        _increaseHashrate(_receiver, miner.hashrate);
    }

    /**
     * @dev Sell miners, if there's a secondary market, player will get cash in return.
     *
     * Players will sell miners in the case they run out of spots in their facility to put new miners.
     */
    function sellMiner(uint256 minerId) external {
        if (!playerMinersOwned[msg.sender].contains(minerId)) {
            revert Errors.PlayerDoesNotOwnMiner();
        }

        Miner memory miner = playerMinersId[minerId];

        uint256 secondHandPrice = minerSecondHandMarket[miner.minerIndex];

        // if there's not enough cash in this contract to pay out, revert
        if (secondHandPrice > ICash(cash).balanceOf(address(this))) {
            revert Errors.GreatDepression();
        }

        Facility storage facility = ownerToFacility[msg.sender];

        // decrease facility miners
        facility.currMiners--;

        // decrease power consumption from factory
        facility.currPowerOutput -= miner.powerConsumption;

        playerMinersOwned[msg.sender].remove(minerId);
        delete playerMinersId[minerId];
        playerOccupiedCoords[msg.sender][miner.x][miner.y] = false;

        emit Events.MinerSold(msg.sender, miner.minerIndex, secondHandPrice, minerId, miner.x, miner.y);

        _decreaseHashrate(msg.sender, miner.hashrate);

        if (secondHandPrice > 0) {
            ICash(cash).transfer(msg.sender, secondHandPrice);
        }
    }

    /**
     * @dev Purchase larger or more power output facility.
     *
     * Players must linearly climb the facilities.
     */
    function buyNewFacility() external {
        // need to purchase initial facility first
        if (!initializedStarterFacility[msg.sender]) {
            revert Errors.NeedToInitializeFacility();
        }

        Facility storage currFacility = ownerToFacility[msg.sender];
        uint256 currFacilityIndex = currFacility.facilityIndex;

        if (currFacilityIndex == facilityCount) {
            revert Errors.AlreadyAtMaxFacility();
        }

        // 24H cooldown between each facility upgrade
        if (block.timestamp - lastFacilityUpgradeTimestamp[msg.sender] < cooldown) {
            revert Errors.CantBuyNewFacilityYet();
        }

        NewFacility memory newFacility = facilities[currFacilityIndex + 1];

        if (!newFacility.inProduction) {
            revert Errors.NewFacilityNotInProduction();
        }

        if (ICash(cash).balanceOf(msg.sender) < newFacility.cost) {
            revert Errors.TooPoor();
        }

        ICash(cash).transferFrom(msg.sender, address(this), newFacility.cost);
        _splitPurchasePayment(newFacility.cost);

        currFacility.facilityIndex++;
        currFacility.maxMiners = newFacility.maxMiners;
        currFacility.totalPowerOutput = newFacility.totalPowerOutput;
        currFacility.x = newFacility.x;
        currFacility.y = newFacility.y;

        lastFacilityUpgradeTimestamp[msg.sender] = block.timestamp;

        emit Events.FacilityBought(msg.sender, currFacility.facilityIndex, newFacility.cost);
    }

    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    //       INTERNAL FUNCTIONS
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    /**
     * @dev Increase players hashrate.
     */
    function _increaseHashrate(address player, uint256 hashrate) internal {
        totalHashrate += hashrate;
        playerHashrate[player] += hashrate;

        _syncPlayerHashrate(player);

        emit Events.PlayerHashrateIncreased(player, playerHashrate[player], 0);
    }

    /**
     * @dev Decrease players hashrate.
     */
    function _decreaseHashrate(address player, uint256 hashrate) internal {
        totalHashrate -= hashrate;
        playerHashrate[player] -= hashrate;

        _syncPlayerHashrate(player);

        emit Events.PlayerHashrateDecreased(player, playerHashrate[player], 0);
    }

    function _syncPlayerHashrate(address player) internal {
        if (lottery != address(0)) {
            ILotteryHashrate(lottery).setPlayerHashrate(player, playerHashrate[player]);
        }
    }

    function _splitPurchasePayment(uint256 amount) internal {
        uint256 burned = FixedPointMathLib.mulWad(amount, burnPct);
        if (burned > 0) ICash(cash).burn(burned);

        uint256 corporationShare = amount - burned;
        if (corporationShare > 0) {
            if (robbersCorporation == address(0)) revert Errors.CorporationNotSet();
            ICash(cash).transfer(robbersCorporation, corporationShare);
        }
    }

    /**
     * @dev checks the miners x,y coords are within bounds and there isn't an existent miner at that position.
     */
    function _isInvalidCoordinates(uint256 desiredX, uint256 desiredY, uint256 facilityX, uint256 facilityY)
        internal
        view
        returns (bool)
    {
        if (desiredX >= facilityX || desiredY >= facilityY) {
            return true;
        }

        return playerOccupiedCoords[msg.sender][desiredX][desiredY];
    }

    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    //         VIEW FUNCTIONS
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    /**
     * @dev Get next available facility upgrade time.
     */
    function timeUntilNextFacilityUpgrade(address player) external view returns (uint256) {
        if (lastFacilityUpgradeTimestamp[player] + cooldown < block.timestamp) {
            return 0;
        }

        return (lastFacilityUpgradeTimestamp[player] + cooldown) - block.timestamp;
    }

    /**
     * @dev Get all miners for a player.
     */
    function getPlayerMinersPaginated(address player, uint256 startIndex, uint256 size)
        external
        view
        returns (Miner[] memory)
    {
        EnumerableSetLib.Uint256Set storage set = playerMinersOwned[player];
        uint256 length = set.length();

        // Return empty array if start index is beyond array bounds
        if (startIndex >= length) {
            return new Miner[](0);
        }

        // Calculate how many items we can actually return
        uint256 remaining = length - startIndex;
        uint256 returnSize = size > remaining ? remaining : size;

        Miner[] memory playerMiners = new Miner[](returnSize);
        for (uint256 i = 0; i < returnSize; i++) {
            playerMiners[i] = playerMinersId[set.at(startIndex + i)];
        }

        return playerMiners;
    }

    /**
     * @dev Get all referred users.
     */
    function getReferrals(address referrer) external view returns (address[] memory) {
        return referredUsers[referrer];
    }

    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    //        OWNER FUNCTIONS
    // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

    /**
     * @dev Add new miner to game.
     */
    function addMiner(uint256 hashrate, uint256 powerConsumption, uint256 cost, bool inProduction) external onlyOwner {
        // must increment first cause compiler evaluates function arg before evaluating the assignment
        ++uniqueMinerCount;
        miners[uniqueMinerCount] = Miner(uniqueMinerCount, 0, 0, 0, hashrate, powerConsumption, cost, inProduction);

        emit Events.NewMinerAdded(uniqueMinerCount, hashrate, powerConsumption, cost, inProduction);
    }

    /**
     * @dev Allows or prevents miner from being purchased.
     *
     * Miners cannot be removed, only toggled off from purchased.
     */
    function toggleMinerProduction(uint256 minerIndex, bool inProduction) external onlyOwner {
        if (minerIndex < STARTER_MINER_INDEX || minerIndex > uniqueMinerCount) {
            revert Errors.InvalidMinerIndex();
        }
        Miner storage miner = miners[minerIndex];
        miner.inProduction = inProduction;

        emit Events.MinerProductionToggled(minerIndex, inProduction);
    }

    /**
     * @dev Add new facility to game.
     */
    function addFacility(
        uint256 maxMiners,
        uint256 totalPowerOutput,
        uint256 cost,
        bool inProduction,
        uint256 x,
        uint256 y
    ) external onlyOwner {
        if (x * y != maxMiners) {
            revert Errors.FacilityDimensionsInvalid();
        }

        if (facilities[facilityCount].x > x || facilities[facilityCount].y > y) {
            revert Errors.FacilityDimensionsInvalid();
        }

        if (facilities[facilityCount].totalPowerOutput > totalPowerOutput) {
            revert Errors.InvalidPowerOutput();
        }

        facilities[++facilityCount] = NewFacility(maxMiners, totalPowerOutput, cost, inProduction, x, y);

        emit Events.NewFacilityAdded(facilityCount, totalPowerOutput, cost, inProduction, x, y);
    }

    /**
     * @dev Allows or prevents new facilities from being purchased.
     *
     * New facilities cannot be removed, only toggled off from purchased.
     */
    function toggleFacilityProduction(uint256 facilityIndex, bool inProduction) external onlyOwner {
        if (facilityIndex < STARTER_FACILITY_INDEX || facilityIndex > facilityCount) {
            revert Errors.InvalidFacilityIndex();
        }

        NewFacility storage facility = facilities[facilityIndex];
        facility.inProduction = inProduction;

        emit Events.FacilityProductionToggled(facilityIndex, inProduction);
    }

    /**
     * @dev Add secondary market for a miner.
     */
    function addSecondaryMarketForMiner(uint256 minerIndex, uint256 price) external onlyOwner {
        minerSecondHandMarket[minerIndex] = price;

        emit Events.MinerSecondaryMarketAdded(minerIndex, price);
    }

    function setCash(address _cash) external onlyOwner {
        cash = _cash;
    }

    function setLottery(address _lottery) external onlyOwner {
        address oldLottery = lottery;
        lottery = _lottery;
        emit Events.LotteryUpdated(oldLottery, _lottery);
    }

    /// @notice Re-publish a player's current hashrate after a lottery migration.
    function syncPlayerHashrate(address player) external {
        _syncPlayerHashrate(player);
    }

    function setCashersCorporation(address _robbersCorporation) external onlyOwner {
        robbersCorporation = _robbersCorporation;
    }

    function setBurnPct(uint256 burn) external onlyOwner {
        if (burn > 1e18) revert Errors.InvalidFee();

        burnPct = burn;
    }

    function setCooldown(uint256 _cooldown) external onlyOwner {
        cooldown = _cooldown;
    }

    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        (bool success,) = payable(robbersCorporation).call{value: balance}("");

        if (!success) revert Errors.WithdrawFailed();
    }

    function withdrawCash(uint256 amt) external onlyOwner {
        ICash(cash).transfer(robbersCorporation, amt);
    }

    function changeMinerCost(uint256 minerIndex, uint256 newCost) external onlyOwner {
        if (minerIndex > uniqueMinerCount) {
            revert Errors.NonExistentMiner();
        }

        if (minerIndex == STARTER_MINER_INDEX) {
            revert Errors.CantModifyStarterMiner();
        }

        Miner storage miner = miners[minerIndex];

        miner.cost = newCost;

        emit Events.MinerCostChanged(minerIndex, newCost);
    }

    function changeFacilityCost(uint256 facilityIndex, uint256 newCost) external onlyOwner {
        if (facilityIndex > facilityCount) {
            revert Errors.NonExistentFacility();
        }

        if (facilityIndex == STARTER_FACILITY_INDEX) {
            revert Errors.CantModifyStarterFacility();
        }

        NewFacility storage facility = facilities[facilityIndex];

        facility.cost = newCost;

        emit Events.FacilityCostChanged(facilityIndex, newCost);
    }

    function governanceRecoverUnsupported(address _token, uint256 amount, address to) external onlyOwner {
        ICash(_token).transfer(to, amount);
    }
}
Chain explorer4790msChain node82ms