Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Purchase Initial... | 6817081 | 284 days ago | IN | 0.01 ETH | 0.00000483 |
Cross-Chain Transactions
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 Name:
Main
Compiler Version
v0.8.24+commit.e11b9ed9
ZkSolc Version
v1.5.12
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
import {FixedPointMathLib} from "solady/utils/FixedPointMathLib.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";
import {IMinereum} from "./interfaces/IMinereum.sol";
// METH main program
contract Main is OwnableUpgradeable {
using EnumerableSetLib for EnumerableSetLib.Uint256Set;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// STORAGE
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/// @dev METH token address.
address public meth;
/// @dev feeReceiver fee recipient.
address public feeReceiver;
/// @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 meth per single hash.
uint256 public cumulativeMETHPerHash;
/// @dev Initial referral fee is 5%.
uint256 public referralFee;
/// @dev Initial burn is 90%.
uint256 public burnPct;
/// @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 playerMETHDebt;
/// @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 each miners coords for a player
mapping(address => mapping(uint256 => mapping(uint256 => bool))) public playerOccupiedCoords;
/// @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 refer fee recipient.
address private referReceiver;
/// @dev Purchasing initial facility price in ETH.
uint256 public initialFacilityPrice;
/// @dev start miner and facility index (these will never change since every player starts with same facility).
uint256 public STARTER_MINER_INDEX;
uint256 public STARTER_FACILITY_INDEX;
/// @dev Halvening every 1_680_000 blocks, roughly 20 days
uint256 public constant HALVING_INTERVAL = 1_680_000;
/// @dev Initial meth per block
uint256 public constant INITIAL_MINECOIN_PER_BLOCK = 2.5e18; // 2.5 METH per block
uint256 public constant REWARDS_PRECISION = 1e18;
uint256 public totalUsers;
uint256 public antiWhaleRate;
address public antiWhaleAddress;
uint256 public constant ANTI_WHALE_MINERS_COUNT = 30;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CONSTRUCTOR
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
function initialize(
address _meth,
address _feeReceiver,
address _referReveicer,
address _antiWhaleAddress
) public initializer {
__Ownable_init(msg.sender);
STARTER_MINER_INDEX = ++uniqueMinerCount;
referralFee = 0.05e18;
burnPct = 0.9e18;
initialFacilityPrice = 0.01 ether;
meth= _meth;
feeReceiver = _feeReceiver;
referReceiver = _referReveicer;
antiWhaleAddress = _antiWhaleAddress;
_increaseHashrate(_antiWhaleAddress, 360000);
antiWhaleRate = 50;
// add starter free miner
miners[STARTER_MINER_INDEX] = Miner(
STARTER_MINER_INDEX,
type(uint256).max,
type(uint256).max,
type(uint256).max,
180,
3,
type(uint256).max, // this is the free starter miner, people cannot buy it
false
);
// add starter facility
facilities[++facilityCount] = NewFacility(
2,
12,
type(uint256).max, // starter facility, people cannot buy it
false,
1,
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;
totalUsers+=1;
if(totalUsers % antiWhaleRate == 0 && totalUsers / antiWhaleRate < ANTI_WHALE_MINERS_COUNT) {
_decreaseHashrate(antiWhaleAddress, 12000);
}
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 meth.
*/
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 (IMinereum(meth).balanceOf(msg.sender) < miner.cost) {
revert Errors.TooPoor();
}
if (facility.currPowerOutput + miner.powerConsumption > facility.totalPowerOutput) {
revert Errors.FacilityInadequatePowerOutput();
}
// transfer correct amt of meth
IMinereum(meth).transferFrom(msg.sender, address(this), miner.cost);
// burn
IMinereum(meth).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 Cancel miners,
* Players will cancel miners in the case they run out of spots in their facility to put new miners.
*/
function cancelMiner(uint256 minerId) external {
if (!playerMinersOwned[msg.sender].contains(minerId)) {
revert Errors.PlayerDoesNotOwnMiner();
}
Miner memory miner = playerMinersId[minerId];
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, minerId, miner.x, miner.y);
_decreaseHashrate(msg.sender, miner.hashrate);
}
/**
* @dev Purchase larger or more power output facility.
*
* Players must linearly climb the facilities.
*/
function buyNewFacility() external payable {
// 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();
}
NewFacility memory newFacility = facilities[currFacilityIndex + 1];
if (!newFacility.inProduction) {
revert Errors.NewFacilityNotInProduction();
}
if (msg.value != newFacility.cost) {
revert Errors.IncorrectValue();
}
currFacility.facilityIndex++;
currFacility.maxMiners = newFacility.maxMiners;
currFacility.totalPowerOutput = newFacility.totalPowerOutput;
currFacility.x = newFacility.x;
currFacility.y = newFacility.y;
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;
IMinereum(meth).mint(msg.sender, finalRewards);
address referrer = referrals[msg.sender];
if (referrer != address(0)) {
IMinereum(meth).mint(referrer, referralBonus);
referralBonusPaid[referrer] += referralBonus;
} else {
IMinereum(meth).mint(referReceiver, referralBonus);
referralBonusPaid[referReceiver] += 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
// meth emissions per halvening
uint256 currentBlock = lastRewardBlock;
uint256 lastMETHPerBlock =
INITIAL_MINECOIN_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
cumulativeMETHPerHash +=
((lastMETHPerBlock * (endBlock - currentBlock) * REWARDS_PRECISION) / totalHashrate);
// move to next segment
currentBlock = endBlock;
// if a halving has happened, apply the new rate
if (currentBlock == nextHalvingBlock) {
lastMETHPerBlock /= 2;
}
}
lastRewardBlock = block.number;
}
function _updateRewards(address player) internal {
_updateCumulativeRewards();
playerPendingRewards[player] +=
(playerHashrate[player] * (cumulativeMETHPerHash - playerMETHDebt[player])) / REWARDS_PRECISION;
playerMETHDebt[player] = cumulativeMETHPerHash;
}
/**
* @dev Increase players hashrate.
*/
function _increaseHashrate(address player, uint256 hashrate) internal {
// only start rewarding meth 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 getMETHPerBlock() public view returns (uint256) {
if (!miningHasStarted) {
return 0;
}
uint256 halvingsSinceStart = (block.number - startBlock) / HALVING_INTERVAL;
return INITIAL_MINECOIN_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 lastMETHPerBlock =
INITIAL_MINECOIN_PER_BLOCK / (2 ** ((lastRewardBlock - startBlock) / HALVING_INTERVAL));
uint256 simulatedCumulativeMETHPerHash = cumulativeMETHPerHash;
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) {
simulatedCumulativeMETHPerHash +=
((lastMETHPerBlock * (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) {
lastMETHPerBlock /= 2;
}
}
return FixedPointMathLib.mulWad(
playerPendingRewards[player]
+ (
(playerHashrate[player] * (simulatedCumulativeMETHPerHash - playerMETHDebt[player]))
/ REWARDS_PRECISION
),
1e18 - referralFee
);
}
/**
* @dev Get current meth a player mines per block.
*/
function playerMETHPerBlock(address player) external view returns (uint256) {
if (totalHashrate == 0) {
return 0; // Prevent division by zero
}
uint256 currMETHPerBlock =
INITIAL_MINECOIN_PER_BLOCK / (2 ** ((block.number - startBlock) / HALVING_INTERVAL));
return FixedPointMathLib.mulDiv(playerHashrate[player], currMETHPerBlock, 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 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);
}
function setMETH(address _meth) external onlyOwner {
meth = _meth;
}
function setAntiWhaleRate(uint256 _rate) external onlyOwner {
antiWhaleRate = _rate;
}
function setFeeReceiver(address _feeReceiver) external onlyOwner {
feeReceiver = _feeReceiver;
}
function setReferReceiver(address _referReceiver) external onlyOwner {
referReceiver = _referReceiver;
}
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 withdraw() external onlyOwner {
uint256 balance = address(this).balance;
(bool success,) = payable(feeReceiver).call{value: balance}("");
if (!success) revert Errors.WithdrawFailed();
}
function withdrawMETH(uint256 amt) external onlyOwner {
IMinereum(meth).transfer(feeReceiver, 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);
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/**
* @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.24;
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.24;
/**
* @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.24;
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 InitialFacilityPurchased(address indexed player);
event FreeMinerRedeemed(address indexed player);
event MinerSold(
address indexed player,
uint256 indexed minerIndex,
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: Unlicense
pragma solidity ^0.8.24;
interface IMinereum {
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.24;
/**
* @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.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/snekmate/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: 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
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @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.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
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) {
OwnableStorage storage $ = _getOwnableStorage();
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 {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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;
}
}{
"optimizer": {
"enabled": true,
"mode": "3"
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"detectMissingLibraries": false,
"forceEVMLA": false,
"enableEraVMExtensions": false,
"codegen": "evmla",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AlreadyAtMaxFacility","type":"error"},{"inputs":[],"name":"AlreadyPurchasedInitialFactory","type":"error"},{"inputs":[],"name":"CantModifyStarterFacility","type":"error"},{"inputs":[],"name":"CantModifyStarterMiner","type":"error"},{"inputs":[],"name":"FacilityDimensionsInvalid","type":"error"},{"inputs":[],"name":"FacilityInadequatePowerOutput","type":"error"},{"inputs":[],"name":"IncorrectValue","type":"error"},{"inputs":[],"name":"IndexOutOfBounds","type":"error"},{"inputs":[],"name":"InvalidFacilityIndex","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"InvalidInitialization","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":[],"name":"NotInitializing","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":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","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":"address","name":"player","type":"address"},{"indexed":true,"internalType":"uint256","name":"minerIndex","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":"ANTI_WHALE_MINERS_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HALVING_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_MINECOIN_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":[],"name":"antiWhaleAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"antiWhaleRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minerId","type":"uint256"}],"name":"cancelMiner","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":"cumulativeMETHPerHash","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":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"name":"getMETHPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"_meth","type":"address"},{"internalType":"address","name":"_feeReceiver","type":"address"},{"internalType":"address","name":"_referReveicer","type":"address"},{"internalType":"address","name":"_antiWhaleAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"initializedStarterFacility","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRewardBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"meth","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"playerHashrate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerMETHDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"playerMETHPerBlock","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":"_rate","type":"uint256"}],"name":"setAntiWhaleRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"burn","type":"uint256"}],"name":"setBurnPct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialPrice","type":"uint256"}],"name":"setInitialFacilityPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_meth","type":"address"}],"name":"setMETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_referReceiver","type":"address"}],"name":"setReferReceiver","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":"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":[],"name":"totalUsers","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":"withdrawMETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
9c4d535b00000000000000000000000000000000000000000000000000000000000000000100068b975578121e95b68562fa6f6f3cebd30d7e07666f7add5aa164e65ceb00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x0001000000000002001100000000000200000000000103550000008004000039000000400040043f0000000100200190000000350000c13d0000006002100270000005b602200197000000040020008c000014370000413d000000000301043b000000e003300270000005b80030009c0000003d0000213d000005e90030009c0000007f0000a13d000005ea0030009c000000dc0000a13d000005eb0030009c0000017c0000a13d000005ec0030009c0000042f0000a13d000005ed0030009c000007130000613d000005ee0030009c000006f10000613d000005ef0030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000062201000041000000000201041a00000619032001970000000005000411000000000053004b000007a40000c13d0000062302200197000000000021041b0000000001000414000005b60010009c000005b601008041000000c00110021000000624011001c70000800d0200003900000003030000390000062504000041000000000600001916d216c80000040f0000000100200190000014370000613d00000a9e0000013d0000000001000416000000000001004b000014370000c13d000000200100003900000100001004430000012000000443000005b701000041000016d30001042e000005b90030009c000000cd0000a13d000005ba0030009c000001060000a13d000005bb0030009c000001870000a13d000005bc0030009c000004380000a13d000005bd0030009c000007200000613d000005be0030009c000007040000613d000005bf0030009c000014370000c13d000000840020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000402100370000000000202043b001100000002001d000006190020009c000014370000213d0000002402100370000000000202043b001000000002001d000006190020009c000014370000213d0000004402100370000000000202043b000f00000002001d000006190020009c000014370000213d0000006401100370000000000101043b000e00000001001d000006190010009c000014370000213d0000061a01000041000000000101041a0000061b02100197000c00000001001d0000061c01100198000d00000002001d00000be30000613d000000010010008c00000bf30000c13d0000061d010000410000000000100443000000000100041000000004001004430000000001000414000005b60010009c000005b601008041000000c0011002100000061e011001c7000080020200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000000000001004b00000be50000613d000000400400043d00000bf30000013d000006020030009c000001210000213d0000060e0030009c000001e20000213d000006140030009c000003060000213d000006170030009c000005470000613d000006180030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000062202000041000000000202041a00000619032001970000000002000411000000000023004b000007560000c13d0000000102000039000000000202041a000000000300041a0000068404000041000000800040043f0000000401100370000000000101043b0000061902200197000000840020043f000000a40010043f00000000010004140000061902300197000005b60010009c000005b601008041000000c00110021000000685011001c716d216c80000040f0000006003100270000005b603300197000000200030008c000000200a000039000000000a0340190000001f05a0018f0000002006a0019000000080046001bf000000b40000613d0000008007000039000000000801034f000000008908043c0000000007970436000000000047004b000000b00000c13d000000000005004b000000c10000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f00000000005404350000000100200190000008cb0000613d000000800100003900000000020a001900110000000a001d16d214640000040f000000110100002900000080021001bf000000800100003916d214760000040f0000000001000019000016d30001042e000005d20030009c000001350000213d000005de0030009c000001f40000213d000005e40030009c0000032d0000213d000005e70030009c0000054c0000613d000005e80030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000000a01000039000007520000013d000005f70030009c000001970000213d000005fd0030009c0000028c0000213d000006000030009c0000047f0000613d000006010030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000062201000041000000000101041a00000619021001970000000001000411000000000012004b000007490000c13d0000066a010000410000000000100443000000000100041000000004001004430000000001000414000005b60010009c000005b601008041000000c0011002100000061e011001c70000800a0200003916d216cd0000040f0000000100200190000012ad0000613d0000000102000039000000000202041a0000061904200197000000000301043b0000000001000414000005b60010009c000005b601008041000000c001100210000000000003004b000009490000c13d00000000020400190000094c0000013d000005c70030009c000001b90000213d000005cd0030009c0000029c0000213d000005d00030009c000004840000613d000005d10030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b0000062202000041000000000202041a00000619032001970000000002000411000000000023004b000007560000c13d000006450010009c000007000000213d0000000b02000039000000000012041b0000000001000019000016d30001042e000006030030009c000002060000213d000006090030009c000003380000213d0000060c0030009c000005510000613d0000060d0030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f00000011010000390000061d0000013d000005d30030009c000002350000213d000005d90030009c000003470000213d000005dc0030009c0000055d0000613d000005dd0030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b001100000001001d000006190010009c000014370000213d0000000801000039000000000101041a000000000001004b000005290000613d000f00000001001d0000000201000039000000000101041a001000000001001d000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000000100110006c000009a40000413d000006420010009c000009a40000213d001000000001001d0000001101000029000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000001002000029000005b602200197000006430220012a000006440220027f000000000101043b000000000301041a00000000012300a9000000000003004b000001790000613d00000000033100d9000000000023004b00000d5c0000c13d0000000f021000fa000000400100043d0000052b0000013d000005f20030009c000002480000213d000005f50030009c000004410000613d000005f60030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000000801000039000007520000013d000005c20030009c000002630000213d000005c50030009c000004460000613d000005c60030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000000000010043f0000000f01000039000002e60000013d000005f80030009c000002b00000213d000005fb0030009c000004a70000613d000005fc0030009c000014370000c13d000000640020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000000000010043f0000000f01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000400400043d000006310040009c0000084e0000a13d0000066801000041000000000010043f0000004101000039000000040010043f0000063601000041000016d400010430000005c80030009c000002d90000213d000005cb0030009c000004f80000613d000005cc0030009c000014370000c13d000000440020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000402100370000000000202043b001100000002001d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039001000000002001d000000000012004b000014370000c13d0000062201000041000000000101041a00000619021001970000000001000411000000000012004b000007490000c13d0000001d01000039000000000101041a0000001102000029000000000012004b000001de0000413d0000000601000039000000000101041a000000000012004b00000a790000a13d0000064001000041000000800010043f0000064101000041000016d4000104300000060f0030009c000003520000213d000006120030009c0000056d0000613d000006130030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f00000019010000390000061d0000013d000005df0030009c0000035b0000213d000005e20030009c000005aa0000613d000005e30030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000001501000039000002ab0000013d000006040030009c000003640000213d000006070030009c000005af0000613d000006080030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000c00000001001d000006190010009c000014370000213d0000000301000039000000000101041a000000ff00100190000005290000613d0000000801000039000000000101041a000e00000001001d000000000001004b0000099c0000c13d0000000c01000029000000000010043f0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000a02000039000000000202041a000006450020009c000009a40000213d000000000101041a00000d340000c13d000000000200001900000d3c0000013d000005d40030009c000004260000213d000005d70030009c000005c30000613d000005d80030009c000014370000c13d000000240020008c000014370000413d0000000001000416000000000001004b000014370000c13d16d214a40000040f00000004010000390000000001100367000000000101043b0000001f02000039000000000012041b0000000001000019000016d30001042e000005f30030009c000004530000613d000005f40030009c000014370000c13d000000440020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000002402100370000000000402043b0000000401100370000000000301043b0000062201000041000000000101041a00000619021001970000000001000411000000000012004b000007490000c13d0000000501000039000000000101041a000000000013004b000008460000a13d0000065701000041000000800010043f0000064101000041000016d400010430000005c30030009c0000045a0000613d000005c40030009c000014370000c13d000000440020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000402100370000000000202043b000006190020009c000014370000213d0000002401100370000000000101043b001100000001001d000000000020043f0000001801000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000000110020006b000014370000813d000000110200002916d214490000040f0000000302200210000000000101041a000000000121022f0000061901100197000000ff0020008c0000000001002019000004780000013d000005fe0030009c000004ff0000613d000005ff0030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000000d010000390000061d0000013d000005ce0030009c000005220000613d000005cf0030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000001401000039000000200010043f0000004002000039000000000100001916d216b30000040f000006c80000013d000005f90030009c000005310000613d000005fa0030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000001301000039000000200010043f0000004002000039000000000100001916d216b30000040f0000000602100039000000000202041a0000000503100039000000000303041a0000000404100039000000000404041a0000000305100039000000000505041a0000000206100039000000000606041a0000000107100039000000000707041a000000000101041a000000800010043f000000a00070043f000000c00060043f000000e00050043f000001000040043f000001200030043f000001400020043f0000065801000041000016d30001042e000005c90030009c000005360000613d000005ca0030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000000000010043f0000001201000039000000200010043f0000004002000039000000000100001916d216b30000040f0000000702100039000000000202041a0000000603100039000000000303041a0000000504100039000000000404041a0000000405100039000000000505041a0000000306100039000000000606041a0000000207100039000000000707041a0000000108100039000000000808041a000000000101041a000000800010043f000000a00080043f000000c00070043f000000e00060043f000001000050043f000001200040043f000001400030043f000000ff002001900000000001000039000000010100c039000001600010043f0000063c01000041000016d30001042e000006150030009c000005c80000613d000006160030009c000014370000c13d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000000000010043f0000001001000039000000200010043f0000004002000039000000000100001916d216b30000040f0000000502100039000000000202041a0000000403100039000000000303041a0000000304100039000000000404041a0000000205100039000000000505041a0000000106100039000000000606041a000000000101041a000000800010043f000000a00060043f000000c00050043f000000ff004001900000000001000039000000010100c039000000e00010043f000001000030043f000001200020043f0000068301000041000016d30001042e000005e50030009c000005cd0000613d000005e60030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000064501000041000000800010043f0000063a01000041000016d30001042e0000060a0030009c000006120000613d0000060b0030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000000201000039000000000101041a000000000001004b000007890000c13d0000067a01000041000000800010043f0000064101000041000016d400010430000005da0030009c000006220000613d000005db0030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000064401000041000000800010043f0000063a01000041000016d30001042e000006100030009c000006940000613d000006110030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000002001000039000006ec0000013d000005e00030009c000006c40000613d000005e10030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000000b01000039000007520000013d000006050030009c000006cf0000613d000006060030009c000014370000c13d000000440020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000002402100370000000000202043b001000000002001d0000000401100370000000000101043b001100000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000ff00100190000008e90000c13d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000006860220019700000001022001bf000000000021041b0000001c01000039000000000101041a000000000010043f0000000f01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000400400043d000006310040009c000001b30000213d000000000101043b0000010002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000c00000003001d00000000002304350000000202100039000000000202041a0000004003400039000e00000003001d00000000002304350000000302100039000000000202041a0000006003400039000d00000003001d00000000002304350000000402100039000000000202041a0000008003400039000b00000003001d00000000002304350000000502100039000000000202041a000000a003400039000f00000003001d00000000002304350000000602100039000000000202041a000000c003400039000800000003001d0000000000230435000a00000004001d000000e0024000390000000701100039000000000101041a000000ff001001900000000001000039000000010100c039000900000002001d00000000001204350000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000700000001001d0000000501100039000000000101041a000000110010006b000009f20000813d00000007010000290000000601100039000000000101041a000000100010006b000009f20000813d0000000001000411000000000010043f0000001601000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000001102000029000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000001002000029000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000ff00100190000009f20000c13d0000000f01000029000000000101043300000007020000290000000402200039000600000002001d000000000202041a000000000021001a000009a40000413d000000000121001900000007020000290000000302200039000000000202041a000000000021004b000010600000a13d000000400100043d000700000001001d000011990000013d000005d50030009c000006e80000613d000005d60030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000001e01000039000007520000013d000005f00030009c000007320000613d000005f10030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000000601000039000007520000013d000005c00030009c0000074e0000613d000005c10030009c000014370000c13d0000000001000416000000000001004b000014370000c13d0000001b01000039000007520000013d0000000001000416000000000001004b000014370000c13d0000001d01000039000007520000013d000000240020008c000014370000413d0000000001000416000000000001004b000014370000c13d16d214a40000040f00000004010000390000000001100367000000000101043b0000001b02000039000000000012041b0000000001000019000016d30001042e0000000001000416000000000001004b000014370000c13d0000064301000041000000800010043f0000063a01000041000016d30001042e0000000001000416000000000001004b000014370000c13d000000000102001916d214390000040f001000000002001d001100000003001d0000061901100197000000000010043f0000001601000039000000200010043f0000004002000039000000000100001916d216b30000040f0000001002000029000000000020043f000000200010043f0000000001000019000000400200003916d216b30000040f0000001102000029000000000020043f000000200010043f0000000001000019000000400200003916d216b30000040f000000000101041a000000ff001001900000000001000039000000010100c039000000400200043d0000000000120435000005b60020009c000005b60200804100000040012002100000063b011001c7000016d30001042e0000000001000416000000000001004b000014370000c13d000000000100041a000006ed0000013d000000440020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000402100370000000000202043b001100000002001d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039001000000002001d000000000012004b000014370000c13d0000062201000041000000000101041a00000619021001970000000001000411000000000012004b000007490000c13d0000001c01000039000000000101041a0000001102000029000000000012004b000004a30000413d0000000501000039000000000101041a000000000012004b000009fd0000a13d0000064701000041000000800010043f0000064101000041000016d400010430000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000001801000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000301041a000000400200043d001000000002001d000f00000003001d0000000002320436001100000002001d000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062b011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000000f05000029000000000005004b00000011060000290000000002060019000004dc0000613d000000000101043b00000000030000190000000002060019000000000401041a0000061904400197000000000242043600000001011000390000000103300039000000000053004b000004d50000413d000000100300002900000000013200490000001f0110003900000687021001970000000001320019000000000021004b000000000200003900000001020040390000061c0010009c000001b30000213d0000000100200190000001b30000c13d000000400010043f00000020020000390000000002210436000000000303043300000000003204350000004002100039000000000003004b00000a700000613d00000000040000190000000065060434000006190550019700000000025204360000000104400039000000000034004b000004f10000413d00000a700000013d0000000001000416000000000001004b000014370000c13d0000001e01000039000000800010043f0000063a01000041000016d30001042e000000240020008c000014370000413d0000000401100370000000000101043b001100000001001d000006190010009c000014370000213d0000001b01000039000000000101041a0000000002000416000000000012004b000007a90000c13d0000000001000411000000000010043f0000001401000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000ff00100190000009f50000c13d0000000001000411000000110010006b00000aa00000c13d000000400100043d0000066902000041000009f70000013d0000000001000416000000000001004b000014370000c13d0000000301000039000000000101041a000000ff001001900000075b0000c13d000000800100003900000000020000190000000000210435000005b60010009c000005b60100804100000040011002100000063b011001c7000016d30001042e0000000001000416000000000001004b000014370000c13d0000000201000039000007520000013d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b001100000001001d000006190010009c000014370000213d16d214a40000040f000000000100041a000006230110019700000011011001af000000000010041b0000000001000019000016d30001042e0000000001000416000000000001004b000014370000c13d0000000901000039000007520000013d0000000001000416000000000001004b000014370000c13d0000000501000039000007520000013d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000000e010000390000061d0000013d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000001701000039000000200010043f0000004002000039000000000100001916d216b30000040f000006ec0000013d000000640020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000402100370000000000202043b000006190020009c000014370000213d0000004403100370000000000303043b001100000003001d0000002401100370000000000101043b000d00000001001d000000000020043f0000001101000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000201043b0000065e01000041000000040010043f001000000002001d000000000020043f0000000001000414000005b60010009c000005b601008041000000c0011002100000065f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000068802100167000000000202041a000000000002004b00000a1f0000c13d000000000201041a000000000002004b0000000002000039000000010200c03900000a200000613d0000000103100039000000000303041a000000000003004b00000a200000613d0000000201100039000000000101041a000000000001004b0000000302000039000000020200603900000a200000013d0000000001000416000000000001004b000014370000c13d0000062201000041000006ec0000013d0000000001000411000000000010043f0000001401000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000ff00100190000007730000c13d000000400100043d0000067902000041000009f70000013d0000000001000416000000000001004b000014370000c13d0000000701000039000007520000013d0000000001000416000000000001004b000014370000c13d0000001f01000039000007520000013d000000c40020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000004402100370000000000202043b000f00000002001d0000002402100370000000000202043b001000000002001d0000000402100370000000000202043b001100000002001d0000006402100370000000000302043b000000000003004b0000000002000039000000010200c039000e00000003001d000000000023004b000014370000c13d000000a402100370000000000402043b0000008401100370000000000301043b0000062201000041000000000101041a00000619021001970000000001000411000000000012004b000007490000c13d00000000013400a9000000000003004b000005f30000613d00000000023100d9000000000042004b000009a40000c13d000000110010006c000009cb0000c13d000c00000004001d000d00000003001d0000000601000039000000000101041a000b00000001001d000000000010043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000402100039000000000202041a0000000d0020006c0000060f0000213d0000000501100039000000000101041a0000000c0010006c00000bfc0000a13d000000400100043d0000064c02000041000009f70000013d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b000006190010009c000014370000213d000000000010043f0000000c01000039000000200010043f0000004002000039000000000100001916d216b30000040f000007520000013d000000840020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000004402100370000000000202043b001000000002001d0000002402100370000000000202043b001100000002001d0000000402100370000000000202043b000f00000002001d0000006401100370000000000201043b000000000002004b0000000001000039000000010100c039000e00000002001d000000000012004b000014370000c13d0000062201000041000000000101041a00000619021001970000000001000411000000000012004b000007490000c13d0000000502000039000000000102041a000000010110003a000009a40000613d000000000012041b0000018002000039000000400020043f000000800010043f000000a00000043f000000c00000043f000000e00000043f0000000f02000029000001000020043f0000001102000029000001200020043f0000001002000029000001400020043f0000000e02000029000001600020043f000000000010043f0000000f01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000800200043d000000000021041b0000000102100039000000a00300043d000000000032041b0000000202100039000000c00300043d000000000032041b0000000302100039000000e00300043d000000000032041b0000000402100039000001000300043d000000000032041b0000000502100039000001200300043d000000000032041b0000000602100039000001400300043d000000000032041b0000000701100039000000000301041a0000068602300197000001600300043d000000000003004b000000010220c1bf000000000021041b0000000501000039000000000501041a000000400100043d00000060021000390000000e0300002900000000003204350000004002100039000000100300002900000000003204350000002002100039000000110300002900000000003204350000000f020000290000000000210435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f00000648011001c70000800d020000390000000203000039000006490400004100000a9b0000013d000000240020008c000014370000413d0000000001000416000000000001004b000014370000c13d0000000001000411000000000010043f0000001101000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d00000004020000390000000002200367000000000202043b001100000002001d000000000101043b0000065e02000041000000040020043f000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000065f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000201043b00000004010000390000000001100367000000000101043b000000000001004b000009cf0000613d000006600010009c0000001104000029000009d00000c13d0000067b01000041000000000010043f0000064b01000041000016d4000104300000000001000416000000000001004b000014370000c13d0000000301000039000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f0000063a01000041000016d30001042e0000000001000416000000000001004b000014370000c13d000000000100041116d214b50000040f0000000001000411000000000010043f0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000000001004b000007ad0000c13d000000400100043d0000067402000041000009f70000013d0000000001000416000000000001004b000014370000c13d0000000101000039000000000101041a0000061901100197000000800010043f0000063a01000041000016d30001042e000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b0000062202000041000000000202041a00000619032001970000000002000411000000000023004b000007560000c13d000006500010009c000008ec0000413d0000065101000041000000800010043f0000064101000041000016d400010430000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b001100000001001d000006190010009c000014370000213d16d214a40000040f000000110100002916d214840000040f0000000001000019000016d30001042e000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b001100000001001d000006190010009c000014370000213d16d214a40000040f0000001a010000390000072c0000013d000000240020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000000401100370000000000101043b001100000001001d000006190010009c000014370000213d16d214a40000040f0000000101000039000000000201041a000006230220019700000011022001af000000000021041b0000000001000019000016d30001042e000000440020008c000014370000413d0000000002000416000000000002004b000014370000c13d0000002402100370000000000402043b0000000401100370000000000301043b0000062201000041000000000101041a00000619021001970000000001000411000000000012004b000007490000c13d0000000601000039000000000101041a000000000013004b000008f00000a13d0000065401000041000000800010043f0000064101000041000016d4000104300000063d02000041000000800020043f000000840010043f0000063e01000041000016d4000104300000000001000416000000000001004b000014370000c13d0000001c01000039000000000101041a000000800010043f0000063a01000041000016d30001042e0000063d01000041000000800010043f000000840020043f0000063e01000041000016d4000104300000000201000039000000000101041a001100000001001d000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000000110210006c000009a40000413d000006420020009c000009a40000213d000000400100043d000005b602200197000006430220012a000006440220027f0000052b0000013d0000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000301043b000000000103041a0000000602000039000000000202041a000000000021004b000008f80000c13d000000400100043d0000067802000041000009f70000013d001100000001001d000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000006430210012a000000010320003900000643023000d100000000033200d9000006430030009c000009a40000c13d0000001103000029000006433030012a000000000032001a000009a40000413d0000000002320019000000000112004b000004780000813d000009a40000013d0000063d01000041000000800010043f000000840050043f0000063e01000041000016d4000104300000066401000041000000800010043f0000064101000041000016d400010430001100000001001d0000000001000411000000000010043f0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000001041b0000000a01000039000000000101041a000000000001004b0000001103000029000007c50000613d0000068802100129000000000032004b00000d380000413d00000000013100a9000f0645001001320000000f0130006c001000000001001d000009a40000413d000000000100041a0000061d0200004100000000002004430000061901100197000e00000001001d00000004001004430000000001000414000005b60010009c000005b601008041000000c0011002100000061e011001c7000080020200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000000000001004b000014370000613d000000400300043d000000240130003900000010020000290000000000210435000006710100004100000000001304350000000001000411000006190110019700000004023000390000000000120435000005b60030009c001000000003001d000005b601000041000000000103401900000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f00000672011001c70000000e0200002916d216c80000040f000000010020019000000d400000613d00000010010000290000061c0010009c000001b30000213d0000001001000029000000400010043f0000000001000411000000000010043f0000001701000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000000200041a0000061d0300004100000000003004430000061902200197001000000002001d0000000400200443000e06190010019c00000f820000c13d0000001a01000039000000000101041a000e00000001001d0000000001000414000005b60010009c000005b601008041000000c0011002100000061e011001c7000080020200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000000000001004b000014370000613d0000000e010000290000061901100197000000400400043d00000024024000390000000f0300002900000000003204350000067102000041000000000024043500000004024000390000000000120435000005b60040009c000e00000004001d000005b601000041000000000104401900000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f00000672011001c7000000100200002916d216c80000040f00000001002001900000119c0000613d0000000e010000290000061c0010009c000001b30000213d0000000e01000029000000400010043f0000001a01000039000000000101041a0000061901100197000000000010043f0000001901000039000000200010043f000000000100041400000fb00000013d0000001c01000039000000000101041a000000000013004b0000097b0000c13d0000065601000041000000800010043f0000064101000041000016d400010430000000000101043b0000010002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000c00000003001d00000000002304350000000202100039000000000202041a0000004003400039000e00000003001d00000000002304350000000302100039000000000202041a0000006003400039000d00000003001d00000000002304350000000402100039000000000202041a0000008003400039000b00000003001d00000000002304350000000502100039000000000202041a000000a003400039000f00000003001d00000000002304350000000602100039000000000202041a000000c003400039001000000003001d0000000000230435000a00000004001d000000e0024000390000000701100039000000000101041a000000ff001001900000000001000039000000010100c039001100000002001d00000000001204350000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d00000000020003670000004403200370000000000403043b000000000301043b0000000601300039000000000101041a0000002402200370000000000502043b000800000003001d0000000502300039000000000202041a000900000005001d000000000025004b000009f20000813d000000000014004b000009f20000813d000700000004001d0000000001000411000000000010043f0000001601000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000902000029000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000702000029000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000ff00100190000009f20000c13d000000400100043d000900000001001d00000011010000290000000001010433000000000001004b00000f270000c13d0000066301000041000000090200002900000c120000013d0000001f0530018f0000065a06300198000000400200043d0000000004620019000008d60000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000008d20000c13d000000000005004b000008e30000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000005b60020009c000005b6020080410000004002200210000000000112019f000016d400010430000000400100043d0000066e02000041000009f70000013d0000000a02000039000000000012041b0000000001000019000016d30001042e0000001d01000039000000000101041a000000000013004b000009aa0000c13d0000065301000041000000800010043f0000064101000041000016d400010430001000000003001d000000010010003a000009a40000413d0000000101100039001100000001001d000000000010043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000400400043d000006320040009c000001b30000213d000000000101043b000000c002400039000000400020043f000000000201041a00000000052404360000000103100039000000000303041a00000000003504350000000205100039000000000505041a000000400640003900000000005604350000000306100039000000000606041a000000ff0060019000000060064000390000000007000039000000010700c03900000000007604350000000406100039000000000806041a00000080074000390000000000870435000000a0074000390000000501100039000000000401041a0000000000470435000000400100043d00000bfa0000613d0000000007000416000000000057004b00000c4f0000c13d00000011060000290000001009000029000000000069041b0000000105900039000000000025041b0000000302900039000000000032041b0000000502900039000000000082041b0000000602900039000000000042041b0000000000710435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d0200003900000003030000390000067704000041000000000500041116d216c80000040f0000000100200190000014370000613d00000a9e0000013d00000624011001c70000800902000039000000000500001916d216c80000040f0000006003100270000005b603300198000009550000c13d000000010020019000000a9e0000c13d000000400100043d0000066d02000041000009f70000013d0000001f043000390000066b044001970000003f044000390000066c04400197000000400500043d0000000004450019000000000054004b000000000600003900000001060040390000061c0040009c000001b30000213d0000000100600190000001b30000c13d000000400040043f0000001f0430018f00000000063504360000065a0530019800000000035600190000096d0000613d000000000701034f000000007807043c0000000006860436000000000036004b000009690000c13d000000000004004b000009500000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000009500000013d001000000004001d001100000003001d000000000030043f0000000f01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b00000006011000390000001002000029000000000021041b000000400100043d0000000000210435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d020000390000000203000039000006550400004100000a9a0000013d0000000201000039000000000101041a0000000702000039000000000302041a000000000213004b000009a40000413d000006420020009c00000b150000a13d0000066801000041000000000010043f0000001101000039000000040010043f0000063601000041000016d400010430001000000004001d001100000003001d000000000030043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b00000002011000390000001002000029000000000021041b000000400100043d0000000000210435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d020000390000000203000039000006520400004100000a9a0000013d0000064c01000041000000800010043f0000064101000041000016d40001043000000660040000410000068803200167000000000303041a000000000003004b000009e00000c13d000000000302041a000000000043004b00000b580000613d0000000103200039000000000303041a000000000043004b00000b580000613d0000000202200039000000000202041a000000000042004b000009ef0000c13d00000b580000013d000000200020043f000000000040043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000000001004b00000b550000c13d000000400100043d0000067c02000041000009f70000013d000000400100043d0000067002000041000009f70000013d000000400100043d00000665020000410000000000210435000005b60010009c000005b601008041000000400110021000000638011001c7000016d400010430000000000020043f0000000f01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000701100039000000000201041a00000686022001970000001003000029000000000232019f000000000021041b000000400100043d0000000000310435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d020000390000000203000039000006460400004100000a9a0000013d00000001022002700000000d0520006c00000a3b0000a13d000000110050006c0000001105008029000006800050009c000001b30000813d00000005015002100000003f021000390000068102200197000000400400043d0000000002240019000000000042004b000000000300003900000001030040390000061c0020009c000001b30000213d0000000100300190000001b30000c13d000000400020043f000c00000004001d0000000002540436000b00000002001d000a00000005001d000000000005004b00000c510000c13d0000000c0300002900000a410000013d000000400300043d0000067f0030009c000001b30000213d0000002001300039000000400010043f0000000000030435000000400100043d000000200200003900000000022104360000000008030019000000000303043300000000003204350000004002100039000000000003004b00000a700000613d0000000004000019000000200880003900000000050804330000000076050434000000000662043600000000070704330000000000760435000000400650003900000000060604330000004007200039000000000067043500000060065000390000000006060433000000600720003900000000006704350000008006500039000000000606043300000080072000390000000000670435000000a0065000390000000006060433000000a0072000390000000000670435000000c0065000390000000006060433000000c0072000390000000000670435000000e0055000390000000005050433000000000005004b0000000005000039000000010500c039000000e006200039000000000056043500000100022000390000000104400039000000000034004b00000a4b0000413d0000000002120049000005b60020009c000005b6020080410000006002200210000005b60010009c000005b6010080410000004001100210000000000112019f000016d30001042e000000000020043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000301100039000000000201041a00000686022001970000001003000029000000000232019f000000000021041b000000400100043d0000000000310435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d0200003900000002030000390000063f04000041000000110500002916d216c80000040f0000000100200190000014370000613d0000000001000019000016d30001042e000000000010043f0000001401000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000006860220019700000001022001bf000000000021041b000000110000006b00000c180000c13d0000001d01000039000000000101041a001100000001001d000000000010043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000400200043d001000000002001d000006320020009c000001b30000213d000000000101043b0000001004000029000000c002400039000000400020043f000000000201041a00000000032404360000000102100039000000000202041a000f00000003001d00000000002304350000000202100039000000000202041a000000400340003900000000002304350000000302100039000000000202041a000000ff002001900000000002000039000000010200c039000000600340003900000000002304350000000402100039000000000202041a0000008003400039000d00000003001d0000000000230435000000a0024000390000000501100039000000000101041a000e00000002001d00000000001204350000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000001102000029000000000021041b000000100200002900000000020204330000000103100039000000000023041b0000000f0200002900000000020204330000000303100039000000000023041b0000000d0200002900000000020204330000000503100039000000000023041b00000006011000390000000e020000290000000002020433000000000021041b0000001e02000039000000000102041a000000010010003a000009a40000413d0000000101100039000000000012041b0000001f02000039000000000202041a000000000002004b00000fce0000c13d0000066801000041000000000010043f0000001201000039000000040010043f0000063601000041000016d400010430001000000003001d000006431010012a000d00000001001d0000000901000039000000000101041a001100000001001d000005b601200197000006430110012a000f064400100287000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b0000001005000029000000000015004b00000011070000290000000d0400002900000cf70000813d000006430250012a000000010320003900000643023000d100000000033200d9000006430030009c0000000f08000029000009a40000c13d000000000042001a000009a40000413d0000000003420019000000000013004b00000000020100190000000002034019000000000452004b000009a40000413d000000000008004b00000b4b0000613d00000000058400a900000000068500d9000000000046004b000009a40000c13d000000000005004b00000b4b0000613d00000645045000d100000000055400d9000006450050009c00000b4c0000613d000009a40000013d00000000040000190000000e044000fa000000000074001a000009a40000413d001100000074001d000000000013004b000000010880a270000f00000008001d001000000002001d00000b1e0000013d00000004010000390000000001100367000000000101043b000000000010043f0000001201000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000400400043d000006310040009c000001b30000213d000000000101043b0000010002400039000000400020043f000000000201041a00000000022404360000000103100039000000000303041a00000000003204350000000202100039000000000202041a0000004003400039001000000003001d00000000002304350000000302100039000000000202041a0000006003400039000f00000003001d00000000002304350000000402100039000000000202041a0000008003400039000d00000003001d00000000002304350000000502100039000000000202041a000000a003400039001100000003001d00000000002304350000000602100039000000000202041a000000c0034000390000000000230435000e00000004001d000000e0024000390000000701100039000000000101041a000000ff001001900000000001000039000000010100c03900000000001204350000000001000411000000000010043f0000001301000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000202100039000000000302041a000000000003004b000009a40000613d000000010330008a000000000032041b0000000401100039000000000201041a00000011030000290000000003030433000000000232004b000009a40000413d000000000021041b0000000001000411000000000010043f0000001101000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d00000004020000390000000002200367000000000202043b001100000002001d000000000101043b0000065e02000041000000040020043f000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000065f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d00000004020000390000000002200367000000000202043b000000000002004b00000011020000290000066002006041001100000002001d000000000201043b000c00000002001d0000068801200167000900000001001d000000000101041a000a00000001001d000000000001004b000010310000c13d0000000c040000290000000201400039000b00000001001d000000000101041a0000000102400039000000000302041a000000000404041a000000110040006c000010cf0000c13d0000000c04000029000000000034041b000010d10000013d000000000002004b00000bf30000c13d0000000c020000290000061f0120019700000001011001bf000006200220019700000621022001c70000000d0000006b000000000201c0190000061a01000041000000000021041b0000061b0020019800000cea0000c13d000000400100043d0000063702000041000009f70000013d00000639010000410000000000140435000005b60040009c000005b604008041000000400140021000000638011001c7000016d4000104300000067602000041000009f70000013d0000000b01000029000000000010043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000400200043d000a00000002001d000000000101043b0000000101100039000000000101041a000000100010006c00000ec10000a13d0000064f010000410000000a020000290000000000120435000005b60020009c000005b602008041000000400120021000000638011001c7000016d4000104300000001701000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a00000623022001970000001103000029000000000232019f000000000021041b000000000030043f0000001801000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a001100000002001d0000061c0020009c000001b30000213d00000011020000290000000102200039000000000021041b000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062b011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000001101100029000000000201041a00000623022001970000000003000411000000000232019f000000000021041b00000ab30000013d0000066402000041000009f70000013d00000000020000190000000b05000029000000400300043d000006310030009c000001b30000213d0000010004300039000000400040043f000000e0043000390000000000040435000000c0043000390000000000040435000000a0043000390000000000040435000000800430003900000000000404350000006004300039000000000004043500000040043000390000000000040435000000200430003900000000000404350000000000030435000000000452001900000000003404350000002002200039000000000012004b00000c530000413d001100000000001d0000065e01000041000000040010043f0000001001000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000065f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000001103000029000f000d0030002d000000000101043b0000000f01100029000000000101041a000e00000001001d0000065e01000041000000040010043f0000001001000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000065f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000201043b0000068801200167000000000101041a000000000001004b00000c940000613d000000010110027000000ca20000013d000000000102041a000000000001004b0000000001000039000000010100c03900000ca20000613d0000000103200039000000000303041a000000000003004b00000ca20000613d0000000201200039000000000101041a000000000001004b000000030100003900000002010060390000000f0010006b0000102e0000813d0000000e01000029000006600010009c0000000001006019000000000010043f0000001201000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000400200043d000006310020009c0000000c050000290000000a060000290000000b07000029000001b30000213d000000000101043b0000010003200039000000400030043f000000000301041a00000000033204360000000104100039000000000404041a00000000004304350000000203100039000000000303041a000000400420003900000000003404350000000303100039000000000303041a000000600420003900000000003404350000000403100039000000000303041a000000800420003900000000003404350000000503100039000000000303041a000000a00420003900000000003404350000000603100039000000000303041a000000c0042000390000000000340435000000e0032000390000000701100039000000000101041a000000ff001001900000000001000039000000010100c039000000000013043500000000010504330000001103000029000000000031004b00000f7c0000a13d0000000501300210000000000171001900000000002104350000000001050433000000000031004b00000f7c0000a13d001100010030003d000000110060006b00000c6d0000413d00000a390000013d0000000001000411000006190610019800000d600000c13d000000400100043d0000063502000041000000000021043500000004021000390000000000020435000005b60010009c000005b601008041000000400110021000000636011001c7000016d4000104300000000c010000290000061901100197000000000010043f0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a001000000001001d0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000f00000001001d0000000e01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000110210006b000009a40000413d0000000f012000b90000000f0000006b00000d2b0000613d0000000f031000fa000000000023004b000009a40000c13d000006450110012a000000100010002a000009a40000413d0000000a02000039000000000202041a000006450020009c000009a40000213d0000001001100029000002330000613d00000645022000990000068803200129000000000013004b00000d3c0000813d0000067501000041000000000010043f0000064b01000041000016d40001043000000000021200a9000000400100043d000006450220012a0000052b0000013d00000060061002700000001f0460018f0000065a05600198000000400200043d000000000352001900000d4c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000d480000c13d000005b606600197000000000004004b00000d5a0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000008e40000013d0000064a01000041000000000010043f0000064b01000041000016d4000104300000062201000041000000000201041a0000062303200197000000000363019f000000000031041b00000000010004140000061905200197000005b60010009c000005b601008041000000c00110021000000624011001c70000800d020000390000000303000039000006250400004116d216c80000040f0000000100200190000014370000613d0000000502000039000000000102041a000000010110003a000009a40000613d00000010030000290000061903300197000000000012041b0000001c02000039000000000012041b00000626010000410000000a02000039000000000012041b00000627010000410000000b02000039000000000012041b00000628010000410000001b02000039000000000012041b000000000100041a000006230110019700000011011001af000000000010041b0000000102000039000000000102041a0000062301100197000000000131019f000000000012041b0000001a01000039000000000201041a00000623022001970000000f022001af000000000021041b0000002001000039000000000201041a00000623022001970000000e022001af000000000021041b0000000301000039000000000101041a000000ff0010019000000dbf0000c13d000006860110019700000001011001bf0000000302000039000000000012041b000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b0000000202000039000000000012041b0000000702000039000000000012041b000000400200043d0000000000120435000005b60020009c000005b60200804100000040012002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d0200003900000001030000390000062c0400004116d216c80000040f0000000100200190000014370000613d0000000e0100002916d214b50000040f0000000801000039000000000201041a0000062e0220009c000009a40000813d000000000021041b0000000e01000029000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a0000062e0220009c000009a40000813d000000000021041b0000000e01000029000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a001100000001001d0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000011010000290000000000120435000005b60020009c000005b60200804100000040012002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062f011001c70000800d0200003900000002030000390000063004000041000000000500041116d216c80000040f0000000100200190000014370000613d00000032010000390000001f02000039000000000012041b000000400100043d001100000001001d000006310010009c000001b30000213d0000001c01000039000000000101041a00000011040000290000010002400039000000400020043f000000a0034000390000000302000039001000000003001d00000000002304350000008003400039000000b402000039000e00000003001d0000000000230435000000c003400039000000010200008a000f00000003001d00000000002304350000006003400039000b00000003001d00000000002304350000004003400039000a00000003001d00000000002304350000002003400039000900000003001d00000000002304350000000000140435000000e002400039000c00000002001d0000000000020435000000000010043f0000000f01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d00000011020000290000000002020433000000000101043b000000000021041b000000090200002900000000020204330000000103100039000000000023041b0000000a0200002900000000020204330000000203100039000000000023041b0000000b0200002900000000020204330000000303100039000000000023041b0000000e0200002900000000020204330000000403100039000000000023041b000000100200002900000000020204330000000503100039000000000023041b0000000f0200002900000000020204330000000603100039000000000023041b0000000701100039000000000201041a00000686022001970000000c030000290000000003030433000000000003004b000000010220c1bf000000000021041b000000400100043d001100000001001d000006320010009c000001b30000213d0000001103000029000000c001300039000000400010043f00000080023000390000000101000039001000000002001d00000000001204350000004002300039000000010100008a000e00000002001d000000000012043500000020023000390000000c01000039000b00000002001d0000000000120435000000a0023000390000000201000039000f00000002001d000000000012043500000000001304350000006001300039000c00000001001d00000000000104350000000601000039000000000101041a000000010110003a000009a40000613d0000000602000039000000000012041b000000000010043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d00000011020000290000000002020433000000000101043b000000000021041b0000000b0200002900000000020204330000000103100039000000000023041b0000000e0200002900000000020204330000000203100039000000000023041b0000000302100039000000000302041a00000686033001970000000c040000290000000004040433000000000004004b000000010330c1bf000000000032041b000000100200002900000000020204330000000403100039000000000023041b00000005011000390000000f020000290000000002020433000000000021041b0000000601000039000000000101041a0000001d02000039000000000012041b0000000d0000006b00000a9e0000c13d0000061a01000041000000000201041a0000063302200197000000000021041b000000400100043d00000001030000390000000000310435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d02000039000006340400004100000a9b0000013d0000000a01000029000006320010009c000001b30000213d0000000a03000029000000c001300039000000400010043f000000a0023000390000000c01000029000900000002001d000000000012043500000080023000390000000d01000029000800000002001d000000000012043500000060023000390000000e01000029000700000002001d000000000012043500000040023000390000000f01000029000600000002001d0000000000120435000000110100002900000000021304360000001001000029001100000002001d00000000001204350000000b01000029000000010110003a000009a40000613d0000000602000039000000000012041b000000000010043f0000001001000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000000a020000290000000002020433000000000101043b000000000021041b000000110200002900000000020204330000000103100039000000000023041b000000060200002900000000020204330000000203100039000000000023041b0000000302100039000000000402041a000006860340019700000007040000290000000004040433000000000004004b000000010330c1bf000000000032041b000000080200002900000000020204330000000403100039000000000023041b000000050110003900000009020000290000000002020433000000000021041b0000000601000039000000000501041a000000400100043d00000080021000390000000c03000029000000000032043500000060021000390000000d03000029000000000032043500000040021000390000000e03000029000000000032043500000020021000390000000f03000029000000000032043500000010020000290000000000210435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000064d011001c70000800d0200003900000002030000390000064e0400004100000a9b0000013d000000000200041a000006590100004100000009040000290000000000140435000000040140003900000000030004110000000000310435000005b60040009c000005b601000041000000000104401900000040011002100000000003000414000005b60030009c000005b603008041000000c003300210000000000113019f00000636011001c70000061902200197000600000002001d16d216cd0000040f0000006003100270000005b603300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000090570002900000f4a0000613d000000000801034f0000000909000029000000008a08043c0000000009a90436000000000059004b00000f460000c13d000000000006004b00000f570000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000010020019000000f700000613d0000001f01400039000000600110018f0000000902100029000000000012004b00000000010000390000000101004039000700000002001d0000061c0020009c000001b30000213d0000000100100190000001b30000c13d0000000701000029000000400010043f000000200030008c000014370000413d0000001001000029000000000101043300000009020000290000000002020433000000000012004b0000118b0000813d00000662010000410000119a0000013d0000001f0530018f0000065a06300198000000400200043d0000000004620019000008d60000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000f770000c13d000008d60000013d0000066801000041000000000010043f0000003201000039000000040010043f0000063601000041000016d4000104300000000001000414000005b60010009c000005b601008041000000c0011002100000061e011001c7000080020200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000000000001004b000014370000613d000000400300043d00000024013000390000000f0200002900000000002104350000067101000041000000000013043500000004013000390000000e020000290000000000210435000005b60030009c000d00000003001d000005b601000041000000000103401900000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f00000672011001c7000000100200002916d216c80000040f0000000100200190000011a90000613d0000000d010000290000061c0010009c000001b30000213d0000000d01000029000000400010043f0000000e01000029000000000010043f0000001901000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a0000000f0020002a000009a40000413d0000000f02200029000000000021041b000000400100043d00000011020000290000000000210435000005b60010009c000005b60100804100000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d0200003900000002030000390000067304000041000010290000013d00000000212100d9000000000002004b000010210000c13d0000001d0010008c000010210000213d0000002001000039000000000101041a0000061901100197001100000001001d16d214b50000040f0000000801000039000000000201041a00002ee00220008c000009a40000413d000000000021041b0000001101000029000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a00002ee00220008c000009a40000413d000000000021041b0000001101000029000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a001100000001001d0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000011010000290000000000120435000005b60020009c000005b60200804100000040012002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062f011001c70000800d0200003900000002030000390000066604000041000000000500041116d216c80000040f0000000100200190000014370000613d0000000001000414000005b60010009c000005b601008041000000c00110021000000624011001c70000800d0200003900000002030000390000066704000041000000000500041116d216c80000040f0000000100200190000014370000613d00000a9e0000013d000000400100043d0000068202000041000009f70000013d0000000c01000029000000200010043f0000001101000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000b00000001001d000000000101041a001100000001001d000000000001004b000010d40000613d0000000a010000290000000101100270000000110010006b0000105b0000613d0000000c02000029000000010220008a00000011032000290000000001210019000000000101041a000000000013041b000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000001102000029000000000021041b0000000a0100002900000001011001bf000000020110008a0000000902000029000010d10000013d00000011010000290000000e02000029000000000012043500000010010000290000000d0200002900000000001204350000000401000039000000000101041a000000010110003a000009a40000613d0000000402000039000000000012041b0000000c0200002900000000001204350000000001000411000000000010043f0000001601000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000001102000029000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000001002000029000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000006860220019700000001022001bf000000000021041b0000000001000411000000000010043f0000001101000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000000402000039000000000202041a000500000002001d000000000101043b0000065e02000041000000040020043f000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000065f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000400000001001d0000000501000029000006600010009c000006c00000613d00000004020000290000068801200167000200000001001d000000000301041a000000200020043f000000050000006b00000005010000290000066001006041000500000001001d000300000003001d000000000003004b000013070000c13d0000000401000029000000000101041a000000000001004b000012ba0000c13d00000005010000290000000402000029000013200000013d000000110030006c000011b60000c13d000000000012041b0000000b01000029000000000001041b00000004010000390000000001100367000000000101043b000000000010043f0000001201000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000001041b0000000102100039000000000002041b0000000202100039000000000002041b0000000302100039000000000002041b0000000402100039000000000002041b0000000502100039000000000002041b0000000602100039000000000002041b0000000701100039000000000001041b0000000001000411000000000010043f0000001601000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b00000010020000290000000002020433000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000f020000290000000002020433000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a0000068602200197000000000021041b000000040100003900000000011003670000000e020000290000000006020433000000000101043b000000100200002900000000020204330000000f030000290000000003030433000000400400043d00000040054000390000000000350435000000200340003900000000002304350000000000140435000005b60040009c000005b60400804100000040014002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000067d011001c70000800d0200003900000003030000390000067e04000041000000000500041116d216c80000040f0000000100200190000014370000613d0000000d010000290000000001010433001100000001001d000000000100041116d214b50000040f0000000801000039000000000201041a000000110220006c000009a40000413d000000000021041b0000000001000411000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000000110220006c000009a40000413d000000000021041b0000000001000411000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a001100000001001d0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000011010000290000000000120435000005b60020009c000005b60200804100000040012002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062f011001c70000800d0200003900000002030000390000066604000041000000000500041100000a9b0000013d0000000f02000029000000000202043300000008030000290000000403300039000900000003001d000000000303041a000000000032001a000009a40000413d000000000232001900000008030000290000000303300039000000000303041a000000000032004b000011b90000a13d0000066f01000041000000070200002900000c120000013d00000060061002700000001f0460018f0000065a05600198000000400200043d000000000352001900000d4c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000011a40000c13d00000d4c0000013d00000060061002700000001f0460018f0000065a05600198000000400200043d000000000352001900000d4c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000011b10000c13d00000d4c0000013d000000110010006c000010d20000613d000010d40000013d0000000703000029000000440230003900000000001204350000002401300039000000000200041000000000002104350000065b010000410000000000130435000000040130003900000000020004110000000000210435000005b60030009c000005b601000041000000000103401900000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000065c011001c7000000060200002916d216c80000040f0000006003100270000005b603300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000705700029000011df0000613d000000000801034f0000000709000029000000008a08043c0000000009a90436000000000059004b000011db0000c13d000000000006004b000011ec0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000012ae0000613d0000001f01400039000000600110018f00000007011000290000061c0010009c000001b30000213d000000400010043f000000200030008c000014370000413d00000007010000290000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000014370000c13d00000010010000290000000001010433000700000001001d000000000100041a0000000b02000039000000000202041a000600000002001d000000000002004b0000120a0000613d000000010200008a00000006022000fa000000070020006c00000d380000413d00000619021001970000061d010000410000000000100443000500000002001d00000004002004430000000001000414000005b60010009c000005b601008041000000c0011002100000061e011001c7000080020200003916d216cd0000040f0000000100200190000012ad0000613d000000000101043b000000000001004b000014370000613d000000060200002900000007012000b9000006450110012a000000400300043d0000065d02000041000000000023043500000004023000390000000000120435000005b60030009c000700000003001d000005b601000041000000000103401900000040011002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f00000636011001c7000000050200002916d216c80000040f0000000100200190000012cd0000613d00000007010000290000061c0010009c000001b30000213d0000000701000029000000400010043f00000000010003670000002402100370000000000202043b0000000e0300002900000000002304350000004401100370000000000101043b0000000d0200002900000000001204350000000401000039000000000101041a000000010110003a000009a40000613d0000000402000039000000000012041b0000000c0200002900000000001204350000000001000411000000000010043f0000001601000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b00000024020000390000000002200367000000000202043b000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b00000044020000390000000002200367000000000202043b000000000020043f000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000006860220019700000001022001bf000000000021041b0000000001000411000000000010043f0000001101000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000000402000039000000000202041a000700000002001d000000000101043b0000065e02000041000000040020043f000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000065f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000600000001001d0000000701000029000006600010009c000006c00000613d00000006020000290000068801200167000400000001001d000000000301041a000000200020043f000000070000006b00000007010000290000066001006041000700000001001d000500000003001d000000000003004b000013c40000c13d0000000601000029000000000101041a000000000001004b000013840000c13d00000007010000290000000602000029000013dd0000013d000000000001042f0000001f0530018f0000065a06300198000000400200043d0000000004620019000008d60000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000012b50000c13d000008d60000013d000000050010006c000013210000613d00000004020000290000000102200039000000000302041a000300000003001d000000000003004b000012cb0000613d0000000303000029000000050030006c000013210000613d00000004020000290000000202200039000000000302041a000100000003001d000000000003004b000012da0000c13d0000000501000029000013200000013d00000060061002700000001f0460018f0000065a05600198000000400200043d000000000352001900000d4c0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000012d50000c13d00000d4c0000013d0000000103000029000000050030006c000013210000613d000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000102000039000000000021041b0000000301000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000202000039000000000021041b0000000101000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000302000039000000000021041b000300070000003d0000000501000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000000000002004b000013210000c13d0000000302000029000000010220027000000004032000290000000504000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000202000029000000000012041b0000000401000039000000000101041a000000000010043f0000001201000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000000a020000290000000002020433000000000301043b000000000023041b0000000c0100002900000000010104330000000102300039000000000012041b0000000e0100002900000000010104330000000202300039000000000012041b0000000d0100002900000000010104330000000302300039000000000012041b0000000b0100002900000000010104330000000402300039000000000012041b0000000f0100002900000000010104330000000502300039000000000012041b000000080200002900000000020204330000000604300039000000000024041b0000000702300039000000000302041a000006860330019700000009040000290000000004040433000000000004004b000000010330c1bf000000000032041b00000007020000290000000202200039000000000302041a000000010330003a000009a40000613d000000000032041b0000000602000029000000000202041a000000000012001a000009a40000413d00000000011200190000000602000029000000000012041b0000001c01000039000000000601041a0000000401000039000000000101041a000000400200043d000000600320003900000010040000290000000000430435000000400320003900000011040000290000000000430435000000200320003900000000001304350000000000020435000005b60020009c000005b60200804100000040012002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f00000648011001c70000800d0200003900000003030000390000066104000041000000000500041116d216c80000040f0000000100200190000014370000613d0000000b010000290000000002010433000000000100041116d215790000040f0000000001000019000016d30001042e000000070010006c000013de0000613d00000006020000290000000102200039000000000302041a000500000003001d000000000003004b0000138e0000c13d0000000701000029000013dd0000013d0000000503000029000000070030006c000013de0000613d00000006020000290000000202200039000000000302041a000300000003001d000000000003004b0000138c0000613d0000000303000029000000070030006c000013de0000613d000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000102000039000000000021041b0000000501000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000202000039000000000021041b0000000301000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b0000000302000039000000000021041b000500070000003d0000000701000029000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d000000000101043b000000000201041a000000000002004b000013de0000c13d0000000502000029000000010220027000000006032000290000000704000029000000000043041b0000000102200039000000000021041b000000010120021000000001011001bf0000000402000029000000000012041b0000000401000039000000000101041a000000000010043f0000001201000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000014370000613d0000000a020000290000000002020433000000000301043b000000000023041b0000000c0100002900000000010104330000000102300039000000000012041b0000000e0100002900000000010104330000000202300039000000000012041b0000000d0100002900000000010104330000000302300039000000000012041b0000000b0100002900000000010104330000000402300039000000000012041b0000000f0100002900000000020104330000000501300039000000000021041b000000100100002900000000010104330000000604300039000000000014041b0000000703300039000000000403041a000006860440019700000011050000290000000005050433000000000005004b000000010440c1bf000000000043041b00000008030000290000000203300039000000000403041a000000010440003a000009a40000613d000000000043041b0000000903000029000000000303041a000000000023001a000009a40000413d00000000022300190000000903000029000000000023041b0000000402000039000000000202041a000000400300043d00000020043000390000000000240435000000000013043500000000010003670000002402100370000000000202043b000000400430003900000000002404350000004402100370000000000202043b00000060043000390000000000240435000005b60030009c000005b60300804100000040023002100000000401100370000000000601043b0000000001000414000005b60010009c000005b601008041000000c001100210000000000121019f000013760000013d0000000001000019000016d400010430000006890010009c000014470000213d000000630010008c000014470000a13d00000000030003670000000401300370000000000101043b000006190010009c000014470000213d0000002402300370000000000202043b0000004403300370000000000303043b000000000001042d0000000001000019000016d4000104300001000000000002000000000301041a000100000002001d000000000023004b0000145c0000a13d000000000010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062b011001c7000080100200003916d216cd0000040f0000000100200190000014620000613d000000000101043b00000001011000290000000002000019000000000001042d0000066801000041000000000010043f0000003201000039000000040010043f0000063601000041000016d4000104300000000001000019000016d4000104300000001f0220003900000687022001970000000001120019000000000021004b000000000200003900000001020040390000061c0010009c000014700000213d0000000100200190000014700000c13d000000400010043f000000000001042d0000066801000041000000000010043f0000004101000039000000040010043f0000063601000041000016d4000104300000000002120049000006890020009c000014820000213d0000001f0020008c000014820000a13d0000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000014820000c13d000000000001042d0000000001000019000016d4000104300000061906100198000014980000613d0000062201000041000000000201041a0000062303200197000000000363019f000000000031041b00000000010004140000061905200197000005b60010009c000005b601008041000000c00110021000000624011001c70000800d020000390000000303000039000006250400004116d216c80000040f0000000100200190000014a20000613d000000000001042d000000400100043d0000063502000041000000000021043500000004021000390000000000020435000005b60010009c000005b601008041000000400110021000000636011001c7000016d4000104300000000001000019000016d4000104300000062201000041000000000101041a00000619021001970000000001000411000000000012004b000014ab0000c13d000000000001042d000000400200043d0000063d03000041000000000032043500000004032000390000000000130435000005b60020009c000005b602008041000000400120021000000636011001c7000016d4000104300003000000000002000100000001001d0000000801000039000000000101041a000000000001004b0000000702000039000015070000613d0000000201000039000000000101041a000000000202041a000000000112004b0000156a0000413d000006420010009c0000156a0000213d000300000002001d000005b601100197000006430110012a0002064400100287000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000015700000613d000000000101043b0000000304000029000000000014004b000015130000813d000006430240012a000000010320003900000643023000d100000000033200d9000006430030009c00000002070000290000156a0000c13d0000000203000039000000000303041a000006433030012a000000000023001a0000156a0000413d0000000003230019000000000013004b00000000020100190000000002034019000000000442004b0000156a0000413d000000000007004b000014f50000613d00000000057400a900000000067500d9000000000046004b0000156a0000c13d000000000005004b000014f50000613d00000645045000d100000000055400d9000006450050009c000014f60000613d0000156a0000013d00000000040000190000000805000039000000000505041a000000000005004b000015710000613d00000000045400d90000000905000039000000000505041a000000000045001a0000156a0000413d00000000044500190000000905000039000000000045041b000000000013004b000000010770a270000200000007001d000300000002001d000014c70000013d000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000015700000613d000000000101043b0000000702000039000000000012041b00000001010000290000061901100197000300000001001d000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000015770000613d0000000902000039000000000202041a000100000002001d000000000101043b000000000101041a000200000001001d0000000e01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000015770000613d000000000101043b000000000101041a000000010110006b00000002020000290000156a0000413d00000000032100a9000000000002004b000015400000613d00000000022300d9000000000012004b0000156a0000c13d000200000003001d0000000301000029000000000010043f0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000015770000613d0000000202000029000006450220012a000000000101043b000000000301041a000000000023001a0000156a0000413d0000000002230019000000000021041b0000000901000039000000000101041a000200000001001d0000000301000029000000000010043f0000000e01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000015770000613d000000000101043b0000000202000029000000000021041b000000000001042d0000066801000041000000000010043f0000001101000039000000040010043f0000063601000041000016d400010430000000000001042f0000066801000041000000000010043f0000001201000039000000040010043f0000063601000041000016d4000104300000000001000019000016d4000104300004000000000002000200000002001d000100000001001d0000000301000039000000000201041a000000ff00200190000015a40000c13d000006860220019700000001022001bf000000000021041b000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000016a90000613d000000000101043b0000000202000039000000000012041b0000000702000039000000000012041b000000400200043d0000000000120435000005b60020009c000005b60200804100000040012002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062b011001c70000800d0200003900000001030000390000062c0400004116d216c80000040f0000000100200190000016b00000613d0000000801000039000000000101041a000000000001004b000015f40000613d0000000201000039000000000101041a0000000702000039000000000202041a000000000112004b000016a30000413d000006420010009c000016a30000213d000400000002001d000005b601100197000006430110012a0003064400100287000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000016a90000613d000000000101043b0000000404000029000000000014004b000016000000813d000006430240012a000000010320003900000643023000d100000000033200d9000006430030009c0000000307000029000016a30000c13d0000000203000039000000000303041a000006433030012a000000000023001a000016a30000413d0000000003230019000000000013004b00000000020100190000000002034019000000000442004b000016a30000413d000000000007004b000015e20000613d00000000057400a900000000067500d9000000000046004b000016a30000c13d000000000005004b000015e20000613d00000645045000d100000000055400d9000006450050009c000015e30000613d000016a30000013d00000000040000190000000805000039000000000505041a000000000005004b000016aa0000613d00000000045400d90000000905000039000000000505041a000000000045001a000016a30000413d00000000044500190000000905000039000000000045041b000000000013004b000000010770a270000300000007001d000400000002001d000015b40000013d000006290100004100000000001004430000000001000414000005b60010009c000005b601008041000000c0011002100000062a011001c70000800b0200003916d216cd0000040f0000000100200190000016a90000613d000000000101043b0000000702000039000000000012041b00000001010000290000061901100197000400000001001d000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000016b00000613d0000000902000039000000000202041a000100000002001d000000000101043b000000000101041a000300000001001d0000000e01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000016b00000613d000000000101043b000000000101041a000000010110006b0000000302000029000016a30000413d00000000032100a9000000000002004b0000162d0000613d00000000022300d9000000000012004b000016a30000c13d000300000003001d0000000401000029000000000010043f0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000016b00000613d0000000302000029000006450220012a000000000101043b000000000301041a000000000023001a000016a30000413d0000000002230019000000000021041b0000000901000039000000000101041a000300000001001d0000000401000029000000000010043f0000000e01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000016b00000613d000000000101043b0000000302000029000000000021041b0000000801000039000000000101041a000000020010002a000016a30000413d00000002011000290000000802000039000000000012041b0000000401000029000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000016b00000613d000000000101043b000000000201041a000000020020002a000016a30000413d0000000202200029000000000021041b0000000401000029000000000010043f0000000c01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000016b00000613d000000000101043b000000000101041a000400000001001d0000000d01000039000000200010043f0000000001000414000005b60010009c000005b601008041000000c0011002100000062f011001c7000080100200003916d216cd0000040f0000000100200190000016b00000613d000000000101043b000000000101041a000000400200043d0000002003200039000000000013043500000004010000290000000000120435000005b60020009c000005b60200804100000040012002100000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f0000062f011001c70000800d0200003900000002030000390000000005000411000006300400004116d216c80000040f0000000100200190000016b00000613d000000000001042d0000066801000041000000000010043f0000001101000039000000040010043f0000063601000041000016d400010430000000000001042f0000066801000041000000000010043f0000001201000039000000040010043f0000063601000041000016d4000104300000000001000019000016d400010430000000000001042f000005b60010009c000005b6010080410000004001100210000005b60020009c000005b6020080410000006002200210000000000112019f0000000002000414000005b60020009c000005b602008041000000c002200210000000000112019f00000624011001c7000080100200003916d216cd0000040f0000000100200190000016c60000613d000000000101043b000000000001042d0000000001000019000016d400010430000016cb002104210000000102000039000000000001042d0000000002000019000000000001042d000016d0002104230000000102000039000000000001042d0000000002000019000000000001042d000016d200000432000016d30001042e000016d40001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000002000000000000000000000000000000400000010000000000000000000000000000000000000000000000000000000000000000000000000072779cb900000000000000000000000000000000000000000000000000000000c243589300000000000000000000000000000000000000000000000000000000df1e3b7e00000000000000000000000000000000000000000000000000000000ea26fa2c00000000000000000000000000000000000000000000000000000000efdcd97300000000000000000000000000000000000000000000000000000000efdcd97400000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000f8c8765e00000000000000000000000000000000000000000000000000000000ea26fa2d00000000000000000000000000000000000000000000000000000000eef3b2d000000000000000000000000000000000000000000000000000000000e2b15d8b00000000000000000000000000000000000000000000000000000000e2b15d8c00000000000000000000000000000000000000000000000000000000e92820e600000000000000000000000000000000000000000000000000000000df1e3b7f00000000000000000000000000000000000000000000000000000000e0d152af00000000000000000000000000000000000000000000000000000000cf5949cf00000000000000000000000000000000000000000000000000000000d32c2b7e00000000000000000000000000000000000000000000000000000000d32c2b7f00000000000000000000000000000000000000000000000000000000dd6a4c6500000000000000000000000000000000000000000000000000000000cf5949d000000000000000000000000000000000000000000000000000000000d147129600000000000000000000000000000000000000000000000000000000ca146bd800000000000000000000000000000000000000000000000000000000ca146bd900000000000000000000000000000000000000000000000000000000ca18117000000000000000000000000000000000000000000000000000000000c243589400000000000000000000000000000000000000000000000000000000c51a2bba000000000000000000000000000000000000000000000000000000009ca423b200000000000000000000000000000000000000000000000000000000a9f8d18000000000000000000000000000000000000000000000000000000000b3f0067300000000000000000000000000000000000000000000000000000000b3f0067400000000000000000000000000000000000000000000000000000000bff1f9e100000000000000000000000000000000000000000000000000000000a9f8d18100000000000000000000000000000000000000000000000000000000aeead5f7000000000000000000000000000000000000000000000000000000009f715f5f000000000000000000000000000000000000000000000000000000009f715f6000000000000000000000000000000000000000000000000000000000a3f9686d000000000000000000000000000000000000000000000000000000009ca423b3000000000000000000000000000000000000000000000000000000009cf0b808000000000000000000000000000000000000000000000000000000008da5cb5a0000000000000000000000000000000000000000000000000000000094fc19e30000000000000000000000000000000000000000000000000000000094fc19e4000000000000000000000000000000000000000000000000000000009618b31c000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000008dfc3933000000000000000000000000000000000000000000000000000000008685e3f1000000000000000000000000000000000000000000000000000000008685e3f20000000000000000000000000000000000000000000000000000000086b3cd260000000000000000000000000000000000000000000000000000000072779cba0000000000000000000000000000000000000000000000000000000084ae2bc6000000000000000000000000000000000000000000000000000000003c9b1f5a0000000000000000000000000000000000000000000000000000000059058ad00000000000000000000000000000000000000000000000000000000069f0ee32000000000000000000000000000000000000000000000000000000006f12bfb1000000000000000000000000000000000000000000000000000000006f12bfb200000000000000000000000000000000000000000000000000000000713494d700000000000000000000000000000000000000000000000000000000715018a60000000000000000000000000000000000000000000000000000000069f0ee33000000000000000000000000000000000000000000000000000000006d12ff52000000000000000000000000000000000000000000000000000000005fd9491c000000000000000000000000000000000000000000000000000000005fd9491d000000000000000000000000000000000000000000000000000000006756a1c70000000000000000000000000000000000000000000000000000000059058ad1000000000000000000000000000000000000000000000000000000005a5ccef00000000000000000000000000000000000000000000000000000000041a0894c0000000000000000000000000000000000000000000000000000000048cd4cb00000000000000000000000000000000000000000000000000000000048cd4cb100000000000000000000000000000000000000000000000000000000542f9e6a0000000000000000000000000000000000000000000000000000000041a0894d00000000000000000000000000000000000000000000000000000000476e2e66000000000000000000000000000000000000000000000000000000003e89bb12000000000000000000000000000000000000000000000000000000003e89bb130000000000000000000000000000000000000000000000000000000040f5da9e000000000000000000000000000000000000000000000000000000003c9b1f5b000000000000000000000000000000000000000000000000000000003ccfd60b000000000000000000000000000000000000000000000000000000001d5750e60000000000000000000000000000000000000000000000000000000030775a9300000000000000000000000000000000000000000000000000000000372500aa00000000000000000000000000000000000000000000000000000000372500ab000000000000000000000000000000000000000000000000000000003a8ee01e0000000000000000000000000000000000000000000000000000000030775a940000000000000000000000000000000000000000000000000000000031d7a26200000000000000000000000000000000000000000000000000000000234f3f1a00000000000000000000000000000000000000000000000000000000234f3f1b000000000000000000000000000000000000000000000000000000002fc96ce6000000000000000000000000000000000000000000000000000000001d5750e7000000000000000000000000000000000000000000000000000000001e57057d00000000000000000000000000000000000000000000000000000000157e204b000000000000000000000000000000000000000000000000000000001b88eafb000000000000000000000000000000000000000000000000000000001b88eafc000000000000000000000000000000000000000000000000000000001d488e2d00000000000000000000000000000000000000000000000000000000157e204c000000000000000000000000000000000000000000000000000000001a267cd2000000000000000000000000000000000000000000000000000000000f4098ee000000000000000000000000000000000000000000000000000000000f4098ef0000000000000000000000000000000000000000000000000000000010d967590000000000000000000000000000000000000000000000000000000002ebba93000000000000000000000000000000000000000000000000000000000e6f257c000000000000000000000000fffffffffffffffffffffffffffffffffffffffff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a000000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000100000000000000019016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e000000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000c7d713b49da0000000000000000000000000000000000000000000000000000002386f26fc1000042cbb15ccdc3cad6266b0e7a08c0454b23bf29dc2df74b6f3c209e9336465bd102000002000000000000000000000000000000040000000000000000000000000200000000000000000000000000000000000020000000000000000000000000daae9aa758637a0d349f036f099afd70aa88d8ac63fce096321de512ffebc16cfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa81bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa81c00200000000000000000000000000000000000040000000000000000000000000a051d58ced8df58040b29d2c939da70a826ae40290f77c9a66b38b8b85315f65000000000000000000000000000000000000000000000000fffffffffffffeff000000000000000000000000000000000000000000000000ffffffffffffff3fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d21e4fbdf7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000d7e6bcf8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000f92ee8a900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000080000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000800000000000000000118cdaa70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000008000000000000000000bd772fd008a8dd5673c42a4f50f72220b2603eee55113cd6c38ff78d71e644fedd999f80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000008000000000000000000000000000000000000000000000000000000000000000000000000019a27fff000000000000000000000000000000000000000000000000000000000019a28000000000000000000000000000000000000000000000000022b1c8c1227a00000000000000000000000000000000000000000000000000000de0b6b3a7640000d0a7ceb410ade2d440d8ed59d6b338fe480f98025101655790e0de736edddabe3b87f109000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000080000000000000000000000000e0a2f8482bbba7e119c069eb63409ac33b15fc516cffed25aeabb6a9669e07c200000000000000000000000000000000000000000000000000000000ad251c2700000000000000000000000000000000000000040000001c0000000000000000472ea01c0000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000a00000000000000000000000006ae4a0e17ec15e82a1af6ff99411c44193a38f27f15c3ddd30b0f09ab1c5fd2cd2a50ed0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000158d620b300000000000000000000000000000000000000000000000000000000f721e9425607d38abda58b925d2a080b3aefa127d46973d2683875dc87cb9a6bf1fa1762000000000000000000000000000000000000000000000000000000006cb4090800000000000000000000000000000000000000000000000000000000f920b24ea96b3814655944622f9eb86875e3193c5de1a9de018777e6c8705cee4705d684000000000000000000000000000000000000000000000000000000003a6c77df0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000080000000000000000070a082310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffe023b872dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006400000000000000000000000042966c68000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018fb586402000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000000000000fbb67fda52d4bfb8bf70a5d2d3258adcf9978a193a4dd8fa309ae83a9f1046a0a5ea99a133bf34f9a5ff0b21e600000000000000000000000000000000000000000000000000000000aa8a9b9800000000000000000000000000000000000000000000000000000000d2ade556000000000000000000000000000000000000000000000000000000008fe6f7d800000000000000000000000000000000000000000000000000000000e331ada0d0e61e9a4196bf4994f2519193d70a601daff346c4276d591664da9ae424ed553a53c3a900c875ed34d63043e4dfb799427ee8ae0836b046a603c90e4e487b710000000000000000000000000000000000000000000000000000000061104228000000000000000000000000000000000000000000000000000000009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f3900000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000003ffffffe0750b219c0000000000000000000000000000000000000000000000000000000070e9a55a00000000000000000000000000000000000000000000000000000000fbfd2f4000000000000000000000000000000000000000000000000000000000a800e0ac0000000000000000000000000000000000000000000000000000000040c10f19000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000fc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe0df723dc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bac65e5b47cd2fa600000000000000000000000000000000000000000000000000000000e2dbc44c627e3876b04b29d12596a77c7d0fa585ccb754b9fcd92e48d813dd7772932dd3000000000000000000000000000000000000000000000000000000000c02d44e00000000000000000000000000000000000000000000000000000000602fe2ca0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f5a267f13d9f63cb000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000060000000000000000000000000a3ba90dab2a94b799931cc7fdbfe68eb1ae3716f001c082a23be2c7edc594647000000000000000000000000000000000000000000000000ffffffffffffffdf00000000000000000000000000000000000000000000000100000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe04e23d0350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000800000000000000000a9059cbb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000800000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa57132197389516c2acb474b33761d4e478c489c9d0355192eb0ceea109da10
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.