ETH Price: $3,163.68 (-2.06%)

Contract

0x00000000fcCe7f938e7aE6D3c335bD6a1a7c593D
 

Overview

ETH Balance

436.475485125478059039 ETH

ETH Value

$1,380,867.77 (@ $3,163.68/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Rent1191924212024-04-24 18:33:3945 secs ago1713983619IN
Farcaster: Storage Registry
0.00094767 ETH0.000002950.06085481
Rent1191922232024-04-24 18:27:037 mins ago1713983223IN
Farcaster: Storage Registry
0.00092611 ETH0.000006760.06199144
Rent1191921812024-04-24 18:25:398 mins ago1713983139IN
Farcaster: Storage Registry
0.00092611 ETH0.000002950.06092641
Rent1191917442024-04-24 18:11:0523 mins ago1713982265IN
Farcaster: Storage Registry
0.00092611 ETH0.00000420.08647885
Rent1191916472024-04-24 18:07:5126 mins ago1713982071IN
Farcaster: Storage Registry
0.00185223 ETH0.000002970.06132037
Rent1191914912024-04-24 18:02:3931 mins ago1713981759IN
Farcaster: Storage Registry
0.00092611 ETH0.000003010.06196963
Rent1191914062024-04-24 17:59:4934 mins ago1713981589IN
Farcaster: Storage Registry
0.00092611 ETH0.000002940.06059124
Rent1191913852024-04-24 17:59:0735 mins ago1713981547IN
Farcaster: Storage Registry
0.00092611 ETH0.000002930.06046876
Rent1191907282024-04-24 17:37:1357 mins ago1713980233IN
Farcaster: Storage Registry
0.00092611 ETH0.000002980.06145336
Rent1191904022024-04-24 17:26:211 hr ago1713979581IN
Farcaster: Storage Registry
0.00185223 ETH0.000002980.06157803
Rent1191904002024-04-24 17:26:171 hr ago1713979577IN
Farcaster: Storage Registry
0.00092611 ETH0.0000030.06178234
Rent1191903982024-04-24 17:26:131 hr ago1713979573IN
Farcaster: Storage Registry
0.00185223 ETH0.000002950.0608904
Rent1191898662024-04-24 17:08:291 hr ago1713978509IN
Farcaster: Storage Registry
0.00092611 ETH0.000002990.06177312
Rent1191898142024-04-24 17:06:451 hr ago1713978405IN
Farcaster: Storage Registry
0.00185223 ETH0.000003010.06206782
Rent1191897202024-04-24 17:03:371 hr ago1713978217IN
Farcaster: Storage Registry
0.00092611 ETH0.0000030.06187999
Rent1191896542024-04-24 17:01:251 hr ago1713978085IN
Farcaster: Storage Registry
0.00185223 ETH0.000002980.0614623
Rent1191892712024-04-24 16:48:391 hr ago1713977319IN
Farcaster: Storage Registry
0.00092611 ETH0.000002980.06153168
Rent1191892702024-04-24 16:48:371 hr ago1713977317IN
Farcaster: Storage Registry
0.00185223 ETH0.000002990.0617431
Rent1191892182024-04-24 16:46:531 hr ago1713977213IN
Farcaster: Storage Registry
0.00092611 ETH0.000002920.06028434
Rent1191892012024-04-24 16:46:191 hr ago1713977179IN
Farcaster: Storage Registry
0.00092611 ETH0.000002990.0615722
Rent1191891372024-04-24 16:44:111 hr ago1713977051IN
Farcaster: Storage Registry
0.00185223 ETH0.000002970.06137466
Rent1191890772024-04-24 16:42:111 hr ago1713976931IN
Farcaster: Storage Registry
0.00092611 ETH0.000002960.06110819
Rent1191889062024-04-24 16:36:291 hr ago1713976589IN
Farcaster: Storage Registry
0.00092611 ETH0.000002970.06115588
Rent1191888322024-04-24 16:34:012 hrs ago1713976441IN
Farcaster: Storage Registry
0.00092611 ETH0.000002990.06170362
Rent1191888002024-04-24 16:32:572 hrs ago1713976377IN
Farcaster: Storage Registry
0.00185223 ETH0.000002980.06161525
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
1191924022024-04-24 18:33:011 min ago1713983581
Farcaster: Storage Registry
0.00094767 ETH
1191923512024-04-24 18:31:193 mins ago1713983479
Farcaster: Storage Registry
0.00094767 ETH
1191923442024-04-24 18:31:053 mins ago1713983465
Farcaster: Storage Registry
0.00094767 ETH
1191922602024-04-24 18:28:176 mins ago1713983297
Farcaster: Storage Registry
0.00094767 ETH
1191922112024-04-24 18:26:397 mins ago1713983199
Farcaster: Storage Registry
0.00092611 ETH
1191921432024-04-24 18:24:2310 mins ago1713983063
Farcaster: Storage Registry
0.00092611 ETH
1191920812024-04-24 18:22:1912 mins ago1713982939
Farcaster: Storage Registry
0.00092611 ETH
1191920372024-04-24 18:20:5113 mins ago1713982851
Farcaster: Storage Registry
0.00092611 ETH
1191920202024-04-24 18:20:1714 mins ago1713982817
Farcaster: Storage Registry
0.00092611 ETH
1191919042024-04-24 18:16:2517 mins ago1713982585
Farcaster: Storage Registry
0.00092611 ETH
1191918782024-04-24 18:15:3318 mins ago1713982533
Farcaster: Storage Registry
0.00092611 ETH
1191918772024-04-24 18:15:3118 mins ago1713982531
Farcaster: Storage Registry
0.00092611 ETH
1191918522024-04-24 18:14:4119 mins ago1713982481
Farcaster: Storage Registry
0.00185223 ETH
1191918202024-04-24 18:13:3720 mins ago1713982417
Farcaster: Storage Registry
0.00092611 ETH
1191917772024-04-24 18:12:1122 mins ago1713982331
Farcaster: Storage Registry
0.00092611 ETH
1191917462024-04-24 18:11:0923 mins ago1713982269
Farcaster: Storage Registry
0.00092611 ETH
1191917302024-04-24 18:10:3723 mins ago1713982237
Farcaster: Storage Registry
0.00092611 ETH
1191915732024-04-24 18:05:2329 mins ago1713981923
Farcaster: Storage Registry
0.00092611 ETH
1191915452024-04-24 18:04:2729 mins ago1713981867
Farcaster: Storage Registry
0.00092611 ETH
1191915352024-04-24 18:04:0730 mins ago1713981847
Farcaster: Storage Registry
0.00092611 ETH
1191915332024-04-24 18:04:0330 mins ago1713981843
Farcaster: Storage Registry
0.00092611 ETH
1191915322024-04-24 18:04:0130 mins ago1713981841
Farcaster: Storage Registry
0.00092611 ETH
1191915242024-04-24 18:03:4530 mins ago1713981825
Farcaster: Storage Registry
0.00092611 ETH
1191915212024-04-24 18:03:3930 mins ago1713981819
Farcaster: Storage Registry
0.00092611 ETH
1191914872024-04-24 18:02:3131 mins ago1713981751
Farcaster: Storage Registry
0.00092611 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StorageRegistry

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 100000 runs

Other Settings:
paris EvmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 17 : StorageRegistry.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.21;

import {AggregatorV3Interface} from "chainlink/v0.8/interfaces/AggregatorV3Interface.sol";
import {AccessControlEnumerable} from "openzeppelin/contracts/access/AccessControlEnumerable.sol";
import {Pausable} from "openzeppelin/contracts/security/Pausable.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";

import {IStorageRegistry} from "./interfaces/IStorageRegistry.sol";
import {TransferHelper} from "./lib/TransferHelper.sol";

/**
 * @title Farcaster StorageRegistry
 *
 * @notice See https://github.com/farcasterxyz/contracts/blob/v3.0.0/docs/docs.md for an overview.
 *
 * @custom:security-contact [email protected]
 */
contract StorageRegistry is IStorageRegistry, AccessControlEnumerable, Pausable {
    using FixedPointMathLib for uint256;
    using TransferHelper for address;

    /*//////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    /// @dev Revert if the caller attempts to rent storage after the contract is deprecated.
    error ContractDeprecated();

    /// @dev Revert if the caller attempts to rent more storage than is available.
    error ExceedsCapacity();

    /// @dev Revert if the caller attempts to rent zero units.
    error InvalidAmount();

    /// @dev Revert if the caller attempts a batch rent with mismatched input array lengths or an empty array.
    error InvalidBatchInput();

    /// @dev Revert if the caller provides the wrong payment amount.
    error InvalidPayment();

    /// @dev Revert if the price feed returns a stale answer.
    error StaleAnswer();

    /// @dev Revert if any data feed round is incomplete and has not yet generated an answer.
    error IncompleteRound();

    /// @dev Revert if any data feed returns a timestamp in the future.
    error InvalidRoundTimestamp();

    /// @dev Revert if the price feed returns a value greater than the min/max bound.
    error PriceOutOfBounds();

    /// @dev Revert if the price feed returns a zero or negative price.
    error InvalidPrice();

    /// @dev Revert if the sequencer uptime feed detects that the L2 sequencer is unavailable.
    error SequencerDown();

    /// @dev Revert if the L2 sequencer restarted less than L2_DOWNTIME_GRACE_PERIOD seconds ago.
    error GracePeriodNotOver();

    /// @dev Revert if the deprecation timestamp parameter is in the past.
    error InvalidDeprecationTimestamp();

    /// @dev Revert if the priceFeedMinAnswer parameter is greater than or equal to priceFeedMaxAnswer.
    error InvalidMinAnswer();

    /// @dev Revert if the priceFeedMaxAnswer parameter is less than or equal to priceFeedMinAnswer.
    error InvalidMaxAnswer();

    /// @dev Revert if the fixedEthUsdPrice is outside the configured price bounds.
    error InvalidFixedPrice();

    /// @dev Revert if the caller is not an owner.
    error NotOwner();

    /// @dev Revert if the caller is not an operator.
    error NotOperator();

    /// @dev Revert if the caller is not a treasurer.
    error NotTreasurer();

    /// @dev Revert if the caller does not have an authorized role.
    error Unauthorized();

    /// @dev Revert if transferred to the zero address.
    error InvalidAddress();

    /// @dev Revert if the caller attempts a continuous credit withan invalid range.
    error InvalidRangeInput();

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev Emit an event when a caller pays rent for an fid's storage.
     *
     *      Hubs increment the units assigned to the fid for exactly 395 days (1 year + grace) from
     *      the event timestamp. Hubs track this for unregistered fids and will assign units when
     *      the fid is registered. Storage credited to fid 0 is a no-op.
     *
     * @param payer     Address of the account paying the storage rent.
     * @param fid       The fid that will receive the storage units.
     * @param units     The number of storage units being rented.
     */
    event Rent(address indexed payer, uint256 indexed fid, uint256 units);

    /**
     * @dev Emit an event when an owner changes the price feed address.
     *
     * @param oldFeed The previous price feed address.
     * @param newFeed The new price feed address.
     */
    event SetPriceFeed(address oldFeed, address newFeed);

    /**
     * @dev Emit an event when an owner changes the uptime feed address.
     *
     * @param oldFeed The previous uptime feed address.
     * @param newFeed The new uptime feed address.
     */
    event SetUptimeFeed(address oldFeed, address newFeed);

    /**
     * @dev Emit an event when an owner changes the price of storage units.
     *
     * @param oldPrice The previous unit price in USD. Fixed point value with 8 decimals.
     * @param newPrice The new unit price in USD. Fixed point value with 8 decimals.
     */
    event SetPrice(uint256 oldPrice, uint256 newPrice);

    /**
     * @dev Emit an event when an owner changes the fixed ETH/USD price.
     *      Setting this value to zero means the fixed price is disabled.
     *
     * @param oldPrice The previous ETH price in USD. Fixed point value with 8 decimals.
     * @param newPrice The new ETH price in USD. Fixed point value with 8 decimals.
     */
    event SetFixedEthUsdPrice(uint256 oldPrice, uint256 newPrice);

    /**
     * @dev Emit an event when an owner changes the maximum supply of storage units.
     *
     *      Hub operators should be made aware of changes to storage requirements before they occur
     *      since it may cause Hubs to fail if they do not allocate sufficient storage.
     *
     * @param oldMax The previous maximum amount.
     * @param newMax The new maximum amount.
     */
    event SetMaxUnits(uint256 oldMax, uint256 newMax);

    /**
     * @dev Emit an event when an owner changes the deprecationTimestamp.
     *
     *      Hubs will stop listening to events after the deprecationTimestamp. This can be used
     *      when cutting over to a new contract. Hubs assume the following invariants:
     *
     *      1. SetDeprecationTimestamp() is only emitted once.
     *
     * @param oldTimestamp The previous deprecationTimestamp.
     * @param newTimestamp The new deprecationTimestamp.
     */
    event SetDeprecationTimestamp(uint256 oldTimestamp, uint256 newTimestamp);

    /**
     * @dev Emit an event when an owner changes the priceFeedCacheDuration.
     *
     * @param oldDuration The previous priceFeedCacheDuration.
     * @param newDuration The new priceFeedCacheDuration.
     */
    event SetCacheDuration(uint256 oldDuration, uint256 newDuration);

    /**
     * @dev Emit an event when an owner changes the priceFeedMaxAge.
     *
     * @param oldAge The previous priceFeedMaxAge.
     * @param newAge The new priceFeedMaxAge.
     */
    event SetMaxAge(uint256 oldAge, uint256 newAge);

    /**
     * @dev Emit an event when an owner changes the priceFeedMinAnswer.
     *
     * @param oldPrice The previous priceFeedMinAnswer.
     * @param newPrice The new priceFeedMaxAnswer.
     */
    event SetMinAnswer(uint256 oldPrice, uint256 newPrice);

    /**
     * @dev Emit an event when an owner changes the priceFeedMaxAnswer.
     *
     * @param oldPrice The previous priceFeedMaxAnswer.
     * @param newPrice The new priceFeedMaxAnswer.
     */
    event SetMaxAnswer(uint256 oldPrice, uint256 newPrice);

    /**
     * @dev Emit an event when an owner changes the uptimeFeedGracePeriod.
     *
     * @param oldPeriod The previous uptimeFeedGracePeriod.
     * @param newPeriod The new uptimeFeedGracePeriod.
     */
    event SetGracePeriod(uint256 oldPeriod, uint256 newPeriod);

    /**
     * @dev Emit an event when an owner changes the vault.
     *
     * @param oldVault The previous vault.
     * @param newVault The new vault.
     */
    event SetVault(address oldVault, address newVault);

    /**
     * @dev Emit an event when a treasurer withdraws any contract balance to the vault.
     *
     * @param to     Address of recipient.
     * @param amount The amount of ether withdrawn.
     */
    event Withdraw(address indexed to, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                                CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IStorageRegistry
     */
    string public constant VERSION = "2023.08.23";

    bytes32 internal constant OWNER_ROLE = keccak256("OWNER_ROLE");
    bytes32 internal constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
    bytes32 internal constant TREASURER_ROLE = keccak256("TREASURER_ROLE");

    /*//////////////////////////////////////////////////////////////
                              PARAMETERS
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IStorageRegistry
     */
    AggregatorV3Interface public priceFeed;

    /**
     * @inheritdoc IStorageRegistry
     */
    AggregatorV3Interface public uptimeFeed;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public deprecationTimestamp;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public usdUnitPrice;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public fixedEthUsdPrice;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public maxUnits;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public priceFeedCacheDuration;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public priceFeedMaxAge;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public priceFeedMinAnswer;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public priceFeedMaxAnswer;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public uptimeFeedGracePeriod;

    /**
     * @inheritdoc IStorageRegistry
     */
    address public vault;

    /*//////////////////////////////////////////////////////////////
                                STORAGE
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public rentedUnits;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public ethUsdPrice;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public prevEthUsdPrice;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public lastPriceFeedUpdateTime;

    /**
     * @inheritdoc IStorageRegistry
     */
    uint256 public lastPriceFeedUpdateBlock;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Set the price feed, uptime feed, and initial parameters.
     *
     * @param _priceFeed                     Chainlink ETH/USD price feed.
     * @param _uptimeFeed                    Chainlink L2 sequencer uptime feed.
     * @param _initialUsdUnitPrice           Initial unit price in USD. Fixed point 8 decimal value.
     * @param _initialMaxUnits               Initial maximum capacity in storage units.
     * @param _initialVault                  Initial vault address.
     * @param _initialRoleAdmin              Initial role admin address.
     * @param _initialOwner                  Initial owner address.
     * @param _initialOperator               Initial operator address.
     * @param _initialTreasurer              Initial treasurer address.
     */
    constructor(
        AggregatorV3Interface _priceFeed,
        AggregatorV3Interface _uptimeFeed,
        uint256 _initialUsdUnitPrice,
        uint256 _initialMaxUnits,
        address _initialVault,
        address _initialRoleAdmin,
        address _initialOwner,
        address _initialOperator,
        address _initialTreasurer
    ) {
        priceFeed = _priceFeed;
        emit SetPriceFeed(address(0), address(_priceFeed));

        uptimeFeed = _uptimeFeed;
        emit SetUptimeFeed(address(0), address(_uptimeFeed));

        deprecationTimestamp = block.timestamp + 365 days;
        emit SetDeprecationTimestamp(0, deprecationTimestamp);

        usdUnitPrice = _initialUsdUnitPrice;
        emit SetPrice(0, _initialUsdUnitPrice);

        maxUnits = _initialMaxUnits;
        emit SetMaxUnits(0, _initialMaxUnits);

        priceFeedCacheDuration = 1 days;
        emit SetCacheDuration(0, 1 days);

        priceFeedMaxAge = 2 hours;
        emit SetMaxAge(0, 2 hours);

        uptimeFeedGracePeriod = 1 hours;
        emit SetGracePeriod(0, 1 hours);

        priceFeedMinAnswer = 100e8; // 100 USD / ETH
        emit SetMinAnswer(0, 100e8);

        priceFeedMaxAnswer = 10_000e8; // 10_000 USD / ETH
        emit SetMaxAnswer(0, 10_000e8);

        vault = _initialVault;
        emit SetVault(address(0), _initialVault);

        _grantRole(DEFAULT_ADMIN_ROLE, _initialRoleAdmin);
        _grantRole(OWNER_ROLE, _initialOwner);
        _grantRole(OPERATOR_ROLE, _initialOperator);
        _grantRole(TREASURER_ROLE, _initialTreasurer);

        _refreshPrice();
    }

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    modifier whenNotDeprecated() {
        if (block.timestamp >= deprecationTimestamp) {
            revert ContractDeprecated();
        }
        _;
    }

    modifier onlyOwner() {
        if (!hasRole(OWNER_ROLE, msg.sender)) revert NotOwner();
        _;
    }

    modifier onlyOperator() {
        if (!hasRole(OPERATOR_ROLE, msg.sender)) revert NotOperator();
        _;
    }

    modifier onlyTreasurer() {
        if (!hasRole(TREASURER_ROLE, msg.sender)) revert NotTreasurer();
        _;
    }

    /*//////////////////////////////////////////////////////////////
                        STORAGE RENTAL LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IStorageRegistry
     */
    function rent(
        uint256 fid,
        uint256 units
    ) external payable whenNotDeprecated whenNotPaused returns (uint256 overpayment) {
        // Checks
        if (units == 0) revert InvalidAmount();
        if (rentedUnits + units > maxUnits) revert ExceedsCapacity();
        uint256 totalPrice = _price(units);
        if (msg.value < totalPrice) revert InvalidPayment();

        // Effects
        rentedUnits += units;
        emit Rent(msg.sender, fid, units);

        // Interactions
        // Safety: overpayment is guaranteed to be >=0 because of checks
        overpayment = msg.value - totalPrice;
        if (overpayment > 0) {
            msg.sender.sendNative(overpayment);
        }
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function batchRent(
        uint256[] calldata fids,
        uint256[] calldata units
    ) external payable whenNotDeprecated whenNotPaused {
        // Pre-checks
        if (fids.length == 0 || units.length == 0) revert InvalidBatchInput();
        if (fids.length != units.length) revert InvalidBatchInput();

        // Effects
        uint256 _usdPrice = usdUnitPrice;
        uint256 _ethPrice = _ethUsdPrice();

        uint256 totalQty;
        for (uint256 i; i < fids.length; ++i) {
            uint256 qty = units[i];
            if (qty == 0) continue;
            totalQty += qty;
            emit Rent(msg.sender, fids[i], qty);
        }
        uint256 totalPrice = _price(totalQty, _usdPrice, _ethPrice);

        // Post-checks
        if (msg.value < totalPrice) revert InvalidPayment();
        if (rentedUnits + totalQty > maxUnits) revert ExceedsCapacity();

        // Effects
        rentedUnits += totalQty;

        // Interactions
        if (msg.value > totalPrice) {
            msg.sender.sendNative(msg.value - totalPrice);
        }
    }

    /*//////////////////////////////////////////////////////////////
                              PRICE VIEWS
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IStorageRegistry
     */
    function unitPrice() external view returns (uint256) {
        return price(1);
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function price(uint256 units) public view returns (uint256) {
        uint256 ethPrice;
        if (fixedEthUsdPrice != 0) {
            ethPrice = fixedEthUsdPrice;

            /**
             *  Slither flags the following line as a dangerous strict equality, but we want to
             *  make an exact comparison here and are not using this value in the context
             *  this detector rule describes.
             */

            // slither-disable-next-line incorrect-equality
        } else if (lastPriceFeedUpdateBlock == block.number) {
            ethPrice = prevEthUsdPrice;
        } else {
            ethPrice = ethUsdPrice;
        }
        return _price(units, usdUnitPrice, ethPrice);
    }

    /**
     * @dev Return the fixed price if present and the cached ethUsdPrice if it is not. If cached
     *      price is no longer valid, refresh the cache from the price feed but return the cached
     *      price for the rest of this block to avoid unexpected price changes.
     */
    function _ethUsdPrice() internal returns (uint256) {
        /**
         *  If a fixed ETH/USD price is set, use it. This disables external calls
         *  to the price feed in case of emergency.
         */
        if (fixedEthUsdPrice != 0) return fixedEthUsdPrice;

        /**
         *  If cache duration has expired, get the latest price from the price feed.
         *  This updates prevEthUsdPrice, ethUsdPrice, lastPriceFeedUpdateTime, and
         *  lastPriceFeedUpdateBlock.
         */
        if (block.timestamp - lastPriceFeedUpdateTime > priceFeedCacheDuration) {
            _refreshPrice();
        }

        /**
         *  We want price changes to take effect in the first block after the price
         *  refresh, rather than immediately, to keep the price from changing intra
         *  block. If we update the price in this block, use the previous price
         *  until the next block. Otherwise, use the latest price.
         *
         *  Slither flags this line as a dangerous strict equality, but we want to
         *  make an exact comparison here and are not using this value in the context
         *  this detector rule describes.
         */

        // slither-disable-next-line incorrect-equality
        return (lastPriceFeedUpdateBlock == block.number) ? prevEthUsdPrice : ethUsdPrice;
    }

    /**
     * @dev Get the latest ETH/USD price from the price feed and update the cached price.
     */
    function _refreshPrice() internal {
        /**
         *  Get and validate the L2 sequencer status.
         *  We ignore the deprecated answeredInRound value.
         */

        // slither-disable-next-line unused-return
        (uint80 uptimeRoundId, int256 sequencerUp, uint256 uptimeStartedAt, uint256 uptimeUpdatedAt,) =
            uptimeFeed.latestRoundData();
        if (sequencerUp != 0) revert SequencerDown();
        if (uptimeRoundId == 0) revert IncompleteRound();
        if (uptimeUpdatedAt == 0) revert IncompleteRound();
        if (uptimeUpdatedAt > block.timestamp) revert InvalidRoundTimestamp();

        /* If the L2 sequencer recently restarted, ensure the grace period has elapsed. */
        uint256 timeSinceUp = block.timestamp - uptimeStartedAt;
        if (timeSinceUp < uptimeFeedGracePeriod) revert GracePeriodNotOver();

        /**
         *  Get and validate the Chainlink ETH/USD price. Validate that the answer is a positive
         *  value, the round is complete, and the answer is not stale by round.
         *
         *  Ignore the deprecated answeredInRound value.
         *
         *  Ignore the price feed startedAt value, which isn't used in validations, since the
         *  priceUpdatedAt timestamp is more meaningful.
         *
         *  Slither flags this as an unused return value error, but this is safe since
         *  we use priceUpdatedAt and are interested in the latest value.
         */

        // slither-disable-next-line unused-return
        (uint80 priceRoundId, int256 answer,, uint256 priceUpdatedAt,) = priceFeed.latestRoundData();
        if (answer <= 0) revert InvalidPrice();
        if (priceRoundId == 0) revert IncompleteRound();
        if (priceUpdatedAt == 0) revert IncompleteRound();
        if (priceUpdatedAt > block.timestamp) revert InvalidRoundTimestamp();
        if (block.timestamp - priceUpdatedAt > priceFeedMaxAge) {
            revert StaleAnswer();
        }
        if (uint256(answer) < priceFeedMinAnswer || uint256(answer) > priceFeedMaxAnswer) revert PriceOutOfBounds();

        /* Set the last update timestamp and block. */
        lastPriceFeedUpdateTime = block.timestamp;
        lastPriceFeedUpdateBlock = block.number;

        if (prevEthUsdPrice == 0 && ethUsdPrice == 0) {
            /* If this is the very first price update, set previous equal to latest. */
            prevEthUsdPrice = ethUsdPrice = uint256(answer);
        } else {
            prevEthUsdPrice = ethUsdPrice;
            ethUsdPrice = uint256(answer);
        }
    }

    /**
     * @dev Calculate the cost in wei to rent storage units.
     */
    function _price(uint256 units) internal returns (uint256) {
        return _price(units, usdUnitPrice, _ethUsdPrice());
    }

    /**
     * @dev Calculate the cost in wei to rent storage units.
     *
     * @param units      Number of storage units. Integer, no decimals.
     * @param usdPerUnit Unit price in USD. Fixed point with 8 decimals.
     * @param usdPerEth  ETH/USD price. Fixed point with 8 decimals.
     *
     * @return uint256 price in wei, i.e. 18 decimals.
     */
    function _price(uint256 units, uint256 usdPerUnit, uint256 usdPerEth) internal pure returns (uint256) {
        return (units * usdPerUnit).divWadUp(usdPerEth);
    }

    /*//////////////////////////////////////////////////////////////
                         PERMISSIONED ACTIONS
    //////////////////////////////////////////////////////////////*/

    /**
     * @inheritdoc IStorageRegistry
     */
    function credit(uint256 fid, uint256 units) external onlyOperator whenNotDeprecated whenNotPaused {
        if (units == 0) revert InvalidAmount();
        if (rentedUnits + units > maxUnits) revert ExceedsCapacity();

        rentedUnits += units;
        emit Rent(msg.sender, fid, units);
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function batchCredit(
        uint256[] calldata fids,
        uint256 units
    ) external onlyOperator whenNotDeprecated whenNotPaused {
        if (units == 0) revert InvalidAmount();
        uint256 totalUnits = fids.length * units;
        if (rentedUnits + totalUnits > maxUnits) revert ExceedsCapacity();
        rentedUnits += totalUnits;
        for (uint256 i; i < fids.length; ++i) {
            emit Rent(msg.sender, fids[i], units);
        }
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function continuousCredit(
        uint256 start,
        uint256 end,
        uint256 units
    ) external onlyOperator whenNotDeprecated whenNotPaused {
        if (units == 0) revert InvalidAmount();
        if (start >= end) revert InvalidRangeInput();

        uint256 len = end - start + 1;
        uint256 totalUnits = len * units;
        if (rentedUnits + totalUnits > maxUnits) revert ExceedsCapacity();
        rentedUnits += totalUnits;
        for (uint256 i; i < len; ++i) {
            emit Rent(msg.sender, start + i, units);
        }
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function refreshPrice() external {
        if (!hasRole(OWNER_ROLE, msg.sender) && !hasRole(TREASURER_ROLE, msg.sender)) revert Unauthorized();
        _refreshPrice();
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setPriceFeed(AggregatorV3Interface feed) external onlyOwner {
        emit SetPriceFeed(address(priceFeed), address(feed));
        priceFeed = feed;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setUptimeFeed(AggregatorV3Interface feed) external onlyOwner {
        emit SetUptimeFeed(address(uptimeFeed), address(feed));
        uptimeFeed = feed;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setPrice(uint256 usdPrice) external onlyOwner {
        emit SetPrice(usdUnitPrice, usdPrice);
        usdUnitPrice = usdPrice;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setFixedEthUsdPrice(uint256 fixedPrice) external onlyOwner {
        if (fixedPrice != 0) {
            if (fixedPrice < priceFeedMinAnswer || fixedPrice > priceFeedMaxAnswer) revert InvalidFixedPrice();
        }
        emit SetFixedEthUsdPrice(fixedEthUsdPrice, fixedPrice);
        fixedEthUsdPrice = fixedPrice;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setMaxUnits(uint256 max) external onlyOwner {
        emit SetMaxUnits(maxUnits, max);
        maxUnits = max;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setDeprecationTimestamp(uint256 timestamp) external onlyOwner {
        if (timestamp < block.timestamp) revert InvalidDeprecationTimestamp();
        emit SetDeprecationTimestamp(deprecationTimestamp, timestamp);
        deprecationTimestamp = timestamp;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setCacheDuration(uint256 duration) external onlyOwner {
        emit SetCacheDuration(priceFeedCacheDuration, duration);
        priceFeedCacheDuration = duration;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setMaxAge(uint256 age) external onlyOwner {
        emit SetMaxAge(priceFeedMaxAge, age);
        priceFeedMaxAge = age;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setMinAnswer(uint256 minPrice) external onlyOwner {
        if (minPrice >= priceFeedMaxAnswer) revert InvalidMinAnswer();
        emit SetMinAnswer(priceFeedMinAnswer, minPrice);
        priceFeedMinAnswer = minPrice;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setMaxAnswer(uint256 maxPrice) external onlyOwner {
        if (maxPrice <= priceFeedMinAnswer) revert InvalidMaxAnswer();
        emit SetMaxAnswer(priceFeedMaxAnswer, maxPrice);
        priceFeedMaxAnswer = maxPrice;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setGracePeriod(uint256 period) external onlyOwner {
        emit SetGracePeriod(uptimeFeedGracePeriod, period);
        uptimeFeedGracePeriod = period;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function setVault(address vaultAddr) external onlyOwner {
        if (vaultAddr == address(0)) revert InvalidAddress();
        emit SetVault(vault, vaultAddr);
        vault = vaultAddr;
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function withdraw(uint256 amount) external onlyTreasurer {
        emit Withdraw(vault, amount);
        vault.sendNative(amount);
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function pause() external onlyOwner {
        _pause();
    }

    /**
     * @inheritdoc IStorageRegistry
     */
    function unpause() external onlyOwner {
        _unpause();
    }
}

File 2 of 17 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AggregatorV3Interface {

  function decimals()
    external
    view
    returns (
      uint8
    );

  function description()
    external
    view
    returns (
      string memory
    );

  function version()
    external
    view
    returns (
      uint256
    );

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(
    uint80 _roundId
  )
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

  function latestRoundData()
    external
    view
    returns (
      uint80 roundId,
      int256 answer,
      uint256 startedAt,
      uint256 updatedAt,
      uint80 answeredInRound
    );

}

File 3 of 17 : AccessControlEnumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override {
        super._grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        super._revokeRole(role, account);
        _roleMembers[role].remove(account);
    }
}

File 4 of 17 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 5 of 17 : FixedPointMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    function powWad(int256 x, int256 y) internal pure returns (int256) {
        // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)
        return expWad((lnWad(x) * y) / int256(WAD)); // Using ln(x) means x must be greater than 0.
    }

    function expWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            // When the result is < 0.5 we return zero. This happens when
            // x <= floor(log(0.5e18) * 1e18) ~ -42e18
            if (x <= -42139678854452767551) return 0;

            // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
            // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
            if (x >= 135305999368893231589) revert("EXP_OVERFLOW");

            // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
            // for more intermediate precision and a binary basis. This base conversion
            // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
            x = (x << 78) / 5**18;

            // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
            // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
            // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
            int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
            x = x - k * 54916777467707473351141471128;

            // k is in the range [-61, 195].

            // Evaluate using a (6, 7)-term rational approximation.
            // p is made monic, we'll multiply by a scale factor later.
            int256 y = x + 1346386616545796478920950773328;
            y = ((y * x) >> 96) + 57155421227552351082224309758442;
            int256 p = y + x - 94201549194550492254356042504812;
            p = ((p * y) >> 96) + 28719021644029726153956944680412240;
            p = p * x + (4385272521454847904659076985693276 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            int256 q = x - 2855989394907223263936484059900;
            q = ((q * x) >> 96) + 50020603652535783019961831881945;
            q = ((q * x) >> 96) - 533845033583426703283633433725380;
            q = ((q * x) >> 96) + 3604857256930695427073651918091429;
            q = ((q * x) >> 96) - 14423608567350463180887372962807573;
            q = ((q * x) >> 96) + 26449188498355588339934803723976023;

            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial won't have zeros in the domain as all its roots are complex.
                // No scaling is necessary because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r should be in the range (0.09, 0.25) * 2**96.

            // We now need to multiply r by:
            // * the scale factor s = ~6.031367120.
            // * the 2**k factor from the range reduction.
            // * the 1e18 / 2**96 factor for base conversion.
            // We do this all at once, with an intermediate result in 2**213
            // basis, so the final right shift is always by a positive amount.
            r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
        }
    }

    function lnWad(int256 x) internal pure returns (int256 r) {
        unchecked {
            require(x > 0, "UNDEFINED");

            // We want to convert x from 10**18 fixed point to 2**96 fixed point.
            // We do this by multiplying by 2**96 / 10**18. But since
            // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
            // and add ln(2**96 / 10**18) at the end.

            // Reduce range of x to (1, 2) * 2**96
            // ln(2^k * x) = k * ln(2) + ln(x)
            int256 k = int256(log2(uint256(x))) - 96;
            x <<= uint256(159 - k);
            x = int256(uint256(x) >> 159);

            // Evaluate using a (8, 8)-term rational approximation.
            // p is made monic, we will multiply by a scale factor later.
            int256 p = x + 3273285459638523848632254066296;
            p = ((p * x) >> 96) + 24828157081833163892658089445524;
            p = ((p * x) >> 96) + 43456485725739037958740375743393;
            p = ((p * x) >> 96) - 11111509109440967052023855526967;
            p = ((p * x) >> 96) - 45023709667254063763336534515857;
            p = ((p * x) >> 96) - 14706773417378608786704636184526;
            p = p * x - (795164235651350426258249787498 << 96);

            // We leave p in 2**192 basis so we don't need to scale it back up for the division.
            // q is monic by convention.
            int256 q = x + 5573035233440673466300451813936;
            q = ((q * x) >> 96) + 71694874799317883764090561454958;
            q = ((q * x) >> 96) + 283447036172924575727196451306956;
            q = ((q * x) >> 96) + 401686690394027663651624208769553;
            q = ((q * x) >> 96) + 204048457590392012362485061816622;
            q = ((q * x) >> 96) + 31853899698501571402653359427138;
            q = ((q * x) >> 96) + 909429971244387300277376558375;
            assembly {
                // Div in assembly because solidity adds a zero check despite the unchecked.
                // The q polynomial is known not to have zeros in the domain.
                // No scaling required because p is already 2**96 too large.
                r := sdiv(p, q)
            }

            // r is in the range (0, 0.125) * 2**96

            // Finalization, we need to:
            // * multiply by the scale factor s = 5.549…
            // * add ln(2**96 / 10**18)
            // * add k * ln(2)
            // * multiply by 10**18 / 2**96 = 5**18 >> 78

            // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
            r *= 1677202110996718588342820967067443963516166;
            // add ln(2) * k * 5e18 * 2**192
            r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
            // add ln(2**96 / 10**18) * 5e18 * 2**192
            r += 600920179829731861736702779321621459595472258049074101567377883020018308;
            // base conversion: mul 2**18 / 2**192
            r >>= 174;
        }
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function log2(uint256 x) internal pure returns (uint256 r) {
        require(x > 0, "UNDEFINED");

        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            r := or(r, shl(2, lt(0xf, shr(r, x))))
            r := or(r, shl(1, lt(0x3, shr(r, x))))
            r := or(r, lt(0x1, shr(r, x)))
        }
    }
}

File 6 of 17 : IStorageRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import {AggregatorV3Interface} from "chainlink/v0.8/interfaces/AggregatorV3Interface.sol";

interface IStorageRegistry {
    /*//////////////////////////////////////////////////////////////
                                CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Contract version specified in the Farcaster protocol version scheme.
     */
    function VERSION() external view returns (string memory);

    /*//////////////////////////////////////////////////////////////
                              PARAMETERS
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Chainlink ETH/USD price feed.
     */
    function priceFeed() external view returns (AggregatorV3Interface);

    /**
     * @notice Chainlink L2 sequencer uptime feed.
     */
    function uptimeFeed() external view returns (AggregatorV3Interface);

    /**
     * @notice Block timestamp at which this contract will no longer accept storage rent payments.
     *         Changeable by owner.
     */
    function deprecationTimestamp() external view returns (uint256);

    /**
     * @notice Price per storage unit in USD. Fixed point value with 8 decimals, e.g. 5e8 = $5 USD.
     *         Changeable by owner.
     */
    function usdUnitPrice() external view returns (uint256);

    /**
     * @notice A fixed ETH/USD price which overrides the Chainlink feed. If this value is nonzero,
     *         we disable external calls to the price feed and use this price. Changeable by owner.
     *         To be used in the event of a price feed failure.
     */
    function fixedEthUsdPrice() external view returns (uint256);

    /**
     * @notice Total capacity of storage units. Changeable by owner.
     */
    function maxUnits() external view returns (uint256);

    /**
     * @notice Duration to cache ethUsdPrice before updating from the price feed. Changeable by owner.
     */
    function priceFeedCacheDuration() external view returns (uint256);

    /**
     * @notice Max age of a price feed answer before it is considered stale. Changeable by owner.
     */
    function priceFeedMaxAge() external view returns (uint256);

    /**
     * @notice Lower bound on acceptable price feed answer. Changeable by owner.
     */
    function priceFeedMinAnswer() external view returns (uint256);

    /**
     * @notice Upper bound on acceptable price feed answer. Changeable by owner.
     */
    function priceFeedMaxAnswer() external view returns (uint256);

    /**
     * @notice Period in seconds to wait after the L2 sequencer restarts before resuming rentals.
     *         See: https://docs.chain.link/data-feeds/l2-sequencer-feeds. Changeable by owner.
     */
    function uptimeFeedGracePeriod() external view returns (uint256);

    /**
     * @notice Address to which the treasurer role can withdraw funds. Changeable by owner.
     */
    function vault() external view returns (address);

    /**
     * @notice Total number of storage units that have been rented.
     */
    function rentedUnits() external view returns (uint256);

    /**
     * @notice Cached Chainlink ETH/USD price.
     */
    function ethUsdPrice() external view returns (uint256);

    /**
     * @notice Previously cached Chainlink ETH/USD price.
     */
    function prevEthUsdPrice() external view returns (uint256);

    /**
     * @notice Timestamp of the last update to ethUsdPrice.
     */
    function lastPriceFeedUpdateTime() external view returns (uint256);

    /**
     * @notice Block number of the last update to ethUsdPrice.
     */
    function lastPriceFeedUpdateBlock() external view returns (uint256);

    /*//////////////////////////////////////////////////////////////
                        STORAGE RENTAL LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Rent storage for a given fid for a year. The caller must provide at least
     *         price(units) wei of payment. Any excess payment will be refunded to the caller. Hubs
     *         will issue storage for 365 days + 30 day grace period after which it expires.
     *
     *         RentedUnits is never decremented on the contract even as the assigned storage expires
     *         on the hubs. This is done to keep the contract simple since we expect to launch a new
     *         storage contract within the year and deprecate this one. Even if that does not occur,
     *         the existing maxUnits parameter can be tweaked to account for expired units.
     *
     * @param fid   The fid that will receive the storage units.
     * @param units Number of storage units to rent.
     */
    function rent(uint256 fid, uint256 units) external payable returns (uint256 overpayment);

    /**
     * @notice Rent storage for multiple fids for a year. The caller must provide at least
     *         price(units) wei of payment where units is the sum of storage units requested across
     *         the fids. See comments on rent() for additional details.
     *
     * @param fids  An array of fids.
     * @param units An array of storage unit quantities. Must be the same length as the fids array.
     */
    function batchRent(uint256[] calldata fids, uint256[] calldata units) external payable;

    /*//////////////////////////////////////////////////////////////
                              PRICE VIEWS
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Calculate the cost in wei to rent one storage unit.
     *
     * @return uint256 cost in wei.
     */
    function unitPrice() external view returns (uint256);

    /**
     * @notice Calculate the cost in wei to rent the given number of storage units.
     *
     * @param units Number of storage units.
     * @return uint256 cost in wei.
     */
    function price(uint256 units) external view returns (uint256);

    /*//////////////////////////////////////////////////////////////
                         PERMISSIONED ACTIONS
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Credit a single fid with free storage units. Only callable by operator.
     *
     * @param fid   The fid that will receive the credit.
     * @param units Number of storage units to credit.
     */
    function credit(uint256 fid, uint256 units) external;

    /**
     * @notice Credit multiple fids with free storage units. Only callable by operator.
     *
     * @param fids  An array of fids.
     * @param units Number of storage units per fid.
     */
    function batchCredit(uint256[] calldata fids, uint256 units) external;

    /**
     * @notice Credit a continuous sequence of fids with free storage units. Only callable by operator.
     *
     * @param start Lowest fid in sequence (inclusive).
     * @param end   Highest fid in sequence (inclusive).
     * @param units Number of storage units per fid.
     */
    function continuousCredit(uint256 start, uint256 end, uint256 units) external;

    /**
     * @notice Force refresh the cached Chainlink ETH/USD price. Callable by owner and treasurer.
     */
    function refreshPrice() external;

    /**
     * @notice Change the price feed addresss. Callable by owner.
     *
     * @param feed The new price feed.
     */
    function setPriceFeed(AggregatorV3Interface feed) external;

    /**
     * @notice Change the uptime feed addresss. Callable by owner.
     *
     * @param feed The new uptime feed.
     */
    function setUptimeFeed(AggregatorV3Interface feed) external;

    /**
     * @notice Change the USD price per storage unit. Callable by owner.
     *
     * @param usdPrice The new unit price in USD. Fixed point value with 8 decimals.
     */
    function setPrice(uint256 usdPrice) external;

    /**
     * @notice Set the fixed ETH/USD price, disabling the price feed if the value is
     *         nonzero. This is an emergency fallback in case of a price feed failure.
     *         Only callable by owner.
     *
     * @param fixedPrice The new fixed ETH/USD price. Fixed point value with 8 decimals.
     *                   Setting this value back to zero from a nonzero value will
     *                   re-enable the price feed.
     */
    function setFixedEthUsdPrice(uint256 fixedPrice) external;

    /**
     * @notice Change the maximum supply of storage units. Only callable by owner.
     *
     * @param max The new maximum supply of storage units.
     */
    function setMaxUnits(uint256 max) external;

    /**
     * @notice Change the deprecationTimestamp. Only callable by owner.
     *
     * @param timestamp The new deprecationTimestamp. Must be at least equal to block.timestamp.
     */
    function setDeprecationTimestamp(uint256 timestamp) external;

    /**
     * @notice Change the priceFeedCacheDuration. Only callable by owner.
     *
     * @param duration The new priceFeedCacheDuration.
     */
    function setCacheDuration(uint256 duration) external;

    /**
     * @notice Change the priceFeedMaxAge. Only callable by owner.
     *
     * @param age The new priceFeedMaxAge.
     */
    function setMaxAge(uint256 age) external;

    /**
     * @notice Change the priceFeedMinAnswer. Only callable by owner.
     *
     * @param minPrice The new priceFeedMinAnswer. Must be less than current priceFeedMaxAnswer.
     */
    function setMinAnswer(uint256 minPrice) external;

    /**
     * @notice Change the priceFeedMaxAnswer. Only callable by owner.
     *
     * @param maxPrice The new priceFeedMaxAnswer. Must be greater than current priceFeedMinAnswer.
     */
    function setMaxAnswer(uint256 maxPrice) external;

    /**
     * @notice Change the uptimeFeedGracePeriod. Only callable by owner.
     *
     * @param period The new uptimeFeedGracePeriod.
     */
    function setGracePeriod(uint256 period) external;

    /**
     * @notice Change the vault address that can receive funds from this contract.
     *         Only callable by owner.
     *
     * @param vaultAddr The new vault address.
     */
    function setVault(address vaultAddr) external;

    /**
     * @notice Withdraw a specified amount of ether from the contract balance to the vault.
     *         Only callable by treasurer.
     *
     * @param amount The amount of ether to withdraw.
     */
    function withdraw(uint256 amount) external;

    /**
     * @notice Pause, disabling rentals and credits.
     *         Only callable by owner.
     */
    function pause() external;

    /**
     * @notice Unpause, enabling rentals and credits.
     *         Only callable by owner.
     */
    function unpause() external;
}

File 7 of 17 : TransferHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

library TransferHelper {
    /// @dev Revert when a native token transfer fails.
    error CallFailed();

    /**
     * @dev Native token transfer helper.
     */
    function sendNative(address to, uint256 amount) internal {
        bool success;

        // solhint-disable-next-line no-inline-assembly
        assembly {
            // Transfer the native token and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        if (!success) revert CallFailed();
    }
}

File 8 of 17 : IAccessControlEnumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

File 9 of 17 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 10 of 17 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 11 of 17 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 12 of 17 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 13 of 17 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 14 of 17 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 15 of 17 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 16 of 17 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 17 of 17 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "solmate/=lib/solmate/",
    "openzeppelin/=lib/openzeppelin-contracts/",
    "openzeppelin-latest/=lib/openzeppelin-latest/",
    "chainlink/=lib/chainlink-brownie-contracts/contracts/src/",
    "chainlink-brownie-contracts/=lib/chainlink-brownie-contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-latest/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract AggregatorV3Interface","name":"_priceFeed","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"_uptimeFeed","type":"address"},{"internalType":"uint256","name":"_initialUsdUnitPrice","type":"uint256"},{"internalType":"uint256","name":"_initialMaxUnits","type":"uint256"},{"internalType":"address","name":"_initialVault","type":"address"},{"internalType":"address","name":"_initialRoleAdmin","type":"address"},{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"address","name":"_initialOperator","type":"address"},{"internalType":"address","name":"_initialTreasurer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallFailed","type":"error"},{"inputs":[],"name":"ContractDeprecated","type":"error"},{"inputs":[],"name":"ExceedsCapacity","type":"error"},{"inputs":[],"name":"GracePeriodNotOver","type":"error"},{"inputs":[],"name":"IncompleteRound","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidBatchInput","type":"error"},{"inputs":[],"name":"InvalidDeprecationTimestamp","type":"error"},{"inputs":[],"name":"InvalidFixedPrice","type":"error"},{"inputs":[],"name":"InvalidMaxAnswer","type":"error"},{"inputs":[],"name":"InvalidMinAnswer","type":"error"},{"inputs":[],"name":"InvalidPayment","type":"error"},{"inputs":[],"name":"InvalidPrice","type":"error"},{"inputs":[],"name":"InvalidRangeInput","type":"error"},{"inputs":[],"name":"InvalidRoundTimestamp","type":"error"},{"inputs":[],"name":"NotOperator","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotTreasurer","type":"error"},{"inputs":[],"name":"PriceOutOfBounds","type":"error"},{"inputs":[],"name":"SequencerDown","type":"error"},{"inputs":[],"name":"StaleAnswer","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"uint256","name":"fid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"units","type":"uint256"}],"name":"Rent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"SetCacheDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"name":"SetDeprecationTimestamp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"SetFixedEthUsdPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPeriod","type":"uint256"}],"name":"SetGracePeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldAge","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAge","type":"uint256"}],"name":"SetMaxAge","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"SetMaxAnswer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMax","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"SetMaxUnits","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"SetMinAnswer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"SetPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldFeed","type":"address"},{"indexed":false,"internalType":"address","name":"newFeed","type":"address"}],"name":"SetPriceFeed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldFeed","type":"address"},{"indexed":false,"internalType":"address","name":"newFeed","type":"address"}],"name":"SetUptimeFeed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldVault","type":"address"},{"indexed":false,"internalType":"address","name":"newVault","type":"address"}],"name":"SetVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"fids","type":"uint256[]"},{"internalType":"uint256","name":"units","type":"uint256"}],"name":"batchCredit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"fids","type":"uint256[]"},{"internalType":"uint256[]","name":"units","type":"uint256[]"}],"name":"batchRent","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"units","type":"uint256"}],"name":"continuousCredit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fid","type":"uint256"},{"internalType":"uint256","name":"units","type":"uint256"}],"name":"credit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deprecationTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethUsdPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fixedEthUsdPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPriceFeedUpdateBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPriceFeedUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxUnits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prevEthUsdPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"units","type":"uint256"}],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedCacheDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedMaxAge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedMaxAnswer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedMinAnswer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refreshPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fid","type":"uint256"},{"internalType":"uint256","name":"units","type":"uint256"}],"name":"rent","outputs":[{"internalType":"uint256","name":"overpayment","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"rentedUnits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setCacheDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"setDeprecationTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fixedPrice","type":"uint256"}],"name":"setFixedEthUsdPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"period","type":"uint256"}],"name":"setGracePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"age","type":"uint256"}],"name":"setMaxAge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxPrice","type":"uint256"}],"name":"setMaxAnswer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"setMaxUnits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minPrice","type":"uint256"}],"name":"setMinAnswer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdPrice","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"}],"name":"setPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AggregatorV3Interface","name":"feed","type":"address"}],"name":"setUptimeFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vaultAddr","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unitPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uptimeFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uptimeFeedGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdUnitPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060405162003ec738038062003ec7833981016040819052620000349162000873565b600280546001600160a81b0319166101006001600160a01b038c1690810291909117909155604080516000815260208101929092527fc02f01e22efc017c1c952d0eef1a8fc038571f14ea5a285d79d1d7ba87d8b001910160405180910390a1600380546001600160a01b0319166001600160a01b038a16908117909155604080516000815260208101929092527fffca0dcf4a77eaddf80becc294c7f9b5fe6afe652e75c888b8afc76c75d8e658910160405180910390a1620000fd426301e1338062000949565b6004819055604080516000815260208101929092527f27e030644fe653b53e98fbd0ca5004392da63705b0806619a43324647715bc6b910160405180910390a160058790556040805160008152602081018990527ff9317dc3bc6dda0e00e43855c2c30847aeafb8dcea9d2ce86e9ce7a83d549f01910160405180910390a160078690556040805160008152602081018890527fa75b962aa425276de62bec76aeb43cacc12d2b132498ae1115500c23dc35fbe4910160405180910390a1620151806008819055604080516000815260208101929092527fba21d40bb8770d5fa02e1971806473e12480167182e829c0fc86addb21e2b77d910160405180910390a1611c206009819055604080516000815260208101929092527fdab04eb6792be47147c80ea1681f6b05c2961bed4ea123bcb7f8d4c10aa2df3e910160405180910390a1610e10600c819055604080516000815260208101929092527f31c130faaf861e1e61ca087cc48c410d9099885350e9beb4dad1175cb77a6545910160405180910390a16402540be400600a819055604080516000815260208101929092527f5ea311a1ef15e7fbfbbe5d4b8160fd93a072abf0c64d50591e17306e3b7aa628910160405180910390a164e8d4a51000600b819055604080516000815260208101929092527fea30ce82bdf6bad7bc587c9a5e15e0f655724d1e3a680df280898a2aab512d39910160405180910390a1600d80546001600160a01b0319166001600160a01b038716908117909155604080516000815260208101929092527f22a9f7c8a21e91a43518238948d4ed67511ad8492ca0e13fdbc93c134701a72a910160405180910390a16200037760008562000414565b620003a37fb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e8462000414565b620003cf7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b9298362000414565b620003fb7f3496e2e73c4d42b75d702e60d9e48102720b8691234415963a5a857b86425d078262000414565b620004056200043f565b505050505050505050620009e7565b62000420828262000747565b60008281526001602052604090206200043a9082620007e8565b505050565b600080600080600360009054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801562000499573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004bf91906200097c565b50935093509350935082600014620004e95760405162032b3d60e81b815260040160405180910390fd5b836001600160501b03166000036200051457604051638ad52bdd60e01b815260040160405180910390fd5b806000036200053657604051638ad52bdd60e01b815260040160405180910390fd5b4281111562000558576040516374016e9d60e11b815260040160405180910390fd5b6000620005668342620009d1565b9050600c548110156200058c5760405163d15f73b560e01b815260040160405180910390fd5b6000806000600260019054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015620005e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200060b91906200097c565b509350509250925060008213620006345760405162bfc92160e01b815260040160405180910390fd5b826001600160501b03166000036200065f57604051638ad52bdd60e01b815260040160405180910390fd5b806000036200068157604051638ad52bdd60e01b815260040160405180910390fd5b42811115620006a3576040516374016e9d60e11b815260040160405180910390fd5b600954620006b28242620009d1565b1115620006d257604051630e09c18960e31b815260040160405180910390fd5b600a54821080620006e45750600b5482115b156200070357604051636e4ba61d60e01b815260040160405180910390fd5b42601155436012556010541580156200071c5750600f54155b156200073257600f82905560108290556200073d565b600f80546010558290555b5050505050505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620007e4576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620007a33390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000620007ff836001600160a01b03841662000808565b90505b92915050565b6000818152600183016020526040812054620008515750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000802565b50600062000802565b6001600160a01b03811681146200087057600080fd5b50565b60008060008060008060008060006101208a8c0312156200089357600080fd5b8951620008a0816200085a565b60208b0151909950620008b3816200085a565b8098505060408a0151965060608a0151955060808a0151620008d5816200085a565b60a08b0151909550620008e8816200085a565b60c08b0151909450620008fb816200085a565b60e08b01519093506200090e816200085a565b6101008b015190925062000922816200085a565b809150509295985092959850929598565b634e487b7160e01b600052601160045260246000fd5b8082018082111562000802576200080262000933565b80516001600160501b03811681146200097757600080fd5b919050565b600080600080600060a086880312156200099557600080fd5b620009a0866200095f565b9450602086015193506040860151925060608601519150620009c5608087016200095f565b90509295509295909350565b8181038181111562000802576200080262000933565b6134d080620009f76000396000f3fe6080604052600436106103345760003560e01c8063783a112b116101b0578063b0949137116100ec578063d547741f11610095578063e75b434b1161006f578063e75b434b146108de578063f2f65960146108fe578063fbfa77cf1461091e578063ffa1ad741461094b57600080fd5b8063d547741f14610893578063e19a963f146108b3578063e73faa2d146108c957600080fd5b8063ca15c873116100c6578063ca15c8731461083d578063cf980c001461085d578063d285e8fd1461087357600080fd5b8063b0949137146107f1578063b3a90c6714610807578063c2e46fe01461082757600080fd5b80639010d07c116101595780639478ab8c116101335780639478ab8c14610793578063a217fddf146107a9578063a82c356e146107be578063ab7ccc1c146107d157600080fd5b80639010d07c1461070257806391b7f5ed1461072257806391d148541461074257600080fd5b80638456cb591161018a5780638456cb59146106ad5780638611e6e7146106c25780638d567f86146106e257600080fd5b8063783a112b1461066e57806378888e41146106815780637c01fc4d1461069757600080fd5b80633c67a5b21161027f5780635ae28fc9116102285780636817031b116102025780636817031b146105e65780637078cc1c14610606578063724e78da1461061c578063741bef1a1461063c57600080fd5b80635ae28fc9146105985780635c975abb146105b857806364996ed8146105d057600080fd5b806341392be81161025957806341392be8146105425780634375948c146105585780634fbd12821461057857600080fd5b80633c67a5b2146105025780633f4ba83a1461051757806340df0ba01461052c57600080fd5b80632751c4fd116102e15780632f2ff15d116102bb5780632f2ff15d1461047057806336568abe146104905780633b56125c146104b057600080fd5b80632751c4fd146104245780632c39d6701461043a5780632e1a7d4d1461045057600080fd5b80631a9d70f6116103125780631a9d70f6146103b4578063248a9ca3146103d457806326a49e371461040457600080fd5b806301ffc9a71461033957806306517a291461036e578063194e995114610392575b600080fd5b34801561034557600080fd5b50610359610354366004612fdc565b6109a1565b60405190151581526020015b60405180910390f35b34801561037a57600080fd5b5061038460075481565b604051908152602001610365565b34801561039e57600080fd5b506103b26103ad36600461301e565b6109fd565b005b3480156103c057600080fd5b506103b26103cf366004613037565b610aa6565b3480156103e057600080fd5b506103846103ef36600461301e565b60009081526020819052604090206001015490565b34801561041057600080fd5b5061038461041f36600461301e565b610cae565b34801561043057600080fd5b50610384600e5481565b34801561044657600080fd5b5061038460045481565b34801561045c57600080fd5b506103b261046b36600461301e565b610cef565b34801561047c57600080fd5b506103b261048b366004613085565b610dcc565b34801561049c57600080fd5b506103b26104ab366004613085565b610df6565b3480156104bc57600080fd5b506003546104dd9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610365565b34801561050e57600080fd5b506103b2610eae565b34801561052357600080fd5b506103b2610f5d565b34801561053857600080fd5b5061038460055481565b34801561054e57600080fd5b5061038460095481565b34801561056457600080fd5b506103b261057336600461301e565b610fcd565b34801561058457600080fd5b506103b261059336600461301e565b6110b1565b3480156105a457600080fd5b506103b26105b336600461301e565b611195565b3480156105c457600080fd5b5060025460ff16610359565b3480156105dc57600080fd5b5061038460125481565b3480156105f257600080fd5b506103b26106013660046130b5565b61123e565b34801561061257600080fd5b50610384600c5481565b34801561062857600080fd5b506103b26106373660046130b5565b61138e565b34801561064857600080fd5b506002546104dd90610100900473ffffffffffffffffffffffffffffffffffffffff1681565b61038461067c3660046130d2565b61149b565b34801561068d57600080fd5b5061038460105481565b3480156106a357600080fd5b50610384600a5481565b3480156106b957600080fd5b506103b261161b565b3480156106ce57600080fd5b506103b26106dd36600461301e565b61168b565b3480156106ee57600080fd5b506103b26106fd36600461301e565b611782565b34801561070e57600080fd5b506104dd61071d3660046130d2565b611865565b34801561072e57600080fd5b506103b261073d36600461301e565b61187d565b34801561074e57600080fd5b5061035961075d366004613085565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561079f57600080fd5b50610384600f5481565b3480156107b557600080fd5b50610384600081565b6103b26107cc366004613140565b611926565b3480156107dd57600080fd5b506103b26107ec3660046130d2565b611b81565b3480156107fd57600080fd5b5061038460065481565b34801561081357600080fd5b506103b26108223660046131ac565b611d01565b34801561083357600080fd5b5061038460085481565b34801561084957600080fd5b5061038461085836600461301e565b611ee0565b34801561086957600080fd5b5061038460115481565b34801561087f57600080fd5b506103b261088e36600461301e565b611ef7565b34801561089f57600080fd5b506103b26108ae366004613085565b611fa0565b3480156108bf57600080fd5b50610384600b5481565b3480156108d557600080fd5b50610384611fc5565b3480156108ea57600080fd5b506103b26108f93660046130b5565b611fd6565b34801561090a57600080fd5b506103b261091936600461301e565b6120d9565b34801561092a57600080fd5b50600d546104dd9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561095757600080fd5b506109946040518060400160405280600a81526020017f323032332e30382e32330000000000000000000000000000000000000000000081525081565b604051610365919061321c565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806109f757506109f782612182565b92915050565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16610a65576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460408051918252602082018390527fba21d40bb8770d5fa02e1971806473e12480167182e829c0fc86addb21e2b77d910160405180910390a1600855565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff16610b0e576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004544210610b49576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b51612219565b80600003610b8b576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818310610bc4576040517f59d0556c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610bd0848461329c565b610bdb9060016132af565b90506000610be983836132c2565b905060075481600e54610bfc91906132af565b1115610c34576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e6000828254610c4691906132af565b90915550600090505b82811015610ca657610c6181876132af565b60405185815233907faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f9060200160405180910390a3610c9f816132d9565b9050610c4f565b505050505050565b600080600654600014610cc45750600654610cdb565b4360125403610cd65750601054610cdb565b50600f545b610ce88360055483612286565b9392505050565b3360009081527f991c3211066600fc98d95d017c66f2884b1fa3d4cabc2576d000f3cc80931bda602052604090205460ff16610d57576040517f5647892800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d5460405182815273ffffffffffffffffffffffffffffffffffffffff909116907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a2600d54610dc99073ffffffffffffffffffffffffffffffffffffffff16826122a4565b50565b600082815260208190526040902060010154610de7816122e9565b610df183836122f3565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610eaa8282612315565b5050565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16158015610f1c57503360009081527f991c3211066600fc98d95d017c66f2884b1fa3d4cabc2576d000f3cc80931bda602052604090205460ff16155b15610f53576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f5b612337565b565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16610fc5576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f5b612770565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611035576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b548110611070576040517f2098bf9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a5460408051918252602082018390527f5ea311a1ef15e7fbfbbe5d4b8160fd93a072abf0c64d50591e17306e3b7aa628910160405180910390a1600a55565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611119576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a548111611154576040517fa768df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b5460408051918252602082018390527fea30ce82bdf6bad7bc587c9a5e15e0f655724d1e3a680df280898a2aab512d39910160405180910390a1600b55565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166111fd576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460408051918252602082018390527fdab04eb6792be47147c80ea1681f6b05c2961bed4ea123bcb7f8d4c10aa2df3e910160405180910390a1600955565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166112a6576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166112f3576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527f22a9f7c8a21e91a43518238948d4ed67511ad8492ca0e13fdbc93c134701a72a910160405180910390a1600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166113f6576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040805173ffffffffffffffffffffffffffffffffffffffff6101009093048316815291831660208301527fc02f01e22efc017c1c952d0eef1a8fc038571f14ea5a285d79d1d7ba87d8b001910160405180910390a16002805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b600060045442106114d8576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e0612219565b8160000361151a576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075482600e5461152b91906132af565b1115611563576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061156e836127ed565b9050803410156115aa576040517f3c6b4b2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82600e60008282546115bc91906132af565b9091555050604051838152849033907faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f9060200160405180910390a3611602813461329c565b915081156116145761161433836122a4565b5092915050565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611683576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f5b612803565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166116f3576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801561174157600a5481108061170a5750600b5481115b15611741576040517f84477d0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065460408051918252602082018390527f93aee10a56f247b278bffd77edfd1772670a0889d16a01f958afebcce8266432910160405180910390a1600655565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166117ea576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b42811015611824576040517f4d9c314900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045460408051918252602082018390527f27e030644fe653b53e98fbd0ca5004392da63705b0806619a43324647715bc6b910160405180910390a1600455565b6000828152600160205260408120610ce8908361285e565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166118e5576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460408051918252602082018390527ff9317dc3bc6dda0e00e43855c2c30847aeafb8dcea9d2ce86e9ce7a83d549f01910160405180910390a1600555565b6004544210611961576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611969612219565b821580611974575080155b156119ab576040517f0a514b9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8281146119e4576040517f0a514b9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460006119f161286a565b90506000805b86811015611ab1576000868683818110611a1357611a13613311565b90506020020135905080600003611a2a5750611aa1565b611a3481846132af565b9250888883818110611a4857611a48613311565b905060200201353373ffffffffffffffffffffffffffffffffffffffff167faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f83604051611a9791815260200190565b60405180910390a3505b611aaa816132d9565b90506119f7565b506000611abf828585612286565b905080341015611afb576040517f3c6b4b2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075482600e54611b0c91906132af565b1115611b44576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600e6000828254611b5691906132af565b909155505034811015611b7757611b77611b70823461329c565b33906122a4565b5050505050505050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff16611be9576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004544210611c24576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c2c612219565b80600003611c66576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075481600e54611c7791906132af565b1115611caf576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e6000828254611cc191906132af565b9091555050604051818152829033907faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f9060200160405180910390a35050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff16611d69576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004544210611da4576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dac612219565b80600003611de6576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611df282846132c2565b905060075481600e54611e0591906132af565b1115611e3d576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e6000828254611e4f91906132af565b90915550600090505b83811015611ed957848482818110611e7257611e72613311565b905060200201353373ffffffffffffffffffffffffffffffffffffffff167faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f85604051611ec191815260200190565b60405180910390a3611ed2816132d9565b9050611e58565b5050505050565b60008181526001602052604081206109f7906128b2565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611f5f576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075460408051918252602082018390527fa75b962aa425276de62bec76aeb43cacc12d2b132498ae1115500c23dc35fbe4910160405180910390a1600755565b600082815260208190526040902060010154611fbb816122e9565b610df18383612315565b6000611fd16001610cae565b905090565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff1661203e576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527fffca0dcf4a77eaddf80becc294c7f9b5fe6afe652e75c888b8afc76c75d8e658910160405180910390a1600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16612141576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c5460408051918252602082018390527f31c130faaf861e1e61ca087cc48c410d9099885350e9beb4dad1175cb77a6545910160405180910390a1600c55565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806109f757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146109f7565b60025460ff1615610f5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610e97565b600061229c8261229685876132c2565b906128bc565b949350505050565b600080600080600085875af1905080610df1576040517f3204506f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dc981336128d1565b6122fd8282612989565b6000828152600160205260409020610df19082612a79565b61231f8282612a9b565b6000828152600160205260409020610df19082612b52565b600080600080600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156123aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ce919061335f565b50935093509350935082600014612411576040517f032b3d0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8369ffffffffffffffffffff16600003612457576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003612491576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428111156124cb576040517fe802dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006124d7834261329c565b9050600c54811015612515576040517fd15f73b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ab919061335f565b5093505092509250600082136125ec576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8269ffffffffffffffffffff16600003612632576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000361266c576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428111156126a6576040517fe802dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546126b3824261329c565b11156126eb576040517f704e0c4800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a548210806126fc5750600b5482115b15612733576040517f6e4ba61d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426011554360125560105415801561274b5750600f54155b1561275f57600f8290556010829055611b77565b50600f805460105555505050505050565b612778612b74565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60006109f7826005546127fe61286a565b612286565b61280b612219565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586127c33390565b6000610ce88383612be0565b600060065460001461287d575060065490565b60085460115461288d904261329c565b111561289b5761289b612337565b43601254146128ab5750600f5490565b5060105490565b60006109f7825490565b6000610ce883670de0b6b3a764000084612c0a565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eaa5761290f81612c38565b61291a836020612c57565b60405160200161292b9291906133af565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610e979160040161321c565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eaa5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612a1b3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610ce88373ffffffffffffffffffffffffffffffffffffffff8416612e9a565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610eaa5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610ce88373ffffffffffffffffffffffffffffffffffffffff8416612ee9565b60025460ff16610f5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610e97565b6000826000018281548110612bf757612bf7613311565b9060005260206000200154905092915050565b828202811515841585830485141716612c2257600080fd5b6001826001830304018115150290509392505050565b60606109f773ffffffffffffffffffffffffffffffffffffffff831660145b60606000612c668360026132c2565b612c719060026132af565b67ffffffffffffffff811115612c8957612c89613430565b6040519080825280601f01601f191660200182016040528015612cb3576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612cea57612cea613311565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612d4d57612d4d613311565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612d898460026132c2565b612d949060016132af565b90505b6001811115612e31577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612dd557612dd5613311565b1a60f81b828281518110612deb57612deb613311565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612e2a8161345f565b9050612d97565b508315610ce8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e97565b6000818152600183016020526040812054612ee1575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556109f7565b5060006109f7565b60008181526001830160205260408120548015612fd2576000612f0d60018361329c565b8554909150600090612f219060019061329c565b9050818114612f86576000866000018281548110612f4157612f41613311565b9060005260206000200154905080876000018481548110612f6457612f64613311565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612f9757612f97613494565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506109f7565b60009150506109f7565b600060208284031215612fee57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610ce857600080fd5b60006020828403121561303057600080fd5b5035919050565b60008060006060848603121561304c57600080fd5b505081359360208301359350604090920135919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610dc957600080fd5b6000806040838503121561309857600080fd5b8235915060208301356130aa81613063565b809150509250929050565b6000602082840312156130c757600080fd5b8135610ce881613063565b600080604083850312156130e557600080fd5b50508035926020909101359150565b60008083601f84011261310657600080fd5b50813567ffffffffffffffff81111561311e57600080fd5b6020830191508360208260051b850101111561313957600080fd5b9250929050565b6000806000806040858703121561315657600080fd5b843567ffffffffffffffff8082111561316e57600080fd5b61317a888389016130f4565b9096509450602087013591508082111561319357600080fd5b506131a0878288016130f4565b95989497509550505050565b6000806000604084860312156131c157600080fd5b833567ffffffffffffffff8111156131d857600080fd5b6131e4868287016130f4565b909790965060209590950135949350505050565b60005b838110156132135781810151838201526020016131fb565b50506000910152565b602081526000825180602084015261323b8160408501602087016131f8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109f7576109f761326d565b808201808211156109f7576109f761326d565b80820281158282048414176109f7576109f761326d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361330a5761330a61326d565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b805169ffffffffffffffffffff8116811461335a57600080fd5b919050565b600080600080600060a0868803121561337757600080fd5b61338086613340565b94506020860151935060408601519250606086015191506133a360808701613340565b90509295509295909350565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516133e78160178501602088016131f8565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516134248160288401602088016131f8565b01602801949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008161346e5761346e61326d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000815000a00000000000000000000000013e3ee699d1909e989722e753853ae30b17e08c5000000000000000000000000371ead81c9102c9bf4874a9075ffff170f2ee389000000000000000000000000000000000000000000000000000000001dcd65000000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000053c6da835c777ad11159198fbe11f95e5ee6b6920000000000000000000000006d2b70e39c6bc63763098e336323591eb77cd0c6000000000000000000000000d84e32224a249a575a09672da9cb58c381c4837a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106103345760003560e01c8063783a112b116101b0578063b0949137116100ec578063d547741f11610095578063e75b434b1161006f578063e75b434b146108de578063f2f65960146108fe578063fbfa77cf1461091e578063ffa1ad741461094b57600080fd5b8063d547741f14610893578063e19a963f146108b3578063e73faa2d146108c957600080fd5b8063ca15c873116100c6578063ca15c8731461083d578063cf980c001461085d578063d285e8fd1461087357600080fd5b8063b0949137146107f1578063b3a90c6714610807578063c2e46fe01461082757600080fd5b80639010d07c116101595780639478ab8c116101335780639478ab8c14610793578063a217fddf146107a9578063a82c356e146107be578063ab7ccc1c146107d157600080fd5b80639010d07c1461070257806391b7f5ed1461072257806391d148541461074257600080fd5b80638456cb591161018a5780638456cb59146106ad5780638611e6e7146106c25780638d567f86146106e257600080fd5b8063783a112b1461066e57806378888e41146106815780637c01fc4d1461069757600080fd5b80633c67a5b21161027f5780635ae28fc9116102285780636817031b116102025780636817031b146105e65780637078cc1c14610606578063724e78da1461061c578063741bef1a1461063c57600080fd5b80635ae28fc9146105985780635c975abb146105b857806364996ed8146105d057600080fd5b806341392be81161025957806341392be8146105425780634375948c146105585780634fbd12821461057857600080fd5b80633c67a5b2146105025780633f4ba83a1461051757806340df0ba01461052c57600080fd5b80632751c4fd116102e15780632f2ff15d116102bb5780632f2ff15d1461047057806336568abe146104905780633b56125c146104b057600080fd5b80632751c4fd146104245780632c39d6701461043a5780632e1a7d4d1461045057600080fd5b80631a9d70f6116103125780631a9d70f6146103b4578063248a9ca3146103d457806326a49e371461040457600080fd5b806301ffc9a71461033957806306517a291461036e578063194e995114610392575b600080fd5b34801561034557600080fd5b50610359610354366004612fdc565b6109a1565b60405190151581526020015b60405180910390f35b34801561037a57600080fd5b5061038460075481565b604051908152602001610365565b34801561039e57600080fd5b506103b26103ad36600461301e565b6109fd565b005b3480156103c057600080fd5b506103b26103cf366004613037565b610aa6565b3480156103e057600080fd5b506103846103ef36600461301e565b60009081526020819052604090206001015490565b34801561041057600080fd5b5061038461041f36600461301e565b610cae565b34801561043057600080fd5b50610384600e5481565b34801561044657600080fd5b5061038460045481565b34801561045c57600080fd5b506103b261046b36600461301e565b610cef565b34801561047c57600080fd5b506103b261048b366004613085565b610dcc565b34801561049c57600080fd5b506103b26104ab366004613085565b610df6565b3480156104bc57600080fd5b506003546104dd9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610365565b34801561050e57600080fd5b506103b2610eae565b34801561052357600080fd5b506103b2610f5d565b34801561053857600080fd5b5061038460055481565b34801561054e57600080fd5b5061038460095481565b34801561056457600080fd5b506103b261057336600461301e565b610fcd565b34801561058457600080fd5b506103b261059336600461301e565b6110b1565b3480156105a457600080fd5b506103b26105b336600461301e565b611195565b3480156105c457600080fd5b5060025460ff16610359565b3480156105dc57600080fd5b5061038460125481565b3480156105f257600080fd5b506103b26106013660046130b5565b61123e565b34801561061257600080fd5b50610384600c5481565b34801561062857600080fd5b506103b26106373660046130b5565b61138e565b34801561064857600080fd5b506002546104dd90610100900473ffffffffffffffffffffffffffffffffffffffff1681565b61038461067c3660046130d2565b61149b565b34801561068d57600080fd5b5061038460105481565b3480156106a357600080fd5b50610384600a5481565b3480156106b957600080fd5b506103b261161b565b3480156106ce57600080fd5b506103b26106dd36600461301e565b61168b565b3480156106ee57600080fd5b506103b26106fd36600461301e565b611782565b34801561070e57600080fd5b506104dd61071d3660046130d2565b611865565b34801561072e57600080fd5b506103b261073d36600461301e565b61187d565b34801561074e57600080fd5b5061035961075d366004613085565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561079f57600080fd5b50610384600f5481565b3480156107b557600080fd5b50610384600081565b6103b26107cc366004613140565b611926565b3480156107dd57600080fd5b506103b26107ec3660046130d2565b611b81565b3480156107fd57600080fd5b5061038460065481565b34801561081357600080fd5b506103b26108223660046131ac565b611d01565b34801561083357600080fd5b5061038460085481565b34801561084957600080fd5b5061038461085836600461301e565b611ee0565b34801561086957600080fd5b5061038460115481565b34801561087f57600080fd5b506103b261088e36600461301e565b611ef7565b34801561089f57600080fd5b506103b26108ae366004613085565b611fa0565b3480156108bf57600080fd5b50610384600b5481565b3480156108d557600080fd5b50610384611fc5565b3480156108ea57600080fd5b506103b26108f93660046130b5565b611fd6565b34801561090a57600080fd5b506103b261091936600461301e565b6120d9565b34801561092a57600080fd5b50600d546104dd9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561095757600080fd5b506109946040518060400160405280600a81526020017f323032332e30382e32330000000000000000000000000000000000000000000081525081565b604051610365919061321c565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806109f757506109f782612182565b92915050565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16610a65576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085460408051918252602082018390527fba21d40bb8770d5fa02e1971806473e12480167182e829c0fc86addb21e2b77d910160405180910390a1600855565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff16610b0e576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004544210610b49576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b51612219565b80600003610b8b576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818310610bc4576040517f59d0556c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610bd0848461329c565b610bdb9060016132af565b90506000610be983836132c2565b905060075481600e54610bfc91906132af565b1115610c34576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e6000828254610c4691906132af565b90915550600090505b82811015610ca657610c6181876132af565b60405185815233907faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f9060200160405180910390a3610c9f816132d9565b9050610c4f565b505050505050565b600080600654600014610cc45750600654610cdb565b4360125403610cd65750601054610cdb565b50600f545b610ce88360055483612286565b9392505050565b3360009081527f991c3211066600fc98d95d017c66f2884b1fa3d4cabc2576d000f3cc80931bda602052604090205460ff16610d57576040517f5647892800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d5460405182815273ffffffffffffffffffffffffffffffffffffffff909116907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a2600d54610dc99073ffffffffffffffffffffffffffffffffffffffff16826122a4565b50565b600082815260208190526040902060010154610de7816122e9565b610df183836122f3565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610eaa8282612315565b5050565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16158015610f1c57503360009081527f991c3211066600fc98d95d017c66f2884b1fa3d4cabc2576d000f3cc80931bda602052604090205460ff16155b15610f53576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f5b612337565b565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16610fc5576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f5b612770565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611035576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b548110611070576040517f2098bf9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a5460408051918252602082018390527f5ea311a1ef15e7fbfbbe5d4b8160fd93a072abf0c64d50591e17306e3b7aa628910160405180910390a1600a55565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611119576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a548111611154576040517fa768df8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b5460408051918252602082018390527fea30ce82bdf6bad7bc587c9a5e15e0f655724d1e3a680df280898a2aab512d39910160405180910390a1600b55565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166111fd576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460408051918252602082018390527fdab04eb6792be47147c80ea1681f6b05c2961bed4ea123bcb7f8d4c10aa2df3e910160405180910390a1600955565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166112a6576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166112f3576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527f22a9f7c8a21e91a43518238948d4ed67511ad8492ca0e13fdbc93c134701a72a910160405180910390a1600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166113f6576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002546040805173ffffffffffffffffffffffffffffffffffffffff6101009093048316815291831660208301527fc02f01e22efc017c1c952d0eef1a8fc038571f14ea5a285d79d1d7ba87d8b001910160405180910390a16002805473ffffffffffffffffffffffffffffffffffffffff909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b600060045442106114d8576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e0612219565b8160000361151a576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075482600e5461152b91906132af565b1115611563576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061156e836127ed565b9050803410156115aa576040517f3c6b4b2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82600e60008282546115bc91906132af565b9091555050604051838152849033907faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f9060200160405180910390a3611602813461329c565b915081156116145761161433836122a4565b5092915050565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611683576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f5b612803565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166116f3576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801561174157600a5481108061170a5750600b5481115b15611741576040517f84477d0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065460408051918252602082018390527f93aee10a56f247b278bffd77edfd1772670a0889d16a01f958afebcce8266432910160405180910390a1600655565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166117ea576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b42811015611824576040517f4d9c314900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045460408051918252602082018390527f27e030644fe653b53e98fbd0ca5004392da63705b0806619a43324647715bc6b910160405180910390a1600455565b6000828152600160205260408120610ce8908361285e565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff166118e5576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460408051918252602082018390527ff9317dc3bc6dda0e00e43855c2c30847aeafb8dcea9d2ce86e9ce7a83d549f01910160405180910390a1600555565b6004544210611961576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611969612219565b821580611974575080155b156119ab576040517f0a514b9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8281146119e4576040517f0a514b9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055460006119f161286a565b90506000805b86811015611ab1576000868683818110611a1357611a13613311565b90506020020135905080600003611a2a5750611aa1565b611a3481846132af565b9250888883818110611a4857611a48613311565b905060200201353373ffffffffffffffffffffffffffffffffffffffff167faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f83604051611a9791815260200190565b60405180910390a3505b611aaa816132d9565b90506119f7565b506000611abf828585612286565b905080341015611afb576040517f3c6b4b2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075482600e54611b0c91906132af565b1115611b44576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81600e6000828254611b5691906132af565b909155505034811015611b7757611b77611b70823461329c565b33906122a4565b5050505050505050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff16611be9576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004544210611c24576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c2c612219565b80600003611c66576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075481600e54611c7791906132af565b1115611caf576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e6000828254611cc191906132af565b9091555050604051818152829033907faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f9060200160405180910390a35050565b3360009081527fee57cd81e84075558e8fcc182a1f4393f91fc97f963a136e66b7f949a62f319f602052604090205460ff16611d69576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004544210611da4576040517fd17e0deb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611dac612219565b80600003611de6576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611df282846132c2565b905060075481600e54611e0591906132af565b1115611e3d576040517f2aa2ed7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600e6000828254611e4f91906132af565b90915550600090505b83811015611ed957848482818110611e7257611e72613311565b905060200201353373ffffffffffffffffffffffffffffffffffffffff167faabd75b90fb7114eb9587a54f00ce5ebe8cb4a70627f3a6c26e506ffd771fe2f85604051611ec191815260200190565b60405180910390a3611ed2816132d9565b9050611e58565b5050505050565b60008181526001602052604081206109f7906128b2565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16611f5f576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60075460408051918252602082018390527fa75b962aa425276de62bec76aeb43cacc12d2b132498ae1115500c23dc35fbe4910160405180910390a1600755565b600082815260208190526040902060010154611fbb816122e9565b610df18383612315565b6000611fd16001610cae565b905090565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff1661203e576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527fffca0dcf4a77eaddf80becc294c7f9b5fe6afe652e75c888b8afc76c75d8e658910160405180910390a1600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b3360009081527fd329ff8a035c3ce5df2b0dae604d660c0d8783bf7e64be00c1d10db96c0b87b4602052604090205460ff16612141576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c5460408051918252602082018390527f31c130faaf861e1e61ca087cc48c410d9099885350e9beb4dad1175cb77a6545910160405180910390a1600c55565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806109f757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146109f7565b60025460ff1615610f5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610e97565b600061229c8261229685876132c2565b906128bc565b949350505050565b600080600080600085875af1905080610df1576040517f3204506f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dc981336128d1565b6122fd8282612989565b6000828152600160205260409020610df19082612a79565b61231f8282612a9b565b6000828152600160205260409020610df19082612b52565b600080600080600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156123aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ce919061335f565b50935093509350935082600014612411576040517f032b3d0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8369ffffffffffffffffffff16600003612457576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003612491576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428111156124cb576040517fe802dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006124d7834261329c565b9050600c54811015612515576040517fd15f73b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000600260019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ab919061335f565b5093505092509250600082136125ec576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8269ffffffffffffffffffff16600003612632576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000361266c576040517f8ad52bdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428111156126a6576040517fe802dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009546126b3824261329c565b11156126eb576040517f704e0c4800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a548210806126fc5750600b5482115b15612733576040517f6e4ba61d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426011554360125560105415801561274b5750600f54155b1561275f57600f8290556010829055611b77565b50600f805460105555505050505050565b612778612b74565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60006109f7826005546127fe61286a565b612286565b61280b612219565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586127c33390565b6000610ce88383612be0565b600060065460001461287d575060065490565b60085460115461288d904261329c565b111561289b5761289b612337565b43601254146128ab5750600f5490565b5060105490565b60006109f7825490565b6000610ce883670de0b6b3a764000084612c0a565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eaa5761290f81612c38565b61291a836020612c57565b60405160200161292b9291906133af565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610e979160040161321c565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610eaa5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612a1b3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610ce88373ffffffffffffffffffffffffffffffffffffffff8416612e9a565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610eaa5760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610ce88373ffffffffffffffffffffffffffffffffffffffff8416612ee9565b60025460ff16610f5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610e97565b6000826000018281548110612bf757612bf7613311565b9060005260206000200154905092915050565b828202811515841585830485141716612c2257600080fd5b6001826001830304018115150290509392505050565b60606109f773ffffffffffffffffffffffffffffffffffffffff831660145b60606000612c668360026132c2565b612c719060026132af565b67ffffffffffffffff811115612c8957612c89613430565b6040519080825280601f01601f191660200182016040528015612cb3576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612cea57612cea613311565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612d4d57612d4d613311565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612d898460026132c2565b612d949060016132af565b90505b6001811115612e31577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612dd557612dd5613311565b1a60f81b828281518110612deb57612deb613311565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612e2a8161345f565b9050612d97565b508315610ce8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610e97565b6000818152600183016020526040812054612ee1575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556109f7565b5060006109f7565b60008181526001830160205260408120548015612fd2576000612f0d60018361329c565b8554909150600090612f219060019061329c565b9050818114612f86576000866000018281548110612f4157612f41613311565b9060005260206000200154905080876000018481548110612f6457612f64613311565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612f9757612f97613494565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506109f7565b60009150506109f7565b600060208284031215612fee57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610ce857600080fd5b60006020828403121561303057600080fd5b5035919050565b60008060006060848603121561304c57600080fd5b505081359360208301359350604090920135919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610dc957600080fd5b6000806040838503121561309857600080fd5b8235915060208301356130aa81613063565b809150509250929050565b6000602082840312156130c757600080fd5b8135610ce881613063565b600080604083850312156130e557600080fd5b50508035926020909101359150565b60008083601f84011261310657600080fd5b50813567ffffffffffffffff81111561311e57600080fd5b6020830191508360208260051b850101111561313957600080fd5b9250929050565b6000806000806040858703121561315657600080fd5b843567ffffffffffffffff8082111561316e57600080fd5b61317a888389016130f4565b9096509450602087013591508082111561319357600080fd5b506131a0878288016130f4565b95989497509550505050565b6000806000604084860312156131c157600080fd5b833567ffffffffffffffff8111156131d857600080fd5b6131e4868287016130f4565b909790965060209590950135949350505050565b60005b838110156132135781810151838201526020016131fb565b50506000910152565b602081526000825180602084015261323b8160408501602087016131f8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109f7576109f761326d565b808201808211156109f7576109f761326d565b80820281158282048414176109f7576109f761326d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361330a5761330a61326d565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b805169ffffffffffffffffffff8116811461335a57600080fd5b919050565b600080600080600060a0868803121561337757600080fd5b61338086613340565b94506020860151935060408601519250606086015191506133a360808701613340565b90509295509295909350565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516133e78160178501602088016131f8565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516134248160288401602088016131f8565b01602801949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008161346e5761346e61326d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000815000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000013e3ee699d1909e989722e753853ae30b17e08c5000000000000000000000000371ead81c9102c9bf4874a9075ffff170f2ee389000000000000000000000000000000000000000000000000000000001dcd65000000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000053c6da835c777ad11159198fbe11f95e5ee6b6920000000000000000000000006d2b70e39c6bc63763098e336323591eb77cd0c6000000000000000000000000d84e32224a249a575a09672da9cb58c381c4837a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _priceFeed (address): 0x13e3Ee699D1909E989722E753853AE30b17e08c5
Arg [1] : _uptimeFeed (address): 0x371EAD81c9102C9BF4874A9075FFFf170F2Ee389
Arg [2] : _initialUsdUnitPrice (uint256): 500000000
Arg [3] : _initialMaxUnits (uint256): 200000
Arg [4] : _initialVault (address): 0x53c6dA835c777AD11159198FBe11f95E5eE6B692
Arg [5] : _initialRoleAdmin (address): 0x6D2b70e39C6bc63763098e336323591eb77Cd0C6
Arg [6] : _initialOwner (address): 0xD84E32224A249A575A09672Da9cb58C381C4837a
Arg [7] : _initialOperator (address): 0x0000000000000000000000000000000000000000
Arg [8] : _initialTreasurer (address): 0x0000000000000000000000000000000000000000

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000013e3ee699d1909e989722e753853ae30b17e08c5
Arg [1] : 000000000000000000000000371ead81c9102c9bf4874a9075ffff170f2ee389
Arg [2] : 000000000000000000000000000000000000000000000000000000001dcd6500
Arg [3] : 0000000000000000000000000000000000000000000000000000000000030d40
Arg [4] : 00000000000000000000000053c6da835c777ad11159198fbe11f95e5ee6b692
Arg [5] : 0000000000000000000000006d2b70e39c6bc63763098e336323591eb77cd0c6
Arg [6] : 000000000000000000000000d84e32224a249a575a09672da9cb58c381c4837a
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

730:26949:14:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;634:212:2;;;;;;;;;;-1:-1:-1;634:212:2;;;;;:::i;:::-;;:::i;:::-;;;516:14:17;;509:22;491:41;;479:2;464:18;634:212:2;;;;;;;;9599:23:14;;;;;;;;;;;;;;;;;;;689:25:17;;;677:2;662:18;9599:23:14;543:177:17;25813:178:14;;;;;;;;;;-1:-1:-1;25813:178:14;;;;;:::i;:::-;;:::i;:::-;;23418:557;;;;;;;;;;-1:-1:-1;23418:557:14;;;;;:::i;:::-;;:::i;4504:129:1:-;;;;;;;;;;-1:-1:-1;4504:129:1;;;;;:::i;:::-;4578:7;4604:12;;;;;;;;;;:22;;;;4504:129;16531:717:14;;;;;;;;;;-1:-1:-1;16531:717:14;;;;;:::i;:::-;;:::i;10403:26::-;;;;;;;;;;;;;;;;9329:35;;;;;;;;;;;;;;;;27299:136;;;;;;;;;;-1:-1:-1;27299:136:14;;;;;:::i;:::-;;:::i;4929:145:1:-;;;;;;;;;;-1:-1:-1;4929:145:1;;;;;:::i;:::-;;:::i;6038:214::-;;;;;;;;;;-1:-1:-1;6038:214:1;;;;;:::i;:::-;;:::i;9231:39:14:-;;;;;;;;;;-1:-1:-1;9231:39:14;;;;;;;;;;;2281:42:17;2269:55;;;2251:74;;2239:2;2224:18;9231:39:14;2077:254:17;24033:174:14;;;;;;;;;;;;;:::i;27612:65::-;;;;;;;;;;;;;:::i;9423:27::-;;;;;;;;;;;;;;;;9777:30;;;;;;;;;;;;;;;;26242:233;;;;;;;;;;-1:-1:-1;26242:233:14;;;;;:::i;:::-;;:::i;26533:::-;;;;;;;;;;-1:-1:-1;26533:233:14;;;;;:::i;:::-;;:::i;26049:135::-;;;;;;;;;;-1:-1:-1;26049:135:14;;;;;:::i;:::-;;:::i;1615:84:5:-;;;;;;;;;;-1:-1:-1;1685:7:5;;;;1615:84;;10759:39:14;;;;;;;;;;;;;;;;27048:193;;;;;;;;;;-1:-1:-1;27048:193:14;;;;;:::i;:::-;;:::i;10050:36::-;;;;;;;;;;;;;;;;24265:164;;;;;;;;;;-1:-1:-1;24265:164:14;;;;;:::i;:::-;;:::i;9134:38::-;;;;;;;;;;-1:-1:-1;9134:38:14;;;;;;;;;;;14303:717;;;;;;:::i;:::-;;:::i;10573:30::-;;;;;;;;;;;;;;;;9866:33;;;;;;;;;;;;;;;;27493:61;;;;;;;;;;;;;:::i;24913:331::-;;;;;;;;;;-1:-1:-1;24913:331:14;;;;;:::i;:::-;;:::i;25485:270::-;;;;;;;;;;-1:-1:-1;25485:270:14;;;;;:::i;:::-;;:::i;1431:151:2:-;;;;;;;;;;-1:-1:-1;1431:151:2;;;;;:::i;:::-;;:::i;24713:142:14:-;;;;;;;;;;-1:-1:-1;24713:142:14;;;;;:::i;:::-;;:::i;3021:145:1:-;;;;;;;;;;-1:-1:-1;3021:145:1;;;;;:::i;:::-;3107:4;3130:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;3021:145;10488:26:14;;;;;;;;;;;;;;;;2153:49:1;;;;;;;;;;-1:-1:-1;2153:49:1;2198:4;2153:49;;15078:1071:14;;;;;;:::i;:::-;;:::i;22544:297::-;;;;;;;;;;-1:-1:-1;22544:297:14;;;;;:::i;:::-;;:::i;9509:31::-;;;;;;;;;;;;;;;;22899:461;;;;;;;;;;-1:-1:-1;22899:461:14;;;;;:::i;:::-;;:::i;9681:37::-;;;;;;;;;;;;;;;;1750:140:2;;;;;;;;;;-1:-1:-1;1750:140:2;;;;;:::i;:::-;;:::i;10662:38:14:-;;;;;;;;;;;;;;;;25302:125;;;;;;;;;;-1:-1:-1;25302:125:14;;;;;:::i;:::-;;:::i;5354:147:1:-;;;;;;;;;;-1:-1:-1;5354:147:1;;;;;:::i;:::-;;:::i;9958:33:14:-;;;;;;;;;;;;;;;;16388:85;;;;;;;;;;;;;:::i;24487:168::-;;;;;;;;;;-1:-1:-1;24487:168:14;;;;;:::i;:::-;;:::i;26824:166::-;;;;;;;;;;-1:-1:-1;26824:166:14;;;;;:::i;:::-;;:::i;10145:20::-;;;;;;;;;;-1:-1:-1;10145:20:14;;;;;;;;8631:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;634:212:2:-;719:4;742:57;;;757:42;742:57;;:97;;;803:36;827:11;803:23;:36::i;:::-;735:104;634:212;-1:-1:-1;;634:212:2:o;25813:178:14:-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;25908:22:::1;::::0;25891:50:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;25891:50:14::1;::::0;6127:18:17;25891:50:14::1;;;;;;;25951:22;:33:::0;25813:178::o;23418:557::-;13888:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13860:61:14;;13908:13;;;;;;;;;;;;;;13860:61;13619:20:::1;;13600:15;:39;13596:97;;13662:20;;;;;;;;;;;;;;13596:97;1239:19:5::2;:17;:19::i;:::-;23585:5:14::3;23594:1;23585:10:::0;23581:38:::3;;23604:15;;;;;;;;;;;;;;23581:38;23642:3;23633:5;:12;23629:44;;23654:19;;;;;;;;;;;;;;23629:44;23684:11;23698;23704:5:::0;23698:3;:11:::3;:::i;:::-;:15;::::0;23712:1:::3;23698:15;:::i;:::-;23684:29:::0;-1:-1:-1;23723:18:14::3;23744:11;23750:5:::0;23684:29;23744:11:::3;:::i;:::-;23723:32;;23796:8;;23783:10;23769:11;;:24;;;;:::i;:::-;:35;23765:65;;;23813:17;;;;;;;;;;;;;;23765:65;23855:10;23840:11;;:25;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;23880:9:14::3;::::0;-1:-1:-1;23875:94:14::3;23895:3;23891:1;:7;23875:94;;;23941:9;23949:1:::0;23941:5;:9:::3;:::i;:::-;23924:34;::::0;689:25:17;;;23929:10:14::3;::::0;23924:34:::3;::::0;677:2:17;662:18;23924:34:14::3;;;;;;;23900:3;::::0;::::3;:::i;:::-;;;23875:94;;;;23571:404;;23418:557:::0;;;:::o;16531:717::-;16582:7;16601:16;16631;;16651:1;16631:21;16627:561;;-1:-1:-1;16679:16:14;;16627:561;;;17070:12;17042:24;;:40;17038:150;;-1:-1:-1;17109:15:14;;17038:150;;;-1:-1:-1;17166:11:14;;17038:150;17204:37;17211:5;17218:12;;17232:8;17204:6;:37::i;:::-;17197:44;16531:717;-1:-1:-1;;;16531:717:14:o;27299:136::-;14009:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13980:63:14;;14029:14;;;;;;;;;;;;;;13980:63;27380:5:::1;::::0;27371:23:::1;::::0;689:25:17;;;27380:5:14::1;::::0;;::::1;::::0;27371:23:::1;::::0;677:2:17;662:18;27371:23:14::1;;;;;;;27404:5;::::0;:24:::1;::::0;:5:::1;;27421:6:::0;27404:16:::1;:24::i;:::-;27299:136:::0;:::o;4929:145:1:-;4578:7;4604:12;;;;;;;;;;:22;;;2631:16;2642:4;2631:10;:16::i;:::-;5042:25:::1;5053:4;5059:7;5042:10;:25::i;:::-;4929:145:::0;;;:::o;6038:214::-;6133:23;;;719:10:6;6133:23:1;6125:83;;;;;;;7260:2:17;6125:83:1;;;7242:21:17;7299:2;7279:18;;;7272:30;7338:34;7318:18;;;7311:62;7409:17;7389:18;;;7382:45;7444:19;;6125:83:1;;;;;;;;;6219:26;6231:4;6237:7;6219:11;:26::i;:::-;6038:214;;:::o;24033:174:14:-;24101:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;24080:32:14;:72;;;;-1:-1:-1;24141:10:14;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;24116:36:14;24080:72;24076:99;;;24161:14;;;;;;;;;;;;;;24076:99;24185:15;:13;:15::i;:::-;24033:174::o;27612:65::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;27660:10:::1;:8;:10::i;26242:233::-:0;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;26327:18:::1;;26315:8;:30;26311:61;;26354:18;;;;;;;;;;;;;;26311:61;26400:18;::::0;26387:42:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;26387:42:14::1;::::0;6127:18:17;26387:42:14::1;;;;;;;26439:18;:29:::0;26242:233::o;26533:::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;26618:18:::1;;26606:8;:30;26602:61;;26645:18;;;;;;;;;;;;;;26602:61;26691:18;::::0;26678:42:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;26678:42:14::1;::::0;6127:18:17;26678:42:14::1;;;;;;;26730:18;:29:::0;26533:233::o;26049:135::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;26125:15:::1;::::0;26115:31:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;26115:31:14::1;::::0;6127:18:17;26115:31:14::1;;;;;;;26156:15;:21:::0;26049:135::o;27048:193::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;27118:23:::1;::::0;::::1;27114:52;;27150:16;;;;;;;;;;;;;;27114:52;27190:5;::::0;27181:26:::1;::::0;;27190:5:::1;::::0;;::::1;7709:34:17::0;;7779:15;;;7774:2;7759:18;;7752:43;27181:26:14::1;::::0;7621:18:17;27181:26:14::1;;;;;;;27217:5;:17:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;27048:193::o;24265:164::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;24370:9:::1;::::0;24349:47:::1;::::0;;24370:9:::1;;::::0;;::::1;::::0;::::1;7709:34:17::0;;7779:15;;;7774:2;7759:18;;7752:43;24349:47:14::1;::::0;7621:18:17;24349:47:14::1;;;;;;;24406:9;:16:::0;;::::1;::::0;;::::1;;;::::0;;;::::1;::::0;;;::::1;::::0;;24265:164::o;14303:717::-;14425:19;13619:20;;13600:15;:39;13596:97;;13662:20;;;;;;;;;;;;;;13596:97;1239:19:5::1;:17;:19::i;:::-;14478:5:14::2;14487:1;14478:10:::0;14474:38:::2;;14497:15;;;;;;;;;;;;;;14474:38;14548:8;;14540:5;14526:11;;:19;;;;:::i;:::-;:30;14522:60;;;14565:17;;;;;;;;;;;;;;14522:60;14592:18;14613:13;14620:5;14613:6;:13::i;:::-;14592:34;;14652:10;14640:9;:22;14636:51;;;14671:16;;;;;;;;;;;;;;14636:51;14732:5;14717:11;;:20;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;14752:28:14::2;::::0;689:25:17;;;14769:3:14;;14757:10:::2;::::0;14752:28:::2;::::0;677:2:17;662:18;14752:28:14::2;;;;;;;14902:22;14914:10:::0;14902:9:::2;:22;:::i;:::-;14888:36:::0;-1:-1:-1;14938:15:14;;14934:80:::2;;14969:34;:10;14991:11:::0;14969:21:::2;:34::i;:::-;14446:574;14303:717:::0;;;;:::o;27493:61::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;27539:8:::1;:6;:8::i;24913:331::-:0;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;24995:15;;24991:144:::1;;25043:18;;25030:10;:31;:66;;;;25078:18;;25065:10;:31;25030:66;25026:98;;;25105:19;;;;;;;;;;;;;;25026:98;25169:16;::::0;25149:49:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;25149:49:14::1;::::0;6127:18:17;25149:49:14::1;;;;;;;25208:16;:29:::0;24913:331::o;25485:270::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;25582:15:::1;25570:9;:27;25566:69;;;25606:29;;;;;;;;;;;;;;25566:69;25674:20;::::0;25650:56:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;25650:56:14::1;::::0;6127:18:17;25650:56:14::1;;;;;;;25716:20;:32:::0;25485:270::o;1431:151:2:-;1521:7;1547:18;;;:12;:18;;;;;:28;;1569:5;1547:21;:28::i;24713:142:14:-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;24792:12:::1;::::0;24783:32:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;24783:32:14::1;::::0;6127:18:17;24783:32:14::1;;;;;;;24825:12;:23:::0;24713:142::o;15078:1071::-;13619:20;;13600:15;:39;13596:97;;13662:20;;;;;;;;;;;;;;13596:97;1239:19:5::1;:17;:19::i;:::-;15255:16:14::0;;;:37:::2;;-1:-1:-1::0;15275:17:14;;15255:37:::2;15251:69;;;15301:19;;;;;;;;;;;;;;15251:69;15334:27:::0;;::::2;15330:59;;15370:19;;;;;;;;;;;;;;15330:59;15439:12;::::0;15419:17:::2;15481:14;:12;:14::i;:::-;15461:34;;15506:16;15537:9:::0;15532:199:::2;15548:15:::0;;::::2;15532:199;;;15584:11;15598:5;;15604:1;15598:8;;;;;;;:::i;:::-;;;;;;;15584:22;;15624:3;15631:1;15624:8:::0;15620:22:::2;;15634:8;;;15620:22;15656:15;15668:3:::0;15656:15;::::2;:::i;:::-;;;15707:4;;15712:1;15707:7;;;;;;;:::i;:::-;;;;;;;15695:10;15690:30;;;15716:3;15690:30;;;;689:25:17::0;;677:2;662:18;;543:177;15690:30:14::2;;;;;;;;15570:161;15532:199;15565:3;::::0;::::2;:::i;:::-;;;15532:199;;;;15740:18;15761:38;15768:8;15778:9;15789;15761:6;:38::i;:::-;15740:59;;15849:10;15837:9;:22;15833:51;;;15868:16;;;;;;;;;;;;;;15833:51;15923:8;;15912;15898:11;;:22;;;;:::i;:::-;:33;15894:63;;;15940:17;;;;;;;;;;;;;;15894:63;16002:8;15987:11;;:23;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;16049:9:14::2;:22:::0;-1:-1:-1;16045:98:14::2;;;16087:45;16109:22;16121:10:::0;16109:9:::2;:22;:::i;:::-;16087:10;::::0;:21:::2;:45::i;:::-;15219:930;;;;15078:1071:::0;;;;:::o;22544:297::-;13888:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13860:61:14;;13908:13;;;;;;;;;;;;;;13860:61;13619:20:::1;;13600:15;:39;13596:97;;13662:20;;;;;;;;;;;;;;13596:97;1239:19:5::2;:17;:19::i;:::-;22656:5:14::3;22665:1;22656:10:::0;22652:38:::3;;22675:15;;;;;;;;;;;;;;22652:38;22726:8;;22718:5;22704:11;;:19;;;;:::i;:::-;:30;22700:60;;;22743:17;;;;;;;;;;;;;;22700:60;22786:5;22771:11;;:20;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;22806:28:14::3;::::0;689:25:17;;;22823:3:14;;22811:10:::3;::::0;22806:28:::3;::::0;677:2:17;662:18;22806:28:14::3;;;;;;;22544:297:::0;;:::o;22899:461::-;13888:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13860:61:14;;13908:13;;;;;;;;;;;;;;13860:61;13619:20:::1;;13600:15;:39;13596:97;;13662:20;;;;;;;;;;;;;;13596:97;1239:19:5::2;:17;:19::i;:::-;23050:5:14::3;23059:1;23050:10:::0;23046:38:::3;;23069:15;;;;;;;;;;;;;;23046:38;23094:18;23115:19;23129:5:::0;23115:4;:19:::3;:::i;:::-;23094:40;;23175:8;;23162:10;23148:11;;:24;;;;:::i;:::-;:35;23144:65;;;23192:17;;;;;;;;;;;;;;23144:65;23234:10;23219:11;;:25;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;23259:9:14::3;::::0;-1:-1:-1;23254:100:14::3;23270:15:::0;;::::3;23254:100;;;23328:4;;23333:1;23328:7;;;;;;;:::i;:::-;;;;;;;23316:10;23311:32;;;23337:5;23311:32;;;;689:25:17::0;;677:2;662:18;;543:177;23311:32:14::3;;;;;;;;23287:3;::::0;::::3;:::i;:::-;;;23254:100;;;;23036:324;22899:461:::0;;;:::o;1750:140:2:-;1830:7;1856:18;;;:12;:18;;;;;:27;;:25;:27::i;25302:125:14:-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;25382:8:::1;::::0;25370:26:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;25370:26:14::1;::::0;6127:18:17;25370:26:14::1;;;;;;;25406:8;:14:::0;25302:125::o;5354:147:1:-;4578:7;4604:12;;;;;;;;;;:22;;;2631:16;2642:4;2631:10;:16::i;:::-;5468:26:::1;5480:4;5486:7;5468:11;:26::i;16388:85:14:-:0;16432:7;16458:8;16464:1;16458:5;:8::i;:::-;16451:15;;16388:85;:::o;24487:168::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;24594:10:::1;::::0;24572:49:::1;::::0;;24594:10:::1;::::0;;::::1;7709:34:17::0;;7779:15;;;7774:2;7759:18;;7752:43;24572:49:14::1;::::0;7621:18:17;24572:49:14::1;;;;;;;24631:10;:17:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;24487:168::o;26824:166::-;13772:10;3107:4:1;3130:29;;;:12;;:29;:12;:29;;;;;13747:55:14;;13792:10;;;;;;;;;;;;;;13747:55;26913:21:::1;::::0;26898:45:::1;::::0;;6154:25:17;;;6210:2;6195:18;;6188:34;;;26898:45:14::1;::::0;6127:18:17;26898:45:14::1;;;;;;;26953:21;:30:::0;26824:166::o;2732:202:1:-;2817:4;2840:47;;;2855:32;2840:47;;:87;;-1:-1:-1;952:25:8;937:40;;;;2891:36:1;829:155:8;1767:106:5;1685:7;;;;1836:9;1828:38;;;;;;;8197:2:17;1828:38:5;;;8179:21:17;8236:2;8216:18;;;8209:30;8275:18;8255;;;8248:46;8311:18;;1828:38:5;7995:340:17;22135:166:14;22228:7;22254:40;22284:9;22255:18;22263:10;22255:5;:18;:::i;:::-;22254:29;;:40::i;:::-;22247:47;22135:166;-1:-1:-1;;;;22135:166:14:o;225:350:16:-;292:12;513:1;510;507;504;496:6;492:2;485:5;480:35;469:46;;540:7;535:33;;556:12;;;;;;;;;;;;;;3460:103:1;3526:30;3537:4;719:10:6;3526::1;:30::i;1978:166:2:-;2065:31;2082:4;2088:7;2065:16;:31::i;:::-;2106:18;;;;:12;:18;;;;;:31;;2129:7;2106:22;:31::i;2233:171::-;2321:32;2339:4;2345:7;2321:17;:32::i;:::-;2363:18;;;;:12;:18;;;;;:34;;2389:7;2363:25;:34::i;18996:2565:14:-;19231:20;19253:18;19273:23;19298;19338:10;;;;;;;;;;;:26;;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;19230:136;;;;;;;;;19380:11;19395:1;19380:16;19376:44;;19405:15;;;;;;;;;;;;;;19376:44;19434:13;:18;;19451:1;19434:18;19430:48;;19461:17;;;;;;;;;;;;;;19430:48;19492:15;19511:1;19492:20;19488:50;;19521:17;;;;;;;;;;;;;;19488:50;19570:15;19552;:33;19548:69;;;19594:23;;;;;;;;;;;;;;19548:69;19719:19;19741:33;19759:15;19741;:33;:::i;:::-;19719:55;;19802:21;;19788:11;:35;19784:68;;;19832:20;;;;;;;;;;;;;;19784:68;20519:19;20540:13;20556:22;20583:9;;;;;;;;;;;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;20518:92;;;;;;;;20634:1;20624:6;:11;20620:38;;20644:14;;;;;;;;;;;;;;20620:38;20672:12;:17;;20688:1;20672:17;20668:47;;20698:17;;;;;;;;;;;;;;20668:47;20729:14;20747:1;20729:19;20725:49;;20757:17;;;;;;;;;;;;;;20725:49;20805:15;20788:14;:32;20784:68;;;20829:23;;;;;;;;;;;;;;20784:68;20901:15;;20866:32;20884:14;20866:15;:32;:::i;:::-;:50;20862:101;;;20939:13;;;;;;;;;;;;;;20862:101;20994:18;;20984:6;20976:36;:76;;;;21034:18;;21024:6;21016:36;20976:76;20972:107;;;21061:18;;;;;;;;;;;;;;20972:107;21171:15;21145:23;:41;21223:12;21196:24;:39;21250:15;;:20;:40;;;;-1:-1:-1;21274:11:14;;:16;21250:40;21246:309;;;21412:11;:29;;;21394:15;:47;;;21246:309;;;-1:-1:-1;21490:11:14;;;21472:15;:29;21515;-1:-1:-1;;;;;;18996:2565:14:o;2433:117:5:-;1486:16;:14;:16::i;:::-;2491:7:::1;:15:::0;;;::::1;::::0;;2521:22:::1;719:10:6::0;2530:12:5::1;2521:22;::::0;2281:42:17;2269:55;;;2251:74;;2239:2;2224:18;2521:22:5::1;;;;;;;2433:117::o:0;21644:125:14:-;21693:7;21719:43;21726:5;21733:12;;21747:14;:12;:14::i;:::-;21719:6;:43::i;2186:115:5:-;1239:19;:17;:19::i;:::-;2245:7:::1;:14:::0;;;::::1;2255:4;2245:14;::::0;;2274:20:::1;2281:12;719:10:6::0;;640:96;9563:156:12;9637:7;9687:22;9691:3;9703:5;9687:3;:22::i;17545:1339:14:-;17587:7;17768:16;;17788:1;17768:21;17764:50;;-1:-1:-1;17798:16:14;;;17545:1339::o;17764:50::-;18104:22;;18078:23;;18060:41;;:15;:41;:::i;:::-;:66;18056:112;;;18142:15;:13;:15::i;:::-;18832:12;18804:24;;:40;18803:74;;-1:-1:-1;18866:11:14;;;16388:85::o;18803:74::-;-1:-1:-1;18848:15:14;;;17545:1339::o;9106:115:12:-;9169:7;9195:19;9203:3;4545:18;;4463:107;1044:158:13;1107:7;1133:19;1142:1;491:4;1150:1;1133:8;:19::i;3844:479:1:-;3107:4;3130:12;;;;;;;;;;;:29;;;;;;;;;;;;;3927:390;;4115:28;4135:7;4115:19;:28::i;:::-;4214:38;4242:4;4249:2;4214:19;:38::i;:::-;4022:252;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;3970:336;;;;;;;;:::i;7587:233::-;3107:4;3130:12;;;;;;;;;;;:29;;;;;;;;;;;;;7665:149;;7708:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;7740:4;7708:36;;;7790:12;719:10:6;;640:96;7790:12:1;7763:40;;7781:7;7763:40;;7775:4;7763:40;;;;;;;;;;7587:233;;:::o;8305:150:12:-;8375:4;8398:50;8403:3;8423:23;;;8398:4;:50::i;7991:234:1:-;3107:4;3130:12;;;;;;;;;;;:29;;;;;;;;;;;;;8070:149;;;8144:5;8112:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;8168:40;719:10:6;;8112:12:1;;8168:40;;8144:5;8168:40;7991:234;;:::o;8623:156:12:-;8696:4;8719:53;8727:3;8747:23;;;8719:7;:53::i;1945:106:5:-;1685:7;;;;2003:41;;;;;;;10021:2:17;2003:41:5;;;10003:21:17;10060:2;10040:18;;;10033:30;10099:22;10079:18;;;10072:50;10139:18;;2003:41:5;9819:344:17;4912:118:12;4979:7;5005:3;:11;;5017:5;5005:18;;;;;;;;:::i;:::-;;;;;;;;;4998:25;;4912:118;;;;:::o;8282:752:13:-;8486:9;;;8617:19;;8610:27;8642:9;;8656;;;8653:16;;8639:31;8606:65;8596:121;;8701:1;8698;8691:12;8596:121;9015:1;9001:11;8997:1;8994;8990:9;8986:27;8982:35;8977:1;8970:9;8963:17;8959:59;8954:64;;8282:752;;;;;:::o;2407:149:7:-;2465:13;2497:52;2509:22;;;343:2;1818:437;1893:13;1918:19;1950:10;1954:6;1950:1;:10;:::i;:::-;:14;;1963:1;1950:14;:::i;:::-;1940:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1940:25:7;;1918:47;;1975:15;:6;1982:1;1975:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;;2000;:6;2007:1;2000:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;-1:-1:-1;2030:9:7;2042:10;2046:6;2042:1;:10;:::i;:::-;:14;;2055:1;2042:14;:::i;:::-;2030:26;;2025:128;2062:1;2058;:5;2025:128;;;2096:8;2105:5;2113:3;2105:11;2096:21;;;;;;;:::i;:::-;;;;2084:6;2091:1;2084:9;;;;;;;;:::i;:::-;;;;:33;;;;;;;;;;-1:-1:-1;2141:1:7;2131:11;;;;;2065:3;;;:::i;:::-;;;2025:128;;;-1:-1:-1;2170:10:7;;2162:55;;;;;;;10760:2:17;2162:55:7;;;10742:21:17;;;10779:18;;;10772:30;10838:34;10818:18;;;10811:62;10890:18;;2162:55:7;10558:356:17;2214:404:12;2277:4;4351:19;;;:12;;;:19;;;;;;2293:319;;-1:-1:-1;2335:23:12;;;;;;;;:11;:23;;;;;;;;;;;;;2515:18;;2493:19;;;:12;;;:19;;;;;;:40;;;;2547:11;;2293:319;-1:-1:-1;2596:5:12;2589:12;;2786:1388;2852:4;2989:19;;;:12;;;:19;;;;;;3023:15;;3019:1149;;3392:21;3416:14;3429:1;3416:10;:14;:::i;:::-;3464:18;;3392:38;;-1:-1:-1;3444:17:12;;3464:22;;3485:1;;3464:22;:::i;:::-;3444:42;;3518:13;3505:9;:26;3501:398;;3551:17;3571:3;:11;;3583:9;3571:22;;;;;;;;:::i;:::-;;;;;;;;;3551:42;;3722:9;3693:3;:11;;3705:13;3693:26;;;;;;;;:::i;:::-;;;;;;;;;;;;:38;;;;3805:23;;;:12;;;:23;;;;;:36;;;3501:398;3977:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;4069:3;:12;;:19;4082:5;4069:19;;;;;;;;;;;4062:26;;;4110:4;4103:11;;;;;;;3019:1149;4152:5;4145:12;;;;;14:332:17;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:180;784:6;837:2;825:9;816:7;812:23;808:32;805:52;;;853:1;850;843:12;805:52;-1:-1:-1;876:23:17;;725:180;-1:-1:-1;725:180:17:o;910:316::-;987:6;995;1003;1056:2;1044:9;1035:7;1031:23;1027:32;1024:52;;;1072:1;1069;1062:12;1024:52;-1:-1:-1;;1095:23:17;;;1165:2;1150:18;;1137:32;;-1:-1:-1;1216:2:17;1201:18;;;1188:32;;910:316;-1:-1:-1;910:316:17:o;1598:154::-;1684:42;1677:5;1673:54;1666:5;1663:65;1653:93;;1742:1;1739;1732:12;1757:315;1825:6;1833;1886:2;1874:9;1865:7;1861:23;1857:32;1854:52;;;1902:1;1899;1892:12;1854:52;1938:9;1925:23;1915:33;;1998:2;1987:9;1983:18;1970:32;2011:31;2036:5;2011:31;:::i;:::-;2061:5;2051:15;;;1757:315;;;;;:::o;2336:247::-;2395:6;2448:2;2436:9;2427:7;2423:23;2419:32;2416:52;;;2464:1;2461;2454:12;2416:52;2503:9;2490:23;2522:31;2547:5;2522:31;:::i;2868:248::-;2936:6;2944;2997:2;2985:9;2976:7;2972:23;2968:32;2965:52;;;3013:1;3010;3003:12;2965:52;-1:-1:-1;;3036:23:17;;;3106:2;3091:18;;;3078:32;;-1:-1:-1;2868:248:17:o;3605:367::-;3668:8;3678:6;3732:3;3725:4;3717:6;3713:17;3709:27;3699:55;;3750:1;3747;3740:12;3699:55;-1:-1:-1;3773:20:17;;3816:18;3805:30;;3802:50;;;3848:1;3845;3838:12;3802:50;3885:4;3877:6;3873:17;3861:29;;3945:3;3938:4;3928:6;3925:1;3921:14;3913:6;3909:27;3905:38;3902:47;3899:67;;;3962:1;3959;3952:12;3899:67;3605:367;;;;;:::o;3977:773::-;4099:6;4107;4115;4123;4176:2;4164:9;4155:7;4151:23;4147:32;4144:52;;;4192:1;4189;4182:12;4144:52;4232:9;4219:23;4261:18;4302:2;4294:6;4291:14;4288:34;;;4318:1;4315;4308:12;4288:34;4357:70;4419:7;4410:6;4399:9;4395:22;4357:70;:::i;:::-;4446:8;;-1:-1:-1;4331:96:17;-1:-1:-1;4534:2:17;4519:18;;4506:32;;-1:-1:-1;4550:16:17;;;4547:36;;;4579:1;4576;4569:12;4547:36;;4618:72;4682:7;4671:8;4660:9;4656:24;4618:72;:::i;:::-;3977:773;;;;-1:-1:-1;4709:8:17;-1:-1:-1;;;;3977:773:17:o;4755:505::-;4850:6;4858;4866;4919:2;4907:9;4898:7;4894:23;4890:32;4887:52;;;4935:1;4932;4925:12;4887:52;4975:9;4962:23;5008:18;5000:6;4997:30;4994:50;;;5040:1;5037;5030:12;4994:50;5079:70;5141:7;5132:6;5121:9;5117:22;5079:70;:::i;:::-;5168:8;;5053:96;;-1:-1:-1;5250:2:17;5235:18;;;;5222:32;;4755:505;-1:-1:-1;;;;4755:505:17:o;5265:250::-;5350:1;5360:113;5374:6;5371:1;5368:13;5360:113;;;5450:11;;;5444:18;5431:11;;;5424:39;5396:2;5389:10;5360:113;;;-1:-1:-1;;5507:1:17;5489:16;;5482:27;5265:250::o;5520:455::-;5669:2;5658:9;5651:21;5632:4;5701:6;5695:13;5744:6;5739:2;5728:9;5724:18;5717:34;5760:79;5832:6;5827:2;5816:9;5812:18;5807:2;5799:6;5795:15;5760:79;:::i;:::-;5891:2;5879:15;5896:66;5875:88;5860:104;;;;5966:2;5856:113;;5520:455;-1:-1:-1;;5520:455:17:o;6233:184::-;6285:77;6282:1;6275:88;6382:4;6379:1;6372:15;6406:4;6403:1;6396:15;6422:128;6489:9;;;6510:11;;;6507:37;;;6524:18;;:::i;6555:125::-;6620:9;;;6641:10;;;6638:36;;;6654:18;;:::i;6685:168::-;6758:9;;;6789;;6806:15;;;6800:22;;6786:37;6776:71;;6827:18;;:::i;6858:195::-;6897:3;6928:66;6921:5;6918:77;6915:103;;6998:18;;:::i;:::-;-1:-1:-1;7045:1:17;7034:13;;6858:195::o;7806:184::-;7858:77;7855:1;7848:88;7955:4;7952:1;7945:15;7979:4;7976:1;7969:15;8340:179;8418:13;;8471:22;8460:34;;8450:45;;8440:73;;8509:1;8506;8499:12;8440:73;8340:179;;;:::o;8524:473::-;8627:6;8635;8643;8651;8659;8712:3;8700:9;8691:7;8687:23;8683:33;8680:53;;;8729:1;8726;8719:12;8680:53;8752:39;8781:9;8752:39;:::i;:::-;8742:49;;8831:2;8820:9;8816:18;8810:25;8800:35;;8875:2;8864:9;8860:18;8854:25;8844:35;;8919:2;8908:9;8904:18;8898:25;8888:35;;8942:49;8986:3;8975:9;8971:19;8942:49;:::i;:::-;8932:59;;8524:473;;;;;;;;:::o;9002:812::-;9413:25;9408:3;9401:38;9383:3;9468:6;9462:13;9484:75;9552:6;9547:2;9542:3;9538:12;9531:4;9523:6;9519:17;9484:75;:::i;:::-;9623:19;9618:2;9578:16;;;9610:11;;;9603:40;9668:13;;9690:76;9668:13;9752:2;9744:11;;9737:4;9725:17;;9690:76;:::i;:::-;9786:17;9805:2;9782:26;;9002:812;-1:-1:-1;;;;9002:812:17:o;10168:184::-;10220:77;10217:1;10210:88;10317:4;10314:1;10307:15;10341:4;10338:1;10331:15;10357:196;10396:3;10424:5;10414:39;;10433:18;;:::i;:::-;-1:-1:-1;10480:66:17;10469:78;;10357:196::o;10919:184::-;10971:77;10968:1;10961:88;11068:4;11065:1;11058:15;11092:4;11089:1;11082:15

Swarm Source

none://164736f6c6343000815000a

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.