MATIC Price: $1.00 (-1.01%)
Gas: 44 GWei
 

Overview

MATIC Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 MATIC

MATIC Value

$0.00

Sponsored

Transaction Hash
Method
Block
From
To
Value
0x60806040285669212022-05-20 23:46:45678 days ago1653090405IN
 Create: RealmFacet
0 MATIC4.3258467955.62687836

Parent Txn Hash Block From To Value
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RealmFacet

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 18 : RealmFacet.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.9;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../libraries/AppStorage.sol";
import "../../libraries/LibDiamond.sol";
import "../../libraries/LibStrings.sol";
import "../../libraries/LibMeta.sol";
import "../../libraries/LibERC721.sol";
import "../../libraries/LibRealm.sol";
import "../../libraries/LibAlchemica.sol";
import {InstallationDiamondInterface} from "../../interfaces/InstallationDiamondInterface.sol";
import "../../libraries/LibSignature.sol";
import "./ERC721Facet.sol";

contract RealmFacet is Modifiers {
  uint256 constant MAX_SUPPLY = 420069;

  struct MintParcelInput {
    uint256 coordinateX;
    uint256 coordinateY;
    uint256 district;
    string parcelId;
    string parcelAddress;
    uint256 size; //0=humble, 1=reasonable, 2=spacious vertical, 3=spacious horizontal, 4=partner
    uint256[4] boost; //fud, fomo, alpha, kek
  }

  event ResyncParcel(uint256 _realmId);
  event EquipInstallation(uint256 _realmId, uint256 _installationId, uint256 _x, uint256 _y);
  event UnequipInstallation(uint256 _realmId, uint256 _installationId, uint256 _x, uint256 _y);
  event EquipTile(uint256 _realmId, uint256 _tileId, uint256 _x, uint256 _y);
  event UnequipTile(uint256 _realmId, uint256 _tileId, uint256 _x, uint256 _y);
  event AavegotchiDiamondUpdated(address _aavegotchiDiamond);
  event InstallationUpgraded(uint256 _realmId, uint256 _prevInstallationId, uint256 _nextInstallationId, uint256 _coordinateX, uint256 _coordinateY);

  /// @notice Return the maximum realm supply
  /// @return The max realm token supply
  function maxSupply() external pure returns (uint256) {
    return MAX_SUPPLY;
  }

  /// @notice Allow the diamond owner to mint new parcels
  /// @param _to The address to mint the parcels to
  /// @param _tokenIds The identifiers of tokens to mint
  /// @param _metadata An array of structs containing the metadata of each parcel being minted
  function mintParcels(
    address _to,
    uint256[] calldata _tokenIds,
    MintParcelInput[] memory _metadata
  ) external onlyOwner {
    for (uint256 index = 0; index < _tokenIds.length; index++) {
      require(s.tokenIds.length < MAX_SUPPLY, "RealmFacet: Cannot mint more than 420,069 parcels");
      uint256 tokenId = _tokenIds[index];
      MintParcelInput memory metadata = _metadata[index];
      require(_tokenIds.length == _metadata.length, "Inputs must be same length");

      Parcel storage parcel = s.parcels[tokenId];
      parcel.coordinateX = metadata.coordinateX;
      parcel.coordinateY = metadata.coordinateY;
      parcel.parcelId = metadata.parcelId;
      parcel.size = metadata.size;
      parcel.district = metadata.district;
      parcel.parcelAddress = metadata.parcelAddress;

      parcel.alchemicaBoost = metadata.boost;

      LibERC721.safeMint(_to, tokenId);
    }
  }

  /// @notice Allow a parcel owner to equip an installation
  /// @dev The _x and _y denote the starting coordinates of the installation and are used to make sure that slot is available on a parcel
  /// @param _realmId The identifier of the parcel which the installation is being equipped on
  /// @param _installationId The identifier of the installation being equipped
  /// @param _x The x(horizontal) coordinate of the installation
  /// @param _y The y(vertical) coordinate of the installation
  function equipInstallation(
    uint256 _realmId,
    uint256 _installationId,
    uint256 _x,
    uint256 _y,
    bytes memory _signature
  ) external onlyParcelOwner(_realmId) gameActive {
    require(
      LibSignature.isValid(keccak256(abi.encodePacked(_realmId, _installationId, _x, _y)), _signature, s.backendPubKey),
      "RealmFacet: Invalid signature"
    );
    InstallationDiamondInterface.InstallationType memory installation = InstallationDiamondInterface(s.installationsDiamond).getInstallationType(
      _installationId
    );
    if (installation.installationType == 1 || installation.installationType == 2) {
      require(s.parcels[_realmId].currentRound >= 1, "RealmFacet: Must survey before equipping");
    }
    if (installation.installationType == 3) {
      require(s.parcels[_realmId].lodgeId == 0, "RealmFacet: Lodge already equipped");
      s.parcels[_realmId].lodgeId = _installationId;
    }

    LibRealm.placeInstallation(_realmId, _installationId, _x, _y);
    InstallationDiamondInterface(s.installationsDiamond).equipInstallation(msg.sender, _realmId, _installationId);

    LibAlchemica.increaseTraits(_realmId, _installationId, false);

    emit EquipInstallation(_realmId, _installationId, _x, _y);
  }

  /// @notice Allow a parcel owner to unequip an installation
  /// @dev The _x and _y denote the starting coordinates of the installation and are used to make sure that slot is available on a parcel
  /// @param _realmId The identifier of the parcel which the installation is being unequipped from
  /// @param _installationId The identifier of the installation being unequipped
  /// @param _x The x(horizontal) coordinate of the installation
  /// @param _y The y(vertical) coordinate of the installation
  function unequipInstallation(
    uint256 _realmId,
    uint256 _installationId,
    uint256 _x,
    uint256 _y,
    bytes memory _signature
  ) external onlyParcelOwner(_realmId) gameActive {
    require(
      LibSignature.isValid(keccak256(abi.encodePacked(_realmId, _installationId, _x, _y)), _signature, s.backendPubKey),
      "RealmFacet: Invalid signature"
    );

    InstallationDiamondInterface installationsDiamond = InstallationDiamondInterface(s.installationsDiamond);
    InstallationDiamondInterface.InstallationType memory installation = installationsDiamond.getInstallationType(_installationId);

    LibRealm.removeInstallation(_realmId, _installationId, _x, _y);

    for (uint256 i; i < installation.alchemicaCost.length; i++) {
      IERC20 alchemica = IERC20(s.alchemicaAddresses[i]);

      //@question : include upgrades in refund?
      uint256 alchemicaRefund = installation.alchemicaCost[i] / 2;

      alchemica.transfer(msg.sender, alchemicaRefund);
    }
    InstallationDiamondInterface(s.installationsDiamond).unequipInstallation(_realmId, _installationId);

    LibAlchemica.reduceTraits(_realmId, _installationId, false);

    emit UnequipInstallation(_realmId, _installationId, _x, _y);
  }

  /// @notice Allow a parcel owner to equip a tile
  /// @dev The _x and _y denote the starting coordinates of the tile and are used to make sure that slot is available on a parcel
  /// @param _realmId The identifier of the parcel which the tile is being equipped on
  /// @param _tileId The identifier of the tile being equipped
  /// @param _x The x(horizontal) coordinate of the tile
  /// @param _y The y(vertical) coordinate of the tile
  function equipTile(
    uint256 _realmId,
    uint256 _tileId,
    uint256 _x,
    uint256 _y,
    bytes memory _signature
  ) external onlyParcelOwner(_realmId) gameActive {
    require(
      LibSignature.isValid(keccak256(abi.encodePacked(_realmId, _tileId, _x, _y)), _signature, s.backendPubKey),
      "RealmFacet: Invalid signature"
    );
    LibRealm.placeTile(_realmId, _tileId, _x, _y);
    TileDiamondInterface(s.tileDiamond).equipTile(msg.sender, _realmId, _tileId);

    emit EquipTile(_realmId, _tileId, _x, _y);
  }

  /// @notice Allow a parcel owner to unequip a tile
  /// @dev The _x and _y denote the starting coordinates of the tile and are used to make sure that slot is available on a parcel
  /// @param _realmId The identifier of the parcel which the tile is being unequipped from
  /// @param _tileId The identifier of the tile being unequipped
  /// @param _x The x(horizontal) coordinate of the tile
  /// @param _y The y(vertical) coordinate of the tile
  function unequipTile(
    uint256 _realmId,
    uint256 _tileId,
    uint256 _x,
    uint256 _y,
    bytes memory _signature
  ) external onlyParcelOwner(_realmId) gameActive {
    require(
      LibSignature.isValid(keccak256(abi.encodePacked(_realmId, _tileId, _x, _y)), _signature, s.backendPubKey),
      "RealmFacet: Invalid signature"
    );
    LibRealm.removeTile(_realmId, _tileId, _x, _y);

    TileDiamondInterface(s.tileDiamond).unequipTile(msg.sender, _realmId, _tileId);

    emit UnequipTile(_realmId, _tileId, _x, _y);
  }

  function setParcelsAccessRights(
    uint256[] calldata _realmIds,
    uint256[] calldata _actionRights,
    uint256[] calldata _accessRights
  ) external gameActive {
    require(_realmIds.length == _accessRights.length && _realmIds.length == _actionRights.length, "RealmFacet: Mismatched arrays");
    for (uint256 i; i < _realmIds.length; i++) {
      require(LibMeta.msgSender() == s.parcels[_realmIds[i]].owner, "RealmFacet: Only Parcel owner can call");
      s.accessRights[_realmIds[i]][_actionRights[i]] = _accessRights[i];
    }
  }

  struct ParcelOutput {
    string parcelId;
    string parcelAddress;
    address owner;
    uint256 coordinateX; //x position on the map
    uint256 coordinateY; //y position on the map
    uint256 size; //0=humble, 1=reasonable, 2=spacious vertical, 3=spacious horizontal, 4=partner
    uint256 district;
    uint256[4] boost;
    uint256 timeRemainingToClaim;
  }

  /**
  @dev Used to resync a parcel on the subgraph if metadata is added later 
@param _tokenIds The parcels to resync
  */
  function resyncParcel(uint256[] calldata _tokenIds) external onlyOwner {
    for (uint256 index = 0; index < _tokenIds.length; index++) {
      emit ResyncParcel(_tokenIds[index]);
    }
  }

  function setGameActive(bool _gameActive) external onlyOwner {
    s.gameActive = _gameActive;
  }

  /// @notice Fetch information about a parcel
  /// @param _realmId The identifier of the parcel being queried
  /// @return output_ A struct containing details about the parcel being queried
  function getParcelInfo(uint256 _realmId) external view returns (ParcelOutput memory output_) {
    Parcel storage parcel = s.parcels[_realmId];
    output_.parcelId = parcel.parcelId;
    output_.owner = parcel.owner;
    output_.coordinateX = parcel.coordinateX;
    output_.coordinateY = parcel.coordinateY;
    output_.size = parcel.size;
    output_.parcelAddress = parcel.parcelAddress;
    output_.district = parcel.district;
    output_.boost = parcel.alchemicaBoost;
    output_.timeRemainingToClaim = s.lastClaimedAlchemica[_realmId];
  }

  function checkCoordinates(
    uint256 _realmId,
    uint256 _coordinateX,
    uint256 _coordinateY,
    uint256 _installationId
  ) public view {
    Parcel storage parcel = s.parcels[_realmId];
    require(parcel.buildGrid[_coordinateX][_coordinateY] == _installationId, "RealmFacet: wrong coordinates");
  }

  function upgradeInstallation(
    uint256 _realmId,
    uint256 _prevInstallationId,
    uint256 _nextInstallationId,
    uint256 _coordinateX,
    uint256 _coordinateY
  ) external onlyInstallationDiamond {
    LibRealm.removeInstallation(_realmId, _prevInstallationId, _coordinateX, _coordinateY);
    LibRealm.placeInstallation(_realmId, _nextInstallationId, _coordinateX, _coordinateY);
    LibAlchemica.reduceTraits(_realmId, _prevInstallationId, true);
    LibAlchemica.increaseTraits(_realmId, _prevInstallationId, true);
    emit InstallationUpgraded(_realmId, _prevInstallationId, _nextInstallationId, _coordinateX, _coordinateY);
  }

  function addUpgradeQueueLength(uint256 _realmId) external onlyInstallationDiamond {
    s.parcels[_realmId].upgradeQueueLength++;
  }

  function subUpgradeQueueLength(uint256 _realmId) external onlyInstallationDiamond {
    s.parcels[_realmId].upgradeQueueLength--;
  }

  function getHumbleGrid(uint256 _parcelId, uint256 _gridType) external view returns (uint256[8][8] memory output_) {
    require(s.parcels[_parcelId].size == 0, "RealmFacet: Not humble");
    for (uint256 i; i < 8; i++) {
      for (uint256 j; j < 8; j++) {
        if (_gridType == 0) {
          output_[i][j] = s.parcels[_parcelId].buildGrid[j][i];
        } else if (_gridType == 1) {
          output_[i][j] = s.parcels[_parcelId].tileGrid[j][i];
        }
      }
    }
  }

  function getReasonableGrid(uint256 _parcelId, uint256 _gridType) external view returns (uint256[16][16] memory output_) {
    require(s.parcels[_parcelId].size == 1, "RealmFacet: Not reasonable");
    for (uint256 i; i < 16; i++) {
      for (uint256 j; j < 16; j++) {
        if (_gridType == 0) {
          output_[i][j] = s.parcels[_parcelId].buildGrid[j][i];
        } else if (_gridType == 1) {
          output_[i][j] = s.parcels[_parcelId].tileGrid[j][i];
        }
      }
    }
  }

  function getSpaciousVerticalGrid(uint256 _parcelId, uint256 _gridType) external view returns (uint256[32][64] memory output_) {
    require(s.parcels[_parcelId].size == 2, "RealmFacet: Not spacious vertical");
    for (uint256 i; i < 64; i++) {
      for (uint256 j; j < 32; j++) {
        if (_gridType == 0) {
          output_[i][j] = s.parcels[_parcelId].buildGrid[j][i];
        } else if (_gridType == 1) {
          output_[i][j] = s.parcels[_parcelId].tileGrid[j][i];
        }
      }
    }
  }

  function getSpaciousHorizontalGrid(uint256 _parcelId, uint256 _gridType) external view returns (uint256[64][32] memory output_) {
    require(s.parcels[_parcelId].size == 3, "RealmFacet: Not spacious horizontal");
    for (uint256 i; i < 32; i++) {
      for (uint256 j; j < 64; j++) {
        if (_gridType == 0) {
          output_[i][j] = s.parcels[_parcelId].buildGrid[j][i];
        } else if (_gridType == 1) {
          output_[i][j] = s.parcels[_parcelId].tileGrid[j][i];
        }
      }
    }
  }

  function getPaartnerGrid(uint256 _parcelId, uint256 _gridType) external view returns (uint256[64][64] memory output_) {
    require(s.parcels[_parcelId].size == 4, "RealmFacet: Not paartner");
    for (uint256 i; i < 64; i++) {
      for (uint256 j; j < 64; j++) {
        if (_gridType == 0) {
          output_[i][j] = s.parcels[_parcelId].buildGrid[j][i];
        } else if (_gridType == 1) {
          output_[i][j] = s.parcels[_parcelId].tileGrid[j][i];
        }
      }
    }
  }

  struct ParcelCoordinates {
    uint256[64][64] coords;
  }

  function batchGetGrid(uint256[] calldata _parcelIds, uint256 _gridType) external view returns (ParcelCoordinates[] memory) {
    ParcelCoordinates[] memory parcels = new ParcelCoordinates[](_parcelIds.length);
    for (uint256 k; k < _parcelIds.length; k++) {
      for (uint256 i; i < 64; i++) {
        for (uint256 j; j < 64; j++) {
          if (_gridType == 0) {
            parcels[k].coords[i][j] = s.parcels[_parcelIds[k]].buildGrid[j][i];
          } else if (_gridType == 1) {
            parcels[k].coords[i][j] = s.parcels[_parcelIds[k]].tileGrid[j][i];
          }
        }
      }
    }
    return parcels;
  }

  function batchGetDistrictParcels(address _owner, uint256 _district) external view returns (uint256[] memory) {
    uint256 totalSupply = ERC721Facet(address(this)).totalSupply();
    uint256 balance = ERC721Facet(address(this)).balanceOf(_owner);
    uint256[] memory output_ = new uint256[](balance);
    uint256 counter;
    for (uint256 i; i < totalSupply; i++) {
      if (s.parcels[i].district == _district && s.parcels[i].owner == _owner) {
        output_[counter] = i;
        counter++;
      }
    }
    return output_;
  }

  function getParcelUpgradeQueueLength(uint256 _parcelId) external view returns (uint256) {
    return s.parcels[_parcelId].upgradeQueueLength;
  }

  function getParcelUpgradeQueueCapacity(uint256 _parcelId) external view returns (uint256) {
    return s.parcels[_parcelId].upgradeQueueCapacity;
  }

  function getParcelsAccessRights(uint256[] calldata _parcelIds, uint256[] calldata _actionRights) external view returns (uint256[] memory output_) {
    require(_parcelIds.length == _actionRights.length, "RealmFacet: Mismatched arrays");
    output_ = new uint256[](_parcelIds.length);
    for (uint256 i; i < _parcelIds.length; i++) {
      output_[i] = s.accessRights[_parcelIds[i]][_actionRights[i]];
    }
  }
}

File 2 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 3 of 18 : AppStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import {LibDiamond} from "./LibDiamond.sol";
import {LibMeta} from "./LibMeta.sol";
import "../interfaces/AavegotchiDiamond.sol";

uint256 constant HUMBLE_WIDTH = 8;
uint256 constant HUMBLE_HEIGHT = 8;
uint256 constant REASONABLE_WIDTH = 16;
uint256 constant REASONABLE_HEIGHT = 16;
uint256 constant SPACIOUS_WIDTH = 32;
uint256 constant SPACIOUS_HEIGHT = 64;
uint256 constant PAARTNER_WIDTH = 64;
uint256 constant PAARTNER_HEIGHT = 64;

uint256 constant FUD = 0;
uint256 constant FOMO = 1;
uint256 constant ALPHA = 2;
uint256 constant KEK = 3;

struct Parcel {
  address owner;
  string parcelAddress; //looks-like-this
  string parcelId; //C-4208-3168-R
  uint256 coordinateX; //x position on the map
  uint256 coordinateY; //y position on the map
  uint256 district;
  uint256 size; //0=humble, 1=reasonable, 2=spacious vertical, 3=spacious horizontal, 4=partner
  uint256[64][64] buildGrid; //x, then y array of positions - for installations
  uint256[64][64] tileGrid; //x, then y array of positions - for tiles under the installations (floor)
  uint256[4] alchemicaBoost; //fud, fomo, alpha, kek
  uint256[4] alchemicaRemaining; //fud, fomo, alpha, kek
  uint256 currentRound; //begins at 0 and increments after surveying has begun
  mapping(uint256 => uint256[]) roundBaseAlchemica; //round alchemica not including boosts
  mapping(uint256 => uint256[]) roundAlchemica; //round alchemica including boosts
  // // alchemicaType => array of reservoir id
  mapping(uint256 => uint256[]) reservoirs;
  uint256[4] alchemicaHarvestRate;
  uint256[4] lastUpdateTimestamp;
  uint256[4] unclaimedAlchemica;
  uint256 altarId;
  uint256 upgradeQueueCapacity;
  uint256 upgradeQueueLength;
  uint256 lodgeId;
  bool surveying;
}

struct RequestConfig {
  uint64 subId;
  uint32 callbackGasLimit;
  uint16 requestConfirmations;
  uint32 numWords;
  bytes32 keyHash;
}

struct AppStorage {
  uint256[] tokenIds;
  mapping(uint256 => Parcel) parcels;
  mapping(address => mapping(uint256 => uint256)) ownerTokenIdIndexes;
  mapping(address => uint256[]) ownerTokenIds;
  mapping(address => mapping(address => bool)) operators;
  mapping(uint256 => address) approved;
  address aavegotchiDiamond;
  address[4] alchemicaAddresses; //fud, fomo, alpha, kek
  address installationsDiamond;
  uint256 surveyingRound;
  uint256[4][5] totalAlchemicas;
  uint256[4] boostMultipliers;
  uint256[4] greatPortalCapacity;
  // VRF
  address vrfCoordinator;
  address linkAddress;
  RequestConfig requestConfig;
  mapping(uint256 => uint256) vrfRequestIdToTokenId;
  mapping(uint256 => uint256) vrfRequestIdToSurveyingRound;
  bytes backendPubKey;
  address gameManager;
  mapping(uint256 => uint256) lastExitTime; //for aavegotchis exiting alchemica
  // gotchiId => lastChanneledGotchi
  mapping(uint256 => uint256) gotchiChannelings;
  // parcelId => lastChanneledParcel
  mapping(uint256 => uint256) parcelChannelings;
  // altarLevel => cooldown hours in seconds
  mapping(uint256 => uint256) channelingLimits;
  // parcelId => lastClaimedAlchemica
  mapping(uint256 => uint256) lastClaimedAlchemica;
  address gltrAddress;
  address tileDiamond;
  bool gameActive;
  // parcelId => action: 0 Alchemical Channeling, 1 Emptying Reservoirs => permission: 0 Owner only, 1 Owner + Borrowed Gotchis, 2 Any Gotchi
  mapping(uint256 => mapping(uint256 => uint256)) accessRights;
  // gotchiId => lastChanneledDay
  mapping(uint256 => uint256) lastChanneledDay;
}

library LibAppStorage {
  function diamondStorage() internal pure returns (AppStorage storage ds) {
    assembly {
      ds.slot := 0
    }
  }
}

contract Modifiers {
  AppStorage internal s;

  modifier onlyParcelOwner(uint256 _tokenId) {
    require(LibMeta.msgSender() == s.parcels[_tokenId].owner, "AppStorage: Only Parcel owner can call");
    _;
  }

  modifier onlyOwner() {
    LibDiamond.enforceIsContractOwner();
    _;
  }

  modifier onlyGotchiOwner(uint256 _gotchiId) {
    AavegotchiDiamond diamond = AavegotchiDiamond(s.aavegotchiDiamond);
    require(LibMeta.msgSender() == diamond.ownerOf(_gotchiId), "AppStorage: Only Gotchi Owner can call");
    _;
  }

  modifier onlyGameManager() {
    require(msg.sender == s.gameManager, "AlchemicaFacet: Only Game Manager");
    _;
  }

  modifier onlyInstallationDiamond() {
    require(LibMeta.msgSender() == s.installationsDiamond, "AppStorage: Only Installation diamond can call");
    _;
  }

  modifier gameActive() {
    require(s.gameActive, "AppStorage: game not active");
    _;
  }
}

File 4 of 18 : LibDiamond.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/
import {IDiamondCut} from "../interfaces/IDiamondCut.sol";

library LibDiamond {
  bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");

  struct DiamondStorage {
    // maps function selectors to the facets that execute the functions.
    // and maps the selectors to their position in the selectorSlots array.
    // func selector => address facet, selector position
    mapping(bytes4 => bytes32) facets;
    // array of slots of function selectors.
    // each slot holds 8 function selectors.
    mapping(uint256 => bytes32) selectorSlots;
    // The number of function selectors in selectorSlots
    uint16 selectorCount;
    // Used to query if a contract implements an interface.
    // Used to implement ERC-165.
    mapping(bytes4 => bool) supportedInterfaces;
    // owner of the contract
    address contractOwner;
  }

  function diamondStorage() internal pure returns (DiamondStorage storage ds) {
    bytes32 position = DIAMOND_STORAGE_POSITION;
    assembly {
      ds.slot := position
    }
  }

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

  function setContractOwner(address _newOwner) internal {
    DiamondStorage storage ds = diamondStorage();
    address previousOwner = ds.contractOwner;
    ds.contractOwner = _newOwner;
    emit OwnershipTransferred(previousOwner, _newOwner);
  }

  function contractOwner() internal view returns (address contractOwner_) {
    contractOwner_ = diamondStorage().contractOwner;
  }

  function enforceIsContractOwner() internal view {
    require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
  }

  event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);

  bytes32 constant CLEAR_ADDRESS_MASK = bytes32(uint256(0xffffffffffffffffffffffff));
  bytes32 constant CLEAR_SELECTOR_MASK = bytes32(uint256(0xffffffff << 224));

  // Internal function version of diamondCut
  // This code is almost the same as the external diamondCut,
  // except it is using 'Facet[] memory _diamondCut' instead of
  // 'Facet[] calldata _diamondCut'.
  // The code is duplicated to prevent copying calldata to memory which
  // causes an error for a two dimensional array.
  function diamondCut(
    IDiamondCut.FacetCut[] memory _diamondCut,
    address _init,
    bytes memory _calldata
  ) internal {
    DiamondStorage storage ds = diamondStorage();
    uint256 originalSelectorCount = ds.selectorCount;
    uint256 selectorCount = originalSelectorCount;
    bytes32 selectorSlot;
    // Check if last selector slot is not full
    if (selectorCount & 7 > 0) {
      // get last selectorSlot
      selectorSlot = ds.selectorSlots[selectorCount >> 3];
    }
    // loop through diamond cut
    for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
      (selectorCount, selectorSlot) = addReplaceRemoveFacetSelectors(
        selectorCount,
        selectorSlot,
        _diamondCut[facetIndex].facetAddress,
        _diamondCut[facetIndex].action,
        _diamondCut[facetIndex].functionSelectors
      );
    }
    if (selectorCount != originalSelectorCount) {
      ds.selectorCount = uint16(selectorCount);
    }
    // If last selector slot is not full
    if (selectorCount & 7 > 0) {
      ds.selectorSlots[selectorCount >> 3] = selectorSlot;
    }
    emit DiamondCut(_diamondCut, _init, _calldata);
    initializeDiamondCut(_init, _calldata);
  }

  function addReplaceRemoveFacetSelectors(
    uint256 _selectorCount,
    bytes32 _selectorSlot,
    address _newFacetAddress,
    IDiamondCut.FacetCutAction _action,
    bytes4[] memory _selectors
  ) internal returns (uint256, bytes32) {
    DiamondStorage storage ds = diamondStorage();
    require(_selectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
    if (_action == IDiamondCut.FacetCutAction.Add) {
      enforceHasContractCode(_newFacetAddress, "LibDiamondCut: Add facet has no code");
      for (uint256 selectorIndex; selectorIndex < _selectors.length; selectorIndex++) {
        bytes4 selector = _selectors[selectorIndex];

        bytes32 oldFacet = ds.facets[selector];

        require(address(bytes20(oldFacet)) == address(0), "LibDiamondCut: Can't add function that already exists");
        // add facet for selector
        ds.facets[selector] = bytes20(_newFacetAddress) | bytes32(_selectorCount);
        uint256 selectorInSlotPosition = (_selectorCount & 7) << 5;
        // clear selector position in slot and add selector
        _selectorSlot = (_selectorSlot & ~(CLEAR_SELECTOR_MASK >> selectorInSlotPosition)) | (bytes32(selector) >> selectorInSlotPosition);
        // if slot is full then write it to storage
        if (selectorInSlotPosition == 224) {
          ds.selectorSlots[_selectorCount >> 3] = _selectorSlot;
          _selectorSlot = 0;
        }
        _selectorCount++;
      }
    } else if (_action == IDiamondCut.FacetCutAction.Replace) {
      enforceHasContractCode(_newFacetAddress, "LibDiamondCut: Replace facet has no code");
      for (uint256 selectorIndex; selectorIndex < _selectors.length; selectorIndex++) {
        bytes4 selector = _selectors[selectorIndex];
        bytes32 oldFacet = ds.facets[selector];
        address oldFacetAddress = address(bytes20(oldFacet));

        // only useful if immutable functions exist
        require(oldFacetAddress != address(this), "LibDiamondCut: Can't replace immutable function");
        require(oldFacetAddress != _newFacetAddress, "LibDiamondCut: Can't replace function with same function");
        require(oldFacetAddress != address(0), "LibDiamondCut: Can't replace function that doesn't exist");
        // replace old facet address
        ds.facets[selector] = (oldFacet & CLEAR_ADDRESS_MASK) | bytes20(_newFacetAddress);
      }
    } else if (_action == IDiamondCut.FacetCutAction.Remove) {
      require(_newFacetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
      uint256 selectorSlotCount = _selectorCount >> 3;
      uint256 selectorInSlotIndex = _selectorCount & 7;
      for (uint256 selectorIndex; selectorIndex < _selectors.length; selectorIndex++) {
        if (_selectorSlot == 0) {
          // get last selectorSlot
          selectorSlotCount--;
          _selectorSlot = ds.selectorSlots[selectorSlotCount];
          selectorInSlotIndex = 7;
        } else {
          selectorInSlotIndex--;
        }
        bytes4 lastSelector;
        uint256 oldSelectorsSlotCount;
        uint256 oldSelectorInSlotPosition;
        // adding a block here prevents stack too deep error
        {
          bytes4 selector = _selectors[selectorIndex];
          bytes32 oldFacet = ds.facets[selector];
          require(address(bytes20(oldFacet)) != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
          // only useful if immutable functions exist
          require(address(bytes20(oldFacet)) != address(this), "LibDiamondCut: Can't remove immutable function");
          // replace selector with last selector in ds.facets
          // gets the last selector
          lastSelector = bytes4(_selectorSlot << (selectorInSlotIndex << 5));
          if (lastSelector != selector) {
            // update last selector slot position info
            ds.facets[lastSelector] = (oldFacet & CLEAR_ADDRESS_MASK) | bytes20(ds.facets[lastSelector]);
          }
          delete ds.facets[selector];
          uint256 oldSelectorCount = uint16(uint256(oldFacet));
          oldSelectorsSlotCount = oldSelectorCount >> 3;
          oldSelectorInSlotPosition = (oldSelectorCount & 7) << 5;
        }
        if (oldSelectorsSlotCount != selectorSlotCount) {
          bytes32 oldSelectorSlot = ds.selectorSlots[oldSelectorsSlotCount];
          // clears the selector we are deleting and puts the last selector in its place.
          oldSelectorSlot =
            (oldSelectorSlot & ~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)) |
            (bytes32(lastSelector) >> oldSelectorInSlotPosition);
          // update storage with the modified slot
          ds.selectorSlots[oldSelectorsSlotCount] = oldSelectorSlot;
        } else {
          // clears the selector we are deleting and puts the last selector in its place.
          _selectorSlot =
            (_selectorSlot & ~(CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)) |
            (bytes32(lastSelector) >> oldSelectorInSlotPosition);
        }
        if (selectorInSlotIndex == 0) {
          delete ds.selectorSlots[selectorSlotCount];
          _selectorSlot = 0;
        }
      }
      _selectorCount = selectorSlotCount * 8 + selectorInSlotIndex;
    } else {
      revert("LibDiamondCut: Incorrect FacetCutAction");
    }
    return (_selectorCount, _selectorSlot);
  }

  function initializeDiamondCut(address _init, bytes memory _calldata) internal {
    if (_init == address(0)) {
      require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
    } else {
      require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
      if (_init != address(this)) {
        enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
      }
      (bool success, bytes memory error) = _init.delegatecall(_calldata);
      if (!success) {
        if (error.length > 0) {
          // bubble up the error
          revert(string(error));
        } else {
          revert("LibDiamondCut: _init function reverted");
        }
      }
    }
  }

  function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
    uint256 contractSize;
    assembly {
      contractSize := extcodesize(_contract)
    }
    require(contractSize > 0, _errorMessage);
  }
}

File 5 of 18 : LibStrings.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

// From Open Zeppelin contracts: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Strings.sol

/**
 * @dev String operations.
 */
library LibStrings {
    /**
     * @dev Converts a `uint256` to its ASCII `string` representation.
     */
    function strWithUint(string memory _str, uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
        bytes memory buffer;
        unchecked {
            if (value == 0) {
                return string(abi.encodePacked(_str, "0"));
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            buffer = new bytes(digits);
            uint256 index = digits - 1;
            temp = value;
            while (temp != 0) {
                buffer[index--] = bytes1(uint8(48 + (temp % 10)));
                temp /= 10;
            }
        }
        return string(abi.encodePacked(_str, buffer));
    }
}

File 6 of 18 : LibMeta.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

library LibMeta {
    bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
        keccak256(bytes("EIP712Domain(string name,string version,uint256 salt,address verifyingContract)"));

    function domainSeparator(string memory name, string memory version) internal view returns (bytes32 domainSeparator_) {
        domainSeparator_ = keccak256(
            abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes(version)), getChainID(), address(this))
        );
    }

    function getChainID() internal view returns (uint256 id) {
        assembly {
            id := chainid()
        }
    }

    function msgSender() internal view returns (address sender_) {
        if (msg.sender == address(this)) {
            bytes memory array = msg.data;
            uint256 index = msg.data.length;
            assembly {
                // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
                sender_ := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
            }
        } else {
            sender_ = msg.sender;
        }
    }
}

File 7 of 18 : LibERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "../interfaces/IERC721TokenReceiver.sol";
import {LibAppStorage, AppStorage} from "./AppStorage.sol";
import "./LibMeta.sol";

library LibERC721 {
  /// @dev This emits when ownership of any NFT changes by any mechanism.
  ///  This event emits when NFTs are created (`from` == 0) and destroyed
  ///  (`to` == 0). Exception: during contract creation, any number of NFTs
  ///  may be created and assigned without emitting Transfer. At the time of
  ///  any transfer, the approved address for that NFT (if any) is reset to none.
  event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

  /// @dev This emits when the approved address for an NFT is changed or
  ///  reaffirmed. The zero address indicates there is no approved address.
  ///  When a Transfer event emits, this also indicates that the approved
  ///  address for that NFT (if any) is reset to none.
  event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

  /// @dev This emits when an operator is enabled or disabled for an owner.
  ///  The operator can manage all NFTs of the owner.
  event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

  bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;

  event MintParcel(address indexed _owner, uint256 indexed _tokenId);

  function checkOnERC721Received(
    address _operator,
    address _from,
    address _to,
    uint256 _tokenId,
    bytes memory _data
  ) internal {
    uint256 size;
    assembly {
      size := extcodesize(_to)
    }
    if (size > 0) {
      require(
        ERC721_RECEIVED == IERC721TokenReceiver(_to).onERC721Received(_operator, _from, _tokenId, _data),
        "LibERC721: Transfer rejected/failed by _to"
      );
    }
  }

  // This function is used by transfer functions
  function transferFrom(
    address _sender,
    address _from,
    address _to,
    uint256 _tokenId
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();
    require(_to != address(0), "ER721: Can't transfer to 0 address");
    address owner = s.parcels[_tokenId].owner;
    require(owner != address(0), "ERC721: Invalid tokenId or can't be transferred");
    require(_sender == owner || s.operators[owner][_sender] || s.approved[_tokenId] == _sender, "LibERC721: Not owner or approved to transfer");
    require(_from == owner, "ERC721: _from is not owner, transfer failed");
    s.parcels[_tokenId].owner = _to;

    //Update indexes and arrays

    //Get the index of the tokenID to transfer
    uint256 transferIndex = s.ownerTokenIdIndexes[_from][_tokenId];

    uint256 lastIndex = s.ownerTokenIds[_from].length - 1;
    uint256 lastTokenId = s.ownerTokenIds[_from][lastIndex];
    uint256 newIndex = s.ownerTokenIds[_to].length;

    //Move the last element of the ownerIds array to replace the tokenId to be transferred
    s.ownerTokenIdIndexes[_from][lastTokenId] = transferIndex;
    s.ownerTokenIds[_from][transferIndex] = lastTokenId;
    delete s.ownerTokenIdIndexes[_from][_tokenId];

    //pop from array
    s.ownerTokenIds[_from].pop();

    //update index of new token
    s.ownerTokenIdIndexes[_to][_tokenId] = newIndex;
    s.ownerTokenIds[_to].push(_tokenId);

    if (s.approved[_tokenId] != address(0)) {
      delete s.approved[_tokenId];
      emit LibERC721.Approval(owner, address(0), _tokenId);
    }

    emit LibERC721.Transfer(_from, _to, _tokenId);
  }

  function safeMint(address _to, uint256 _tokenId) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();

    require(s.parcels[_tokenId].owner == address(0), "LibERC721: tokenId already minted");
    s.parcels[_tokenId].owner = _to;
    s.tokenIds.push(_tokenId);
    s.ownerTokenIdIndexes[_to][_tokenId] = s.ownerTokenIds[_to].length;
    s.ownerTokenIds[_to].push(_tokenId);

    emit MintParcel(_to, _tokenId);
    emit LibERC721.Transfer(address(0), _to, _tokenId);
  }
}

File 8 of 18 : LibRealm.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import {InstallationDiamondInterface} from "../interfaces/InstallationDiamondInterface.sol";
import {TileDiamondInterface} from "../interfaces/TileDiamond.sol";
import "./AppStorage.sol";

library LibRealm {
  event SurveyParcel(uint256 _tokenId, uint256[] _alchemicas);

  //Place installation
  function placeInstallation(
    uint256 _realmId,
    uint256 _installationId,
    uint256 _x,
    uint256 _y
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();
    uint256[5] memory widths = getWidths();

    uint256[5] memory heights = getHeights();

    InstallationDiamondInterface installationsDiamond = InstallationDiamondInterface(s.installationsDiamond);
    InstallationDiamondInterface.InstallationType memory installation = installationsDiamond.getInstallationType(_installationId);

    Parcel storage parcel = s.parcels[_realmId];

    //Check if these slots are available onchain
    require(_x <= widths[parcel.size] - installation.width, "LibRealm: x exceeding width");
    require(_y <= heights[parcel.size] - installation.height, "LibRealm: y exceeding height");
    for (uint256 indexW = _x; indexW < _x + installation.width; indexW++) {
      for (uint256 indexH = _y; indexH < _y + installation.height; indexH++) {
        require(parcel.buildGrid[indexW][indexH] == 0, "LibRealm: Invalid spot");
        parcel.buildGrid[indexW][indexH] = _installationId;
      }
    }
  }

  function removeInstallation(
    uint256 _realmId,
    uint256 _installationId,
    uint256 _x,
    uint256 _y
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();
    InstallationDiamondInterface installationsDiamond = InstallationDiamondInterface(s.installationsDiamond);
    InstallationDiamondInterface.InstallationType memory installation = installationsDiamond.getInstallationType(_installationId);
    Parcel storage parcel = s.parcels[_realmId];
    require(parcel.buildGrid[_x][_y] == _installationId, "LibRealm: wrong installationId");
    for (uint256 indexW = _x; indexW < _x + installation.width; indexW++) {
      for (uint256 indexH = _y; indexH < _y + installation.height; indexH++) {
        parcel.buildGrid[indexW][indexH] = 0;
      }
    }
  }

  function placeTile(
    uint256 _realmId,
    uint256 _tileId,
    uint256 _x,
    uint256 _y
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();
    uint256[5] memory widths = getWidths();

    uint256[5] memory heights = getHeights();

    TileDiamondInterface tilesDiamond = TileDiamondInterface(s.tileDiamond);
    TileDiamondInterface.TileType memory tile = tilesDiamond.getTileType(_tileId);

    Parcel storage parcel = s.parcels[_realmId];

    //Check if these slots are available onchain
    require(_x <= widths[parcel.size] - tile.width, "LibRealm: x exceeding width");
    require(_y <= heights[parcel.size] - tile.height, "LibRealm: y exceeding height");
    for (uint256 indexW = _x; indexW < _x + tile.width; indexW++) {
      for (uint256 indexH = _y; indexH < _y + tile.height; indexH++) {
        require(parcel.tileGrid[indexW][indexH] == 0, "LibRealm: Invalid spot");
        parcel.tileGrid[indexW][indexH] = _tileId;
      }
    }
  }

  function removeTile(
    uint256 _realmId,
    uint256 _tileId,
    uint256 _x,
    uint256 _y
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();
    TileDiamondInterface tilesDiamond = TileDiamondInterface(s.tileDiamond);
    TileDiamondInterface.TileType memory tile = tilesDiamond.getTileType(_tileId);
    Parcel storage parcel = s.parcels[_realmId];
    require(parcel.tileGrid[_x][_y] == _tileId, "LibRealm: wrong tileId");
    for (uint256 indexW = _x; indexW < _x + tile.width; indexW++) {
      for (uint256 indexH = _y; indexH < _y + tile.height; indexH++) {
        parcel.tileGrid[indexW][indexH] = 0;
      }
    }
  }

  function calculateAmount(
    uint256 _tokenId,
    uint256[] memory randomWords,
    uint256 i
  ) internal view returns (uint256) {
    AppStorage storage s = LibAppStorage.diamondStorage();
    return (randomWords[i] % s.totalAlchemicas[s.parcels[_tokenId].size][i]);
  }

  function updateRemainingAlchemica(
    uint256 _tokenId,
    uint256[] memory randomWords,
    uint256 _round
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();
    require(s.parcels[_tokenId].currentRound <= s.surveyingRound, "AlchemicaFacet: Round not released");
    s.parcels[_tokenId].currentRound++;
    s.parcels[_tokenId].surveying = false;

    uint256[] memory alchemicas = new uint256[](4);
    uint256[] memory roundAmounts = new uint256[](4);
    for (uint256 i; i < 4; i++) {
      uint256 baseAmount = calculateAmount(_tokenId, randomWords, i); //100%;

      //first round is 25%, rounds after are 8.3%
      uint256 roundAmount = _round == 0 ? baseAmount / 4 : (baseAmount - (baseAmount / 4)) / 9;
      uint256 boost = s.parcels[_tokenId].alchemicaBoost[i] * s.boostMultipliers[i];

      s.parcels[_tokenId].alchemicaRemaining[i] += roundAmount + boost;
      roundAmounts[i] = roundAmount;
      alchemicas[i] = roundAmount + boost;
    }
    //update round alchemica
    s.parcels[_tokenId].roundAlchemica[_round] = alchemicas;
    s.parcels[_tokenId].roundBaseAlchemica[_round] = roundAmounts;
    emit SurveyParcel(_tokenId, alchemicas);
  }

  function getWidths() internal pure returns (uint256[5] memory) {
    uint256[5] memory widths = [
      HUMBLE_WIDTH, //humble
      REASONABLE_WIDTH, //reasonable
      SPACIOUS_WIDTH, //spacious vertical
      SPACIOUS_HEIGHT, //spacious horizontal
      PAARTNER_WIDTH //partner
    ];
    return widths;
  }

  function getHeights() internal pure returns (uint256[5] memory) {
    uint256[5] memory heights = [
      HUMBLE_HEIGHT, //humble
      REASONABLE_HEIGHT, //reasonable
      SPACIOUS_HEIGHT, //spacious vertical
      SPACIOUS_WIDTH, //spacious horizontal
      PAARTNER_HEIGHT //partner
    ];
    return heights;
  }
}

File 9 of 18 : LibAlchemica.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import {InstallationDiamondInterface} from "../interfaces/InstallationDiamondInterface.sol";
import {LibAppStorage, AppStorage, Parcel} from "./AppStorage.sol";

library LibAlchemica {
  function settleUnclaimedAlchemica(uint256 _tokenId, uint256 _alchemicaType) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();

    // uint256 capacity = s.parcels[_tokenId].reservoirCapacity[_alchemicaType];
    uint256 capacity = calculateTotalCapacity(_tokenId, _alchemicaType);

    uint256 alchemicaSinceUpdate = alchemicaSinceLastUpdate(_tokenId, _alchemicaType);

    if (alchemicaSinceUpdate > 0) {
      //Cannot settle more than capacity
      if (s.parcels[_tokenId].unclaimedAlchemica[_alchemicaType] + alchemicaSinceUpdate > capacity) {
        s.parcels[_tokenId].unclaimedAlchemica[_alchemicaType] = capacity;
      } else {
        //Increment alchemica
        s.parcels[_tokenId].unclaimedAlchemica[_alchemicaType] += alchemicaSinceUpdate;
      }
    }

    s.parcels[_tokenId].lastUpdateTimestamp[_alchemicaType] = block.timestamp;
  }

  function alchemicaSinceLastUpdate(uint256 _tokenId, uint256 _alchemicaType) internal view returns (uint256) {
    AppStorage storage s = LibAppStorage.diamondStorage();
    uint256 amount = s.parcels[_tokenId].alchemicaHarvestRate[_alchemicaType] *
      (block.timestamp - s.parcels[_tokenId].lastUpdateTimestamp[_alchemicaType]);

    return amount;
  }

  function increaseTraits(
    uint256 _realmId,
    uint256 _installationId,
    bool isUpgrade
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();

    //First save the current harvested amount
    InstallationDiamondInterface.InstallationType memory installationType = InstallationDiamondInterface(s.installationsDiamond).getInstallationType(
      _installationId
    );

    uint256 altarPrerequisite = installationType.prerequisites[0];
    uint256 lodgePrerequisite = installationType.prerequisites[1];

    // check altar requirement
    uint256 equippedAltarId = s.parcels[_realmId].altarId;
    uint256 equippedAltarLevel = InstallationDiamondInterface(s.installationsDiamond).getInstallationType(equippedAltarId).level;
    require(equippedAltarLevel >= altarPrerequisite, "RealmFacet: Altar Tech Tree Reqs not met");

    // check lodge requirement
    if (lodgePrerequisite > 0) {
      uint256 equippedLodgeId = s.parcels[_realmId].lodgeId;
      uint256 equippedLodgeLevel = InstallationDiamondInterface(s.installationsDiamond).getInstallationType(equippedLodgeId).level;
      require(equippedLodgeLevel >= lodgePrerequisite, "RealmFacet: Lodge Tech Tree Reqs not met");
    }

    // check harvester requirement
    if (installationType.installationType == 1) {
      require(s.parcels[_realmId].reservoirs[installationType.alchemicaType].length > 0, "RealmFacet: Must equip reservoir of type");
    }

    uint256 alchemicaType = installationType.alchemicaType;

    //unclaimed alchemica must be settled before mutating harvestRate and capacity
    settleUnclaimedAlchemica(_realmId, alchemicaType);

    //handle harvester
    if (installationType.harvestRate > 0) {
      s.parcels[_realmId].alchemicaHarvestRate[alchemicaType] += installationType.harvestRate;
    }

    //reservoir
    if (installationType.capacity > 0) {
      s.parcels[_realmId].reservoirs[alchemicaType].push(_installationId);
    }

    //Altar
    if (installationType.installationType == 0) {
      require(isUpgrade || s.parcels[_realmId].altarId == 0, "LibAlchemica: Cannot equip two altars");
      s.parcels[_realmId].altarId = _installationId;
    }

    // upgradeQueueBoost
    if (installationType.upgradeQueueBoost > 0) {
      s.parcels[_realmId].upgradeQueueCapacity += installationType.upgradeQueueBoost;
    }
  }

  function reduceTraits(
    uint256 _realmId,
    uint256 _installationId,
    bool isUpgrade
  ) internal {
    AppStorage storage s = LibAppStorage.diamondStorage();

    InstallationDiamondInterface installationsDiamond = InstallationDiamondInterface(s.installationsDiamond);
    InstallationDiamondInterface.InstallationType memory installationType = InstallationDiamondInterface(s.installationsDiamond).getInstallationType(
      _installationId
    );
    InstallationDiamondInterface.InstallationIdIO[] memory installationBalances = installationsDiamond.installationBalancesOfToken(
      address(this),
      _realmId
    );

    for (uint256 i; i < installationBalances.length; i++) {
      InstallationDiamondInterface.InstallationType memory equippedInstallaion = installationsDiamond.getInstallationType(_installationId);

      // check altar requirement
      require(
        InstallationDiamondInterface(s.installationsDiamond).getInstallationType(s.parcels[_realmId].altarId).level >=
          equippedInstallaion.prerequisites[0],
        "RealmFacet: Altar Tech Tree Reqs not met"
      );

      // check lodge requirement
      if (equippedInstallaion.prerequisites[1] > 0) {
        require(
          InstallationDiamondInterface(s.installationsDiamond).getInstallationType(s.parcels[_realmId].lodgeId).level >=
            equippedInstallaion.prerequisites[1],
          "RealmFacet: Lodge Tech Tree Reqs not met"
        );
      }
    }

    uint256 alchemicaType = installationType.alchemicaType;

    //unclaimed alchemica must be settled before updating harvestRate and capacity
    settleUnclaimedAlchemica(_realmId, alchemicaType);

    //Decrement harvest variables
    if (installationType.harvestRate > 0) {
      s.parcels[_realmId].alchemicaHarvestRate[alchemicaType] -= installationType.harvestRate;
    }

    //Altar
    if (installationType.installationType == 0 && !isUpgrade) {
      //@question: do we need any special exceptions for the Altar? Should be handled by tech tree
      s.parcels[_realmId].altarId = 0;
    }

    // Lodge
    if (installationType.installationType == 3) {
      s.parcels[_realmId].lodgeId = 0;
    }

    //Decrement reservoir variables
    if (installationType.capacity > 0) {
      for (uint256 i; i < s.parcels[_realmId].reservoirs[alchemicaType].length; i++) {
        if (s.parcels[_realmId].reservoirs[alchemicaType][i] == _installationId) {
          popArray(s.parcels[_realmId].reservoirs[alchemicaType], i);
          break;
        }
      }
      if (s.parcels[_realmId].unclaimedAlchemica[alchemicaType] > calculateTotalCapacity(_realmId, alchemicaType)) {
        //step 1 - unequip all harvesters
        //step 2 - claim alchemica balance
        //step 3 - unequip reservoir
        revert("LibAlchemica: Unclaimed alchemica greater than reservoir capacity");
      }
    }

    // upgradeQueueBoost
    if (installationType.upgradeQueueBoost > 0) {
      s.parcels[_realmId].upgradeQueueCapacity -= installationType.upgradeQueueBoost;
    }
  }

  function calculateTotalCapacity(uint256 _tokenId, uint256 _alchemicaType) internal view returns (uint256 capacity_) {
    AppStorage storage s = LibAppStorage.diamondStorage();
    for (uint256 i; i < s.parcels[_tokenId].reservoirs[_alchemicaType].length; i++) {
      capacity_ += InstallationDiamondInterface(s.installationsDiamond).getReservoirCapacity(s.parcels[_tokenId].reservoirs[_alchemicaType][i]);
    }
  }

  function popArray(uint256[] storage _array, uint256 _index) internal {
    _array[_index] = _array[_array.length - 1];
    _array.pop();
  }
}

File 10 of 18 : InstallationDiamondInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

interface InstallationDiamondInterface {
  struct InstallationType {
    //slot 1
    uint8 width;
    uint8 height;
    uint16 installationType; //0 = altar, 1 = harvester, 2 = reservoir, 3 = gotchi lodge, 4 = wall, 5 = NFT display, 6 = buildqueue booster
    uint8 level; //max level 9
    uint8 alchemicaType; //0 = none 1 = fud, 2 = fomo, 3 = alpha, 4 = kek
    uint32 spillRadius;
    uint16 spillRate;
    uint8 upgradeQueueBoost;
    uint32 craftTime; // in blocks
    uint32 nextLevelId; //the ID of the next level of this installation. Used for upgrades.
    bool deprecated; //bool
    //slot 2
    uint256[4] alchemicaCost; // [fud, fomo, alpha, kek]
    //slot 3
    uint256 harvestRate;
    //slot 4
    uint256 capacity;
    //slot 5
    uint256[] prerequisites; //IDs of installations that must be present before this installation can be added
    //slot 6
    string name;
  }

  struct UpgradeQueue {
    uint256 parcelId;
    uint256 coordinateX;
    uint256 coordinateY;
    uint256 installationId;
    uint256 readyBlock;
    bool claimed;
    address owner;
  }

  struct InstallationIdIO {
    uint256 installationId;
    uint256 balance;
  }

  struct ReservoirStats {
    uint256 spillRate;
    uint256 spillRadius;
    uint256 capacity;
  }

  function craftInstallations(uint256[] calldata _installationTypes) external;

  function claimInstallations(uint256[] calldata _queueIds) external;

  function equipInstallation(
    address _owner,
    uint256 _realmTokenId,
    uint256 _installationId
  ) external;

  function unequipInstallation(uint256 _realmId, uint256 _installationId) external;

  function addInstallationTypes(InstallationType[] calldata _installationTypes) external;

  function getInstallationType(uint256 _itemId) external view returns (InstallationType memory installationType);

  function getInstallationTypes(uint256[] calldata _itemIds) external view returns (InstallationType[] memory itemTypes_);

  function getAlchemicaAddresses() external view returns (address[] memory);

  function balanceOf(address _owner, uint256 _id) external view returns (uint256 bal_);

  function installationBalancesOfTokenByIds(
    address _tokenContract,
    uint256 _tokenId,
    uint256[] calldata _ids
  ) external view returns (uint256[] memory);

  function installationBalancesOfToken(address _tokenContract, uint256 _tokenId) external view returns (InstallationIdIO[] memory bals_);

  function spilloverRatesOfIds(uint256[] calldata _ids) external view returns (uint256[] memory);

  function upgradeInstallation(UpgradeQueue calldata _upgradeQueue, bytes memory _signature) external;

  function finalizeUpgrade() external;

  function installationsBalances(address _account) external view returns (InstallationIdIO[] memory bals_);

  function spilloverRateAndRadiusOfId(uint256 _id) external view returns (uint256, uint256);

  function getAltarLevel(uint256 _altarId) external view returns (uint256 altarLevel_);

  function getLodgeLevel(uint256 _installationId) external view returns (uint256 lodgeLevel_);

  function getReservoirCapacity(uint256 _installationId) external view returns (uint256 capacity_);

  function getReservoirStats(uint256 _installationId) external view returns (ReservoirStats memory reservoirStats_);
}

File 11 of 18 : LibSignature.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library LibSignature {

    function isValid(bytes32 messageHash, bytes memory signature, bytes memory pubKey) internal pure returns (bool) {
        bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);

        return recoverSigner(ethSignedMessageHash, signature) == address(uint160(uint256(keccak256(pubKey))));
    }

    function getEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash));
    }

    function recoverSigner(bytes32 ethSignedMessageHash, bytes memory signature) internal pure returns (address)
    {
        (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature);

        return ecrecover(ethSignedMessageHash, v, r, s);
    }

    function splitSignature(bytes memory sig) internal pure returns (bytes32 r, bytes32 s, uint8 v)
    {
        require(sig.length == 65, "Invalid signature length");

        assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            v := byte(0, mload(add(sig, 96)))
        }
        // implicitly return (r, s, v)
    }
}

File 12 of 18 : ERC721Facet.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.9;

import "../../libraries/AppStorage.sol";
import "../../libraries/LibDiamond.sol";
import "../../libraries/LibStrings.sol";
import "../../libraries/LibMeta.sol";
import "../../libraries/LibERC721.sol";
import {IERC721} from "../../interfaces/IERC721.sol";
import {ERC721Marketplace} from "../../interfaces/ERC721Marketplace.sol";

contract ERC721Facet is Modifiers {
  // bytes4 private constant ERC721_RECEIVED = 0x150b7a02;

  function tokenIdsOfOwner(address _owner) external view returns (uint256[] memory tokenIds_) {
    return s.ownerTokenIds[_owner];
  }

  function totalSupply() external view returns (uint256) {
    return s.tokenIds.length;
  }

  /// @notice Enumerate valid NFTs
  /// @dev Throws if `_index` >= `totalSupply()`.
  /// @param _index A counter less than `totalSupply()`
  /// @return tokenId_ The token identifier for the `_index`th NFT,
  ///  (sort order not specified)
  function tokenByIndex(uint256 _index) external view returns (uint256 tokenId_) {
    require(_index < s.tokenIds.length, "AavegotchiFacet: _index is greater than total supply.");
    tokenId_ = s.tokenIds[_index];
  }

  /// @notice Count all NFTs assigned to an owner
  /// @dev NFTs assigned to the zero address are considered invalid, and this.
  ///  function throws for queries about the zero address.
  /// @param _owner An address for whom to query the balance
  /// @return balance_ The number of NFTs owned by `_owner`, possibly zero
  function balanceOf(address _owner) external view returns (uint256 balance_) {
    balance_ = s.ownerTokenIds[_owner].length;
  }

  /// @notice Find the owner of an NFT
  /// @dev NFTs assigned to zero address are considered invalid, and queries
  ///  about them do throw.
  /// @param _tokenId The identifier for an NFT
  /// @return owner_ The address of the owner of the NFT
  function ownerOf(uint256 _tokenId) external view returns (address owner_) {
    owner_ = s.parcels[_tokenId].owner;
  }

  /// @notice Get the approved address for a single NFT
  /// @dev Throws if `_tokenId` is not a valid NFT.
  /// @param _tokenId The NFT to find the approved address for
  /// @return approved_ The approved address for this NFT, or the zero address if there is none
  function getApproved(uint256 _tokenId) external view returns (address approved_) {
    require(s.parcels[_tokenId].owner != address(0), "AavegotchiFacet: tokenId is invalid or is not owned");
    approved_ = s.approved[_tokenId];
  }

  /// @notice Query if an address is an authorized operator for another address
  /// @param _owner The address that owns the NFTs
  /// @param _operator The address that acts on behalf of the owner
  /// @return approved_ True if `_operator` is an approved operator for `_owner`, false otherwise
  function isApprovedForAll(address _owner, address _operator) external view returns (bool approved_) {
    approved_ = s.operators[_owner][_operator];
  }

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @dev Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `_from` is
  ///  not the current owner. Throws if `_to` is the zero address. Throws if
  ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
  ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
  ///  `onERC721Received` on `_to` and throws if the return value is not
  ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  /// @param _data Additional data with no specified format, sent in call to `_to`
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId,
    bytes calldata _data
  ) public {
    address sender = LibMeta.msgSender();
    LibERC721.transferFrom(sender, _from, _to, _tokenId);
    LibERC721.checkOnERC721Received(sender, _from, _to, _tokenId, _data);

    //Update baazaar listing

    if (s.aavegotchiDiamond != address(0)) {
      ERC721Marketplace(s.aavegotchiDiamond).updateERC721Listing(address(this), _tokenId, _from);
    }
  }

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @dev This works identically to the other function with an extra data parameter,
  ///  except this function just sets data to "".
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  ) external {
    address sender = LibMeta.msgSender();
    LibERC721.transferFrom(sender, _from, _to, _tokenId);
    LibERC721.checkOnERC721Received(sender, _from, _to, _tokenId, "");

    //Update baazaar listing
    if (s.aavegotchiDiamond != address(0)) {
      ERC721Marketplace(s.aavegotchiDiamond).updateERC721Listing(address(this), _tokenId, _from);
    }
  }

  /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
  ///  THEY MAY BE PERMANENTLY LOST
  /// @dev Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `_from` is
  ///  not the current owner. Throws if `_to` is the zero address. Throws if
  ///  `_tokenId` is not a valid NFT.
  /// @param _from The current owner of the NFT
  /// @param _to The new owner
  /// @param _tokenId The NFT to transfer
  function transferFrom(
    address _from,
    address _to,
    uint256 _tokenId
  ) external {
    address sender = LibMeta.msgSender();
    LibERC721.transferFrom(sender, _from, _to, _tokenId);

    if (s.aavegotchiDiamond != address(0)) {
      ERC721Marketplace(s.aavegotchiDiamond).updateERC721Listing(address(this), _tokenId, _from);
    }
  }

  /// @notice Change or reaffirm the approved address for an NFT
  /// @dev The zero address indicates there is no approved address.
  ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
  ///  operator of the current owner.
  /// @param _approved The new approved NFT controller
  /// @param _tokenId The NFT to approve
  function approve(address _approved, uint256 _tokenId) external {
    address owner = s.parcels[_tokenId].owner;
    address sender = LibMeta.msgSender();
    require(owner == sender || s.operators[owner][sender], "ERC721: Not owner or operator of token.");
    s.approved[_tokenId] = _approved;
    emit LibERC721.Approval(owner, _approved, _tokenId);
  }

  /// @notice Enable or disable approval for a third party ("operator") to manage
  ///  all of `msg.sender`'s assets
  /// @dev Emits the ApprovalForAll event. The contract MUST allow
  ///  multiple operators per owner.
  /// @param _operator Address to add to the set of authorized operators
  /// @param _approved True if the operator is approved, false to revoke approval
  function setApprovalForAll(address _operator, bool _approved) external {
    address sender = LibMeta.msgSender();
    s.operators[sender][_operator] = _approved;
    emit LibERC721.ApprovalForAll(sender, _operator, _approved);
  }

  function name() external pure returns (string memory) {
    return "Gotchiverse REALM Parcel";
  }

  /// @notice An abbreviated name for NFTs in this contract
  function symbol() external pure returns (string memory) {
    return "REALM";
  }

  /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
  /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
  ///  3986. The URI may point to a JSON file that conforms to the "ERC721
  ///  Metadata JSON Schema".
  function tokenURI(uint256 _tokenId) external pure returns (string memory) {
    return LibStrings.strWithUint("https://app.aavegotchi.com/metadata/realm/", _tokenId); //Here is your URL!
  }

  struct MintParcelInput {
    uint256 coordinateX;
    uint256 coordinateY;
    uint256 parcelId;
    uint256 size; //0=humble, 1=reasonable, 2=spacious vertical, 3=spacious horizontal, 4=partner
    uint256 fomoBoost;
    uint256 fudBoost;
    uint256 kekBoost;
    uint256 alphaBoost;
  }

  function safeBatchTransfer(
    address _from,
    address _to,
    uint256[] calldata _tokenIds,
    bytes calldata _data
  ) external {
    for (uint256 index = 0; index < _tokenIds.length; index++) {
      safeTransferFrom(_from, _to, _tokenIds[index], _data);
    }
  }

  function addSupportForERC165() external onlyOwner {
    LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
    ds.supportedInterfaces[type(IERC721).interfaceId] = true;
  }
}

File 13 of 18 : AavegotchiDiamond.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.1;

interface AavegotchiDiamond {
  struct GotchiLending {
    // storage slot 1
    address lender;
    uint96 initialCost; // GHST in wei, can be zero
    // storage slot 2
    address borrower;
    uint32 listingId;
    uint32 erc721TokenId;
    uint32 whitelistId; // can be zero
    // storage slot 3
    address originalOwner; // if original owner is lender, same as lender
    uint40 timeCreated;
    uint40 timeAgreed;
    bool canceled;
    bool completed;
    // storage slot 4
    address thirdParty; // can be address(0)
    uint8[3] revenueSplit; // lender/original owner, borrower, thirdParty
    uint40 lastClaimed; //timestamp
    uint32 period; //in seconds
    // storage slot 5
    address[] revenueTokens;
  }

  function ownerOf(uint256 _tokenId) external view returns (address owner_);

  function gotchiEscrow(uint256 _tokenId) external view returns (address);

  function isAavegotchiLent(uint32 _erc721TokenId) external view returns (bool);

  function getGotchiLendingFromToken(uint32 _erc721TokenId) external view returns (GotchiLending memory listing_);

  function addGotchiLending(
    uint32 _erc721TokenId,
    uint96 _initialCost,
    uint32 _period,
    uint8[3] calldata _revenueSplit,
    address _originalOwner,
    address _thirdParty,
    uint32 _whitelistId,
    address[] calldata _revenueTokens
  ) external;

  function agreeGotchiLending(
    uint32 _listingId,
    uint32 _erc721TokenId,
    uint96 _initialCost,
    uint32 _period,
    uint8[3] calldata _revenueSplit
  ) external;

  function kinship(uint256 _tokenId) external view returns (uint256 score_);
}

File 14 of 18 : IDiamondCut.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

interface IDiamondCut {
    enum FacetCutAction {Add, Replace, Remove}
    // Add=0, Replace=1, Remove=2

    struct FacetCut {
        address facetAddress;
        FacetCutAction action;
        bytes4[] functionSelectors;
    }

    /// @notice Add/replace/remove any number of functions and optionally execute
    ///         a function with delegatecall
    /// @param _diamondCut Contains the facet addresses and function selectors
    /// @param _init The address of the contract or facet to execute _calldata
    /// @param _calldata A function call, including function selector and arguments
    ///                  _calldata is executed with delegatecall on _init
    function diamondCut(
        FacetCut[] calldata _diamondCut,
        address _init,
        bytes calldata _calldata
    ) external;

    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}

File 15 of 18 : IERC721TokenReceiver.sol
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

/// @title IERC721TokenReceiver
/// @dev See https://eips.ethereum.org/EIPS/eip-721. Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface IERC721TokenReceiver {
    /// @notice Handle the receipt of an NFT
    /// @dev The ERC721 smart contract calls this function on the recipient
    ///  after a `transfer`. This function MAY throw to revert and reject the
    ///  transfer. Return of other than the magic value MUST result in the
    ///  transaction being reverted.
    ///  Note: the contract address is always the message sender.
    /// @param _operator The address which called `safeTransferFrom` function
    /// @param _from The address which previously owned the token
    /// @param _tokenId The NFT identifier which is being transferred
    /// @param _data Additional data with no specified format
    /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    ///  unless throwing
    function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns(bytes4);
}

File 16 of 18 : TileDiamond.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/

interface TileDiamondInterface {
  struct TileType {
    uint256 width;
    uint256 height;
    bool deprecated;
    uint16 tileType;
    uint256[4] alchemicaCost; // [fud, fomo, alpha, kek]
    uint256 craftTime; // in blocks
    string name;
  }

  struct TileIdIO {
    uint256 tileId;
    uint256 balance;
  }

  function craftTiles(uint256[] calldata _tileTypes) external;

  function claimTiles(uint256[] calldata _queueIds) external;

  function equipTile(
    address _owner,
    uint256 _realmTokenId,
    uint256 _tileId
  ) external;

  function unequipTile(
    address _owner,
    uint256 _realmId,
    uint256 _tileId
  ) external;

  function addTileTypes(TileType[] calldata _tileTypes) external;

  function getTileType(uint256 _itemId) external view returns (TileType memory tileType);

  function getTileTypes(uint256[] calldata _itemIds) external view returns (TileType[] memory itemTypes_);

  function getAlchemicaAddresses() external view returns (address[] memory);

  function balanceOf(address _owner, uint256 _id) external view returns (uint256 bal_);

  function tileBalancesOfTokenByIds(
    address _tokenContract,
    uint256 _tokenId,
    uint256[] calldata _ids
  ) external view returns (uint256[] memory);

  function tilesBalances(address _account) external view returns (TileIdIO[] memory bals_);
}

File 17 of 18 : IERC721.sol
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface IERC721 /* is ERC165 */ {
    /// @dev This emits when ownership of any NFT changes by any mechanism.
    ///  This event emits when NFTs are created (`from` == 0) and destroyed
    ///  (`to` == 0). Exception: during contract creation, any number of NFTs
    ///  may be created and assigned without emitting Transfer. At the time of
    ///  any transfer, the approved address for that NFT (if any) is reset to none.
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

    /// @dev This emits when the approved address for an NFT is changed or
    ///  reaffirmed. The zero address indicates there is no approved address.
    ///  When a Transfer event emits, this also indicates that the approved
    ///  address for that NFT (if any) is reset to none.
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

    /// @dev This emits when an operator is enabled or disabled for an owner.
    ///  The operator can manage all NFTs of the owner.
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

    /// @notice Count all NFTs assigned to an owner
    /// @dev NFTs assigned to the zero address are considered invalid, and this
    ///  function throws for queries about the zero address.
    /// @param _owner An address for whom to query the balance
    /// @return The number of NFTs owned by `_owner`, possibly zero
    function balanceOf(address _owner) external view returns (uint256);

    /// @notice Find the owner of an NFT
    /// @dev NFTs assigned to zero address are considered invalid, and queries
    ///  about them do throw.
    /// @param _tokenId The identifier for an NFT
    /// @return The address of the owner of the NFT
    function ownerOf(uint256 _tokenId) external view returns (address);

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    ///  operator, or the approved address for this NFT. Throws if `_from` is
    ///  not the current owner. Throws if `_to` is the zero address. Throws if
    ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
    ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
    ///  `onERC721Received` on `_to` and throws if the return value is not
    ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    /// @param data Additional data with no specified format, sent in call to `_to`
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable;

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev This works identically to the other function with an extra data parameter,
    ///  except this function just sets data to "".
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
    ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
    ///  THEY MAY BE PERMANENTLY LOST
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    ///  operator, or the approved address for this NFT. Throws if `_from` is
    ///  not the current owner. Throws if `_to` is the zero address. Throws if
    ///  `_tokenId` is not a valid NFT.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

    /// @notice Change or reaffirm the approved address for an NFT
    /// @dev The zero address indicates there is no approved address.
    ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
    ///  operator of the current owner.
    /// @param _approved The new approved NFT controller
    /// @param _tokenId The NFT to approve
    function approve(address _approved, uint256 _tokenId) external payable;

    /// @notice Enable or disable approval for a third party ("operator") to manage
    ///  all of `msg.sender`'s assets
    /// @dev Emits the ApprovalForAll event. The contract MUST allow
    ///  multiple operators per owner.
    /// @param _operator Address to add to the set of authorized operators
    /// @param _approved True if the operator is approved, false to revoke approval
    function setApprovalForAll(address _operator, bool _approved) external;

    /// @notice Get the approved address for a single NFT
    /// @dev Throws if `_tokenId` is not a valid NFT.
    /// @param _tokenId The NFT to find the approved address for
    /// @return The approved address for this NFT, or the zero address if there is none
    function getApproved(uint256 _tokenId) external view returns (address);

    /// @notice Query if an address is an authorized operator for another address
    /// @param _owner The address that owns the NFTs
    /// @param _operator The address that acts on behalf of the owner
    /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

File 18 of 18 : ERC721Marketplace.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ERC721Marketplace {
  function updateERC721Listing(
    address _erc721TokenAddress,
    uint256 _erc721TokenId,
    address _owner
  ) external;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_aavegotchiDiamond","type":"address"}],"name":"AavegotchiDiamondUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_realmId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_installationId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_x","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_y","type":"uint256"}],"name":"EquipInstallation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_realmId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_tileId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_x","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_y","type":"uint256"}],"name":"EquipTile","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_realmId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_prevInstallationId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nextInstallationId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_coordinateX","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_coordinateY","type":"uint256"}],"name":"InstallationUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_realmId","type":"uint256"}],"name":"ResyncParcel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_realmId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_installationId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_x","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_y","type":"uint256"}],"name":"UnequipInstallation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_realmId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_tileId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_x","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_y","type":"uint256"}],"name":"UnequipTile","type":"event"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"}],"name":"addUpgradeQueueLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_district","type":"uint256"}],"name":"batchGetDistrictParcels","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_parcelIds","type":"uint256[]"},{"internalType":"uint256","name":"_gridType","type":"uint256"}],"name":"batchGetGrid","outputs":[{"components":[{"internalType":"uint256[64][64]","name":"coords","type":"uint256[64][64]"}],"internalType":"struct RealmFacet.ParcelCoordinates[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"},{"internalType":"uint256","name":"_coordinateX","type":"uint256"},{"internalType":"uint256","name":"_coordinateY","type":"uint256"},{"internalType":"uint256","name":"_installationId","type":"uint256"}],"name":"checkCoordinates","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"},{"internalType":"uint256","name":"_installationId","type":"uint256"},{"internalType":"uint256","name":"_x","type":"uint256"},{"internalType":"uint256","name":"_y","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"equipInstallation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"},{"internalType":"uint256","name":"_tileId","type":"uint256"},{"internalType":"uint256","name":"_x","type":"uint256"},{"internalType":"uint256","name":"_y","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"equipTile","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parcelId","type":"uint256"},{"internalType":"uint256","name":"_gridType","type":"uint256"}],"name":"getHumbleGrid","outputs":[{"internalType":"uint256[8][8]","name":"output_","type":"uint256[8][8]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parcelId","type":"uint256"},{"internalType":"uint256","name":"_gridType","type":"uint256"}],"name":"getPaartnerGrid","outputs":[{"internalType":"uint256[64][64]","name":"output_","type":"uint256[64][64]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"}],"name":"getParcelInfo","outputs":[{"components":[{"internalType":"string","name":"parcelId","type":"string"},{"internalType":"string","name":"parcelAddress","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"coordinateX","type":"uint256"},{"internalType":"uint256","name":"coordinateY","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"district","type":"uint256"},{"internalType":"uint256[4]","name":"boost","type":"uint256[4]"},{"internalType":"uint256","name":"timeRemainingToClaim","type":"uint256"}],"internalType":"struct RealmFacet.ParcelOutput","name":"output_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parcelId","type":"uint256"}],"name":"getParcelUpgradeQueueCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parcelId","type":"uint256"}],"name":"getParcelUpgradeQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_parcelIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_actionRights","type":"uint256[]"}],"name":"getParcelsAccessRights","outputs":[{"internalType":"uint256[]","name":"output_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parcelId","type":"uint256"},{"internalType":"uint256","name":"_gridType","type":"uint256"}],"name":"getReasonableGrid","outputs":[{"internalType":"uint256[16][16]","name":"output_","type":"uint256[16][16]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parcelId","type":"uint256"},{"internalType":"uint256","name":"_gridType","type":"uint256"}],"name":"getSpaciousHorizontalGrid","outputs":[{"internalType":"uint256[64][32]","name":"output_","type":"uint256[64][32]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_parcelId","type":"uint256"},{"internalType":"uint256","name":"_gridType","type":"uint256"}],"name":"getSpaciousVerticalGrid","outputs":[{"internalType":"uint256[32][64]","name":"output_","type":"uint256[32][64]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"coordinateX","type":"uint256"},{"internalType":"uint256","name":"coordinateY","type":"uint256"},{"internalType":"uint256","name":"district","type":"uint256"},{"internalType":"string","name":"parcelId","type":"string"},{"internalType":"string","name":"parcelAddress","type":"string"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256[4]","name":"boost","type":"uint256[4]"}],"internalType":"struct RealmFacet.MintParcelInput[]","name":"_metadata","type":"tuple[]"}],"name":"mintParcels","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"resyncParcel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_gameActive","type":"bool"}],"name":"setGameActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_realmIds","type":"uint256[]"},{"internalType":"uint256[]","name":"_actionRights","type":"uint256[]"},{"internalType":"uint256[]","name":"_accessRights","type":"uint256[]"}],"name":"setParcelsAccessRights","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"}],"name":"subUpgradeQueueLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"},{"internalType":"uint256","name":"_installationId","type":"uint256"},{"internalType":"uint256","name":"_x","type":"uint256"},{"internalType":"uint256","name":"_y","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"unequipInstallation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"},{"internalType":"uint256","name":"_tileId","type":"uint256"},{"internalType":"uint256","name":"_x","type":"uint256"},{"internalType":"uint256","name":"_y","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"unequipTile","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_realmId","type":"uint256"},{"internalType":"uint256","name":"_prevInstallationId","type":"uint256"},{"internalType":"uint256","name":"_nextInstallationId","type":"uint256"},{"internalType":"uint256","name":"_coordinateX","type":"uint256"},{"internalType":"uint256","name":"_coordinateY","type":"uint256"}],"name":"upgradeInstallation","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b506150ee806100206000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80637690a6b3116100c3578063c96fd9c51161007c578063c96fd9c51461030c578063ccc089741461032c578063d5abeb011461033f578063da80c76e14610352578063dd71950a14610376578063e45c7de21461039657600080fd5b80637690a6b314610273578063ad3d0f6514610293578063adf68808146102b3578063bc6c0d33146102c6578063bd6a3295146102d9578063c3671216146102ec57600080fd5b806351caf05c1161011557806351caf05c146101f45780635505421b1461020757806356ba6c551461021a578063579fa4af1461022d578063594a0a701461024057806375438cd41461026057600080fd5b80631628652a1461015d5780631ef25f94146101725780632d7e13011461019b578063347373c7146101bb578063367e3dac146101ce5780633fa75b65146101e1575b600080fd5b61017061016b366004614093565b6103ba565b005b61018561018036600461410a565b61076d565b6040516101929190614161565b60405180910390f35b6101ae6101a936600461410a565b6108ff565b604051610192919061419a565b6101706101c93660046141fb565b610a94565b6101706101dc366004614278565b610b27565b6101706101ef366004614093565b610ceb565b610170610202366004614093565b611025565b610170610215366004614311565b6111a6565b610170610228366004614402565b611266565b61017061023b366004614584565b611419565b61025361024e36600461459d565b611479565b60405161019291906145c7565b61017061026e366004614584565b611647565b61028661028136600461410a565b61169f565b60405161019291906145ff565b6102a66102a136600461410a565b611821565b6040516101929190614657565b6102536102c136600461468b565b6119b8565b6101706102d43660046146f6565b611ae5565b6101706102e7366004614093565b611b60565b6102ff6102fa36600461410a565b611cd5565b6040516101929190614737565b61031f61031a36600461478f565b611e61565b60405161019291906147da565b61017061033a36600461485e565b612069565b620668e55b604051908152602001610192565b610344610360366004614584565b6000908152600160205260409020612020015490565b610389610384366004614584565b61208f565b60405161019291906148fa565b6103446103a4366004614584565b6000908152600160205260409020612021015490565b60008581526001602052604090205485906001600160a01b03166103dc61224f565b6001600160a01b03161461040b5760405162461bcd60e51b8152600401610402906149a1565b60405180910390fd5b603754600160a01b900460ff166104345760405162461bcd60e51b8152600401610402906149e7565b604080516020810188905290810186905260608101859052608081018490526105059060a0015b60405160208183030381529060405280519060200120836000602f01805461048290614a1e565b80601f01602080910402602001604051908101604052809291908181526020018280546104ae90614a1e565b80156104fb5780601f106104d0576101008083540402835291602001916104fb565b820191906000526020600020905b8154815290600101906020018083116104de57829003601f168201915b50505050506122ac565b6105215760405162461bcd60e51b815260040161040290614a59565b600b5460405163109e13c560e21b8152600481018790526001600160a01b039091169060009082906342784f149060240160006040518083038186803b15801561056a57600080fd5b505afa15801561057e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105a69190810190614bca565b90506105b488888888612336565b60005b60048110156106a9576000600782600481106105d5576105d5614d4a565b01546101608401516001600160a01b039091169150600090600290846004811061060157610601614d4a565b60200201516106109190614d76565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0383169063a9059cbb90604401602060405180830381600087803b15801561065b57600080fd5b505af115801561066f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106939190614d98565b50505080806106a190614db5565b9150506105b7565b50600b54604051633240806960e01b8152600481018a9052602481018990526001600160a01b0390911690633240806990604401600060405180830381600087803b1580156106f757600080fd5b505af115801561070b573d6000803e3d6000fd5b5050505061071b888860006124e2565b6040805189815260208101899052908101879052606081018690527feb8dc37534b72de521d16884c32148e05abe550c5627ee4ba527ddfa1a7717ff9060800160405180910390a15050505050505050565b610775613c82565b6000838152600160205260409020600601546004146107d65760405162461bcd60e51b815260206004820152601860248201527f5265616c6d46616365743a204e6f742070616172746e657200000000000000006044820152606401610402565b60005b60408110156108f85760005b60408110156108e557836108605760008581526001602052604090819020600701908290811061081757610817614d4a565b60400201826040811061082c5761082c614d4a565b015483836040811061084057610840614d4a565b6020020151826040811061085657610856614d4a565b60200201526108d3565b83600114156108d3576000858152600160205260409081902061100701908290811061088e5761088e614d4a565b6040020182604081106108a3576108a3614d4a565b01548383604081106108b7576108b7614d4a565b602002015182604081106108cd576108cd614d4a565b60200201525b806108dd81614db5565b9150506107e5565b50806108f081614db5565b9150506107d9565b5092915050565b610907613cb0565b6000838152600160205260409020600601546002146109725760405162461bcd60e51b815260206004820152602160248201527f5265616c6d46616365743a204e6f742073706163696f757320766572746963616044820152601b60fa1b6064820152608401610402565b60005b60408110156108f85760005b6020811015610a8157836109fc576000858152600160205260409081902060070190829081106109b3576109b3614d4a565b6040020182604081106109c8576109c8614d4a565b01548383604081106109dc576109dc614d4a565b602002015182602081106109f2576109f2614d4a565b6020020152610a6f565b8360011415610a6f5760008581526001602052604090819020611007019082908110610a2a57610a2a614d4a565b604002018260408110610a3f57610a3f614d4a565b0154838360408110610a5357610a53614d4a565b60200201518260208110610a6957610a69614d4a565b60200201525b80610a7981614db5565b915050610981565b5080610a8c81614db5565b915050610975565b60008481526001602052604090819020908290600783019086908110610abc57610abc614d4a565b604002018460408110610ad157610ad1614d4a565b015414610b205760405162461bcd60e51b815260206004820152601d60248201527f5265616c6d46616365743a2077726f6e6720636f6f7264696e617465730000006044820152606401610402565b5050505050565b603754600160a01b900460ff16610b505760405162461bcd60e51b8152600401610402906149e7565b8481148015610b5e57508483145b610baa5760405162461bcd60e51b815260206004820152601d60248201527f5265616c6d46616365743a204d69736d617463686564206172726179730000006044820152606401610402565b60005b85811015610ce25760016000888884818110610bcb57610bcb614d4a565b60209081029290920135835250810191909152604001600020546001600160a01b0316610bf661224f565b6001600160a01b031614610c5b5760405162461bcd60e51b815260206004820152602660248201527f5265616c6d46616365743a204f6e6c792050617263656c206f776e65722063616044820152651b8818d85b1b60d21b6064820152608401610402565b828282818110610c6d57610c6d614d4a565b9050602002013560006038016000898985818110610c8d57610c8d614d4a565b9050602002013581526020019081526020016000206000878785818110610cb657610cb6614d4a565b905060200201358152602001908152602001600020819055508080610cda90614db5565b915050610bad565b50505050505050565b60008581526001602052604090205485906001600160a01b0316610d0d61224f565b6001600160a01b031614610d335760405162461bcd60e51b8152600401610402906149a1565b603754600160a01b900460ff16610d5c5760405162461bcd60e51b8152600401610402906149e7565b60408051602081018890529081018690526060810185905260808101849052610d879060a00161045b565b610da35760405162461bcd60e51b815260040161040290614a59565b600b5460405163109e13c560e21b8152600481018790526000916001600160a01b0316906342784f149060240160006040518083038186803b158015610de857600080fd5b505afa158015610dfc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e249190810190614bca565b9050806040015161ffff1660011480610e455750806040015161ffff166002145b15610ebf57600087815260016020819052604090912061200f01541015610ebf5760405162461bcd60e51b815260206004820152602860248201527f5265616c6d46616365743a204d75737420737572766579206265666f726520656044820152677175697070696e6760c01b6064820152608401610402565b806040015161ffff1660031415610f51576000878152600160205260409020612022015415610f3b5760405162461bcd60e51b815260206004820152602260248201527f5265616c6d46616365743a204c6f64676520616c726561647920657175697070604482015261195960f21b6064820152608401610402565b6000878152600160205260409020612022018690555b610f5d87878787612afd565b600b546040516364e5b7a960e01b815233600482015260248101899052604481018890526001600160a01b03909116906364e5b7a990606401600060405180830381600087803b158015610fb057600080fd5b505af1158015610fc4573d6000803e3d6000fd5b50505050610fd487876000612dae565b6040805188815260208101889052908101869052606081018590527f28ee8f870fbf2fc8ef414198cb263e6f548ce9a10088c76c2821b66cf61dddc49060800160405180910390a150505050505050565b60008581526001602052604090205485906001600160a01b031661104761224f565b6001600160a01b03161461106d5760405162461bcd60e51b8152600401610402906149a1565b603754600160a01b900460ff166110965760405162461bcd60e51b8152600401610402906149e7565b604080516020810188905290810186905260608101859052608081018490526110c19060a00161045b565b6110dd5760405162461bcd60e51b815260040161040290614a59565b6110e98686868661322e565b60375460405163e700cdd760e01b815233600482015260248101889052604481018790526001600160a01b039091169063e700cdd790606401600060405180830381600087803b15801561113c57600080fd5b505af1158015611150573d6000803e3d6000fd5b50506040805189815260208101899052908101879052606081018690527ffcb7d72e94eee47cfef784f5d54e1f07cc20dff2f9627de06f1f061428c7c91e925060800190505b60405180910390a1505050505050565b600b546001600160a01b03166111ba61224f565b6001600160a01b0316146111e05760405162461bcd60e51b815260040161040290614dd0565b6111ec85858484612336565b6111f885848484612afd565b611204858560016124e2565b61121085856001612dae565b604080518681526020810186905290810184905260608101839052608081018290527f74b654614ea2444b876a14dec11c709807cda89060906c4b7e443e4f8ff9ed539060a00160405180910390a15050505050565b61126e6134c5565b60005b82811015610b2057600054620668e5116112e75760405162461bcd60e51b815260206004820152603160248201527f5265616c6d46616365743a2043616e6e6f74206d696e74206d6f7265207468616044820152706e203432302c3036392070617263656c7360781b6064820152608401610402565b60008484838181106112fb576112fb614d4a565b905060200201359050600083838151811061131857611318614d4a565b60200260200101519050835186869050146113755760405162461bcd60e51b815260206004820152601a60248201527f496e70757473206d7573742062652073616d65206c656e6774680000000000006044820152606401610402565b6000828152600160209081526040909120825160038201558282015160048201556060830151805191926113b192600285019290910190613cde565b5060a0820151600682015560408201516005820155608082015180516113e1916001840191602090910190613cde565b5060c08201516113f8906120078301906004613d62565b50611403888461354e565b505050808061141190614db5565b915050611271565b600b546001600160a01b031661142d61224f565b6001600160a01b0316146114535760405162461bcd60e51b815260040161040290614dd0565b60008181526001602052604081206120210180549161147183614db5565b919050555050565b60606000306001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114b657600080fd5b505afa1580156114ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ee9190614e1e565b6040516370a0823160e01b81526001600160a01b038616600482015290915060009030906370a082319060240160206040518083038186803b15801561153357600080fd5b505afa158015611547573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156b9190614e1e565b90506000816001600160401b0381111561158757611587613f59565b6040519080825280602002602001820160405280156115b0578160200160208202803683370190505b5090506000805b8481101561163b57600081815260016020526040902060050154871480156115f857506000818152600160205260409020546001600160a01b038981169116145b15611629578083838151811061161057611610614d4a565b60209081029190910101528161162581614db5565b9250505b8061163381614db5565b9150506115b7565b50909695505050505050565b600b546001600160a01b031661165b61224f565b6001600160a01b0316146116815760405162461bcd60e51b815260040161040290614dd0565b60008181526001602052604081206120210180549161147183614e37565b6116a7613d8f565b600083815260016020526040902060060154156116ff5760405162461bcd60e51b81526020600482015260166024820152755265616c6d46616365743a204e6f742068756d626c6560501b6044820152606401610402565b60005b60088110156108f85760005b600881101561180e57836117895760008581526001602052604090819020600701908290811061174057611740614d4a565b60400201826040811061175557611755614d4a565b015483836008811061176957611769614d4a565b6020020151826008811061177f5761177f614d4a565b60200201526117fc565b83600114156117fc57600085815260016020526040908190206110070190829081106117b7576117b7614d4a565b6040020182604081106117cc576117cc614d4a565b01548383600881106117e0576117e0614d4a565b602002015182600881106117f6576117f6614d4a565b60200201525b8061180681614db5565b91505061170e565b508061181981614db5565b915050611702565b611829613dbd565b6000838152600160205260409020600601546003146118965760405162461bcd60e51b815260206004820152602360248201527f5265616c6d46616365743a204e6f742073706163696f757320686f72697a6f6e6044820152621d185b60ea1b6064820152608401610402565b60005b60208110156108f85760005b60408110156119a55783611920576000858152600160205260409081902060070190829081106118d7576118d7614d4a565b6040020182604081106118ec576118ec614d4a565b015483836020811061190057611900614d4a565b6020020151826040811061191657611916614d4a565b6020020152611993565b8360011415611993576000858152600160205260409081902061100701908290811061194e5761194e614d4a565b60400201826040811061196357611963614d4a565b015483836020811061197757611977614d4a565b6020020151826040811061198d5761198d614d4a565b60200201525b8061199d81614db5565b9150506118a5565b50806119b081614db5565b915050611899565b6060838214611a095760405162461bcd60e51b815260206004820152601d60248201527f5265616c6d46616365743a204d69736d617463686564206172726179730000006044820152606401610402565b836001600160401b03811115611a2157611a21613f59565b604051908082528060200260200182016040528015611a4a578160200160208202803683370190505b50905060005b84811015611adc5760386000878784818110611a6e57611a6e614d4a565b9050602002013581526020019081526020016000206000858584818110611a9757611a97614d4a565b90506020020135815260200190815260200160002054828281518110611abf57611abf614d4a565b602090810291909101015280611ad481614db5565b915050611a50565b50949350505050565b611aed6134c5565b60005b81811015611b5b577ff20fad4a9aa47ceeb29a7f693b89871de4b3b9ed2fc1fdf327785476f9938c97838383818110611b2b57611b2b614d4a565b90506020020135604051611b4191815260200190565b60405180910390a180611b5381614db5565b915050611af0565b505050565b60008581526001602052604090205485906001600160a01b0316611b8261224f565b6001600160a01b031614611ba85760405162461bcd60e51b8152600401610402906149a1565b603754600160a01b900460ff16611bd15760405162461bcd60e51b8152600401610402906149e7565b60408051602081018890529081018690526060810185905260808101849052611bfc9060a00161045b565b611c185760405162461bcd60e51b815260040161040290614a59565b611c2486868686613699565b6037546040516315b194ef60e21b815233600482015260248101889052604481018790526001600160a01b03909116906356c653bc90606401600060405180830381600087803b158015611c7757600080fd5b505af1158015611c8b573d6000803e3d6000fd5b50506040805189815260208101899052908101879052606081018690527fb1e943c280d055bfe1686ba119599cd2071f18e1f3bce12ad3c3c4f0d5b4541f92506080019050611196565b611cdd613deb565b60008381526001602081905260409091206006015414611d3f5760405162461bcd60e51b815260206004820152601a60248201527f5265616c6d46616365743a204e6f7420726561736f6e61626c650000000000006044820152606401610402565b60005b60108110156108f85760005b6010811015611e4e5783611dc957600085815260016020526040908190206007019082908110611d8057611d80614d4a565b604002018260408110611d9557611d95614d4a565b0154838360108110611da957611da9614d4a565b60200201518260108110611dbf57611dbf614d4a565b6020020152611e3c565b8360011415611e3c5760008581526001602052604090819020611007019082908110611df757611df7614d4a565b604002018260408110611e0c57611e0c614d4a565b0154838360108110611e2057611e20614d4a565b60200201518260108110611e3657611e36614d4a565b60200201525b80611e4681614db5565b915050611d4e565b5080611e5981614db5565b915050611d42565b60606000836001600160401b03811115611e7d57611e7d613f59565b604051908082528060200260200182016040528015611eb657816020015b611ea3613e19565b815260200190600190039081611e9b5790505b50905060005b84811015611adc5760005b60408110156120565760005b60408110156120435785611f865760016000898986818110611ef757611ef7614d4a565b9050602002013581526020019081526020016000206007018160408110611f2057611f20614d4a565b604002018260408110611f3557611f35614d4a565b0154848481518110611f4957611f49614d4a565b6020026020010151600001518360408110611f6657611f66614d4a565b60200201518260408110611f7c57611f7c614d4a565b6020020152612031565b85600114156120315760016000898986818110611fa557611fa5614d4a565b905060200201358152602001908152602001600020611007018160408110611fcf57611fcf614d4a565b604002018260408110611fe457611fe4614d4a565b0154848481518110611ff857611ff8614d4a565b602002602001015160000151836040811061201557612015614d4a565b6020020151826040811061202b5761202b614d4a565b60200201525b8061203b81614db5565b915050611ed3565b508061204e81614db5565b915050611ec7565b508061206181614db5565b915050611ebc565b6120716134c5565b60378054911515600160a01b0260ff60a01b19909216919091179055565b612097613e31565b60008281526001602052604090206002810180546120b490614a1e565b80601f01602080910402602001604051908101604052809291908181526020018280546120e090614a1e565b801561212d5780601f106121025761010080835404028352916020019161212d565b820191906000526020600020905b81548152906001019060200180831161211057829003601f168201915b505050918452505080546001600160a01b031660408301526003810154606083015260048101546080830152600681015460a083015260018101805461217290614a1e565b80601f016020809104026020016040519081016040528092919081815260200182805461219e90614a1e565b80156121eb5780601f106121c0576101008083540402835291602001916121eb565b820191906000526020600020905b8154815290600101906020018083116121ce57829003601f168201915b50505050506020830152600581015460c08301526040805160808101918290529061200783019060049082845b81548152602001906001019080831161221857505050505060e0830152506000918252603560205260409091205461010082015290565b6000333014156122a657600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506122a99050565b50335b90565b600080612306856040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b835160208501209091506001600160a01b0316612323828661382f565b6001600160a01b03161495945050505050565b600080600b81015460405163109e13c560e21b8152600481018790529192506001600160a01b03169060009082906342784f149060240160006040518083038186803b15801561238557600080fd5b505afa158015612399573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123c19190810190614bca565b60008881526001850160205260409081902091925087906007830190889081106123ed576123ed614d4a565b60400201866040811061240257612402614d4a565b0154146124515760405162461bcd60e51b815260206004820152601e60248201527f4c69625265616c6d3a2077726f6e6720696e7374616c6c6174696f6e496400006044820152606401610402565b855b82516124629060ff1688614e4e565b8110156124d757855b602084015161247d9060ff1688614e4e565b8110156124c457600083600701836040811061249b5761249b614d4a565b6040020182604081106124b0576124b0614d4a565b0155806124bc81614db5565b91505061246b565b50806124cf81614db5565b915050612453565b505050505050505050565b600080600b81015460405163109e13c560e21b8152600481018690529192506001600160a01b03169060009082906342784f149060240160006040518083038186803b15801561253157600080fd5b505afa158015612545573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261256d9190810190614bca565b6040516324a7504960e11b8152306004820152602481018890529091506000906001600160a01b0384169063494ea0929060440160006040518083038186803b1580156125b957600080fd5b505afa1580156125cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125f59190810190614e66565b905060005b81518110156128915760405163109e13c560e21b8152600481018890526000906001600160a01b038616906342784f149060240160006040518083038186803b15801561264657600080fd5b505afa15801561265a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126829190810190614bca565b9050806101c0015160008151811061269c5761269c614d4a565b602090810291909101810151600b88015460008c815260018a0190935260409283902061201f0154925163109e13c560e21b815291926001600160a01b03909116916342784f14916126f49160040190815260200190565b60006040518083038186803b15801561270c57600080fd5b505afa158015612720573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127489190810190614bca565b6060015160ff16101561276d5760405162461bcd60e51b815260040161040290614f1b565b6000816101c0015160018151811061278757612787614d4a565b6020026020010151111561287e57806101c001516001815181106127ad576127ad614d4a565b602090810291909101810151600b88015460008c815260018a019093526040928390206120220154925163109e13c560e21b815291926001600160a01b03909116916342784f14916128059160040190815260200190565b60006040518083038186803b15801561281d57600080fd5b505afa158015612831573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128599190810190614bca565b6060015160ff16101561287e5760405162461bcd60e51b815260040161040290614f63565b508061288981614db5565b9150506125fa565b50608082015160ff166128a488826138ae565b610180830151156128f057610180830151600089815260018701602052604090206120130182600481106128da576128da614d4a565b0160008282546128ea9190614fab565b90915550505b604083015161ffff16158015612904575085155b1561291f576000888152600186016020526040812061201f01555b826040015161ffff1660031415612946576000888152600186016020526040812061202201555b6101a083015115612ab05760005b6000898152600187016020908152604080832085845261201201909152902054811015612a0057600089815260018701602090815260408083208584526120120190915290208054899190839081106129af576129af614d4a565b906000526020600020015414156129ee57600089815260018701602090815260408083208584526120120190915290206129e990826139a7565b612a00565b806129f881614db5565b915050612954565b50612a0b8882613a1c565b6000898152600187016020526040902061201b018260048110612a3057612a30614d4a565b01541115612ab05760405162461bcd60e51b815260206004820152604160248201527f4c6962416c6368656d6963613a20556e636c61696d656420616c6368656d696360448201527f612067726561746572207468616e207265736572766f697220636170616369746064820152607960f81b608482015260a401610402565b60e083015160ff1615612af3578260e0015160ff168560010160008a8152602001908152602001600020612020016000828254612aed9190614fab565b90915550505b5050505050505050565b600080612b08613b31565b90506000612b14613b69565b600b84015460405163109e13c560e21b8152600481018990529192506001600160a01b03169060009082906342784f149060240160006040518083038186803b158015612b6057600080fd5b505afa158015612b74573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b9c9190810190614bca565b60008a8152600187016020526040902081516006820154929350909160ff90911690869060058110612bd057612bd0614d4a565b6020020151612bdf9190614fab565b881115612c2e5760405162461bcd60e51b815260206004820152601b60248201527f4c69625265616c6d3a207820657863656564696e6720776964746800000000006044820152606401610402565b816020015160ff1684826006015460058110612c4c57612c4c614d4a565b6020020151612c5b9190614fab565b871115612caa5760405162461bcd60e51b815260206004820152601c60248201527f4c69625265616c6d3a207920657863656564696e6720686569676874000000006044820152606401610402565b875b8251612cbb9060ff168a614e4e565b811015612da157875b6020840151612cd69060ff168a614e4e565b811015612d8e57826007018260408110612cf257612cf2614d4a565b604002018160408110612d0757612d07614d4a565b015415612d4f5760405162461bcd60e51b8152602060048201526016602482015275131a589499585b1b4e88125b9d985b1a59081cdc1bdd60521b6044820152606401610402565b8a836007018360408110612d6557612d65614d4a565b604002018260408110612d7a57612d7a614d4a565b015580612d8681614db5565b915050612cc4565b5080612d9981614db5565b915050612cac565b5050505050505050505050565b600080600b81015460405163109e13c560e21b8152600481018690529192506000916001600160a01b03909116906342784f149060240160006040518083038186803b158015612dfd57600080fd5b505afa158015612e11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e399190810190614bca565b90506000816101c00151600081518110612e5557612e55614d4a565b602002602001015190506000826101c00151600181518110612e7957612e79614d4a565b602090810291909101810151600089815260018701909252604080832061201f0154600b880154915163109e13c560e21b81526004810182905292945092916001600160a01b03909116906342784f149060240160006040518083038186803b158015612ee557600080fd5b505afa158015612ef9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f219190810190614bca565b6060015160ff16905083811015612f4a5760405162461bcd60e51b815260040161040290614f1b565b82156130145760008981526001870160205260408082206120220154600b890154915163109e13c560e21b8152600481018290529092916001600160a01b0316906342784f149060240160006040518083038186803b158015612fac57600080fd5b505afa158015612fc0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fe89190810190614bca565b6060015160ff169050848110156130115760405162461bcd60e51b815260040161040290614f63565b50505b846040015161ffff16600114156130a95760008981526001870160209081526040808320608089015160ff168452612012019091529020546130a95760405162461bcd60e51b815260206004820152602860248201527f5265616c6d46616365743a204d757374206571756970207265736572766f6972604482015267206f66207479706560c01b6064820152608401610402565b608085015160ff166130bb8a826138ae565b610180860151156131075761018086015160008b815260018901602052604090206120130182600481106130f1576130f1614d4a565b0160008282546131019190614e4e565b90915550505b6101a0860151156131425760008a81526001808901602090815260408084208585526120120182528320805492830181558352909120018990555b604086015161ffff166131df57878061316d575060008a8152600188016020526040902061201f0154155b6131c75760405162461bcd60e51b815260206004820152602560248201527f4c6962416c6368656d6963613a2043616e6e6f742065717569702074776f20616044820152646c7461727360d81b6064820152608401610402565b60008a8152600188016020526040902061201f018990555b60e086015160ff1615613222578560e0015160ff168760010160008c815260200190815260200160002061202001600082825461321c9190614e4e565b90915550505b50505050505050505050565b600080613239613b31565b90506000613245613b69565b603784015460405163e042161f60e01b8152600481018990529192506001600160a01b031690600090829063e042161f9060240160006040518083038186803b15801561329157600080fd5b505afa1580156132a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526132cd9190810190614fc2565b60008a815260018701602052604090208151600682015492935090918690600581106132fb576132fb614d4a565b602002015161330a9190614fab565b8811156133595760405162461bcd60e51b815260206004820152601b60248201527f4c69625265616c6d3a207820657863656564696e6720776964746800000000006044820152606401610402565b81602001518482600601546005811061337457613374614d4a565b60200201516133839190614fab565b8711156133d25760405162461bcd60e51b815260206004820152601c60248201527f4c69625265616c6d3a207920657863656564696e6720686569676874000000006044820152606401610402565b875b82516133e0908a614e4e565b811015612da157875b60208401516133f8908a614e4e565b8110156134b2578261100701826040811061341557613415614d4a565b60400201816040811061342a5761342a614d4a565b0154156134725760405162461bcd60e51b8152602060048201526016602482015275131a589499585b1b4e88125b9d985b1a59081cdc1bdd60521b6044820152606401610402565b8a8361100701836040811061348957613489614d4a565b60400201826040811061349e5761349e614d4a565b0155806134aa81614db5565b9150506133e9565b50806134bd81614db5565b9150506133d4565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c600401546001600160a01b0316331461354c5760405162461bcd60e51b815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201526132b960f11b6064820152608401610402565b565b6000818152600160205260408120546001600160a01b0316156135bd5760405162461bcd60e51b815260206004820152602160248201527f4c69624552433732313a20746f6b656e496420616c7265616479206d696e74656044820152601960fa1b6064820152608401610402565b600082815260018281016020908152604080842080546001600160a01b0319166001600160a01b03891690811790915585548085018755868652838620018790558085526003860180845282862080546002890186528488208a895286528488208190559185529481018555938552918420909201859055905184927f1661e9eb70c35142fbb4190fa06d962636cf9ccd88dd913f90c08bcbf0d43e9191a360405182906001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b600080603781015460405163e042161f60e01b8152600481018790529192506001600160a01b031690600090829063e042161f9060240160006040518083038186803b1580156136e857600080fd5b505afa1580156136fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526137249190810190614fc2565b60008881526001850160205260409081902091925087906110078301908890811061375157613751614d4a565b60400201866040811061376657613766614d4a565b0154146137ae5760405162461bcd60e51b8152602060048201526016602482015275131a589499585b1b4e881ddc9bdb99c81d1a5b19525960521b6044820152606401610402565b855b82516137bc9088614e4e565b8110156124d757855b60208401516137d49088614e4e565b81101561381c576000836110070183604081106137f3576137f3614d4a565b60400201826040811061380857613808614d4a565b01558061381481614db5565b9150506137c5565b508061382781614db5565b9150506137b0565b60008060008061383e85613ba1565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015613899573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6000806138bb8484613a1c565b905060006138c98585613c15565b9050801561397757600085815260018401602052604090208290829061201b0186600481106138fa576138fa614d4a565b01546139069190614e4e565b111561393a5760008581526001840160205260409020829061201b01856004811061393357613933614d4a565b0155613977565b60008581526001840160205260409020819061201b01856004811061396157613961614d4a565b0160008282546139719190614e4e565b90915550505b60008581526001840160205260409020429061201701856004811061399e5761399e614d4a565b01555050505050565b815482906139b790600190614fab565b815481106139c7576139c7614d4a565b90600052602060002001548282815481106139e4576139e4614d4a565b906000526020600020018190555081805480613a0257613a02615083565b600190038181906000526020600020016000905590555050565b60008060005b6000858152600183016020908152604080832087845261201201909152902054811015613b2957600b8201546000868152600184016020908152604080832088845261201201909152902080546001600160a01b039092169163d3606249919084908110613a9257613a92614d4a565b90600052602060002001546040518263ffffffff1660e01b8152600401613abb91815260200190565b60206040518083038186803b158015613ad357600080fd5b505afa158015613ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0b9190614e1e565b613b159084614e4e565b925080613b2181614db5565b915050613a22565b505092915050565b613b39613e8c565b506040805160a0810182526008815260106020808301919091528183015260608101829052608081019190915290565b613b71613e8c565b506040805160a0810182526008815260106020808301919091528183018390526060820152608081019190915290565b60008060008351604114613bf75760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606401610402565b50505060208101516040820151606090920151909260009190911a90565b600082815260016020526040812081908190612017018460048110613c3c57613c3c614d4a565b0154613c489042614fab565b60008681526001840160205260409020612013018560048110613c6d57613c6d614d4a565b0154613c799190615099565b95945050505050565b6040518061080001604052806040905b613c9a613eaa565b815260200190600190039081613c925790505090565b6040518061080001604052806040905b613cc8613ec9565b815260200190600190039081613cc05790505090565b828054613cea90614a1e565b90600052602060002090601f016020900481019282613d0c5760008555613d52565b82601f10613d2557805160ff1916838001178555613d52565b82800160010185558215613d52579182015b82811115613d52578251825591602001919060010190613d37565b50613d5e929150613ee8565b5090565b8260048101928215613d525791602002820182811115613d52578251825591602001919060010190613d37565b6040518061010001604052806008905b613da7613efd565b815260200190600190039081613d9f5790505090565b6040518061040001604052806020905b613dd5613eaa565b815260200190600190039081613dcd5790505090565b6040518061020001604052806010905b613e03613f1c565b815260200190600190039081613dfb5790505090565b6040518060200160405280613e2c613c82565b905290565b604051806101200160405280606081526020016060815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001613e7f613f3b565b8152602001600081525090565b6040518060a001604052806005906020820280368337509192915050565b6040518061080001604052806040906020820280368337509192915050565b6040518061040001604052806020906020820280368337509192915050565b5b80821115613d5e5760008155600101613ee9565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715613f9157613f91613f59565b60405290565b60405161020081016001600160401b0381118282101715613f9157613f91613f59565b604080519081016001600160401b0381118282101715613f9157613f91613f59565b604051608081016001600160401b0381118282101715613f9157613f91613f59565b604051601f8201601f191681016001600160401b038111828210171561402657614026613f59565b604052919050565b60006001600160401b0382111561404757614047613f59565b50601f01601f191660200190565b60006140686140638461402e565b613ffe565b905082815283838301111561407c57600080fd5b828260208301376000602084830101529392505050565b600080600080600060a086880312156140ab57600080fd5b8535945060208601359350604086013592506060860135915060808601356001600160401b038111156140dd57600080fd5b8601601f810188136140ee57600080fd5b6140fd88823560208401614055565b9150509295509295909350565b6000806040838503121561411d57600080fd5b50508035926020909101359150565b60008282825b6040811015614151578151835260209283019290910190600101614132565b5050506108008301905092915050565b620200008101818360005b60408110156141915761418083835161412c565b92506020919091019060010161416c565b50505092915050565b62010000810181836000805b60408110156141f157825184835b60208082106141c357506141d7565b8351835292830192909101906001016141b4565b5050506104009390930192602092909201916001016141a6565b5050505092915050565b6000806000806080858703121561421157600080fd5b5050823594602084013594506040840135936060013592509050565b60008083601f84011261423f57600080fd5b5081356001600160401b0381111561425657600080fd5b6020830191508360208260051b850101111561427157600080fd5b9250929050565b6000806000806000806060878903121561429157600080fd5b86356001600160401b03808211156142a857600080fd5b6142b48a838b0161422d565b909850965060208901359150808211156142cd57600080fd5b6142d98a838b0161422d565b909650945060408901359150808211156142f257600080fd5b506142ff89828a0161422d565b979a9699509497509295939492505050565b600080600080600060a0868803121561432957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b80356001600160a01b038116811461436357600080fd5b919050565b60006001600160401b0382111561438157614381613f59565b5060051b60200190565b600082601f83011261439c57600080fd5b6143ab83833560208501614055565b9392505050565b600082601f8301126143c357600080fd5b6143cb613fdc565b8060808401858111156143dd57600080fd5b845b818110156143f75780358452602093840193016143df565b509095945050505050565b6000806000806060858703121561441857600080fd5b6144218561434c565b935060208501356001600160401b038082111561443d57600080fd5b6144498883890161422d565b9095509350604087013591508082111561446257600080fd5b818701915087601f83011261447657600080fd5b6144836140638335614368565b82358082526020808301929160051b8501018a8111156144a257600080fd5b602085015b818110156145725784813511156144bd57600080fd5b80358601610140818e03601f190112156144d657600080fd5b6144de613f6f565b60208201358152604082013560208201526060820135604082015260808201358781111561450b57600080fd5b61451a8f60208386010161438b565b60608301525060a08201358781111561453257600080fd5b6145418f60208386010161438b565b60808301525060c082013560a082015261455e8e60e084016143b2565b60c0820152855250602093840193016144a7565b50508094505050505092959194509250565b60006020828403121561459657600080fd5b5035919050565b600080604083850312156145b057600080fd5b6145b98361434c565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b8181101561163b578351835292840192918401916001016145e3565b610800810181836000805b600880821061461957506141f1565b835185845b8381101561463c57825182526020928301929091019060010161461e565b5050506101009490940193506020929092019160010161460a565b620100008101818360005b60208082106146715750614191565b61467c84845161412c565b93509190910190600101614662565b600080600080604085870312156146a157600080fd5b84356001600160401b03808211156146b857600080fd5b6146c48883890161422d565b909650945060208701359150808211156146dd57600080fd5b506146ea8782880161422d565b95989497509550505050565b6000806020838503121561470957600080fd5b82356001600160401b0381111561471f57600080fd5b61472b8582860161422d565b90969095509350505050565b612000810181836000805b601080821061475157506141f1565b835185845b83811015614774578251825260209283019290910190600101614756565b50505061020094909401935060209290920191600101614742565b6000806000604084860312156147a457600080fd5b83356001600160401b038111156147ba57600080fd5b6147c68682870161422d565b909790965060209590950135949350505050565b60208082528251828201819052600091906040908185019086840185805b8381101561483f5782515185835b888110156148275761481982845161412c565b928a01929150600101614806565b505050620200009490940193918601916001016147f8565b509298975050505050505050565b801515811461485b57600080fd5b50565b60006020828403121561487057600080fd5b81356143ab8161484d565b60005b8381101561489657818101518382015260200161487e565b838111156148a5576000848401525b50505050565b600081518084526148c381602086016020860161487b565b601f01601f19169290920160200192915050565b8060005b60048110156148a55781518452602093840193909101906001016148db565b60208152600082516101808060208501526149196101a08501836148ab565b91506020850151601f1985840301604086015261493683826148ab565b925050604085015161495360608601826001600160a01b03169052565b5060608501516080850152608085015160a085015260a085015160c085015260c085015160e085015260e0850151610100614990818701836148d7565b959095015193019290925250919050565b60208082526026908201527f41707053746f726167653a204f6e6c792050617263656c206f776e65722063616040820152651b8818d85b1b60d21b606082015260800190565b6020808252601b908201527f41707053746f726167653a2067616d65206e6f74206163746976650000000000604082015260600190565b600181811c90821680614a3257607f821691505b60208210811415614a5357634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252601d908201527f5265616c6d46616365743a20496e76616c6964207369676e6174757265000000604082015260600190565b805160ff8116811461436357600080fd5b805161ffff8116811461436357600080fd5b805163ffffffff8116811461436357600080fd5b80516143638161484d565b600082601f830112614ae357600080fd5b614aeb613fdc565b806080840185811115614afd57600080fd5b845b818110156143f7578051845260209384019301614aff565b600082601f830112614b2857600080fd5b81516020614b3861406383614368565b82815260059290921b84018101918181019086841115614b5757600080fd5b8286015b84811015614b725780518352918301918301614b5b565b509695505050505050565b600082601f830112614b8e57600080fd5b8151614b9c6140638261402e565b818152846020838601011115614bb157600080fd5b614bc282602083016020870161487b565b949350505050565b600060208284031215614bdc57600080fd5b81516001600160401b0380821115614bf357600080fd5b908301906102608286031215614c0857600080fd5b614c10613f97565b614c1983614a90565b8152614c2760208401614a90565b6020820152614c3860408401614aa1565b6040820152614c4960608401614a90565b6060820152614c5a60808401614a90565b6080820152614c6b60a08401614ab3565b60a0820152614c7c60c08401614aa1565b60c0820152614c8d60e08401614a90565b60e0820152610100614ca0818501614ab3565b90820152610120614cb2848201614ab3565b90820152610140614cc4848201614ac7565b90820152610160614cd787858301614ad2565b908201526101e0838101516101808301526102008401516101a083015261022084015183811115614d0757600080fd5b614d1388828701614b17565b6101c08401525061024084015183811115614d2d57600080fd5b614d3988828701614b7d565b918301919091525095945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082614d9357634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215614daa57600080fd5b81516143ab8161484d565b6000600019821415614dc957614dc9614d60565b5060010190565b6020808252602e908201527f41707053746f726167653a204f6e6c7920496e7374616c6c6174696f6e20646960408201526d185b5bdb990818d85b8818d85b1b60921b606082015260800190565b600060208284031215614e3057600080fd5b5051919050565b600081614e4657614e46614d60565b506000190190565b60008219821115614e6157614e61614d60565b500190565b60006020808385031215614e7957600080fd5b82516001600160401b03811115614e8f57600080fd5b8301601f81018513614ea057600080fd5b8051614eae61406382614368565b81815260069190911b82018301908381019087831115614ecd57600080fd5b928401925b82841015614f105760408489031215614eeb5760008081fd5b614ef3613fba565b845181528585015186820152825260409093019290840190614ed2565b979650505050505050565b60208082526028908201527f5265616c6d46616365743a20416c746172205465636820547265652052657173604082015267081b9bdd081b595d60c21b606082015260800190565b60208082526028908201527f5265616c6d46616365743a204c6f646765205465636820547265652052657173604082015267081b9bdd081b595d60c21b606082015260800190565b600082821015614fbd57614fbd614d60565b500390565b600060208284031215614fd457600080fd5b81516001600160401b0380821115614feb57600080fd5b90830190610140828603121561500057600080fd5b615008613f6f565b825181526020830151602082015261502260408401614ac7565b604082015261503360608401614aa1565b60608201526150458660808501614ad2565b608082015261010083015160a08201526101208301518281111561506857600080fd5b61507487828601614b7d565b60c08301525095945050505050565b634e487b7160e01b600052603160045260246000fd5b60008160001904831182151516156150b3576150b3614d60565b50029056fea26469706673582212203e356204c71794312c4bceaf768bd607f53b51e38f1bd09cb48996c468f6babd64736f6c63430008090033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101585760003560e01c80637690a6b3116100c3578063c96fd9c51161007c578063c96fd9c51461030c578063ccc089741461032c578063d5abeb011461033f578063da80c76e14610352578063dd71950a14610376578063e45c7de21461039657600080fd5b80637690a6b314610273578063ad3d0f6514610293578063adf68808146102b3578063bc6c0d33146102c6578063bd6a3295146102d9578063c3671216146102ec57600080fd5b806351caf05c1161011557806351caf05c146101f45780635505421b1461020757806356ba6c551461021a578063579fa4af1461022d578063594a0a701461024057806375438cd41461026057600080fd5b80631628652a1461015d5780631ef25f94146101725780632d7e13011461019b578063347373c7146101bb578063367e3dac146101ce5780633fa75b65146101e1575b600080fd5b61017061016b366004614093565b6103ba565b005b61018561018036600461410a565b61076d565b6040516101929190614161565b60405180910390f35b6101ae6101a936600461410a565b6108ff565b604051610192919061419a565b6101706101c93660046141fb565b610a94565b6101706101dc366004614278565b610b27565b6101706101ef366004614093565b610ceb565b610170610202366004614093565b611025565b610170610215366004614311565b6111a6565b610170610228366004614402565b611266565b61017061023b366004614584565b611419565b61025361024e36600461459d565b611479565b60405161019291906145c7565b61017061026e366004614584565b611647565b61028661028136600461410a565b61169f565b60405161019291906145ff565b6102a66102a136600461410a565b611821565b6040516101929190614657565b6102536102c136600461468b565b6119b8565b6101706102d43660046146f6565b611ae5565b6101706102e7366004614093565b611b60565b6102ff6102fa36600461410a565b611cd5565b6040516101929190614737565b61031f61031a36600461478f565b611e61565b60405161019291906147da565b61017061033a36600461485e565b612069565b620668e55b604051908152602001610192565b610344610360366004614584565b6000908152600160205260409020612020015490565b610389610384366004614584565b61208f565b60405161019291906148fa565b6103446103a4366004614584565b6000908152600160205260409020612021015490565b60008581526001602052604090205485906001600160a01b03166103dc61224f565b6001600160a01b03161461040b5760405162461bcd60e51b8152600401610402906149a1565b60405180910390fd5b603754600160a01b900460ff166104345760405162461bcd60e51b8152600401610402906149e7565b604080516020810188905290810186905260608101859052608081018490526105059060a0015b60405160208183030381529060405280519060200120836000602f01805461048290614a1e565b80601f01602080910402602001604051908101604052809291908181526020018280546104ae90614a1e565b80156104fb5780601f106104d0576101008083540402835291602001916104fb565b820191906000526020600020905b8154815290600101906020018083116104de57829003601f168201915b50505050506122ac565b6105215760405162461bcd60e51b815260040161040290614a59565b600b5460405163109e13c560e21b8152600481018790526001600160a01b039091169060009082906342784f149060240160006040518083038186803b15801561056a57600080fd5b505afa15801561057e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105a69190810190614bca565b90506105b488888888612336565b60005b60048110156106a9576000600782600481106105d5576105d5614d4a565b01546101608401516001600160a01b039091169150600090600290846004811061060157610601614d4a565b60200201516106109190614d76565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0383169063a9059cbb90604401602060405180830381600087803b15801561065b57600080fd5b505af115801561066f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106939190614d98565b50505080806106a190614db5565b9150506105b7565b50600b54604051633240806960e01b8152600481018a9052602481018990526001600160a01b0390911690633240806990604401600060405180830381600087803b1580156106f757600080fd5b505af115801561070b573d6000803e3d6000fd5b5050505061071b888860006124e2565b6040805189815260208101899052908101879052606081018690527feb8dc37534b72de521d16884c32148e05abe550c5627ee4ba527ddfa1a7717ff9060800160405180910390a15050505050505050565b610775613c82565b6000838152600160205260409020600601546004146107d65760405162461bcd60e51b815260206004820152601860248201527f5265616c6d46616365743a204e6f742070616172746e657200000000000000006044820152606401610402565b60005b60408110156108f85760005b60408110156108e557836108605760008581526001602052604090819020600701908290811061081757610817614d4a565b60400201826040811061082c5761082c614d4a565b015483836040811061084057610840614d4a565b6020020151826040811061085657610856614d4a565b60200201526108d3565b83600114156108d3576000858152600160205260409081902061100701908290811061088e5761088e614d4a565b6040020182604081106108a3576108a3614d4a565b01548383604081106108b7576108b7614d4a565b602002015182604081106108cd576108cd614d4a565b60200201525b806108dd81614db5565b9150506107e5565b50806108f081614db5565b9150506107d9565b5092915050565b610907613cb0565b6000838152600160205260409020600601546002146109725760405162461bcd60e51b815260206004820152602160248201527f5265616c6d46616365743a204e6f742073706163696f757320766572746963616044820152601b60fa1b6064820152608401610402565b60005b60408110156108f85760005b6020811015610a8157836109fc576000858152600160205260409081902060070190829081106109b3576109b3614d4a565b6040020182604081106109c8576109c8614d4a565b01548383604081106109dc576109dc614d4a565b602002015182602081106109f2576109f2614d4a565b6020020152610a6f565b8360011415610a6f5760008581526001602052604090819020611007019082908110610a2a57610a2a614d4a565b604002018260408110610a3f57610a3f614d4a565b0154838360408110610a5357610a53614d4a565b60200201518260208110610a6957610a69614d4a565b60200201525b80610a7981614db5565b915050610981565b5080610a8c81614db5565b915050610975565b60008481526001602052604090819020908290600783019086908110610abc57610abc614d4a565b604002018460408110610ad157610ad1614d4a565b015414610b205760405162461bcd60e51b815260206004820152601d60248201527f5265616c6d46616365743a2077726f6e6720636f6f7264696e617465730000006044820152606401610402565b5050505050565b603754600160a01b900460ff16610b505760405162461bcd60e51b8152600401610402906149e7565b8481148015610b5e57508483145b610baa5760405162461bcd60e51b815260206004820152601d60248201527f5265616c6d46616365743a204d69736d617463686564206172726179730000006044820152606401610402565b60005b85811015610ce25760016000888884818110610bcb57610bcb614d4a565b60209081029290920135835250810191909152604001600020546001600160a01b0316610bf661224f565b6001600160a01b031614610c5b5760405162461bcd60e51b815260206004820152602660248201527f5265616c6d46616365743a204f6e6c792050617263656c206f776e65722063616044820152651b8818d85b1b60d21b6064820152608401610402565b828282818110610c6d57610c6d614d4a565b9050602002013560006038016000898985818110610c8d57610c8d614d4a565b9050602002013581526020019081526020016000206000878785818110610cb657610cb6614d4a565b905060200201358152602001908152602001600020819055508080610cda90614db5565b915050610bad565b50505050505050565b60008581526001602052604090205485906001600160a01b0316610d0d61224f565b6001600160a01b031614610d335760405162461bcd60e51b8152600401610402906149a1565b603754600160a01b900460ff16610d5c5760405162461bcd60e51b8152600401610402906149e7565b60408051602081018890529081018690526060810185905260808101849052610d879060a00161045b565b610da35760405162461bcd60e51b815260040161040290614a59565b600b5460405163109e13c560e21b8152600481018790526000916001600160a01b0316906342784f149060240160006040518083038186803b158015610de857600080fd5b505afa158015610dfc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e249190810190614bca565b9050806040015161ffff1660011480610e455750806040015161ffff166002145b15610ebf57600087815260016020819052604090912061200f01541015610ebf5760405162461bcd60e51b815260206004820152602860248201527f5265616c6d46616365743a204d75737420737572766579206265666f726520656044820152677175697070696e6760c01b6064820152608401610402565b806040015161ffff1660031415610f51576000878152600160205260409020612022015415610f3b5760405162461bcd60e51b815260206004820152602260248201527f5265616c6d46616365743a204c6f64676520616c726561647920657175697070604482015261195960f21b6064820152608401610402565b6000878152600160205260409020612022018690555b610f5d87878787612afd565b600b546040516364e5b7a960e01b815233600482015260248101899052604481018890526001600160a01b03909116906364e5b7a990606401600060405180830381600087803b158015610fb057600080fd5b505af1158015610fc4573d6000803e3d6000fd5b50505050610fd487876000612dae565b6040805188815260208101889052908101869052606081018590527f28ee8f870fbf2fc8ef414198cb263e6f548ce9a10088c76c2821b66cf61dddc49060800160405180910390a150505050505050565b60008581526001602052604090205485906001600160a01b031661104761224f565b6001600160a01b03161461106d5760405162461bcd60e51b8152600401610402906149a1565b603754600160a01b900460ff166110965760405162461bcd60e51b8152600401610402906149e7565b604080516020810188905290810186905260608101859052608081018490526110c19060a00161045b565b6110dd5760405162461bcd60e51b815260040161040290614a59565b6110e98686868661322e565b60375460405163e700cdd760e01b815233600482015260248101889052604481018790526001600160a01b039091169063e700cdd790606401600060405180830381600087803b15801561113c57600080fd5b505af1158015611150573d6000803e3d6000fd5b50506040805189815260208101899052908101879052606081018690527ffcb7d72e94eee47cfef784f5d54e1f07cc20dff2f9627de06f1f061428c7c91e925060800190505b60405180910390a1505050505050565b600b546001600160a01b03166111ba61224f565b6001600160a01b0316146111e05760405162461bcd60e51b815260040161040290614dd0565b6111ec85858484612336565b6111f885848484612afd565b611204858560016124e2565b61121085856001612dae565b604080518681526020810186905290810184905260608101839052608081018290527f74b654614ea2444b876a14dec11c709807cda89060906c4b7e443e4f8ff9ed539060a00160405180910390a15050505050565b61126e6134c5565b60005b82811015610b2057600054620668e5116112e75760405162461bcd60e51b815260206004820152603160248201527f5265616c6d46616365743a2043616e6e6f74206d696e74206d6f7265207468616044820152706e203432302c3036392070617263656c7360781b6064820152608401610402565b60008484838181106112fb576112fb614d4a565b905060200201359050600083838151811061131857611318614d4a565b60200260200101519050835186869050146113755760405162461bcd60e51b815260206004820152601a60248201527f496e70757473206d7573742062652073616d65206c656e6774680000000000006044820152606401610402565b6000828152600160209081526040909120825160038201558282015160048201556060830151805191926113b192600285019290910190613cde565b5060a0820151600682015560408201516005820155608082015180516113e1916001840191602090910190613cde565b5060c08201516113f8906120078301906004613d62565b50611403888461354e565b505050808061141190614db5565b915050611271565b600b546001600160a01b031661142d61224f565b6001600160a01b0316146114535760405162461bcd60e51b815260040161040290614dd0565b60008181526001602052604081206120210180549161147183614db5565b919050555050565b60606000306001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114b657600080fd5b505afa1580156114ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ee9190614e1e565b6040516370a0823160e01b81526001600160a01b038616600482015290915060009030906370a082319060240160206040518083038186803b15801561153357600080fd5b505afa158015611547573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156b9190614e1e565b90506000816001600160401b0381111561158757611587613f59565b6040519080825280602002602001820160405280156115b0578160200160208202803683370190505b5090506000805b8481101561163b57600081815260016020526040902060050154871480156115f857506000818152600160205260409020546001600160a01b038981169116145b15611629578083838151811061161057611610614d4a565b60209081029190910101528161162581614db5565b9250505b8061163381614db5565b9150506115b7565b50909695505050505050565b600b546001600160a01b031661165b61224f565b6001600160a01b0316146116815760405162461bcd60e51b815260040161040290614dd0565b60008181526001602052604081206120210180549161147183614e37565b6116a7613d8f565b600083815260016020526040902060060154156116ff5760405162461bcd60e51b81526020600482015260166024820152755265616c6d46616365743a204e6f742068756d626c6560501b6044820152606401610402565b60005b60088110156108f85760005b600881101561180e57836117895760008581526001602052604090819020600701908290811061174057611740614d4a565b60400201826040811061175557611755614d4a565b015483836008811061176957611769614d4a565b6020020151826008811061177f5761177f614d4a565b60200201526117fc565b83600114156117fc57600085815260016020526040908190206110070190829081106117b7576117b7614d4a565b6040020182604081106117cc576117cc614d4a565b01548383600881106117e0576117e0614d4a565b602002015182600881106117f6576117f6614d4a565b60200201525b8061180681614db5565b91505061170e565b508061181981614db5565b915050611702565b611829613dbd565b6000838152600160205260409020600601546003146118965760405162461bcd60e51b815260206004820152602360248201527f5265616c6d46616365743a204e6f742073706163696f757320686f72697a6f6e6044820152621d185b60ea1b6064820152608401610402565b60005b60208110156108f85760005b60408110156119a55783611920576000858152600160205260409081902060070190829081106118d7576118d7614d4a565b6040020182604081106118ec576118ec614d4a565b015483836020811061190057611900614d4a565b6020020151826040811061191657611916614d4a565b6020020152611993565b8360011415611993576000858152600160205260409081902061100701908290811061194e5761194e614d4a565b60400201826040811061196357611963614d4a565b015483836020811061197757611977614d4a565b6020020151826040811061198d5761198d614d4a565b60200201525b8061199d81614db5565b9150506118a5565b50806119b081614db5565b915050611899565b6060838214611a095760405162461bcd60e51b815260206004820152601d60248201527f5265616c6d46616365743a204d69736d617463686564206172726179730000006044820152606401610402565b836001600160401b03811115611a2157611a21613f59565b604051908082528060200260200182016040528015611a4a578160200160208202803683370190505b50905060005b84811015611adc5760386000878784818110611a6e57611a6e614d4a565b9050602002013581526020019081526020016000206000858584818110611a9757611a97614d4a565b90506020020135815260200190815260200160002054828281518110611abf57611abf614d4a565b602090810291909101015280611ad481614db5565b915050611a50565b50949350505050565b611aed6134c5565b60005b81811015611b5b577ff20fad4a9aa47ceeb29a7f693b89871de4b3b9ed2fc1fdf327785476f9938c97838383818110611b2b57611b2b614d4a565b90506020020135604051611b4191815260200190565b60405180910390a180611b5381614db5565b915050611af0565b505050565b60008581526001602052604090205485906001600160a01b0316611b8261224f565b6001600160a01b031614611ba85760405162461bcd60e51b8152600401610402906149a1565b603754600160a01b900460ff16611bd15760405162461bcd60e51b8152600401610402906149e7565b60408051602081018890529081018690526060810185905260808101849052611bfc9060a00161045b565b611c185760405162461bcd60e51b815260040161040290614a59565b611c2486868686613699565b6037546040516315b194ef60e21b815233600482015260248101889052604481018790526001600160a01b03909116906356c653bc90606401600060405180830381600087803b158015611c7757600080fd5b505af1158015611c8b573d6000803e3d6000fd5b50506040805189815260208101899052908101879052606081018690527fb1e943c280d055bfe1686ba119599cd2071f18e1f3bce12ad3c3c4f0d5b4541f92506080019050611196565b611cdd613deb565b60008381526001602081905260409091206006015414611d3f5760405162461bcd60e51b815260206004820152601a60248201527f5265616c6d46616365743a204e6f7420726561736f6e61626c650000000000006044820152606401610402565b60005b60108110156108f85760005b6010811015611e4e5783611dc957600085815260016020526040908190206007019082908110611d8057611d80614d4a565b604002018260408110611d9557611d95614d4a565b0154838360108110611da957611da9614d4a565b60200201518260108110611dbf57611dbf614d4a565b6020020152611e3c565b8360011415611e3c5760008581526001602052604090819020611007019082908110611df757611df7614d4a565b604002018260408110611e0c57611e0c614d4a565b0154838360108110611e2057611e20614d4a565b60200201518260108110611e3657611e36614d4a565b60200201525b80611e4681614db5565b915050611d4e565b5080611e5981614db5565b915050611d42565b60606000836001600160401b03811115611e7d57611e7d613f59565b604051908082528060200260200182016040528015611eb657816020015b611ea3613e19565b815260200190600190039081611e9b5790505b50905060005b84811015611adc5760005b60408110156120565760005b60408110156120435785611f865760016000898986818110611ef757611ef7614d4a565b9050602002013581526020019081526020016000206007018160408110611f2057611f20614d4a565b604002018260408110611f3557611f35614d4a565b0154848481518110611f4957611f49614d4a565b6020026020010151600001518360408110611f6657611f66614d4a565b60200201518260408110611f7c57611f7c614d4a565b6020020152612031565b85600114156120315760016000898986818110611fa557611fa5614d4a565b905060200201358152602001908152602001600020611007018160408110611fcf57611fcf614d4a565b604002018260408110611fe457611fe4614d4a565b0154848481518110611ff857611ff8614d4a565b602002602001015160000151836040811061201557612015614d4a565b6020020151826040811061202b5761202b614d4a565b60200201525b8061203b81614db5565b915050611ed3565b508061204e81614db5565b915050611ec7565b508061206181614db5565b915050611ebc565b6120716134c5565b60378054911515600160a01b0260ff60a01b19909216919091179055565b612097613e31565b60008281526001602052604090206002810180546120b490614a1e565b80601f01602080910402602001604051908101604052809291908181526020018280546120e090614a1e565b801561212d5780601f106121025761010080835404028352916020019161212d565b820191906000526020600020905b81548152906001019060200180831161211057829003601f168201915b505050918452505080546001600160a01b031660408301526003810154606083015260048101546080830152600681015460a083015260018101805461217290614a1e565b80601f016020809104026020016040519081016040528092919081815260200182805461219e90614a1e565b80156121eb5780601f106121c0576101008083540402835291602001916121eb565b820191906000526020600020905b8154815290600101906020018083116121ce57829003601f168201915b50505050506020830152600581015460c08301526040805160808101918290529061200783019060049082845b81548152602001906001019080831161221857505050505060e0830152506000918252603560205260409091205461010082015290565b6000333014156122a657600080368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506122a99050565b50335b90565b600080612306856040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b835160208501209091506001600160a01b0316612323828661382f565b6001600160a01b03161495945050505050565b600080600b81015460405163109e13c560e21b8152600481018790529192506001600160a01b03169060009082906342784f149060240160006040518083038186803b15801561238557600080fd5b505afa158015612399573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123c19190810190614bca565b60008881526001850160205260409081902091925087906007830190889081106123ed576123ed614d4a565b60400201866040811061240257612402614d4a565b0154146124515760405162461bcd60e51b815260206004820152601e60248201527f4c69625265616c6d3a2077726f6e6720696e7374616c6c6174696f6e496400006044820152606401610402565b855b82516124629060ff1688614e4e565b8110156124d757855b602084015161247d9060ff1688614e4e565b8110156124c457600083600701836040811061249b5761249b614d4a565b6040020182604081106124b0576124b0614d4a565b0155806124bc81614db5565b91505061246b565b50806124cf81614db5565b915050612453565b505050505050505050565b600080600b81015460405163109e13c560e21b8152600481018690529192506001600160a01b03169060009082906342784f149060240160006040518083038186803b15801561253157600080fd5b505afa158015612545573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261256d9190810190614bca565b6040516324a7504960e11b8152306004820152602481018890529091506000906001600160a01b0384169063494ea0929060440160006040518083038186803b1580156125b957600080fd5b505afa1580156125cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125f59190810190614e66565b905060005b81518110156128915760405163109e13c560e21b8152600481018890526000906001600160a01b038616906342784f149060240160006040518083038186803b15801561264657600080fd5b505afa15801561265a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126829190810190614bca565b9050806101c0015160008151811061269c5761269c614d4a565b602090810291909101810151600b88015460008c815260018a0190935260409283902061201f0154925163109e13c560e21b815291926001600160a01b03909116916342784f14916126f49160040190815260200190565b60006040518083038186803b15801561270c57600080fd5b505afa158015612720573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127489190810190614bca565b6060015160ff16101561276d5760405162461bcd60e51b815260040161040290614f1b565b6000816101c0015160018151811061278757612787614d4a565b6020026020010151111561287e57806101c001516001815181106127ad576127ad614d4a565b602090810291909101810151600b88015460008c815260018a019093526040928390206120220154925163109e13c560e21b815291926001600160a01b03909116916342784f14916128059160040190815260200190565b60006040518083038186803b15801561281d57600080fd5b505afa158015612831573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128599190810190614bca565b6060015160ff16101561287e5760405162461bcd60e51b815260040161040290614f63565b508061288981614db5565b9150506125fa565b50608082015160ff166128a488826138ae565b610180830151156128f057610180830151600089815260018701602052604090206120130182600481106128da576128da614d4a565b0160008282546128ea9190614fab565b90915550505b604083015161ffff16158015612904575085155b1561291f576000888152600186016020526040812061201f01555b826040015161ffff1660031415612946576000888152600186016020526040812061202201555b6101a083015115612ab05760005b6000898152600187016020908152604080832085845261201201909152902054811015612a0057600089815260018701602090815260408083208584526120120190915290208054899190839081106129af576129af614d4a565b906000526020600020015414156129ee57600089815260018701602090815260408083208584526120120190915290206129e990826139a7565b612a00565b806129f881614db5565b915050612954565b50612a0b8882613a1c565b6000898152600187016020526040902061201b018260048110612a3057612a30614d4a565b01541115612ab05760405162461bcd60e51b815260206004820152604160248201527f4c6962416c6368656d6963613a20556e636c61696d656420616c6368656d696360448201527f612067726561746572207468616e207265736572766f697220636170616369746064820152607960f81b608482015260a401610402565b60e083015160ff1615612af3578260e0015160ff168560010160008a8152602001908152602001600020612020016000828254612aed9190614fab565b90915550505b5050505050505050565b600080612b08613b31565b90506000612b14613b69565b600b84015460405163109e13c560e21b8152600481018990529192506001600160a01b03169060009082906342784f149060240160006040518083038186803b158015612b6057600080fd5b505afa158015612b74573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b9c9190810190614bca565b60008a8152600187016020526040902081516006820154929350909160ff90911690869060058110612bd057612bd0614d4a565b6020020151612bdf9190614fab565b881115612c2e5760405162461bcd60e51b815260206004820152601b60248201527f4c69625265616c6d3a207820657863656564696e6720776964746800000000006044820152606401610402565b816020015160ff1684826006015460058110612c4c57612c4c614d4a565b6020020151612c5b9190614fab565b871115612caa5760405162461bcd60e51b815260206004820152601c60248201527f4c69625265616c6d3a207920657863656564696e6720686569676874000000006044820152606401610402565b875b8251612cbb9060ff168a614e4e565b811015612da157875b6020840151612cd69060ff168a614e4e565b811015612d8e57826007018260408110612cf257612cf2614d4a565b604002018160408110612d0757612d07614d4a565b015415612d4f5760405162461bcd60e51b8152602060048201526016602482015275131a589499585b1b4e88125b9d985b1a59081cdc1bdd60521b6044820152606401610402565b8a836007018360408110612d6557612d65614d4a565b604002018260408110612d7a57612d7a614d4a565b015580612d8681614db5565b915050612cc4565b5080612d9981614db5565b915050612cac565b5050505050505050505050565b600080600b81015460405163109e13c560e21b8152600481018690529192506000916001600160a01b03909116906342784f149060240160006040518083038186803b158015612dfd57600080fd5b505afa158015612e11573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e399190810190614bca565b90506000816101c00151600081518110612e5557612e55614d4a565b602002602001015190506000826101c00151600181518110612e7957612e79614d4a565b602090810291909101810151600089815260018701909252604080832061201f0154600b880154915163109e13c560e21b81526004810182905292945092916001600160a01b03909116906342784f149060240160006040518083038186803b158015612ee557600080fd5b505afa158015612ef9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612f219190810190614bca565b6060015160ff16905083811015612f4a5760405162461bcd60e51b815260040161040290614f1b565b82156130145760008981526001870160205260408082206120220154600b890154915163109e13c560e21b8152600481018290529092916001600160a01b0316906342784f149060240160006040518083038186803b158015612fac57600080fd5b505afa158015612fc0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612fe89190810190614bca565b6060015160ff169050848110156130115760405162461bcd60e51b815260040161040290614f63565b50505b846040015161ffff16600114156130a95760008981526001870160209081526040808320608089015160ff168452612012019091529020546130a95760405162461bcd60e51b815260206004820152602860248201527f5265616c6d46616365743a204d757374206571756970207265736572766f6972604482015267206f66207479706560c01b6064820152608401610402565b608085015160ff166130bb8a826138ae565b610180860151156131075761018086015160008b815260018901602052604090206120130182600481106130f1576130f1614d4a565b0160008282546131019190614e4e565b90915550505b6101a0860151156131425760008a81526001808901602090815260408084208585526120120182528320805492830181558352909120018990555b604086015161ffff166131df57878061316d575060008a8152600188016020526040902061201f0154155b6131c75760405162461bcd60e51b815260206004820152602560248201527f4c6962416c6368656d6963613a2043616e6e6f742065717569702074776f20616044820152646c7461727360d81b6064820152608401610402565b60008a8152600188016020526040902061201f018990555b60e086015160ff1615613222578560e0015160ff168760010160008c815260200190815260200160002061202001600082825461321c9190614e4e565b90915550505b50505050505050505050565b600080613239613b31565b90506000613245613b69565b603784015460405163e042161f60e01b8152600481018990529192506001600160a01b031690600090829063e042161f9060240160006040518083038186803b15801561329157600080fd5b505afa1580156132a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526132cd9190810190614fc2565b60008a815260018701602052604090208151600682015492935090918690600581106132fb576132fb614d4a565b602002015161330a9190614fab565b8811156133595760405162461bcd60e51b815260206004820152601b60248201527f4c69625265616c6d3a207820657863656564696e6720776964746800000000006044820152606401610402565b81602001518482600601546005811061337457613374614d4a565b60200201516133839190614fab565b8711156133d25760405162461bcd60e51b815260206004820152601c60248201527f4c69625265616c6d3a207920657863656564696e6720686569676874000000006044820152606401610402565b875b82516133e0908a614e4e565b811015612da157875b60208401516133f8908a614e4e565b8110156134b2578261100701826040811061341557613415614d4a565b60400201816040811061342a5761342a614d4a565b0154156134725760405162461bcd60e51b8152602060048201526016602482015275131a589499585b1b4e88125b9d985b1a59081cdc1bdd60521b6044820152606401610402565b8a8361100701836040811061348957613489614d4a565b60400201826040811061349e5761349e614d4a565b0155806134aa81614db5565b9150506133e9565b50806134bd81614db5565b9150506133d4565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c600401546001600160a01b0316331461354c5760405162461bcd60e51b815260206004820152602260248201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60448201526132b960f11b6064820152608401610402565b565b6000818152600160205260408120546001600160a01b0316156135bd5760405162461bcd60e51b815260206004820152602160248201527f4c69624552433732313a20746f6b656e496420616c7265616479206d696e74656044820152601960fa1b6064820152608401610402565b600082815260018281016020908152604080842080546001600160a01b0319166001600160a01b03891690811790915585548085018755868652838620018790558085526003860180845282862080546002890186528488208a895286528488208190559185529481018555938552918420909201859055905184927f1661e9eb70c35142fbb4190fa06d962636cf9ccd88dd913f90c08bcbf0d43e9191a360405182906001600160a01b038516906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4505050565b600080603781015460405163e042161f60e01b8152600481018790529192506001600160a01b031690600090829063e042161f9060240160006040518083038186803b1580156136e857600080fd5b505afa1580156136fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526137249190810190614fc2565b60008881526001850160205260409081902091925087906110078301908890811061375157613751614d4a565b60400201866040811061376657613766614d4a565b0154146137ae5760405162461bcd60e51b8152602060048201526016602482015275131a589499585b1b4e881ddc9bdb99c81d1a5b19525960521b6044820152606401610402565b855b82516137bc9088614e4e565b8110156124d757855b60208401516137d49088614e4e565b81101561381c576000836110070183604081106137f3576137f3614d4a565b60400201826040811061380857613808614d4a565b01558061381481614db5565b9150506137c5565b508061382781614db5565b9150506137b0565b60008060008061383e85613ba1565b6040805160008152602081018083528b905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015613899573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6000806138bb8484613a1c565b905060006138c98585613c15565b9050801561397757600085815260018401602052604090208290829061201b0186600481106138fa576138fa614d4a565b01546139069190614e4e565b111561393a5760008581526001840160205260409020829061201b01856004811061393357613933614d4a565b0155613977565b60008581526001840160205260409020819061201b01856004811061396157613961614d4a565b0160008282546139719190614e4e565b90915550505b60008581526001840160205260409020429061201701856004811061399e5761399e614d4a565b01555050505050565b815482906139b790600190614fab565b815481106139c7576139c7614d4a565b90600052602060002001548282815481106139e4576139e4614d4a565b906000526020600020018190555081805480613a0257613a02615083565b600190038181906000526020600020016000905590555050565b60008060005b6000858152600183016020908152604080832087845261201201909152902054811015613b2957600b8201546000868152600184016020908152604080832088845261201201909152902080546001600160a01b039092169163d3606249919084908110613a9257613a92614d4a565b90600052602060002001546040518263ffffffff1660e01b8152600401613abb91815260200190565b60206040518083038186803b158015613ad357600080fd5b505afa158015613ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0b9190614e1e565b613b159084614e4e565b925080613b2181614db5565b915050613a22565b505092915050565b613b39613e8c565b506040805160a0810182526008815260106020808301919091528183015260608101829052608081019190915290565b613b71613e8c565b506040805160a0810182526008815260106020808301919091528183018390526060820152608081019190915290565b60008060008351604114613bf75760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606401610402565b50505060208101516040820151606090920151909260009190911a90565b600082815260016020526040812081908190612017018460048110613c3c57613c3c614d4a565b0154613c489042614fab565b60008681526001840160205260409020612013018560048110613c6d57613c6d614d4a565b0154613c799190615099565b95945050505050565b6040518061080001604052806040905b613c9a613eaa565b815260200190600190039081613c925790505090565b6040518061080001604052806040905b613cc8613ec9565b815260200190600190039081613cc05790505090565b828054613cea90614a1e565b90600052602060002090601f016020900481019282613d0c5760008555613d52565b82601f10613d2557805160ff1916838001178555613d52565b82800160010185558215613d52579182015b82811115613d52578251825591602001919060010190613d37565b50613d5e929150613ee8565b5090565b8260048101928215613d525791602002820182811115613d52578251825591602001919060010190613d37565b6040518061010001604052806008905b613da7613efd565b815260200190600190039081613d9f5790505090565b6040518061040001604052806020905b613dd5613eaa565b815260200190600190039081613dcd5790505090565b6040518061020001604052806010905b613e03613f1c565b815260200190600190039081613dfb5790505090565b6040518060200160405280613e2c613c82565b905290565b604051806101200160405280606081526020016060815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001613e7f613f3b565b8152602001600081525090565b6040518060a001604052806005906020820280368337509192915050565b6040518061080001604052806040906020820280368337509192915050565b6040518061040001604052806020906020820280368337509192915050565b5b80821115613d5e5760008155600101613ee9565b6040518061010001604052806008906020820280368337509192915050565b6040518061020001604052806010906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b0381118282101715613f9157613f91613f59565b60405290565b60405161020081016001600160401b0381118282101715613f9157613f91613f59565b604080519081016001600160401b0381118282101715613f9157613f91613f59565b604051608081016001600160401b0381118282101715613f9157613f91613f59565b604051601f8201601f191681016001600160401b038111828210171561402657614026613f59565b604052919050565b60006001600160401b0382111561404757614047613f59565b50601f01601f191660200190565b60006140686140638461402e565b613ffe565b905082815283838301111561407c57600080fd5b828260208301376000602084830101529392505050565b600080600080600060a086880312156140ab57600080fd5b8535945060208601359350604086013592506060860135915060808601356001600160401b038111156140dd57600080fd5b8601601f810188136140ee57600080fd5b6140fd88823560208401614055565b9150509295509295909350565b6000806040838503121561411d57600080fd5b50508035926020909101359150565b60008282825b6040811015614151578151835260209283019290910190600101614132565b5050506108008301905092915050565b620200008101818360005b60408110156141915761418083835161412c565b92506020919091019060010161416c565b50505092915050565b62010000810181836000805b60408110156141f157825184835b60208082106141c357506141d7565b8351835292830192909101906001016141b4565b5050506104009390930192602092909201916001016141a6565b5050505092915050565b6000806000806080858703121561421157600080fd5b5050823594602084013594506040840135936060013592509050565b60008083601f84011261423f57600080fd5b5081356001600160401b0381111561425657600080fd5b6020830191508360208260051b850101111561427157600080fd5b9250929050565b6000806000806000806060878903121561429157600080fd5b86356001600160401b03808211156142a857600080fd5b6142b48a838b0161422d565b909850965060208901359150808211156142cd57600080fd5b6142d98a838b0161422d565b909650945060408901359150808211156142f257600080fd5b506142ff89828a0161422d565b979a9699509497509295939492505050565b600080600080600060a0868803121561432957600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b80356001600160a01b038116811461436357600080fd5b919050565b60006001600160401b0382111561438157614381613f59565b5060051b60200190565b600082601f83011261439c57600080fd5b6143ab83833560208501614055565b9392505050565b600082601f8301126143c357600080fd5b6143cb613fdc565b8060808401858111156143dd57600080fd5b845b818110156143f75780358452602093840193016143df565b509095945050505050565b6000806000806060858703121561441857600080fd5b6144218561434c565b935060208501356001600160401b038082111561443d57600080fd5b6144498883890161422d565b9095509350604087013591508082111561446257600080fd5b818701915087601f83011261447657600080fd5b6144836140638335614368565b82358082526020808301929160051b8501018a8111156144a257600080fd5b602085015b818110156145725784813511156144bd57600080fd5b80358601610140818e03601f190112156144d657600080fd5b6144de613f6f565b60208201358152604082013560208201526060820135604082015260808201358781111561450b57600080fd5b61451a8f60208386010161438b565b60608301525060a08201358781111561453257600080fd5b6145418f60208386010161438b565b60808301525060c082013560a082015261455e8e60e084016143b2565b60c0820152855250602093840193016144a7565b50508094505050505092959194509250565b60006020828403121561459657600080fd5b5035919050565b600080604083850312156145b057600080fd5b6145b98361434c565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b8181101561163b578351835292840192918401916001016145e3565b610800810181836000805b600880821061461957506141f1565b835185845b8381101561463c57825182526020928301929091019060010161461e565b5050506101009490940193506020929092019160010161460a565b620100008101818360005b60208082106146715750614191565b61467c84845161412c565b93509190910190600101614662565b600080600080604085870312156146a157600080fd5b84356001600160401b03808211156146b857600080fd5b6146c48883890161422d565b909650945060208701359150808211156146dd57600080fd5b506146ea8782880161422d565b95989497509550505050565b6000806020838503121561470957600080fd5b82356001600160401b0381111561471f57600080fd5b61472b8582860161422d565b90969095509350505050565b612000810181836000805b601080821061475157506141f1565b835185845b83811015614774578251825260209283019290910190600101614756565b50505061020094909401935060209290920191600101614742565b6000806000604084860312156147a457600080fd5b83356001600160401b038111156147ba57600080fd5b6147c68682870161422d565b909790965060209590950135949350505050565b60208082528251828201819052600091906040908185019086840185805b8381101561483f5782515185835b888110156148275761481982845161412c565b928a01929150600101614806565b505050620200009490940193918601916001016147f8565b509298975050505050505050565b801515811461485b57600080fd5b50565b60006020828403121561487057600080fd5b81356143ab8161484d565b60005b8381101561489657818101518382015260200161487e565b838111156148a5576000848401525b50505050565b600081518084526148c381602086016020860161487b565b601f01601f19169290920160200192915050565b8060005b60048110156148a55781518452602093840193909101906001016148db565b60208152600082516101808060208501526149196101a08501836148ab565b91506020850151601f1985840301604086015261493683826148ab565b925050604085015161495360608601826001600160a01b03169052565b5060608501516080850152608085015160a085015260a085015160c085015260c085015160e085015260e0850151610100614990818701836148d7565b959095015193019290925250919050565b60208082526026908201527f41707053746f726167653a204f6e6c792050617263656c206f776e65722063616040820152651b8818d85b1b60d21b606082015260800190565b6020808252601b908201527f41707053746f726167653a2067616d65206e6f74206163746976650000000000604082015260600190565b600181811c90821680614a3257607f821691505b60208210811415614a5357634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252601d908201527f5265616c6d46616365743a20496e76616c6964207369676e6174757265000000604082015260600190565b805160ff8116811461436357600080fd5b805161ffff8116811461436357600080fd5b805163ffffffff8116811461436357600080fd5b80516143638161484d565b600082601f830112614ae357600080fd5b614aeb613fdc565b806080840185811115614afd57600080fd5b845b818110156143f7578051845260209384019301614aff565b600082601f830112614b2857600080fd5b81516020614b3861406383614368565b82815260059290921b84018101918181019086841115614b5757600080fd5b8286015b84811015614b725780518352918301918301614b5b565b509695505050505050565b600082601f830112614b8e57600080fd5b8151614b9c6140638261402e565b818152846020838601011115614bb157600080fd5b614bc282602083016020870161487b565b949350505050565b600060208284031215614bdc57600080fd5b81516001600160401b0380821115614bf357600080fd5b908301906102608286031215614c0857600080fd5b614c10613f97565b614c1983614a90565b8152614c2760208401614a90565b6020820152614c3860408401614aa1565b6040820152614c4960608401614a90565b6060820152614c5a60808401614a90565b6080820152614c6b60a08401614ab3565b60a0820152614c7c60c08401614aa1565b60c0820152614c8d60e08401614a90565b60e0820152610100614ca0818501614ab3565b90820152610120614cb2848201614ab3565b90820152610140614cc4848201614ac7565b90820152610160614cd787858301614ad2565b908201526101e0838101516101808301526102008401516101a083015261022084015183811115614d0757600080fd5b614d1388828701614b17565b6101c08401525061024084015183811115614d2d57600080fd5b614d3988828701614b7d565b918301919091525095945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082614d9357634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215614daa57600080fd5b81516143ab8161484d565b6000600019821415614dc957614dc9614d60565b5060010190565b6020808252602e908201527f41707053746f726167653a204f6e6c7920496e7374616c6c6174696f6e20646960408201526d185b5bdb990818d85b8818d85b1b60921b606082015260800190565b600060208284031215614e3057600080fd5b5051919050565b600081614e4657614e46614d60565b506000190190565b60008219821115614e6157614e61614d60565b500190565b60006020808385031215614e7957600080fd5b82516001600160401b03811115614e8f57600080fd5b8301601f81018513614ea057600080fd5b8051614eae61406382614368565b81815260069190911b82018301908381019087831115614ecd57600080fd5b928401925b82841015614f105760408489031215614eeb5760008081fd5b614ef3613fba565b845181528585015186820152825260409093019290840190614ed2565b979650505050505050565b60208082526028908201527f5265616c6d46616365743a20416c746172205465636820547265652052657173604082015267081b9bdd081b595d60c21b606082015260800190565b60208082526028908201527f5265616c6d46616365743a204c6f646765205465636820547265652052657173604082015267081b9bdd081b595d60c21b606082015260800190565b600082821015614fbd57614fbd614d60565b500390565b600060208284031215614fd457600080fd5b81516001600160401b0380821115614feb57600080fd5b90830190610140828603121561500057600080fd5b615008613f6f565b825181526020830151602082015261502260408401614ac7565b604082015261503360608401614aa1565b60608201526150458660808501614ad2565b608082015261010083015160a08201526101208301518281111561506857600080fd5b61507487828601614b7d565b60c08301525095945050505050565b634e487b7160e01b600052603160045260246000fd5b60008160001904831182151516156150b3576150b3614d60565b50029056fea26469706673582212203e356204c71794312c4bceaf768bd607f53b51e38f1bd09cb48996c468f6babd64736f6c63430008090033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.