More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 438,894 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Claim Rewards | 6576676 | 8 secs ago | IN | 0 ETH | 0.00000639 | ||||
Purchase Initial... | 6576674 | 10 secs ago | IN | 0.0075 ETH | 0.00000664 | ||||
Get Free Starter... | 6576673 | 11 secs ago | IN | 0 ETH | 0.00000536 | ||||
Claim Rewards | 6576672 | 12 secs ago | IN | 0 ETH | 0.00000564 | ||||
Claim Rewards | 6576668 | 16 secs ago | IN | 0 ETH | 0.00000712 | ||||
Claim Rewards | 6576666 | 18 secs ago | IN | 0 ETH | 0.00000677 | ||||
Get Free Starter... | 6576665 | 19 secs ago | IN | 0 ETH | 0.00000536 | ||||
Claim Rewards | 6576664 | 20 secs ago | IN | 0 ETH | 0.00000612 | ||||
Claim Rewards | 6576661 | 23 secs ago | IN | 0 ETH | 0.00000576 | ||||
Claim Rewards | 6576661 | 23 secs ago | IN | 0 ETH | 0.00000572 | ||||
Claim Rewards | 6576658 | 26 secs ago | IN | 0 ETH | 0.0000064 | ||||
Claim Rewards | 6576657 | 27 secs ago | IN | 0 ETH | 0.00000444 | ||||
Get Free Starter... | 6576649 | 35 secs ago | IN | 0 ETH | 0.00000536 | ||||
Claim Rewards | 6576649 | 35 secs ago | IN | 0 ETH | 0.00000669 | ||||
Claim Rewards | 6576647 | 37 secs ago | IN | 0 ETH | 0.00000733 | ||||
Purchase Initial... | 6576644 | 40 secs ago | IN | 0.0075 ETH | 0.00000847 | ||||
Claim Rewards | 6576643 | 41 secs ago | IN | 0 ETH | 0.00000564 | ||||
Claim Rewards | 6576642 | 42 secs ago | IN | 0 ETH | 0.00000573 | ||||
Claim Rewards | 6576642 | 42 secs ago | IN | 0 ETH | 0.00000564 | ||||
Purchase Initial... | 6576641 | 43 secs ago | IN | 0.0075 ETH | 0.00000806 | ||||
Claim Rewards | 6576639 | 45 secs ago | IN | 0 ETH | 0.00000642 | ||||
Purchase Initial... | 6576639 | 45 secs ago | IN | 0.0075 ETH | 0.00000634 | ||||
Get Free Starter... | 6576637 | 47 secs ago | IN | 0 ETH | 0.00000536 | ||||
Claim Rewards | 6576630 | 54 secs ago | IN | 0 ETH | 0.00000665 | ||||
Claim Rewards | 6576630 | 54 secs ago | IN | 0 ETH | 0.00000669 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
6576674 | 10 secs ago | 0.0075 ETH | ||||
6576644 | 40 secs ago | 0.0075 ETH | ||||
6576641 | 43 secs ago | 0.0075 ETH | ||||
6576639 | 45 secs ago | 0.0075 ETH | ||||
6576614 | 1 min ago | 0.0075 ETH | ||||
6576580 | 1 min ago | 0.0075 ETH | ||||
6576557 | 2 mins ago | 0.0075 ETH | ||||
6576520 | 2 mins ago | 0.0075 ETH | ||||
6576468 | 3 mins ago | 0.0075 ETH | ||||
6576456 | 3 mins ago | 0.0075 ETH | ||||
6576428 | 4 mins ago | 0.0075 ETH | ||||
6576375 | 5 mins ago | 0.0075 ETH | ||||
6576349 | 5 mins ago | 0.0075 ETH | ||||
6576294 | 6 mins ago | 0.0075 ETH | ||||
6576262 | 7 mins ago | 0.0075 ETH | ||||
6576256 | 7 mins ago | 0.0075 ETH | ||||
6576230 | 7 mins ago | 0.0075 ETH | ||||
6576211 | 8 mins ago | 0.0075 ETH | ||||
6576190 | 8 mins ago | 0.0075 ETH | ||||
6576181 | 8 mins ago | 0.0075 ETH | ||||
6576165 | 8 mins ago | 0.0075 ETH | ||||
6576163 | 8 mins ago | 0.0075 ETH | ||||
6576057 | 10 mins ago | 0.0075 ETH | ||||
6576043 | 10 mins ago | 0.0075 ETH | ||||
6576040 | 10 mins ago | 0.0075 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
Main
Compiler Version
v0.8.26+commit.8a97fa7a
ZkSolc Version
v1.5.11
Optimization Enabled:
Yes with Mode 3
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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 {IBigcoin} from "./interfaces/IBigcoin.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"; // Bigcoin main program contract Main is Ownable { using EnumerableSetLib for EnumerableSetLib.Uint256Set; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // STORAGE // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /// @dev Bigcoin token address. address public bigcoin; /// @dev bigtoshi fee recipient. address public bigtoshi; /// @dev Mining start block. uint256 public startBlock; bool public miningHasStarted; // every miner has an id uint256 universalMinerId; /// @dev Total unique miners. uint256 public uniqueMinerCount; /// @dev Total facilities. uint256 public facilityCount; /// @dev Tracks last time we updated rewards. uint256 public lastRewardBlock; /// @dev Total network hashrate. uint256 public totalHashrate; /// @dev Tracks bigcoin per single hash. uint256 public cumulativeBigcoinPerHash; /// @dev Initial cooldown time is 24H. uint256 public cooldown = 24 hours; /// @dev Initial referral fee is 2.5%. uint256 public referralFee = 0.025e18; /// @dev Initial burn is 75%. uint256 public burnPct = 0.75e18; /// @dev Players total hashrate. mapping(address => uint256) public playerHashrate; /// @dev Players pending rewards. mapping(address => uint256) public playerPendingRewards; /// @dev Players debt (updated after rewards are updated for a player). mapping(address => uint256) public playerBigcoinDebt; /// @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 Track how much each referrer got paid. mapping(address => uint256) public referralBonusPaid; /// @dev Purchasing initial facility price in ETH. uint256 public initialFacilityPrice = 0.005 ether; /// @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; /// @dev Halvening every 4,200,000 blocks, roughly 50 days uint256 public constant HALVING_INTERVAL = 4_200_000; /// @dev Initial bigcoin per block uint256 public constant INITIAL_BIGCOIN_PER_BLOCK = 2.5e18; // 2.5 Bigcoin per block uint256 public constant REWARDS_PRECISION = 1e18; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // 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 must purchase an initial facility with ETH. * * Players can only purchase new facilities after acquiring initial Facility. */ function purchaseInitialFacility(address referrer) external payable { if (msg.value != initialFacilityPrice) { revert Errors.IncorrectValue(); } 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, STARTER_MINER_INDEX, 0, universalMinerId, x, y); _increaseHashrate(msg.sender, miner.hashrate); } /** * @dev Purchase new miners using bigcoin. */ function buyMiner(uint256 minerIndex, uint256 x, uint256 y) external { // check user has enough funds for miner and facility allows it Miner memory miner = miners[minerIndex]; Facility storage facility = ownerToFacility[msg.sender]; 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 (IBigcoin(bigcoin).balanceOf(msg.sender) < miner.cost) { revert Errors.TooPoor(); } if (facility.currPowerOutput + miner.powerConsumption > facility.totalPowerOutput) { revert Errors.FacilityInadequatePowerOutput(); } // transfer correct amt of bigcoin IBigcoin(bigcoin).transferFrom(msg.sender, address(this), miner.cost); // burn IBigcoin(bigcoin).burn(FixedPointMathLib.mulWad(miner.cost, burnPct)); 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.MinerBought(msg.sender, minerIndex, miner.cost, universalMinerId, x, y); _increaseHashrate(msg.sender, miner.hashrate); } /** * @dev Sell miners, if there's a secondary market, player will get bigcoin 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 bigcoin in this contract to pay out, revert if (secondHandPrice > IBigcoin(bigcoin).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) { IBigcoin(bigcoin).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 (IBigcoin(bigcoin).balanceOf(msg.sender) < newFacility.cost) { revert Errors.TooPoor(); } IBigcoin(bigcoin).transferFrom(msg.sender, address(this), newFacility.cost); // burn IBigcoin(bigcoin).burn(FixedPointMathLib.mulWad(newFacility.cost, burnPct)); 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); } /** * @dev Claim rewards for player. */ function claimRewards() external { _updateRewards(msg.sender); uint256 rewards = playerPendingRewards[msg.sender]; if (rewards == 0) { revert Errors.NoRewardsPending(); } playerPendingRewards[msg.sender] = 0; // referral bonus uint256 referralBonus = FixedPointMathLib.mulWad(rewards, referralFee); uint256 finalRewards = rewards - referralBonus; IBigcoin(bigcoin).mint(msg.sender, finalRewards); address referrer = referrals[msg.sender]; if (referrer != address(0)) { IBigcoin(bigcoin).mint(referrer, referralBonus); referralBonusPaid[referrer] += referralBonus; } else { // else mint referral fee to this contract IBigcoin(bigcoin).mint(address(this), referralBonus); referralBonusPaid[address(this)] += referralBonus; } emit Events.RewardsClaimed(msg.sender, rewards); } // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // INTERNAL FUNCTIONS // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /** * @dev Update global cumulative rewards before game state changes. */ function _updateCumulativeRewards() internal { if (totalHashrate == 0) { lastRewardBlock = block.number; return; } // if we have not updated rewards and a halvening occurs, we must add the different // bigcoin emissions per halvening uint256 currentBlock = lastRewardBlock; uint256 lastBigcoinPerBlock = INITIAL_BIGCOIN_PER_BLOCK / (2 ** ((lastRewardBlock - startBlock) / HALVING_INTERVAL)); while (currentBlock < block.number) { uint256 nextHalvingBlock = (startBlock % HALVING_INTERVAL) + ((currentBlock / HALVING_INTERVAL) + 1) * HALVING_INTERVAL; uint256 endBlock = (nextHalvingBlock < block.number) ? nextHalvingBlock : block.number; // apply correct emission rate for this segment cumulativeBigcoinPerHash += ((lastBigcoinPerBlock * (endBlock - currentBlock) * REWARDS_PRECISION) / totalHashrate); // move to next segment currentBlock = endBlock; // if a halving has happened, apply the new rate if (currentBlock == nextHalvingBlock) { lastBigcoinPerBlock /= 2; } } lastRewardBlock = block.number; } function _updateRewards(address player) internal { _updateCumulativeRewards(); playerPendingRewards[player] += (playerHashrate[player] * (cumulativeBigcoinPerHash - playerBigcoinDebt[player])) / REWARDS_PRECISION; playerBigcoinDebt[player] = cumulativeBigcoinPerHash; } /** * @dev Increase players hashrate. */ function _increaseHashrate(address player, uint256 hashrate) internal { // only start rewarding bigcoin per block when the first miner is added if (!miningHasStarted) { miningHasStarted = true; startBlock = block.number; lastRewardBlock = block.number; emit Events.MiningStarted(startBlock); } // update rewards and global state before modifying players state _updateRewards(player); totalHashrate += hashrate; playerHashrate[player] += hashrate; emit Events.PlayerHashrateIncreased(msg.sender, playerHashrate[player], playerPendingRewards[player]); } /** * @dev Decrease players hashrate. */ function _decreaseHashrate(address player, uint256 hashrate) internal { // update rewards and global state before modifying players state _updateRewards(player); totalHashrate -= hashrate; playerHashrate[player] -= hashrate; emit Events.PlayerHashrateDecreased(msg.sender, playerHashrate[player], playerPendingRewards[player]); } /** * @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 the current mining emission rate based on halvings */ function getBigcoinPerBlock() public view returns (uint256) { if (!miningHasStarted) { return 0; } uint256 halvingsSinceStart = (block.number - startBlock) / HALVING_INTERVAL; return INITIAL_BIGCOIN_PER_BLOCK / (2 ** halvingsSinceStart); } /** * @dev Get current pending rewards for player. */ function pendingRewards(address player) external view returns (uint256) { // below is basically the same logic as _updateCumulativeRewards() but doesnt change state if (!miningHasStarted) { return 0; } if (totalHashrate == 0) { return FixedPointMathLib.mulWad(playerPendingRewards[player], 1e18 - referralFee); } uint256 currentBlock = lastRewardBlock; uint256 lastBigcoinPerBlock = INITIAL_BIGCOIN_PER_BLOCK / (2 ** ((lastRewardBlock - startBlock) / HALVING_INTERVAL)); uint256 simulatedCumulativeBigcoinPerHash = cumulativeBigcoinPerHash; while (currentBlock < block.number) { uint256 nextHalvingBlock = (startBlock % HALVING_INTERVAL) + ((currentBlock / HALVING_INTERVAL) + 1) * HALVING_INTERVAL; uint256 endBlock = (nextHalvingBlock < block.number) ? nextHalvingBlock : block.number; // simulate rewards accumulation if (totalHashrate > 0) { simulatedCumulativeBigcoinPerHash += ((lastBigcoinPerBlock * (endBlock - currentBlock) * REWARDS_PRECISION) / totalHashrate); } // move to next segment currentBlock = endBlock; // if we reached a halving point, apply the new emission rate if (currentBlock == nextHalvingBlock) { lastBigcoinPerBlock /= 2; } } return FixedPointMathLib.mulWad( playerPendingRewards[player] + ( (playerHashrate[player] * (simulatedCumulativeBigcoinPerHash - playerBigcoinDebt[player])) / REWARDS_PRECISION ), 1e18 - referralFee ); } /** * @dev Get current bigcoin a player mines per block. */ function playerBigcoinPerBlock(address player) external view returns (uint256) { if (totalHashrate == 0) { return 0; // Prevent division by zero } uint256 currBigcoinPerBlock = INITIAL_BIGCOIN_PER_BLOCK / (2 ** ((block.number - startBlock) / HALVING_INTERVAL)); return FixedPointMathLib.mulDiv(playerHashrate[player], currBigcoinPerBlock, totalHashrate); } /** * @dev Get blocks till next halvening. */ function blocksUntilNextHalving() external view returns (uint256) { if (startBlock == 0) revert Errors.MiningHasntStarted(); uint256 nextHalvingBlock = (startBlock % HALVING_INTERVAL) + ((block.number / HALVING_INTERVAL) + 1) * HALVING_INTERVAL; return nextHalvingBlock - block.number; } /** * @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 setBigcoin(address _bigcoin) external onlyOwner { bigcoin = _bigcoin; } function setBigtoshi(address _bigtoshi) external onlyOwner { bigtoshi = _bigtoshi; } function setInitialFacilityPrice(uint256 _initialPrice) external onlyOwner { initialFacilityPrice = _initialPrice; } function setReferralFee(uint256 fee) external onlyOwner { if (fee > 1e18) revert Errors.InvalidFee(); referralFee = fee; } 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(bigtoshi).call{value: balance}(""); if (!success) revert Errors.WithdrawFailed(); } function withdrawBigcoin(uint256 amt) external onlyOwner { IBigcoin(bigcoin).transfer(bigtoshi, 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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for managing enumerable sets in storage. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EnumerableSetLib.sol) /// /// @dev Note: /// In many applications, the number of elements in an enumerable set is small. /// This enumerable set implementation avoids storing the length and indices /// for up to 3 elements. Once the length exceeds 3 for the first time, the length /// and indices will be initialized. The amortized cost of adding elements is O(1). /// /// The AddressSet implementation packs the length with the 0th entry. /// /// All enumerable sets except Uint8Set use a pop and swap mechanism to remove elements. /// This means that the iteration order of elements can change between element removals. library EnumerableSetLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The index must be less than the length. error IndexOutOfBounds(); /// @dev The value cannot be the zero sentinel. error ValueIsZeroSentinel(); /// @dev Cannot accommodate a new unique value with the capacity. error ExceedsCapacity(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A sentinel value to denote the zero value in storage. /// No elements can be equal to this value. /// `uint72(bytes9(keccak256(bytes("_ZERO_SENTINEL"))))`. uint256 private constant _ZERO_SENTINEL = 0xfbb67fda52d4bfb8bf; /// @dev The storage layout is given by: /// ``` /// mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED) /// mstore(0x00, set.slot) /// let rootSlot := keccak256(0x00, 0x24) /// mstore(0x20, rootSlot) /// mstore(0x00, shr(96, shl(96, value))) /// let positionSlot := keccak256(0x00, 0x40) /// let valueSlot := add(rootSlot, sload(positionSlot)) /// let valueInStorage := shr(96, sload(valueSlot)) /// let lazyLength := shr(160, shl(160, sload(rootSlot))) /// ``` uint256 private constant _ENUMERABLE_ADDRESS_SET_SLOT_SEED = 0x978aab92; /// @dev The storage layout is given by: /// ``` /// mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED) /// mstore(0x00, set.slot) /// let rootSlot := keccak256(0x00, 0x24) /// mstore(0x20, rootSlot) /// mstore(0x00, value) /// let positionSlot := keccak256(0x00, 0x40) /// let valueSlot := add(rootSlot, sload(positionSlot)) /// let valueInStorage := sload(valueSlot) /// let lazyLength := sload(not(rootSlot)) /// ``` uint256 private constant _ENUMERABLE_WORD_SET_SLOT_SEED = 0x18fb5864; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An enumerable address set in storage. struct AddressSet { uint256 _spacer; } /// @dev An enumerable bytes32 set in storage. struct Bytes32Set { uint256 _spacer; } /// @dev An enumerable uint256 set in storage. struct Uint256Set { uint256 _spacer; } /// @dev An enumerable int256 set in storage. struct Int256Set { uint256 _spacer; } /// @dev An enumerable uint8 set in storage. Useful for enums. struct Uint8Set { uint256 data; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GETTERS / SETTERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of elements in the set. function length(AddressSet storage set) internal view returns (uint256 result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let rootPacked := sload(rootSlot) let n := shr(160, shl(160, rootPacked)) result := shr(1, n) for {} iszero(or(iszero(shr(96, rootPacked)), n)) {} { result := 1 if iszero(sload(add(rootSlot, result))) { break } result := 2 if iszero(sload(add(rootSlot, result))) { break } result := 3 break } } } /// @dev Returns the number of elements in the set. function length(Bytes32Set storage set) internal view returns (uint256 result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let n := sload(not(rootSlot)) result := shr(1, n) for {} iszero(n) {} { result := 0 if iszero(sload(add(rootSlot, result))) { break } result := 1 if iszero(sload(add(rootSlot, result))) { break } result := 2 if iszero(sload(add(rootSlot, result))) { break } result := 3 break } } } /// @dev Returns the number of elements in the set. function length(Uint256Set storage set) internal view returns (uint256 result) { result = length(_toBytes32Set(set)); } /// @dev Returns the number of elements in the set. function length(Int256Set storage set) internal view returns (uint256 result) { result = length(_toBytes32Set(set)); } /// @dev Returns the number of elements in the set. function length(Uint8Set storage set) internal view returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let packed := sload(set.slot) } packed { result := add(1, result) } { packed := xor(packed, and(packed, add(1, not(packed)))) } } } /// @dev Returns whether `value` is in the set. function contains(AddressSet storage set, address value) internal view returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { value := shr(96, shl(96, value)) if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } let rootPacked := sload(rootSlot) for {} 1 {} { if iszero(shr(160, shl(160, rootPacked))) { result := 1 if eq(shr(96, rootPacked), value) { break } if eq(shr(96, sload(add(rootSlot, 1))), value) { break } if eq(shr(96, sload(add(rootSlot, 2))), value) { break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) result := iszero(iszero(sload(keccak256(0x00, 0x40)))) break } } } /// @dev Returns whether `value` is in the set. function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } for {} 1 {} { if iszero(sload(not(rootSlot))) { result := 1 if eq(sload(rootSlot), value) { break } if eq(sload(add(rootSlot, 1)), value) { break } if eq(sload(add(rootSlot, 2)), value) { break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) result := iszero(iszero(sload(keccak256(0x00, 0x40)))) break } } } /// @dev Returns whether `value` is in the set. function contains(Uint256Set storage set, uint256 value) internal view returns (bool result) { result = contains(_toBytes32Set(set), bytes32(value)); } /// @dev Returns whether `value` is in the set. function contains(Int256Set storage set, int256 value) internal view returns (bool result) { result = contains(_toBytes32Set(set), bytes32(uint256(value))); } /// @dev Returns whether `value` is in the set. function contains(Uint8Set storage set, uint8 value) internal view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := and(1, shr(and(0xff, value), sload(set.slot))) } } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(AddressSet storage set, address value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { value := shr(96, shl(96, value)) if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } let rootPacked := sload(rootSlot) for { let n := shr(160, shl(160, rootPacked)) } 1 {} { mstore(0x20, rootSlot) if iszero(n) { let v0 := shr(96, rootPacked) if iszero(v0) { sstore(rootSlot, shl(96, value)) result := 1 break } if eq(v0, value) { break } let v1 := shr(96, sload(add(rootSlot, 1))) if iszero(v1) { sstore(add(rootSlot, 1), shl(96, value)) result := 1 break } if eq(v1, value) { break } let v2 := shr(96, sload(add(rootSlot, 2))) if iszero(v2) { sstore(add(rootSlot, 2), shl(96, value)) result := 1 break } if eq(v2, value) { break } mstore(0x00, v0) sstore(keccak256(0x00, 0x40), 1) mstore(0x00, v1) sstore(keccak256(0x00, 0x40), 2) mstore(0x00, v2) sstore(keccak256(0x00, 0x40), 3) rootPacked := or(rootPacked, 7) n := 7 } mstore(0x00, value) let p := keccak256(0x00, 0x40) if iszero(sload(p)) { n := shr(1, n) result := 1 sstore(p, add(1, n)) if iszero(n) { sstore(rootSlot, or(3, shl(96, value))) break } sstore(add(rootSlot, n), shl(96, value)) sstore(rootSlot, add(2, rootPacked)) break } break } } } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(Bytes32Set storage set, bytes32 value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } for { let n := sload(not(rootSlot)) } 1 {} { mstore(0x20, rootSlot) if iszero(n) { let v0 := sload(rootSlot) if iszero(v0) { sstore(rootSlot, value) result := 1 break } if eq(v0, value) { break } let v1 := sload(add(rootSlot, 1)) if iszero(v1) { sstore(add(rootSlot, 1), value) result := 1 break } if eq(v1, value) { break } let v2 := sload(add(rootSlot, 2)) if iszero(v2) { sstore(add(rootSlot, 2), value) result := 1 break } if eq(v2, value) { break } mstore(0x00, v0) sstore(keccak256(0x00, 0x40), 1) mstore(0x00, v1) sstore(keccak256(0x00, 0x40), 2) mstore(0x00, v2) sstore(keccak256(0x00, 0x40), 3) n := 7 } mstore(0x00, value) let p := keccak256(0x00, 0x40) if iszero(sload(p)) { n := shr(1, n) sstore(add(rootSlot, n), value) sstore(p, add(1, n)) sstore(not(rootSlot), or(1, shl(1, add(1, n)))) result := 1 break } break } } } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(Uint256Set storage set, uint256 value) internal returns (bool result) { result = add(_toBytes32Set(set), bytes32(value)); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(Int256Set storage set, int256 value) internal returns (bool result) { result = add(_toBytes32Set(set), bytes32(uint256(value))); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. function add(Uint8Set storage set, uint8 value) internal returns (bool result) { /// @solidity memory-safe-assembly assembly { result := sload(set.slot) let mask := shl(and(0xff, value), 1) sstore(set.slot, or(result, mask)) result := iszero(and(result, mask)) } } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. function add(AddressSet storage set, address value, uint256 cap) internal returns (bool result) { if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. function add(Bytes32Set storage set, bytes32 value, uint256 cap) internal returns (bool result) { if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. function add(Uint256Set storage set, uint256 value, uint256 cap) internal returns (bool result) { if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. function add(Int256Set storage set, int256 value, uint256 cap) internal returns (bool result) { if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); } /// @dev Adds `value` to the set. Returns whether `value` was not in the set. /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. function add(Uint8Set storage set, uint8 value, uint256 cap) internal returns (bool result) { if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(AddressSet storage set, address value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { value := shr(96, shl(96, value)) if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } let rootPacked := sload(rootSlot) for { let n := shr(160, shl(160, rootPacked)) } 1 {} { if iszero(n) { result := 1 if eq(shr(96, rootPacked), value) { sstore(rootSlot, sload(add(rootSlot, 1))) sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(shr(96, sload(add(rootSlot, 1))), value) { sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(shr(96, sload(add(rootSlot, 2))), value) { sstore(add(rootSlot, 2), 0) break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) let p := keccak256(0x00, 0x40) let position := sload(p) if iszero(position) { break } n := sub(shr(1, n), 1) if iszero(eq(sub(position, 1), n)) { let lastValue := shr(96, sload(add(rootSlot, n))) sstore(add(rootSlot, sub(position, 1)), shl(96, lastValue)) mstore(0x00, lastValue) sstore(keccak256(0x00, 0x40), position) } sstore(rootSlot, or(shl(96, shr(96, sload(rootSlot))), or(shl(1, n), 1))) sstore(p, 0) result := 1 break } } } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(Bytes32Set storage set, bytes32 value) internal returns (bool result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { if eq(value, _ZERO_SENTINEL) { mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. revert(0x1c, 0x04) } if iszero(value) { value := _ZERO_SENTINEL } for { let n := sload(not(rootSlot)) } 1 {} { if iszero(n) { result := 1 if eq(sload(rootSlot), value) { sstore(rootSlot, sload(add(rootSlot, 1))) sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(sload(add(rootSlot, 1)), value) { sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) sstore(add(rootSlot, 2), 0) break } if eq(sload(add(rootSlot, 2)), value) { sstore(add(rootSlot, 2), 0) break } result := 0 break } mstore(0x20, rootSlot) mstore(0x00, value) let p := keccak256(0x00, 0x40) let position := sload(p) if iszero(position) { break } n := sub(shr(1, n), 1) if iszero(eq(sub(position, 1), n)) { let lastValue := sload(add(rootSlot, n)) sstore(add(rootSlot, sub(position, 1)), lastValue) mstore(0x00, lastValue) sstore(keccak256(0x00, 0x40), position) } sstore(not(rootSlot), or(shl(1, n), 1)) sstore(p, 0) result := 1 break } } } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(Uint256Set storage set, uint256 value) internal returns (bool result) { result = remove(_toBytes32Set(set), bytes32(value)); } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(Int256Set storage set, int256 value) internal returns (bool result) { result = remove(_toBytes32Set(set), bytes32(uint256(value))); } /// @dev Removes `value` from the set. Returns whether `value` was in the set. function remove(Uint8Set storage set, uint8 value) internal returns (bool result) { /// @solidity memory-safe-assembly assembly { result := sload(set.slot) let mask := shl(and(0xff, value), 1) sstore(set.slot, and(result, not(mask))) result := iszero(iszero(and(result, mask))) } } /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. function update(AddressSet storage set, address value, bool isAdd, uint256 cap) internal returns (bool) { return isAdd ? add(set, value, cap) : remove(set, value); } /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. function update(Bytes32Set storage set, bytes32 value, bool isAdd, uint256 cap) internal returns (bool) { return isAdd ? add(set, value, cap) : remove(set, value); } /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. function update(Uint256Set storage set, uint256 value, bool isAdd, uint256 cap) internal returns (bool) { return isAdd ? add(set, value, cap) : remove(set, value); } /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. function update(Int256Set storage set, int256 value, bool isAdd, uint256 cap) internal returns (bool) { return isAdd ? add(set, value, cap) : remove(set, value); } /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. function update(Uint8Set storage set, uint8 value, bool isAdd, uint256 cap) internal returns (bool) { return isAdd ? add(set, value, cap) : remove(set, value); } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(AddressSet storage set) internal view returns (address[] memory result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let zs := _ZERO_SENTINEL let rootPacked := sload(rootSlot) let n := shr(160, shl(160, rootPacked)) result := mload(0x40) let o := add(0x20, result) let v := shr(96, rootPacked) mstore(o, mul(v, iszero(eq(v, zs)))) for {} 1 {} { if iszero(n) { if v { n := 1 v := shr(96, sload(add(rootSlot, n))) if v { n := 2 mstore(add(o, 0x20), mul(v, iszero(eq(v, zs)))) v := shr(96, sload(add(rootSlot, n))) if v { n := 3 mstore(add(o, 0x40), mul(v, iszero(eq(v, zs)))) } } } break } n := shr(1, n) for { let i := 1 } lt(i, n) { i := add(i, 1) } { v := shr(96, sload(add(rootSlot, i))) mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs)))) } break } mstore(result, n) mstore(0x40, add(o, shl(5, n))) } } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(Bytes32Set storage set) internal view returns (bytes32[] memory result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { let zs := _ZERO_SENTINEL let n := sload(not(rootSlot)) result := mload(0x40) let o := add(0x20, result) for {} 1 {} { if iszero(n) { let v := sload(rootSlot) if v { n := 1 mstore(o, mul(v, iszero(eq(v, zs)))) v := sload(add(rootSlot, n)) if v { n := 2 mstore(add(o, 0x20), mul(v, iszero(eq(v, zs)))) v := sload(add(rootSlot, n)) if v { n := 3 mstore(add(o, 0x40), mul(v, iszero(eq(v, zs)))) } } } break } n := shr(1, n) for { let i := 0 } lt(i, n) { i := add(i, 1) } { let v := sload(add(rootSlot, i)) mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs)))) } break } mstore(result, n) mstore(0x40, add(o, shl(5, n))) } } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(Uint256Set storage set) internal view returns (uint256[] memory result) { result = _toUints(values(_toBytes32Set(set))); } /// @dev Returns all of the values in the set. /// Note: This can consume more gas than the block gas limit for large sets. function values(Int256Set storage set) internal view returns (int256[] memory result) { result = _toInts(values(_toBytes32Set(set))); } /// @dev Returns all of the values in the set. function values(Uint8Set storage set) internal view returns (uint8[] memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let ptr := add(result, 0x20) let o := 0 for { let packed := sload(set.slot) } packed {} { if iszero(and(packed, 0xffff)) { o := add(o, 16) packed := shr(16, packed) continue } mstore(ptr, o) ptr := add(ptr, shl(5, and(packed, 1))) o := add(o, 1) packed := shr(1, packed) } mstore(result, shr(5, sub(ptr, add(result, 0x20)))) mstore(0x40, ptr) } } /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. function at(AddressSet storage set, uint256 i) internal view returns (address result) { bytes32 rootSlot = _rootSlot(set); /// @solidity memory-safe-assembly assembly { result := shr(96, sload(add(rootSlot, i))) result := mul(result, iszero(eq(result, _ZERO_SENTINEL))) } if (i >= length(set)) revert IndexOutOfBounds(); } /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. function at(Bytes32Set storage set, uint256 i) internal view returns (bytes32 result) { result = _rootSlot(set); /// @solidity memory-safe-assembly assembly { result := sload(add(result, i)) result := mul(result, iszero(eq(result, _ZERO_SENTINEL))) } if (i >= length(set)) revert IndexOutOfBounds(); } /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. function at(Uint256Set storage set, uint256 i) internal view returns (uint256 result) { result = uint256(at(_toBytes32Set(set), i)); } /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. function at(Int256Set storage set, uint256 i) internal view returns (int256 result) { result = int256(uint256(at(_toBytes32Set(set), i))); } /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. function at(Uint8Set storage set, uint256 i) internal view returns (uint8 result) { /// @solidity memory-safe-assembly assembly { let packed := sload(set.slot) for {} 1 { mstore(0x00, 0x4e23d035) // `IndexOutOfBounds()`. revert(0x1c, 0x04) } { if iszero(lt(i, 256)) { continue } for { let j := 0 } iszero(eq(i, j)) {} { packed := xor(packed, and(packed, add(1, not(packed)))) j := add(j, 1) } if iszero(packed) { continue } break } // Find first set subroutine, optimized for smaller bytecode size. let x := and(packed, add(1, not(packed))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) // For the lower 5 bits of the result, use a De Bruijn lookup. // forgefmt: disable-next-item result := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f), 0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the root slot. function _rootSlot(AddressSet storage s) private pure returns (bytes32 r) { /// @solidity memory-safe-assembly assembly { mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED) mstore(0x00, s.slot) r := keccak256(0x00, 0x24) } } /// @dev Returns the root slot. function _rootSlot(Bytes32Set storage s) private pure returns (bytes32 r) { /// @solidity memory-safe-assembly assembly { mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED) mstore(0x00, s.slot) r := keccak256(0x00, 0x24) } } /// @dev Casts to a Bytes32Set. function _toBytes32Set(Uint256Set storage s) private pure returns (Bytes32Set storage c) { /// @solidity memory-safe-assembly assembly { c.slot := s.slot } } /// @dev Casts to a Bytes32Set. function _toBytes32Set(Int256Set storage s) private pure returns (Bytes32Set storage c) { /// @solidity memory-safe-assembly assembly { c.slot := s.slot } } /// @dev Casts to a uint256 array. function _toUints(bytes32[] memory a) private pure returns (uint256[] memory c) { /// @solidity memory-safe-assembly assembly { c := a } } /// @dev Casts to a int256 array. function _toInts(bytes32[] memory a) private pure returns (int256[] memory c) { /// @solidity memory-safe-assembly assembly { c := a } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if gt(x, div(not(0), y)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if iszero(eq(div(z, y), x)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := add(iszero(iszero(mod(z, WAD))), div(z, WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(mul(y, eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. /// Note: This function is an approximation. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96` // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // `k` is in the range `[-61, 195]`. // Evaluate using a (6, 7)-term rational approximation. // `p` is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already `2**96` too large. r := sdiv(p, q) } // r should be in the range `(0.09, 0.25) * 2**96`. // We now need to multiply r by: // - The scale factor `s ≈ 6.031367120`. // - The `2**k` factor from the range reduction. // - The `1e18 / 2**96` factor for base conversion. // We do this all at once, with an intermediate result in `2**213` // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. /// Note: This function is an approximation. Monotonically increasing. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. (int256 wad, int256 p) = (int256(WAD), x); uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (uint256(w >> 63) == uint256(0)) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == uint256(0)) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != uint256(0)); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c == uint256(0)) return w; int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `a * b == x * y`, with full precision. function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0)))) } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. for {} 1 {} { // If overflows. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. let r := mulmod(x, y, d) // Compute remainder using mulmod. let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`. // Make sure `z` is less than `2**256`. Also prevents `d == 0`. // Placing the check here seems to give more optimal stack operations. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } d := div(d, t) // Divide `d` by `t`, which is a power of two. // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(2, mul(3, d)) // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 z := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256 ) break } z := div(z, d) break } } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits. /// Performs the full 512 bit calculation regardless. function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) let t := and(d, sub(0, d)) let r := mulmod(x, y, d) d := div(d, t) let inv := xor(2, mul(3, d)) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) z := mul( or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) ) } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { z = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { z := add(z, 1) if iszero(z) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Calculates `floor(x * y / 2 ** n)` with full precision. /// Throws if result overflows a uint256. /// Credit to Philogy under MIT license: /// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`. for {} 1 {} { if iszero(or(iszero(x), eq(div(z, x), y))) { let k := and(n, 0xff) // `n`, cleaned. let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. // | p1 | z | // Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 | // Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 | // Check that final `z` doesn't overflow by checking that p1_0 = 0. if iszero(shr(k, p1)) { z := add(shl(sub(256, k), p1), shr(k, z)) break } mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } z := shr(and(n, 0xff), z) break } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(z, d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(z, d))), div(z, d)) } } /// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`. function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) { /// @solidity memory-safe-assembly assembly { let g := n let r := mod(a, n) for { let y := 1 } 1 {} { let q := div(g, r) let t := g g := r r := sub(t, mul(r, q)) let u := x x := y y := sub(u, mul(y, q)) if iszero(r) { break } } x := mul(eq(g, 1), add(x, mul(slt(x, 0), n))) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. Alias for `saturatingSub`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `max(0, x - y)`. function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `min(2 ** 256 - 1, x + y)`. function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(sub(0, lt(add(x, y), x)), add(x, y)) } } /// @dev Returns `min(2 ** 256 - 1, x * y)`. function saturatingMul(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(sub(or(iszero(x), eq(div(mul(x, y), x), y)), 1), mul(x, y)) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, address x, address y) internal pure returns (address z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `x != 0 ? x : y`, without branching. function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(x))) } } /// @dev Returns `x != bytes32(0) ? x : y`, without branching. function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(x))) } } /// @dev Returns `x != address(0) ? x : y`, without branching. function coalesce(address x, address y) internal pure returns (address z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(shl(96, x)))) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if x { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`, rounded down. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`, rounded down. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // Makeshift lookup table to nudge the approximate log2 result. z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) // Newton-Raphson's. z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) // Round down. z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18); z = (1 + sqrt(x)) * 10 ** 9; z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1; } /// @solidity memory-safe-assembly assembly { z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down. } } /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down. /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36); z = (1 + cbrt(x)) * 10 ** 12; z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3; } /// @solidity memory-safe-assembly assembly { let p := x for {} 1 {} { if iszero(shr(229, p)) { if iszero(shr(199, p)) { p := mul(p, 100000000000000000) // 10 ** 17. break } p := mul(p, 100000000) // 10 ** 8. break } if iszero(shr(249, p)) { p := mul(p, 100) } break } let t := mulmod(mul(z, z), z, p) z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down. } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := 1 if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for {} x { x := sub(x, 1) } { z := mul(z, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. Rounds towards zero. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. Rounds towards negative infinity. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { unchecked { z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255); } } /// @dev Returns the absolute distance between `x` and `y`. function dist(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`, /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end) internal pure returns (uint256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; unchecked { if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin); return a - fullMulDiv(a - b, t - begin, end - begin); } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`. /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end) internal pure returns (int256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; // forgefmt: disable-next-item unchecked { if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a), uint256(t - begin), uint256(end - begin))); return int256(uint256(a) - fullMulDiv(uint256(a - b), uint256(t - begin), uint256(end - begin))); } } /// @dev Returns if `x` is an even number. Some people may need this. function isEven(uint256 x) internal pure returns (bool) { return x & uint256(1) == uint256(0); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
//SPDX-License-Identifier: Unlicense pragma solidity ^0.8.19; interface IBigcoin { function mint(address to, uint256 amt) external; function burn(uint256 value) external; function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 value) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /** * @dev Miners that can be purchased in the game. */ struct Miner { uint256 minerIndex; uint256 id; uint256 x; uint256 y; uint256 hashrate; uint256 powerConsumption; uint256 cost; bool inProduction; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /** * @dev Current player's facility. */ struct Facility { uint256 facilityIndex; uint256 maxMiners; // x * y uint256 currMiners; uint256 totalPowerOutput; uint256 currPowerOutput; uint256 x; // number of x quadrants uint256 y; // number of y qudrants }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /** * @dev Facilities that can be purchased in game. */ struct NewFacility { uint256 maxMiners; uint256 totalPowerOutput; uint256 cost; bool inProduction; uint256 x; // number of x quadrants uint256 y; // number of y qudrants }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; library Errors { error IncorrectValue(); error AlreadyPurchasedInitialFactory(); error StarterMinerAlreadyAcquired(); error FacilityAtMaxCapacity(); error FacilityInadequatePowerOutput(); error PlayerDoesNotOwnMiner(); error GreatDepression(); error MinerNotInProduction(); error TooPoor(); error NewFacilityNotInProduction(); error CannotDowngradeAFacility(); error NoRewardsPending(); error CannotDecreaseBelowZero(); error InvalidMinerCoordinates(); error FacilityDimensionsInvalid(); error NeedToInitializeFacility(); error InvalidReferrer(); error NonExistentMiner(); error CantModifyStarterMiner(); error NonExistentFacility(); error CantModifyStarterFacility(); error AlreadyAtMaxFacility(); error CantBuyNewFacilityYet(); error InvalidMinerIndex(); error InvalidFacilityIndex(); error InvalidFee(); error InvalidPowerOutput(); error MiningHasntStarted(); error WithdrawFailed(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; library Events { event MiningStarted(uint256 startBlock); event NewMinerAdded( uint256 indexed minerIndex, uint256 hashRate, uint256 powerConsumption, uint256 cost, bool inProduction ); event MinerProductionToggled(uint256 indexed minerIndex, bool inProduction); event FacilityProductionToggled(uint256 indexed facilityIndex, bool inProduction); event NewFacilityAdded( uint256 indexed facilityIndex, uint256 totalPowerOutput, uint256 cost, bool inProduction, uint256 x, uint256 y ); event MinerSecondaryMarketAdded(uint256 indexed minerIndex, uint256 price); event InitialFacilityPurchased(address indexed player); event FreeMinerRedeemed(address indexed player); event MinerSold( address indexed player, uint256 indexed minerIndex, uint256 secondHandPrice, uint256 minerId, uint256 x, uint256 y ); event MinerBought( address indexed player, uint256 indexed minerIndex, uint256 cost, uint256 minerId, uint256 x, uint256 y ); event FacilityBought(address indexed player, uint256 indexed facilityIndex, uint256 cost); event PlayerHashrateIncreased(address indexed player, uint256 playerHashrate, uint256 playerPendingRewards); event PlayerHashrateDecreased(address indexed player, uint256 playerHashrate, uint256 playerPendingRewards); event RewardsClaimed(address indexed player, uint256 rewards); event MinerCostChanged(uint256 indexed minerIndex, uint256 newCost); event FacilityCostChanged(uint256 indexed facilityIndex, uint256 newCost); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
{ "viaIR": false, "codegen": "yul", "remappings": [ "@openzeppelin/=lib/openzeppelin-contracts/contracts/", "solady/=lib/solady/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/" ], "evmVersion": "cancun", "outputSelection": { "*": { "*": [ "abi" ] } }, "optimizer": { "enabled": true, "mode": "3", "fallback_to_optimizing_for_size": false, "disable_system_request_memoization": true }, "metadata": {}, "libraries": {}, "enableEraVMExtensions": false, "forceEVMLA": false }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"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":"FacilityDimensionsInvalid","type":"error"},{"inputs":[],"name":"FacilityInadequatePowerOutput","type":"error"},{"inputs":[],"name":"GreatDepression","type":"error"},{"inputs":[],"name":"IncorrectValue","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":"MiningHasntStarted","type":"error"},{"inputs":[],"name":"NeedToInitializeFacility","type":"error"},{"inputs":[],"name":"NewFacilityNotInProduction","type":"error"},{"inputs":[],"name":"NoRewardsPending","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":"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":false,"internalType":"uint256","name":"startBlock","type":"uint256"}],"name":"MiningStarted","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"inputs":[],"name":"HALVING_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_BIGCOIN_PER_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARDS_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"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":"bigcoin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bigtoshi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blocksUntilNextHalving","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[],"name":"buyNewFacility","outputs":[],"stateMutability":"nonpayable","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":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cumulativeBigcoinPerHash","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":[],"name":"getBigcoinPerBlock","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":[],"name":"initialFacilityPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"lastRewardBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"miningHasStarted","outputs":[{"internalType":"bool","name":"","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":"player","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerBigcoinDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"playerBigcoinPerBlock","outputs":[{"internalType":"uint256","name":"","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":"","type":"address"}],"name":"playerPendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"purchaseInitialFacility","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralBonusPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[{"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"sellMiner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bigcoin","type":"address"}],"name":"setBigcoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bigtoshi","type":"address"}],"name":"setBigtoshi","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"burn","type":"uint256"}],"name":"setBurnPct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cooldown","type":"uint256"}],"name":"setCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialPrice","type":"uint256"}],"name":"setInitialFacilityPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setReferralFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"withdrawBigcoin","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
9c4d535b0000000000000000000000000000000000000000000000000000000000000000010006e1c8168773598c4871d2cb6bfd7749522704aa9a639d44893da0b9389200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x00010000000000020016000000000002000000000001035500000001002001900000003c0000c13d000000600210027000000614022001970000008003000039000000400030043f000000040020008c000015b80000413d000000000301043b000000e003300270000006210030009c0000006f0000a13d000006220030009c0000009e0000a13d000006230030009c000000db0000a13d000006240030009c000001e60000a13d000006250030009c000003e20000a13d000006260030009c000009400000613d000006270030009c000009750000613d000006280030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000601043b000006160060009c000015b80000213d000000000100041a00000616021001970000000005000411000000000052004b0000097f0000c13d000000000006004b000000440000613d0000061501100197000000000161019f000000000010041b0000000001000414000006140010009c0000061401008041000000c00110021000000617011001c70000800d0200003900000003030000390000061804000041184d18430000040f000000010020019000000b2a0000c13d000015b80000013d000000c001000039000000400010043f0000000001000416000000000001004b000015b80000c13d0000000006000411000000000006004b000000490000c13d0000068301000041000000000010043f000000040000043f00000682010000410000184f00010430000000000100041a0000061502100197000000000262019f000000000020041b00000000020004140000061605100197000006140020009c0000061402008041000000c00120021000000617011001c70000800d0200003900000003030000390000061804000041184d18430000040f0000000100200190000015b80000613d00000619010000410000000b02000039000000000012041b0000061a010000410000000c02000039000000000012041b0000061b010000410000000d02000039000000000012041b0000061c010000410000001e02000039000000000012041b0000000602000039000000000102041a000000010110003a000000d00000c13d000006d601000041000000000010043f0000001101000039000000040010043f00000682010000410000184f00010430000006520030009c000000ba0000213d0000066a0030009c000000f70000213d000006760030009c000001f60000213d0000067c0030009c0000032e0000213d0000067f0030009c000005d10000613d000006800030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000000000010043f0000001201000039000000200010043f00000040020000390000000001000019184d18100000040f0000000502100039000000000202041a0000000403100039000000000303041a0000000304100039000000000404041a0000000205100039000000000505041a0000000106100039000000000606041a000000000101041a000000800010043f000000a00060043f000000c00050043f000000ff004001900000000001000039000000010100c039000000e00010043f000001000030043f000001200020043f000006d7010000410000184e0001042e0000063b0030009c000000e80000213d000006470030009c000001c90000213d0000064d0030009c000002cb0000213d000006500030009c000004e00000613d000006510030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000000000200041a00000616032001970000000002000411000000000023004b0000097a0000c13d000006aa0010009c000001c50000813d0000000c02000039000000000012041b00000000010000190000184e0001042e000006530030009c000001090000213d0000065f0030009c000002080000213d000006650030009c0000033f0000213d000006680030009c000006100000613d000006690030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000000f01000039000007d70000013d000000000012041b000000800010043f000000400400043d0000061d0040009c000001160000413d000006d601000041000000000010043f0000004101000039000000040010043f00000682010000410000184f00010430000006300030009c000001b10000213d000006360030009c0000024f0000213d000006390030009c0000040b0000613d0000063a0030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000801000039000007db0000013d0000063c0030009c000001db0000213d000006420030009c000002d40000213d000006450030009c000004e50000613d000006460030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000069b01000041000000800010043f00000684010000410000184e0001042e0000066b0030009c000002130000213d000006710030009c000003550000213d000006740030009c000006340000613d000006750030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000000000010043f0000001801000039000007d70000013d000006540030009c000002330000213d0000065a0030009c000003710000213d0000065d0030009c000006400000613d0000065e0030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000901000039000007db0000013d0000010002400039000000400020043f000000a0034000390000000102000039001200000003001d000000000023043500000080034000390000006402000039001000000003001d0000000000230435000000c003400039000000010200008a001100000003001d00000000002304350000006003400039000d00000003001d00000000002304350000004003400039000c00000003001d00000000002304350000002003400039000b00000003001d00000000002304350000000000140435000e00000004001d000000e001400039000f00000001001d0000000000010435000000800100043d000000000010043f0000001101000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d0000000e020000290000000002020433000000000101043b000000000021041b0000000b0200002900000000020204330000000103100039000000000023041b0000000c0200002900000000020204330000000203100039000000000023041b0000000d0200002900000000020204330000000303100039000000000023041b000000100200002900000000020204330000000403100039000000000023041b000000120200002900000000020204330000000503100039000000000023041b000000110200002900000000020204330000000603100039000000000023041b0000000701100039000000000201041a000006d9022001970000000f030000290000000003030433000000000003004b000000010220c1bf000000000021041b000000400200043d0000061f0020009c000000d50000213d000000c001200039000000400010043f000000a00320003900000002010000390000000000130435000000800520003900000000001504350000004007200039000000010100008a000000000017043500000020092000390000001c01000039000000000019043500000004010000390000000000120435000000600820003900000000000804350000000706000039000000000106041a000000010110003a000000690000613d000000000016041b000000000010043f0000001201000039000000200010043f000e00000002001d00000040020000390000000001000019001200000003001d001100000005001d000f00000007001d001000000008001d000d00000009001d184d18100000040f0000000e020000290000000002020433000000000021041b0000000d0200002900000000020204330000000103100039000000000023041b0000000f0200002900000000020204330000000203100039000000000023041b0000000302100039000000000302041a000006d90330019700000010040000290000000004040433000000000004004b000000010330c1bf000000000032041b000000110200002900000000020204330000000403100039000000000023041b000000050110003900000012020000290000000002020433000000000021041b0000000701000039000000000101041a000000a00010043f000000800200043d0000014000000443000001600020044300000020020000390000018000200443000001a00010044300000100002004430000000201000039000001200010044300000620010000410000184e0001042e000006310030009c000002970000213d000006340030009c0000047c0000613d000006350030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000000000200041a00000616032001970000000002000411000000000023004b0000097a0000c13d0000069b0010009c000009a30000a13d000006ab01000041000000000010043f0000068c010000410000184f00010430000006480030009c000002e40000213d0000064b0030009c000005260000613d0000064c0030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001a01000039000007d70000013d0000063d0030009c000002ed0000213d000006400030009c0000052b0000613d000006410030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000401000039000004d90000013d0000062b0030009c000003010000213d0000062e0030009c0000059a0000613d0000062f0030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000000000010043f00000014010000390000030e0000013d000006770030009c0000037a0000213d0000067a0030009c0000064b0000613d0000067b0030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001d01000039000007d70000013d000006600030009c0000038a0000213d000006630030009c000006880000613d000006640030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000301000039000007db0000013d0000066c0030009c000003b30000213d0000066f0030009c0000071a0000613d000006700030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000001000411184d16100000040f0000000001000411000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000000001004b000009fd0000c13d000006ca01000041000000000010043f0000068c010000410000184f00010430000006550030009c000003d80000213d000006580030009c000007300000613d000006590030009c000015b80000c13d000000440020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000002402100370000000000402043b0000000401100370000000000301043b000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d0000000601000039000000000101041a000000000013004b00000aaa0000a13d000006b101000041000000000010043f0000068c010000410000184f00010430000006370030009c000004ab0000613d000006380030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d000000000200041a00000616032001970000000002000411000000000023004b0000097a0000c13d0000000102000039000000000202041a0000000203000039000000000303041a0000069404000041000000800040043f0000000401100370000000000101043b0000061603300197000000840030043f000000a40010043f00000000010004140000061602200197000006140010009c0000061401008041000000c0011002100000069e011001c7184d18430000040f000000800900003900000060031002700000061403300197000000200030008c000000200a000039000000000a0340190000001f05a0018f0000002006a0019000000080046001bf0000027e0000613d000000000701034f000000007807043c0000000009890436000000000049004b0000027a0000c13d000000000005004b0000028b0000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f00000000005404350000000100200190000009a70000613d000000800100003900000000020a001900120000000a001d184d15e50000040f000000120100002900000080021001bf0000008001000039184d15f70000040f00000000010000190000184e0001042e000006320030009c000004ca0000613d000006330030009c000015b80000c13d000000440020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000402100370000000000202043b001200000002001d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039001100000002001d000000000012004b000015b80000c13d000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d0000068501000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000006140010009c0000061401008041000000c00110021000000697011001c70000800502000039184d18480000040f0000000100200190000012c40000613d000000000101043b0000001202000029000000000012004b000002c70000413d0000000701000039000000000101041a000000000012004b00000d5a0000a13d0000069a01000041000000000010043f0000068c010000410000184f000104300000064e0030009c000005300000613d0000064f0030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000601000039000007db0000013d000006430030009c000005470000613d000006440030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001701000039000004d50000013d000006490030009c0000054f0000613d0000064a0030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000c01000039000007db0000013d0000063e0030009c000005950000613d0000063f0030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001b01000039000000200010043f00000040020000390000000001000019184d18100000040f000003e00000013d0000062c0030009c000005c40000613d0000062d0030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000000000010043f0000001101000039000000200010043f00000040020000390000000001000019184d18100000040f0000000702100039000000000202041a0000000603100039000000000303041a0000000504100039000000000404041a0000000405100039000000000505041a0000000306100039000000000606041a0000000207100039000000000707041a0000000108100039000000000808041a000000000101041a000000800010043f000000a00080043f000000c00070043f000000e00060043f000001000050043f000001200040043f000001400030043f000000ff002001900000000001000039000000010100c039000001600010043f00000687010000410000184e0001042e0000067d0030009c000007370000613d0000067e0030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b001200000001001d000006160010009c000015b80000213d184d16050000040f00000002010000390000034f0000013d000006660030009c0000073e0000613d000006670030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b001200000001001d000006160010009c000015b80000213d184d16050000040f0000000101000039000000000201041a000006150220019700000012022001af000000000021041b00000000010000190000184e0001042e000006720030009c0000078f0000613d000006730030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000001000411000000000010043f0000001601000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000ff0010019000000a930000c13d000006d101000041000000000010043f0000068c010000410000184f000104300000065b0030009c0000079a0000613d0000065c0030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000101000039000003e00000013d000006780030009c000007cc0000613d000006790030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001301000039000007d70000013d000006610030009c000007df0000613d000006620030009c000015b80000c13d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001501000039000000200010043f00000040020000390000000001000019184d18100000040f0000000602100039000000000202041a0000000503100039000000000303041a0000000404100039000000000404041a0000000305100039000000000505041a0000000206100039000000000606041a0000000107100039000000000707041a000000000101041a000000800010043f000000a00070043f000000c00060043f000000e00050043f000001000040043f000001200030043f000001400020043f000006b3010000410000184e0001042e0000066d0030009c000007ec0000613d0000066e0030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d000006bf010000410000000000100443000000000100041000000004001004430000000001000414000006140010009c0000061401008041000000c001100210000006b7011001c70000800a02000039184d18480000040f0000000100200190000012c40000613d0000000202000039000000000202041a0000061604200197000000000301043b0000000001000414000006140010009c0000061401008041000000c001100210000000000003004b00000b210000c13d000000000204001900000b240000013d000006560030009c000009250000613d000006570030009c000015b80000c13d0000000001000416000000000001004b000015b80000c13d0000000201000039000000000101041a0000054b0000013d000006290030009c000009500000613d0000062a0030009c000015b80000c13d000000440020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000402100370000000000202043b000006160020009c000015b80000213d0000002401100370000000000101043b001200000001001d000000000020043f0000001c01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000000120020006b000015b80000813d0000001202000029184d15ca0000040f0000000302200210000000000101041a000000000121022f0000061601100197000000ff0020008c00000000010020190000096e0000013d000000840020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000004402100370000000000202043b001100000002001d0000002402100370000000000202043b001200000002001d0000000402100370000000000202043b001000000002001d0000006401100370000000000201043b000000000002004b0000000001000039000000010100c039000f00000002001d000000000012004b000015b80000c13d000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d0000000602000039000000000102041a000000010110003a000000690000613d000000000012041b0000018002000039000000400020043f000000800010043f000000a00000043f000000c00000043f000000e00000043f0000001002000029000001000020043f0000001202000029000001200020043f0000001102000029000001400020043f0000000f02000029000001600020043f000000000010043f0000001101000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000800200043d000000000021041b0000000102100039000000a00300043d000000000032041b0000000202100039000000c00300043d000000000032041b0000000302100039000000e00300043d000000000032041b0000000402100039000001000300043d000000000032041b0000000502100039000001200300043d000000000032041b0000000602100039000001400300043d000000000032041b0000000701100039000000000301041a000006d902300197000001600300043d000000000003004b000000010220c1bf000000000021041b0000000601000039000000000501041a000000400100043d00000060021000390000000f03000029000000000032043500000040021000390000001103000029000000000032043500000020021000390000001203000029000000000032043500000010020000290000000000210435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000691011001c70000800d020000390000000203000039000006a404000041000007c80000013d000000440020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000402100370000000000202043b001200000002001d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039001100000002001d000000000012004b000015b80000c13d000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d000006850100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000006140010009c0000061401008041000000c00110021000000697011001c70000800502000039184d18480000040f0000000100200190000012c40000613d000000000101043b0000001202000029000000000012004b000004a70000413d0000000601000039000000000101041a000000000012004b00000cbb0000a13d0000069d01000041000000000010043f0000068c010000410000184f000104300000000001000416000000000001004b000015b80000c13d0000000401000039000000000101041a000000ff00100190000007280000613d0000000301000039000000000101041a001200000001001d0000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000120210006c000000690000413d000006a10020009c000000690000213d000000400100043d0000061402200197000006a20220012a000006a30220027f0000072a0000013d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001601000039000000200010043f00000040020000390000000001000019184d18100000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f00000684010000410000184e0001042e0000000001000416000000000001004b000015b80000c13d0000000701000039000007db0000013d000000c40020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000004402100370000000000202043b001000000002001d0000002402100370000000000202043b001100000002001d0000000402100370000000000202043b001200000002001d0000006402100370000000000302043b000000000003004b0000000002000039000000010200c039000f00000003001d000000000023004b000015b80000c13d000000a402100370000000000402043b0000008401100370000000000301043b000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d00000000013400a9000000000003004b0000050a0000613d00000000023100d9000000000042004b000000690000c13d000e00000004001d000000120010006c000005220000c13d000d00000003001d0000000701000039000000000101041a000c00000001001d000000000010043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000401100039000000000101041a0000000d0010006c00000d7c0000a13d000006a801000041000000000010043f0000068c010000410000184f000104300000000001000416000000000001004b000015b80000c13d0000000b01000039000007db0000013d0000000001000416000000000001004b000015b80000c13d0000000a01000039000007db0000013d0000000001000416000000000001004b000015b80000c13d000000000100041a00000616021001970000000005000411000000000052004b0000097f0000c13d0000061501100197000000000010041b0000000001000414000006140010009c0000061401008041000000c00110021000000617011001c70000800d02000039000000030300003900000618040000410000000006000019184d18430000040f000000010020019000000b2a0000c13d000015b80000013d0000000001000416000000000001004b000015b80000c13d000000000100041a0000061601100197000000800010043f00000684010000410000184e0001042e000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b001200000001001d000006160010009c000015b80000213d0000001201000029000000000010043f0000001a01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d0000000b02000039000000000202041a000000000101043b000000000101041a001100000002001d001000000001001d000000000012001a000000690000413d000006a90100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000012c40000613d00000010030000290000001102300029000000000101043b001000000001001d000000000012004b00000000010000190000096e0000413d0000001201000029000000000010043f0000001a01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000110010002a000000690000413d0000001101100029000000100110006c0000096e0000813d000000690000013d0000000001000416000000000001004b000015b80000c13d0000000d01000039000007db0000013d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b001200000001001d0000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000068802000041000000040020043f000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000689011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b00000012030000290000068a0030009c00000ac20000c13d000006c401000041000000000010043f000006c5010000410000184f00010430000000240020008c000015b80000413d0000000001000416000000000001004b000015b80000c13d184d16050000040f00000004010000390000000001100367000000000101043b0000001e02000039000000000012041b00000000010000190000184e0001042e000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b001200000001001d000006160010009c000015b80000213d0000000901000039000000000101041a000000000001004b000007280000613d001000000001001d0000000301000039000000000101041a001100000001001d0000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000110110006c000000690000413d000006a10010009c000000690000213d001100000001001d0000001201000029000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d00000011020000290000061402200197000006a20220012a000006a30220027f000000000101043b000000000301041a00000000012300a9000000000003004b0000060d0000613d00000000033100d9000000000023004b00000eec0000c13d00000010021000fa000000400100043d0000072a0000013d000000240020008c000015b80000413d0000000401100370000000000101043b001200000001001d000006160010009c000015b80000213d0000001e01000039000000000101041a0000000002000416000000000012004b0000099f0000c13d0000000001000411000000000010043f0000001601000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000ff0010019000000b5a0000c13d0000000001000411000000120010006b00000cdd0000c13d000006be01000041000000000010043f0000068c010000410000184f00010430000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000000e01000039000007d70000013d0000000001000416000000000001004b000015b80000c13d0000000001000412001600000001001d001500200000003d000080050100003900000044030000390000000004000415000000160440008a0000094a0000013d000000640020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000402100370000000000202043b000006160020009c000015b80000213d0000004403100370000000000303043b001200000003001d0000002401100370000000000101043b000e00000001001d000000000020043f0000001301000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000201043b0000068801000041000000040010043f001100000002001d000000000020043f0000000001000414000006140010009c0000061401008041000000c00110021000000689011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000006da02100167000000000202041a000000000002004b00000bfd0000c13d000000000201041a000000000002004b0000000002000039000000010200c03900000bfe0000613d0000000103100039000000000303041a000000000003004b00000bfe0000613d0000000201100039000000000101041a000000000001004b0000000302000039000000020200603900000bfe0000013d000000640020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000004402100370000000000202043b001100000002001d0000002402100370000000000202043b001200000002001d0000000401100370000000000101043b001000000001001d000000000010043f0000001101000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000400400043d0000068d0040009c000000d50000213d000000000101043b0000010002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000a00000003001d00000000002304350000000202100039000000000202041a0000004003400039000c00000003001d00000000002304350000000302100039000000000202041a0000006003400039000b00000003001d00000000002304350000000402100039000000000202041a0000008003400039000900000003001d00000000002304350000000502100039000000000202041a000000a003400039000d00000003001d00000000002304350000000602100039000000000202041a000000c003400039000e00000003001d0000000000230435000800000004001d000000e0024000390000000701100039000000000101041a000000ff001001900000000001000039000000010100c039000f00000002001d00000000001204350000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000301043b0000000501300039000000000101041a000000120010006b00000b560000813d0000000601300039000000000101041a000000110010006b00000b560000813d000700000003001d0000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001202000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001102000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000ff0010019000000b560000c13d0000000f010000290000000001010433000000000001004b000010380000c13d000006ba01000041000000000010043f0000068c010000410000184f00010430000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000d00000001001d000006160010009c000015b80000213d0000000401000039000000000101041a000000ff00100190000009c50000c13d000000800100003900000000020000190000000000210435000006140010009c0000061401008041000000400110021000000686011001c70000184e0001042e0000000001000416000000000001004b000015b80000c13d000006a201000041000000800010043f00000684010000410000184e0001042e0000000001000416000000000001004b000015b80000c13d000006a301000041000000800010043f00000684010000410000184e0001042e000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001c01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000301041a000000400200043d001100000002001d001000000003001d0000000002320436001200000002001d000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000698011001c70000801002000039184d18480000040f0000000100200190000015b80000613d0000001005000029000000000005004b00000012060000290000000002060019000007730000613d000000000101043b00000000030000190000000002060019000000000401041a0000061604400197000000000242043600000001011000390000000103300039000000000053004b0000076c0000413d000000110300002900000000013200490000001f01100039000006db021001970000000001320019000000000021004b00000000020000390000000102004039000006900010009c000000d50000213d0000000100200190000000d50000c13d000000400010043f00000020020000390000000002210436000000000303043300000000003204350000004002100039000000000003004b00000c6d0000613d00000000040000190000000065060434000006160550019700000000025204360000000104400039000000000034004b000007880000413d00000c6d0000013d0000000001000416000000000001004b000015b80000c13d0000000301000039000000000101041a000000000001004b000009840000c13d000006d201000041000000000010043f0000068c010000410000184f00010430000000440020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000002402100370000000000402043b0000000401100370000000000301043b000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d001100000004001d001200000003001d000000000030043f0000001801000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001102000029000000000021041b000000400100043d0000000000210435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d020000390000000203000039000006b2040000410000001205000029184d18430000040f000000010020019000000b2a0000c13d000015b80000013d000000240020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000000401100370000000000101043b000006160010009c000015b80000213d000000000010043f0000001001000039000000200010043f00000040020000390000000001000019184d18100000040f000000000101041a000000800010043f00000684010000410000184e0001042e000000240020008c000015b80000413d0000000001000416000000000001004b000015b80000c13d184d16050000040f00000004010000390000000001100367000000000101043b0000000b02000039000000000012041b00000000010000190000184e0001042e000000440020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000002402100370000000000202043b001100000002001d0000000401100370000000000101043b001200000001001d0000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000ff00100190000009e00000c13d0000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000006d90220019700000001022001bf000000000021041b000006850100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000006140010009c0000061401008041000000c00110021000000697011001c70000800502000039184d18480000040f0000000100200190000012c40000613d000000000101043b001000000001001d000000000010043f0000001101000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000400200043d000f00000002001d0000068d0020009c000000d50000213d000000000101043b0000000f040000290000010002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000b00000003001d00000000002304350000000202100039000000000202041a0000004003400039000d00000003001d00000000002304350000000302100039000000000202041a0000006003400039000c00000003001d00000000002304350000000402100039000000000202041a0000008003400039000a00000003001d00000000002304350000000502100039000000000202041a000000a003400039000e00000003001d00000000002304350000000602100039000000000202041a000000c003400039000800000003001d0000000000230435000000e0024000390000000701100039000000000101041a000000ff001001900000000001000039000000010100c039000900000002001d00000000001204350000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000700000001001d0000000501100039000000000101041a000000120010006b00000b560000813d00000007010000290000000601100039000000000101041a000000110010006b00000b560000813d0000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001202000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001102000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000ff0010019000000b560000c13d0000000e01000029000000000101043300000007020000290000000402200039000600000002001d000000000202041a000000000021001a000000690000413d000000000121001900000007020000290000000302200039000000000202041a000000000021004b000011aa0000213d00000012010000290000000d02000029000000000012043500000011010000290000000c0200002900000000001204350000000501000039000000000101041a000000010110003a000000690000613d0000000502000039000000000012041b0000000b0200002900000000001204350000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001202000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001102000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000006d90220019700000001022001bf000000000021041b0000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d0000000502000039000000000202041a000500000002001d000000000101043b0000068802000041000000040020043f000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000689011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000400000001001d00000005010000290000068a0010009c000005c00000613d0000000402000029000006da01200167000200000001001d000000000301041a000000200020043f000000050000006b00000005010000290000068a01006041000500000001001d000300000003001d000000000003004b000014780000c13d0000000401000029000000000101041a000000000001004b0000142b0000c13d00000005010000290000000402000029000014910000013d000000440020008c000015b80000413d0000000002000416000000000002004b000015b80000c13d0000002402100370000000000402043b0000000401100370000000000301043b000000000100041a00000616021001970000000001000411000000000012004b0000093b0000c13d0000000701000039000000000101041a000000000013004b000009e40000a13d000006ae01000041000000000010043f0000068c010000410000184f000104300000068102000041000000000020043f000000040010043f00000682010000410000184f000104300000000001000416000000000001004b000015b80000c13d0000000001000412001400000001001d001300000000003d000080050100003900000044030000390000000004000415000000140440008a00000005044002100000068502000041184d18250000040f000000800010043f00000684010000410000184e0001042e0000000001000416000000000001004b000015b80000c13d0000000001020019184d15ba0000040f001100000002001d001200000003001d0000061601100197000000000010043f0000001901000039000000200010043f00000040020000390000000001000019184d18100000040f0000001102000029000000000020043f000000200010043f00000000010000190000004002000039184d18100000040f0000001202000029000000000020043f000000200010043f00000000010000190000004002000039184d18100000040f000000000101041a000000ff001001900000000001000039000000010100c039000000400200043d0000000000120435000006140020009c0000061402008041000000400120021000000686011001c70000184e0001042e0000000001000416000000000001004b000015b80000c13d0000001e01000039000007db0000013d0000068101000041000000000010043f000000040020043f00000682010000410000184f000104300000068101000041000000000010043f000000040050043f00000682010000410000184f00010430001200000001001d0000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000012c40000613d000000000101043b000006a20210012a0000000103200039000006a2023000d100000000033200d9000006a20030009c000000690000c13d0000001203000029000006a23030012a000000000032001a000000690000413d0000000002320019000000000112004b0000096e0000813d000000690000013d000006bb01000041000000000010043f0000068c010000410000184f000104300000000d02000039000000000012041b00000000010000190000184e0001042e0000001f0530018f0000068f06300198000000400200043d0000000004620019000009b20000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000009ae0000c13d000000000005004b000009bf0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000006140020009c00000614020080410000004002200210000000000112019f0000184f000104300000000901000039000000000101041a000f00000001001d000000000001004b00000ad90000c13d0000000d01000029000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000c02000039000000000202041a0000069b0020009c000000690000213d000000000101041a00000eb80000c13d000000000200001900000ec00000013d000006c301000041000000000010043f0000068c010000410000184f00010430001100000004001d001200000003001d0000068501000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000006140010009c0000061401008041000000c00110021000000697011001c70000800502000039184d18480000040f0000000100200190000012c40000613d000000000101043b0000001202000029000000000012004b00000c190000c13d000006ad01000041000000000010043f0000068c010000410000184f00010430001200000001001d0000000001000411000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000001041b0000000c01000039000000000101041a000000000001004b000000120300002900000a150000613d000006da02100129000000000032004b00000ebc0000413d00000000013100a90010069b00100132000000100130006c001100000001001d000000690000413d0000000101000039000000000101041a000006b60200004100000000002004430000061601100197000f00000001001d00000004001004430000000001000414000006140010009c0000061401008041000000c001100210000006b7011001c70000800202000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000000001004b000015b80000613d000000400300043d000000240130003900000011020000290000000000210435000006c80100004100000000001304350000000001000411000006160110019700000004023000390000000000120435000006140030009c001100000003001d0000061401000041000000000103401900000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000695011001c70000000f02000029184d18430000040f000000010020019000000ec40000613d0000001101000029000006900010009c000000d50000213d0000001101000029000000400010043f0000000001000411000000000010043f0000001b01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a0000000102000039000000000202041a000006b60300004100000000003004430000061602200197001100000002001d0000000400200443000f06160010019c000010fe0000c13d0000000001000414000006140010009c0000061401008041000000c001100210000006b7011001c70000800202000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000000001004b000015b80000613d000000400300043d000000240130003900000010020000290000000000210435000006c80100004100000000001304350000000001000410000006160110019700000004023000390000000000120435000006140030009c000f00000003001d0000061401000041000000000103401900000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000695011001c70000001102000029184d18430000040f0000000100200190000011ba0000613d0000000f01000029000006900010009c000000d50000213d0000000f01000029000000400010043f0000000001000410000000000010043f0000001d01000039000000200010043f00000000010004140000112c0000013d0000001501000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b001100000001001d000000000201041a0000000701000039000000000101041a001200000002001d000000000012004b00000c760000c13d000006d001000041000000000010043f0000068c010000410000184f00010430001100000004001d001200000003001d000006850100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000006140010009c0000061401008041000000c00110021000000697011001c70000800502000039184d18480000040f0000000100200190000012c40000613d000000000101043b0000001202000029000000000012004b00000c9c0000c13d000006b001000041000000000010043f0000068c010000410000184f00010430000006da02100167000000000003004b00000000040300190000068a04006041000000000202041a000000000002004b001100000004001d00000b5e0000c13d000000000201041a000000000042004b00000b6e0000613d0000000102100039000000000202041a000000110020006c00000b6e0000613d0000000201100039000000000101041a000000110010006c00000b6e0000613d0000068b01000041000000000010043f0000068c010000410000184f000104300000000301000039000000000101041a0000000802000039000000000302041a000000000213004b000000690000413d000006a10020009c000000690000213d001100000003001d000006a21010012a000e00000001001d0000000a01000039000000000101041a001200000001001d0000061401200197000006a20110012a001006a3001002870000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000012c40000613d000000000101043b0000001105000029000000000015004b00000012070000290000000e0400002900000e760000813d000006a20250012a0000000103200039000006a2023000d100000000033200d9000006a20030009c0000001008000029000000690000c13d000000000042001a000000690000413d0000000003420019000000000013004b00000000020100190000000002034019000000000452004b000000690000413d000000000008004b00000b170000613d00000000058400a900000000068500d9000000000046004b000000690000c13d000000000005004b00000b170000613d0000069b045000d100000000055400d90000069b0050009c00000b180000613d000000690000013d00000000040000190000000f044000fa000000000074001a000000690000413d001200000074001d000000000013004b000000010880a270001000000008001d001100000002001d00000aea0000013d00000617011001c700008009020000390000000005000019184d18430000040f0000006003100270000006140330019800000b2c0000c13d000000010020019000000b520000613d00000000010000190000184e0001042e0000001f04300039000006c0044001970000003f04400039000006c104400197000000400500043d0000000004450019000000000054004b00000000060000390000000106004039000006900040009c000000d50000213d0000000100600190000000d50000c13d000000400040043f0000001f0430018f00000000063504360000068f05300198000000000356001900000b440000613d000000000701034f000000007807043c0000000006860436000000000036004b00000b400000c13d000000000004004b00000b280000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000b280000013d000006c201000041000000000010043f0000068c010000410000184f00010430000006c701000041000000000010043f0000068c010000410000184f00010430000006bc01000041000000000010043f0000068c010000410000184f00010430000000200010043f000000000040043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000000001004b000000120300002900000ad50000613d000000000030043f0000001401000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000400200043d001000000002001d0000068d0020009c000000d50000213d000000000201043b00000010050000290000010001500039000000400010043f000000000102041a00000000031504360000000104200039000000000404041a00000000004304350000000203200039000000000303041a0000004004500039000e00000004001d00000000003404350000000303200039000000000303041a0000006004500039000d00000004001d00000000003404350000000403200039000000000303041a0000008004500039000c00000004001d00000000003404350000000503200039000000000303041a000000a004500039000f00000004001d00000000003404350000000603200039000000000303041a000000c0045000390000000000340435000000e0035000390000000702200039000000000202041a000000ff002001900000000002000039000000010200c0390000000000230435000000000010043f0000001801000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000a00000001001d0000000101000039000000000101041a000000400400043d000b00000004001d0000068e020000410000000000240435000000040240003900000000030004100000000000320435000006140040009c0000061402000041000000000204401900000040022002100000000003000414000006140030009c0000061403008041000000c003300210000000000323019f000006160210019700000682013001c7184d18480000040f00000060031002700000061403300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000b0b0000290000000b0570002900000bda0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000bd60000c13d000000000006004b00000be70000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000ee00000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000006900010009c000000d50000213d0000000100200190000000d50000c13d000000400010043f000000200030008c000015b80000413d00000000010b04330000000a0010006b0000114b0000a13d0000069601000041000000000010043f0000068c010000410000184f0001043000000001022002700000000e0520006c00000c380000a13d000000120050006c0000001205008029000006900050009c000000d50000213d00000005015002100000003f02100039000006d402200197000000400400043d0000000002240019000000000042004b00000000030000390000000103004039000006900020009c000000d50000213d0000000100300190000000d50000c13d000000400020043f000d00000004001d0000000002540436000c00000002001d000b00000005001d000000000005004b00000ddd0000c13d0000000d0300002900000c3e0000013d000000000020043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b00000002011000390000001102000029000000000021041b000000400100043d0000000000210435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d020000390000000203000039000006ac04000041000007c70000013d000000400300043d000006d30030009c000000d50000213d0000002001300039000000400010043f0000000000030435000000400100043d000000200200003900000000022104360000000008030019000000000303043300000000003204350000004002100039000000000003004b00000c6d0000613d0000000004000019000000200880003900000000050804330000000076050434000000000662043600000000070704330000000000760435000000400650003900000000060604330000004007200039000000000067043500000060065000390000000006060433000000600720003900000000006704350000008006500039000000000606043300000080072000390000000000670435000000a0065000390000000006060433000000a0072000390000000000670435000000c0065000390000000006060433000000c0072000390000000000670435000000e0055000390000000005050433000000000005004b0000000005000039000000010500c039000000e006200039000000000056043500000100022000390000000104400039000000000034004b00000c480000413d0000000002120049000006140020009c00000614020080410000006002200210000006140010009c00000614010080410000004001100210000000000112019f0000184e0001042e0000000001000411000000000010043f0000001a01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a001000000001001d000006a90100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000100110006c000000690000413d0000000b02000039000000000202041a000000000021004b00000ef00000813d000006cf01000041000000000010043f0000068c010000410000184f00010430000000000020043f0000001101000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b00000006011000390000001102000029000000000021041b000000400100043d0000000000210435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d020000390000000203000039000006af04000041000007c70000013d000000000020043f0000001101000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000701100039000000000201041a000006d9022001970000001103000029000000000232019f000000000021041b000000400100043d0000000000310435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d0200003900000002030000390000069c04000041000007c70000013d000000000010043f0000001601000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000006d90220019700000001022001bf000000000021041b000000120000006b00000da40000c13d0000068501000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000006140010009c0000061401008041000000c00110021000000697011001c70000800502000039184d18480000040f0000000100200190000012c40000613d000000000101043b001200000001001d000000000010043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000400200043d001100000002001d0000061f0020009c000000d50000213d000000000101043b0000001104000029000000c002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a001000000003001d00000000002304350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a000000ff002001900000000002000039000000010200c039000000600340003900000000002304350000000402100039000000000202041a0000008003400039000e00000003001d0000000000230435000000a0024000390000000501100039000000000101041a000f00000002001d00000000001204350000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001202000029000000000021041b000000110200002900000000020204330000000103100039000000000023041b000000100200002900000000020204330000000303100039000000000023041b0000000e0200002900000000020204330000000503100039000000000023041b00000006011000390000000f020000290000000002020433000000000021041b0000000001000414000006140010009c0000061401008041000000c00110021000000617011001c70000800d020000390000000203000039000006bd040000410000000005000411000007c80000013d000000000020043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000301100039000000000201041a000006d9022001970000001103000029000000000232019f000000000021041b000000400100043d0000000000310435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d0200003900000002030000390000069904000041000007c70000013d0000000c01000029000000000010043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000501100039000000000101041a0000000e0010006c000005220000213d0000000c01000029000000000010043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000101100039000000000101041a000000110010006c000010850000a13d000006a701000041000000000010043f0000068c010000410000184f000104300000000001000411000000000010043f0000001b01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a00000615022001970000001203000029000000000232019f000000000021041b000000000030043f0000001c01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a001200000002001d000006900020009c000000d50000213d00000012020000290000000102200039000000000021041b000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000698011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001201100029000000000201041a00000615022001970000000003000411000000000232019f000000000021041b00000cf00000013d00000000020000190000000c05000029000000400300043d0000068d0030009c000000d50000213d0000010004300039000000400040043f000000e0043000390000000000040435000000c0043000390000000000040435000000a0043000390000000000040435000000800430003900000000000404350000006004300039000000000004043500000040043000390000000000040435000000200430003900000000000404350000000000030435000000000452001900000000003404350000002002200039000000000012004b00000ddf0000413d001200000000001d0000068801000041000000040010043f0000001101000029000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000689011001c70000801002000039184d18480000040f0000000100200190000015b80000613d00000012030000290010000e0030002d000000000101043b0000001001100029000000000101041a000f00000001001d0000068801000041000000040010043f0000001101000029000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000689011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000201043b000006da01200167000000000101041a000000000001004b00000e200000613d000000010110027000000e2e0000013d000000000102041a000000000001004b0000000001000039000000010100c03900000e2e0000613d0000000103200039000000000303041a000000000003004b00000e2e0000613d0000000201200039000000000101041a000000000001004b00000003010000390000000201006039000000100010006b000011940000813d0000000f010000290000068a0010009c0000000001006019000000000010043f0000001401000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000400200043d0000068d0020009c0000000d050000290000000b060000290000000c07000029000000d50000213d000000000101043b0000010003200039000000400030043f000000000301041a00000000033204360000000104100039000000000404041a00000000004304350000000203100039000000000303041a000000400420003900000000003404350000000303100039000000000303041a000000600420003900000000003404350000000403100039000000000303041a000000800420003900000000003404350000000503100039000000000303041a000000a00420003900000000003404350000000603100039000000000303041a000000c0042000390000000000340435000000e0032000390000000701100039000000000101041a000000ff001001900000000001000039000000010100c039000000000013043500000000010504330000001203000029000000000031004b000010f80000a13d0000000501300210000000000171001900000000002104350000000001050433000000000031004b000010f80000a13d001200010030003d000000120060006b00000df90000413d00000c170000013d0000000d010000290000061601100197001100000001001d000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a001000000001001d0000001101000029000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000f00000001001d0000001101000029000000000010043f0000001001000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000120210006b000000690000413d0000000f012000b90000000f0000006b00000eaf0000613d0000000f031000fa000000000023004b000000690000c13d0000069b0110012a000000100010002a000000690000413d0000000c02000039000000000202041a0000069b0020009c000000690000213d0000001001100029000009de0000613d0000069b02200099000006da03200129000000000013004b00000ec00000813d000006cc01000041000000000010043f000006c5010000410000184f0001043000000000021200a9000000400100043d0000069b0220012a0000072a0000013d00000060061002700000001f0460018f0000068f05600198000000400200043d000000000352001900000ed00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000ecc0000c13d0000061406600197000000000004004b00000ede0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000009c00000013d0000001f0530018f0000068f06300198000000400200043d0000000004620019000009b20000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000ee70000c13d000009b20000013d000006d801000041000000000010043f000006c5010000410000184f000104300000001201000029000000010110003a000000690000613d000000000010043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000400200043d001200000002001d0000061f0020009c000000d50000213d000000000101043b0000001204000029000000c002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000f00000003001d00000000002304350000000202100039000000000202041a0000004003400039001000000003001d00000000002304350000000302100039000000000202041a000000ff0020019000000060024000390000000003000039000000010300c03900000000003204350000000402100039000000000202041a0000008003400039000d00000003001d0000000000230435000000a0024000390000000501100039000000000101041a000e00000002001d0000000000120435000011980000613d0000000101000039000000000201041a000000400400043d000c00000004001d0000068e010000410000000000140435000000040140003900000000030004110000000000310435000006140040009c0000061401000041000000000104401900000040011002100000000003000414000006140030009c0000061403008041000000c003300210000000000113019f00000682011001c70000061602200197000b00000002001d184d18480000040f00000060031002700000061403300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000c0b0000290000000c0570002900000f4a0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b00000f460000c13d000000000006004b00000f570000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000011ae0000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000a00000002001d000006900020009c000000d50000213d0000000100100190000000d50000c13d0000000a01000029000000400010043f000000200030008c000015b80000413d0000001001000029000000000101043300000000020b0433000000000012004b000010810000413d0000000a03000029000000440230003900000000001204350000000001000410000006160110019700000024023000390000000000120435000006b40100004100000000001304350000000001000411000006160110019700000004023000390000000000120435000006140030009c0000061401000041000000000103401900000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f000006b5011001c70000000b02000029184d18430000040f00000060031002700000061403300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000a0570002900000f950000613d000000000801034f0000000a09000029000000008a08043c0000000009a90436000000000059004b00000f910000c13d000000000006004b00000fa20000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000013020000613d0000001f01400039000000600110018f0000000a01100029000006900010009c000000d50000213d000000400010043f000000200030008c000015b80000413d0000000a010000290000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000015b80000c13d00000010010000290000000001010433000c00000001001d0000000101000039000000000101041a0000000d02000039000000000202041a000b00000002001d000000000002004b00000fc10000613d000000010200008a0000000b022000fa0000000c0020006c00000ebc0000413d0000061602100197000006b6010000410000000000100443000a00000002001d00000004002004430000000001000414000006140010009c0000061401008041000000c001100210000006b7011001c70000800202000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000000001004b000015b80000613d0000000b020000290000000c012000b90000069b0110012a000000400300043d000006b802000041000000000023043500000004023000390000000000120435000006140030009c000c00000003001d0000061401000041000000000103401900000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000682011001c70000000a02000029184d18430000040f0000000100200190000014350000613d0000000c01000029000006900010009c000000d50000213d0000000c01000029000000400010043f0000001101000029000000000101041a000000010110003a000000690000613d0000001103000029000000000013041b000000120100002900000000010104330000000102300039000000000012041b0000000f0100002900000000010104330000000302300039000000000012041b0000000d0100002900000000010104330000000502300039000000000012041b00000006013000390000000e020000290000000002020433000000000021041b0000000001000411000000000010043f0000001a01000039000000200010043f000006a90100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000012c40000613d000000000101043b001200000001001d0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001202000029000000000021041b0000001101000029000000000601041a00000010010000290000000001010433000000400200043d0000000000120435000006140020009c000006140200804100000040012002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d020000390000000303000039000006cd040000410000000005000411184d18430000040f000000010020019000000b2a0000c13d000015b80000013d0000000101000039000000000201041a000000400400043d000600000004001d0000068e010000410000000000140435000000040140003900000000030004110000000000310435000006140040009c0000061401000041000000000104401900000040011002100000000003000414000006140030009c0000061403008041000000c003300210000000000113019f00000682011001c70000061602200197000500000002001d184d18480000040f00000060031002700000061403300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000060b00002900000006057000290000105e0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000105a0000c13d000000000006004b0000106b0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000010ec0000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000400000002001d000006900020009c000000d50000213d0000000100100190000000d50000c13d0000000401000029000000400010043f000000200030008c000015b80000413d0000000e01000029000000000101043300000000020b0433000000000012004b0000119c0000813d000006ce01000041000000000010043f0000068c010000410000184f00010430000000400100043d000b00000001001d0000061f0010009c000000d50000213d0000000b03000029000000c001300039000000400010043f000000a0023000390000000e01000029000a00000002001d000000000012043500000080023000390000000d01000029000900000002001d000000000012043500000060023000390000000f01000029000800000002001d000000000012043500000040023000390000001001000029000700000002001d0000000000120435000000120100002900000000021304360000001101000029001200000002001d00000000001204350000000c01000029000000010110003a000000690000613d0000000702000039000000000012041b000000000010043f0000001201000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d0000000b020000290000000002020433000000000101043b000000000021041b000000120200002900000000020204330000000103100039000000000023041b000000070200002900000000020204330000000203100039000000000023041b0000000302100039000000000402041a000006d90340019700000008040000290000000004040433000000000004004b000000010330c1bf000000000032041b000000090200002900000000020204330000000403100039000000000023041b00000005011000390000000a020000290000000002020433000000000021041b0000000701000039000000000501041a000000400100043d00000080021000390000000e03000029000000000032043500000060021000390000000d03000029000000000032043500000040021000390000000f03000029000000000032043500000020021000390000001003000029000000000032043500000011020000290000000000210435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f000006a5011001c70000800d020000390000000203000039000006a604000041000007c80000013d0000001f0530018f0000068f06300198000000400200043d0000000004620019000009b20000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000010f30000c13d000009b20000013d000006d601000041000000000010043f0000003201000039000000040010043f00000682010000410000184f000104300000000001000414000006140010009c0000061401008041000000c001100210000006b7011001c70000800202000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000000001004b000015b80000613d000000400300043d000000240130003900000010020000290000000000210435000006c801000041000000000013043500000004013000390000000f020000290000000000210435000006140030009c000e00000003001d0000061401000041000000000103401900000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000695011001c70000001102000029184d18430000040f0000000100200190000011c70000613d0000000e01000029000006900010009c000000d50000213d0000000e01000029000000400010043f0000000f01000029000000000010043f0000001d01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000000100020002a000000690000413d0000001002200029000000000021041b000000400100043d00000012020000290000000000210435000006140010009c000006140100804100000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d020000390000000203000039000006c9040000410000000005000411000007c80000013d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000202100039000000000302041a000000000003004b000000690000613d000000010330008a000000000032041b0000000401100039000000000201041a0000000f030000290000000003030433000000000232004b000000690000413d000000000021041b0000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000068802000041000000040020043f000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000689011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000201043b000f00000002001d000006da01200167000800000001001d000000000101041a000900000001001d000000000001004b000012d10000c13d0000000f040000290000000201400039000b00000001001d000000000101041a0000000102400039000000000302041a000000000404041a000000110040006c0000130e0000c13d0000000f04000029000000000034041b000013100000013d000006d501000041000000000010043f0000068c010000410000184f00010430000006cb01000041000000000010043f0000068c010000410000184f000104300000000d02000029000000000202043300000007030000290000000403300039000600000003001d000000000303041a000000000032001a000000690000413d000000000232001900000007030000290000000303300039000000000303041a000000000032004b000011d40000a13d000006c601000041000000000010043f0000068c010000410000184f000104300000001f0530018f0000068f06300198000000400200043d0000000004620019000009b20000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000011b50000c13d000009b20000013d00000060061002700000001f0460018f0000068f05600198000000400200043d000000000352001900000ed00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000011c20000c13d00000ed00000013d00000060061002700000001f0460018f0000068f05600198000000400200043d000000000352001900000ed00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000011cf0000c13d00000ed00000013d0000000403000029000000440230003900000000001204350000000001000410000006160110019700000024023000390000000000120435000006b40100004100000000001304350000000001000411000006160110019700000004023000390000000000120435000006140030009c0000061401000041000000000103401900000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f000006b5011001c70000000502000029184d18430000040f00000060031002700000061403300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000405700029000011fc0000613d000000000801034f0000000409000029000000008a08043c0000000009a90436000000000059004b000011f80000c13d000000000006004b000012090000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000012c50000613d0000001f01400039000000600110018f0000000401100029000006900010009c000000d50000213d000000400010043f000000200030008c000015b80000413d00000004010000290000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000015b80000c13d0000000e010000290000000001010433000500000001001d0000000101000039000000000101041a0000000d02000039000000000202041a000400000002001d000000000002004b000012280000613d000000010200008a00000004022000fa000000050020006c00000ebc0000413d0000061602100197000006b6010000410000000000100443000300000002001d00000004002004430000000001000414000006140010009c0000061401008041000000c001100210000006b7011001c70000800202000039184d18480000040f0000000100200190000012c40000613d000000000101043b000000000001004b000015b80000613d000000040200002900000005012000b90000069b0110012a000000400300043d000006b802000041000000000023043500000004023000390000000000120435000006140030009c000500000003001d0000061401000041000000000103401900000040011002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000682011001c70000000302000029184d18430000040f00000001002001900000141e0000613d0000000501000029000006900010009c000000d50000213d0000000501000029000000400010043f00000012010000290000000c02000029000000000012043500000011010000290000000b0200002900000000001204350000000501000039000000000101041a000000010110003a000000690000613d0000000502000039000000000012041b0000000a0200002900000000001204350000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001202000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001102000029000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000006d90220019700000001022001bf000000000021041b0000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d0000000502000039000000000202041a000500000002001d000000000101043b0000068802000041000000040020043f000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000689011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000400000001001d00000005010000290000068a0010009c000005c00000613d0000000402000029000006da01200167000200000001001d000000000301041a000000200020043f000000050000006b00000005010000290000068a01006041000500000001001d000300000003001d000000000003004b000015400000c13d0000000401000029000000000101041a000000000001004b000015000000c13d00000005010000290000000402000029000015590000013d000000000001042f0000001f0530018f0000068f06300198000000400200043d0000000004620019000009b20000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000012cc0000c13d000009b20000013d0000000f01000029000000200010043f0000001101000029000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000b00000001001d000000000101041a001100000001001d000000000001004b000013130000613d000000090100002900000001011002700009000100100092000000110010006b000012fd0000613d00000011010000290000000f0110002900000009030000290000000f02300029000000000202041a000000010110008a000000000021041b000000000020043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000001102000029000000000021041b0000000901000029000000010110021000000001011001bf0000000802000029000013100000013d0000001f0530018f0000068f06300198000000400200043d0000000004620019000009b20000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000013090000c13d000009b20000013d000000110030006c0000141b0000c13d000000000012041b0000000b01000029000000000001041b0000001201000029000000000010043f0000001401000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000701100039000000000001041b0000000001000411000000000010043f0000001901000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000e020000290000000002020433000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000d020000290000000002020433000000000020043f000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000006d902200197000000000021041b000000100100002900000000060104330000000e0100002900000000010104330000000d020000290000000002020433000000400300043d00000060043000390000000000240435000000400230003900000000001204350000002001300039000000120200002900000000002104350000000a010000290000000000130435000006140030009c000006140300804100000040013002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000691011001c70000800d02000039000000030300003900000692040000410000000005000411184d18430000040f0000000100200190000015b80000613d0000000c010000290000000001010433001200000001001d0000000001000411184d16100000040f0000000901000039000000000201041a000000120220006c000000690000413d000000000021041b0000000001000411000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000000120220006c000000690000413d000000000021041b0000000001000411000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a001200000001001d0000000001000411000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000012010000290000000000120435000006140020009c000006140200804100000040012002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f0000061e011001c70000800d02000039000000020300003900000693040000410000000005000411184d18430000040f0000000100200190000015b80000613d0000000a0000006b00000b2a0000613d0000000101000039000000000201041a000000400400043d001200000004001d00000024014000390000000a030000290000000000310435000006940100004100000000001404350000000001000411000006160110019700000004034000390000000000130435000006140040009c0000061401000041000000000104401900000040011002100000000003000414000006140030009c0000061403008041000000c003300210000000000113019f00000695011001c70000061602200197184d18430000040f00000060031002700000061403300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000120b0000290000001205700029000013f80000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000013f40000c13d000000000006004b000014050000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000014f40000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000006900010009c000000d50000213d0000000100200190000000d50000c13d000000400010043f000000200030008c000015b80000413d00000000010b0433000000000001004b0000000002000039000000010200c039000000000021004b00000b2a0000613d000015b80000013d000000110010006c000013110000613d000013130000013d00000060061002700000001f0460018f0000068f05600198000000400200043d000000000352001900000ed00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000014260000c13d00000ed00000013d000000050010006c000014920000613d00000004020000290000000102200039000000000302041a000300000003001d000000000003004b000014420000c13d0000000501000029000014910000013d00000060061002700000001f0460018f0000068f05600198000000400200043d000000000352001900000ed00000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b0000143d0000c13d00000ed00000013d0000000303000029000000050030006c000014920000613d00000004020000290000000202200039000000000302041a000100000003001d000000000003004b000014330000613d0000000103000029000000050030006c000014920000613d000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000102000039000000000021041b0000000301000029000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000202000039000000000021041b0000000101000029000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000302000039000000000021041b000300070000003d0000000501000029000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000000000002004b000014920000c13d0000000302000029000000010220027000000004032000290000000504000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000202000029000000000012041b0000000501000039000000000101041a000000000010043f0000001401000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d0000000f020000290000000002020433000000000301043b000000000023041b0000000b0100002900000000010104330000000102300039000000000012041b0000000d0100002900000000010104330000000202300039000000000012041b0000000c0100002900000000010104330000000302300039000000000012041b0000000a0100002900000000010104330000000402300039000000000012041b0000000e0100002900000000010104330000000502300039000000000012041b000000080200002900000000020204330000000604300039000000000024041b0000000702300039000000000302041a000006d90330019700000009040000290000000004040433000000000004004b000000010330c1bf000000000032041b00000007020000290000000202200039000000000302041a000000010330003a000000690000613d000000000032041b0000000602000029000000000202041a000000000012001a000000690000413d00000000011200190000000602000029000000000012041b0000000501000039000000000101041a000000400200043d000000600320003900000011040000290000000000430435000000400320003900000012040000290000000000430435000000200320003900000000001304350000000000020435000006140020009c000006140200804100000040012002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000691011001c70000800d020000390000000303000039000006b90400004100000000050004110000001006000029184d18430000040f0000000100200190000015b80000613d0000000a0100002900000000020104330000000001000411184d16d40000040f00000000010000190000184e0001042e0000001f0530018f0000068f06300198000000400200043d0000000004620019000009b20000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000014fb0000c13d000009b20000013d000000050010006c0000155a0000613d00000004020000290000000102200039000000000302041a000300000003001d000000000003004b0000150a0000c13d0000000501000029000015590000013d0000000303000029000000050030006c0000155a0000613d00000004020000290000000202200039000000000302041a000100000003001d000000000003004b000015080000613d0000000103000029000000050030006c0000155a0000613d000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000102000039000000000021041b0000000301000029000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000202000039000000000021041b0000000101000029000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b0000000302000039000000000021041b000300070000003d0000000501000029000000000010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d000000000101043b000000000201041a000000000002004b0000155a0000c13d0000000302000029000000010220027000000004032000290000000504000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000202000029000000000012041b0000000501000039000000000101041a000000000010043f0000001401000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000015b80000613d00000008020000290000000002020433000000000301043b000000000023041b0000000a0100002900000000010104330000000102300039000000000012041b0000000c0100002900000000010104330000000202300039000000000012041b0000000b0100002900000000010104330000000302300039000000000012041b000000090100002900000000010104330000000402300039000000000012041b0000000d0100002900000000020104330000000501300039000000000021041b0000000e0100002900000000010104330000000604300039000000000014041b0000000703300039000000000403041a000006d9044001970000000f050000290000000005050433000000000005004b000000010440c1bf000000000043041b00000007030000290000000203300039000000000403041a000000010440003a000000690000613d000000000043041b0000000603000029000000000303041a000000000023001a000000690000413d00000000022300190000000603000029000000000023041b0000000502000039000000000202041a000000400300043d000000600430003900000011050000290000000000540435000000400430003900000012050000290000000000540435000000200430003900000000002404350000000000130435000006140030009c000006140300804100000040013002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000691011001c70000800d020000390000000303000039000006b90400004100000000050004110000001006000029184d18430000040f0000000100200190000015b80000613d0000000901000029000014ef0000013d00000000010000190000184f00010430000006dc0010009c000015c80000213d000000630010008c000015c80000a13d00000000030003670000000401300370000000000101043b000006160010009c000015c80000213d0000002402300370000000000202043b0000004403300370000000000303043b000000000001042d00000000010000190000184f000104300001000000000002000000000301041a000100000002001d000000000023004b000015dd0000a13d000000000010043f0000000001000414000006140010009c0000061401008041000000c00110021000000698011001c70000801002000039184d18480000040f0000000100200190000015e30000613d000000000101043b00000001011000290000000002000019000000000001042d000006d601000041000000000010043f0000003201000039000000040010043f00000682010000410000184f0001043000000000010000190000184f000104300000001f02200039000006db022001970000000001120019000000000021004b00000000020000390000000102004039000006900010009c000015f10000213d0000000100200190000015f10000c13d000000400010043f000000000001042d000006d601000041000000000010043f0000004101000039000000040010043f00000682010000410000184f000104300000000002120049000006dc0020009c000016030000213d0000001f0020008c000016030000a13d0000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000016030000c13d000000000001042d00000000010000190000184f00010430000000000100041a00000616021001970000000001000411000000000012004b0000160b0000c13d000000000001042d0000068102000041000000000020043f000000040010043f00000682010000410000184f000104300003000000000002000100000001001d0000000901000039000000000101041a000000000001004b0000000802000039000016620000613d0000000301000039000000000101041a000000000202041a000000000112004b000016c50000413d000006a10010009c000016c50000213d000300000002001d0000061401100197000006a20110012a000206a3001002870000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000016cb0000613d000000000101043b0000000304000029000000000014004b0000166e0000813d000006a20240012a0000000103200039000006a2023000d100000000033200d9000006a20030009c0000000207000029000016c50000c13d0000000303000039000000000303041a000006a23030012a000000000023001a000016c50000413d0000000003230019000000000013004b00000000020100190000000002034019000000000442004b000016c50000413d000000000007004b000016500000613d00000000057400a900000000067500d9000000000046004b000016c50000c13d000000000005004b000016500000613d0000069b045000d100000000055400d90000069b0050009c000016510000613d000016c50000013d00000000040000190000000905000039000000000505041a000000000005004b000016cc0000613d00000000045400d90000000a05000039000000000505041a000000000045001a000016c50000413d00000000044500190000000a05000039000000000045041b000000000013004b000000010770a270000200000007001d000300000002001d000016220000013d0000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000016cb0000613d000000000101043b0000000802000039000000000012041b00000001010000290000061601100197000300000001001d000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000016d20000613d0000000a02000039000000000202041a000100000002001d000000000101043b000000000101041a000200000001001d0000001001000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000016d20000613d000000000101043b000000000101041a000000010110006b0000000202000029000016c50000413d00000000032100a9000000000002004b0000169b0000613d00000000022300d9000000000012004b000016c50000c13d000200000003001d0000000301000029000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000016d20000613d00000002020000290000069b0220012a000000000101043b000000000301041a000000000023001a000016c50000413d0000000002230019000000000021041b0000000a01000039000000000101041a000200000001001d0000000301000029000000000010043f0000001001000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f0000000100200190000016d20000613d000000000101043b0000000202000029000000000021041b000000000001042d000006d601000041000000000010043f0000001101000039000000040010043f00000682010000410000184f00010430000000000001042f000006d601000041000000000010043f0000001201000039000000040010043f00000682010000410000184f0001043000000000010000190000184f000104300004000000000002000200000002001d000100000001001d0000000401000039000000000201041a000000ff00200190000016ff0000c13d000006d90220019700000001022001bf000000000021041b0000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000018060000613d000000000101043b0000000302000039000000000012041b0000000802000039000000000012041b000000400200043d0000000000120435000006140020009c000006140200804100000040012002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000698011001c70000800d020000390000000103000039000006dd04000041184d18430000040f00000001002001900000180d0000613d0000000901000039000000000101041a000000000001004b0000174f0000613d0000000301000039000000000101041a0000000802000039000000000202041a000000000112004b000018000000413d000006a10010009c000018000000213d000400000002001d0000061401100197000006a20110012a000306a3001002870000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000018060000613d000000000101043b0000000404000029000000000014004b0000175b0000813d000006a20240012a0000000103200039000006a2023000d100000000033200d9000006a20030009c0000000307000029000018000000c13d0000000303000039000000000303041a000006a23030012a000000000023001a000018000000413d0000000003230019000000000013004b00000000020100190000000002034019000000000442004b000018000000413d000000000007004b0000173d0000613d00000000057400a900000000067500d9000000000046004b000018000000c13d000000000005004b0000173d0000613d0000069b045000d100000000055400d90000069b0050009c0000173e0000613d000018000000013d00000000040000190000000905000039000000000505041a000000000005004b000018070000613d00000000045400d90000000a05000039000000000505041a000000000045001a000018000000413d00000000044500190000000a05000039000000000045041b000000000013004b000000010770a270000300000007001d000400000002001d0000170f0000013d0000069f0100004100000000001004430000000001000414000006140010009c0000061401008041000000c001100210000006a0011001c70000800b02000039184d18480000040f0000000100200190000018060000613d000000000101043b0000000802000039000000000012041b00000001010000290000061601100197000400000001001d000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f00000001002001900000180d0000613d0000000a02000039000000000202041a000100000002001d000000000101043b000000000101041a000300000001001d0000001001000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f00000001002001900000180d0000613d000000000101043b000000000101041a000000010110006b0000000302000029000018000000413d00000000032100a9000000000002004b000017880000613d00000000022300d9000000000012004b000018000000c13d000300000003001d0000000401000029000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f00000001002001900000180d0000613d00000003020000290000069b0220012a000000000101043b000000000301041a000000000023001a000018000000413d0000000002230019000000000021041b0000000a01000039000000000101041a000300000001001d0000000401000029000000000010043f0000001001000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f00000001002001900000180d0000613d000000000101043b0000000302000029000000000021041b0000000901000039000000000101041a000000020010002a000018000000413d00000002011000290000000902000039000000000012041b0000000401000029000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f00000001002001900000180d0000613d000000000101043b000000000201041a000000020020002a000018000000413d0000000202200029000000000021041b0000000401000029000000000010043f0000000e01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f00000001002001900000180d0000613d000000000101043b000000000101041a000300000001001d0000000401000029000000000010043f0000000f01000039000000200010043f0000000001000414000006140010009c0000061401008041000000c0011002100000061e011001c70000801002000039184d18480000040f00000001002001900000180d0000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000003010000290000000000120435000006140020009c000006140200804100000040012002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f0000061e011001c70000800d0200003900000002030000390000000005000411000006de04000041184d18430000040f00000001002001900000180d0000613d000000000001042d000006d601000041000000000010043f0000001101000039000000040010043f00000682010000410000184f00010430000000000001042f000006d601000041000000000010043f0000001201000039000000040010043f00000682010000410000184f0001043000000000010000190000184f00010430000000000001042f000006140010009c00000614010080410000004001100210000006140020009c00000614020080410000006002200210000000000112019f0000000002000414000006140020009c0000061402008041000000c002200210000000000112019f00000617011001c70000801002000039184d18480000040f0000000100200190000018230000613d000000000101043b000000000001042d00000000010000190000184f0001043000000000050100190000000000200443000000050030008c000018330000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b0000182b0000413d000006140030009c000006140300804100000060013002100000000002000414000006140020009c0000061402008041000000c002200210000000000112019f000006df011001c70000000002050019184d18480000040f0000000100200190000018420000613d000000000101043b000000000001042d000000000001042f00001846002104210000000102000039000000000001042d0000000002000019000000000001042d0000184b002104230000000102000039000000000001042d0000000002000019000000000001042d0000184d000004320000184e0001042e0000184f0001043000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff02000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000058d15e176280000000000000000000000000000000000000000000000000000a688906bd8b00000000000000000000000000000000000000000000000000000011c37937e08000000000000000000000000000000000000000000000000000ffffffffffffff000200000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff3f00000002000000000000000000000000000000c0000001000000000000000000000000000000000000000000000000000000000000000000000000006d12ff51000000000000000000000000000000000000000000000000000000009f715f5f00000000000000000000000000000000000000000000000000000000d9ba62b200000000000000000000000000000000000000000000000000000000e2b15d8b00000000000000000000000000000000000000000000000000000000ea26fa2c00000000000000000000000000000000000000000000000000000000ea26fa2d00000000000000000000000000000000000000000000000000000000eef3b2d000000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000e2b15d8c00000000000000000000000000000000000000000000000000000000e92820e600000000000000000000000000000000000000000000000000000000df1e3b7e00000000000000000000000000000000000000000000000000000000df1e3b7f00000000000000000000000000000000000000000000000000000000e0d152af00000000000000000000000000000000000000000000000000000000d9ba62b300000000000000000000000000000000000000000000000000000000dd6a4c6500000000000000000000000000000000000000000000000000000000c243589300000000000000000000000000000000000000000000000000000000ca18116f00000000000000000000000000000000000000000000000000000000ca18117000000000000000000000000000000000000000000000000000000000d147129600000000000000000000000000000000000000000000000000000000c243589400000000000000000000000000000000000000000000000000000000c51a2bba00000000000000000000000000000000000000000000000000000000adadbd2600000000000000000000000000000000000000000000000000000000adadbd2700000000000000000000000000000000000000000000000000000000bbfcddd5000000000000000000000000000000000000000000000000000000009f715f6000000000000000000000000000000000000000000000000000000000a9f8d181000000000000000000000000000000000000000000000000000000008685e3f1000000000000000000000000000000000000000000000000000000009292ae9a000000000000000000000000000000000000000000000000000000009618b31b000000000000000000000000000000000000000000000000000000009618b31c000000000000000000000000000000000000000000000000000000009ca423b3000000000000000000000000000000000000000000000000000000009292ae9b0000000000000000000000000000000000000000000000000000000094fc19e4000000000000000000000000000000000000000000000000000000008da5cb5a000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000008dfc3933000000000000000000000000000000000000000000000000000000008685e3f20000000000000000000000000000000000000000000000000000000086b3cd2600000000000000000000000000000000000000000000000000000000787a08a500000000000000000000000000000000000000000000000000000000811c508800000000000000000000000000000000000000000000000000000000811c50890000000000000000000000000000000000000000000000000000000084ae2bc600000000000000000000000000000000000000000000000000000000787a08a6000000000000000000000000000000000000000000000000000000007e08b5b300000000000000000000000000000000000000000000000000000000715018a500000000000000000000000000000000000000000000000000000000715018a60000000000000000000000000000000000000000000000000000000072779cba000000000000000000000000000000000000000000000000000000006d12ff5200000000000000000000000000000000000000000000000000000000713494d7000000000000000000000000000000000000000000000000000000003e89bb120000000000000000000000000000000000000000000000000000000059058ad0000000000000000000000000000000000000000000000000000000005fd9491c0000000000000000000000000000000000000000000000000000000069f0ee320000000000000000000000000000000000000000000000000000000069f0ee33000000000000000000000000000000000000000000000000000000006ba4f47f000000000000000000000000000000000000000000000000000000005fd9491d000000000000000000000000000000000000000000000000000000006756a1c7000000000000000000000000000000000000000000000000000000005c7421e2000000000000000000000000000000000000000000000000000000005c7421e3000000000000000000000000000000000000000000000000000000005d4954110000000000000000000000000000000000000000000000000000000059058ad1000000000000000000000000000000000000000000000000000000005a5ccef000000000000000000000000000000000000000000000000000000000476e2e65000000000000000000000000000000000000000000000000000000004fc3f419000000000000000000000000000000000000000000000000000000004fc3f41a00000000000000000000000000000000000000000000000000000000542f9e6a00000000000000000000000000000000000000000000000000000000476e2e660000000000000000000000000000000000000000000000000000000048cd4cb10000000000000000000000000000000000000000000000000000000041a0894c0000000000000000000000000000000000000000000000000000000041a0894d00000000000000000000000000000000000000000000000000000000444d51ad000000000000000000000000000000000000000000000000000000003e89bb130000000000000000000000000000000000000000000000000000000040f5da9e00000000000000000000000000000000000000000000000000000000234f3f1a0000000000000000000000000000000000000000000000000000000031d7a261000000000000000000000000000000000000000000000000000000003a8ee01d000000000000000000000000000000000000000000000000000000003a8ee01e000000000000000000000000000000000000000000000000000000003ccfd60b0000000000000000000000000000000000000000000000000000000031d7a26200000000000000000000000000000000000000000000000000000000372500ab000000000000000000000000000000000000000000000000000000002fc96ce5000000000000000000000000000000000000000000000000000000002fc96ce60000000000000000000000000000000000000000000000000000000030775a9400000000000000000000000000000000000000000000000000000000234f3f1b0000000000000000000000000000000000000000000000000000000024b4464e00000000000000000000000000000000000000000000000000000000157e204b000000000000000000000000000000000000000000000000000000001bce7820000000000000000000000000000000000000000000000000000000001bce7821000000000000000000000000000000000000000000000000000000001e57057d00000000000000000000000000000000000000000000000000000000157e204c000000000000000000000000000000000000000000000000000000001a267cd20000000000000000000000000000000000000000000000000000000011d988bb0000000000000000000000000000000000000000000000000000000011d988bc00000000000000000000000000000000000000000000000000000000155dd47a00000000000000000000000000000000000000000000000000000000032fca010000000000000000000000000000000000000000000000000000000010d96759118cdaa70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000001e4fbdf7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000800000000000000000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000008000000000000000000000000000000000000000000000000000000000000000000000000018fb586402000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000000000000fbb67fda52d4bfb8bf3d9f63cb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffeff70a082310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000000000000000000000000000ffffffffffffffff0200000000000000000000000000000000000080000000000000000000000000952aa29dabfc45e8c9bba19903b0a8bb9031c952db14a06ad48af137e5835b07e331ada0d0e61e9a4196bf4994f2519193d70a601daff346c4276d591664da9aa9059cbb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000515d3e8100000000000000000000000000000000000000000000000000000000020000020000000000000000000000000000004400000000000000000000000002000000000000000000000000000000000000200000000000000000000000000bd772fd008a8dd5673c42a4f50f72220b2603eee55113cd6c38ff78d71e644fedd999f8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000d0a7ceb410ade2d440d8ed59d6b338fe480f98025101655790e0de736edddabe3b87f10900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004400000080000000000000000042cbb15ccdc3cad6266b0e7a08c0454b23bf29dc2df74b6f3c209e9336465bd102000002000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000040163fff000000000000000000000000000000000000000000000000000000000040164000000000000000000000000000000000000000000000000022b1c8c1227a0000e0a2f8482bbba7e119c069eb63409ac33b15fc516cffed25aeabb6a9669e07c202000000000000000000000000000000000000a00000000000000000000000006ae4a0e17ec15e82a1af6ff99411c44193a38f27f15c3ddd30b0f09ab1c5fd2cd2a50ed000000000000000000000000000000000000000000000000000000000472ea01c00000000000000000000000000000000000000000000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320000000000000000000000000000000000000000000000000de0b6b3a764000158d620b300000000000000000000000000000000000000000000000000000000f721e9425607d38abda58b925d2a080b3aefa127d46973d2683875dc87cb9a6bf1fa1762000000000000000000000000000000000000000000000000000000006cb4090800000000000000000000000000000000000000000000000000000000f920b24ea96b3814655944622f9eb86875e3193c5de1a9de018777e6c8705cee4705d684000000000000000000000000000000000000000000000000000000003a6c77df0000000000000000000000000000000000000000000000000000000086257f0afab037798cc4548a6d86125f52c92410a1e29aff03d787d49dac20db00000000000000000000000000000000000000e000000080000000000000000023b872dd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000042966c680000000000000000000000000000000000000000000000000000000070a5d2d3258adcf9978a193a4dd8fa309ae83a9f1046a0a5ea99a133bf34f9a5aa8a9b9800000000000000000000000000000000000000000000000000000000d2ade556000000000000000000000000000000000000000000000000000000008fe6f7d800000000000000000000000000000000000000000000000000000000e424ed553a53c3a900c875ed34d63043e4dfb799427ee8ae0836b046a603c90e61104228000000000000000000000000000000000000000000000000000000009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f3900000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000003ffffffe0750b219c0000000000000000000000000000000000000000000000000000000070e9a55a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f5a267f100000000000000000000000000000000000000040000001c0000000000000000fbfd2f4000000000000000000000000000000000000000000000000000000000a800e0ac0000000000000000000000000000000000000000000000000000000040c10f1900000000000000000000000000000000000000000000000000000000fc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe0df723dc0000000000000000000000000000000000000000000000000000000047cd2fa60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bac65e5be2dbc44c627e3876b04b29d12596a77c7d0fa585ccb754b9fcd92e48d813dd77ff0b21e60000000000000000000000000000000000000000000000000000000041fde9ef0000000000000000000000000000000000000000000000000000000072932dd3000000000000000000000000000000000000000000000000000000000c02d44e00000000000000000000000000000000000000000000000000000000602fe2ca00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe04e23d035000000000000000000000000000000000000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000080000000000000000000000000000000000000000000000000000000000000000000000000ad251c27ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdaae9aa758637a0d349f036f099afd70aa88d8ac63fce096321de512ffebc16ca051d58ced8df58040b29d2c939da70a826ae40290f77c9a66b38b8b85315f6502000002000000000000000000000000000000000000000000000000000000000d4e1c9cf47b66892ca11d09723f471006f66f0bed215fb3245f280e013046b2
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $1,649.67 | 0.01 | $16.5 |
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.