ETH Price: $3,351.16 (-1.97%)

Contract

0xaE8aa2782799f9034208E19b486eE7CE5AF2954D
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LockedStaking

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 5500 runs

Other Settings:
default evmVersion, Unlicense license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-03-07
*/

//SPDX-License-Identifier: Unlicense
pragma solidity 0.8.17;

interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)

// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

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

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/BitMaps.sol)

/**
 * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential.
 * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor].
 */
library BitMaps {
    struct BitMap {
        mapping(uint256 => uint256) _data;
    }

    /**
     * @dev Returns whether the bit at `index` is set.
     */
    function get(BitMap storage bitmap, uint256 index) internal view returns (bool) {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        return bitmap._data[bucket] & mask != 0;
    }

    /**
     * @dev Sets the bit at `index` to the boolean `value`.
     */
    function setTo(BitMap storage bitmap, uint256 index, bool value) internal {
        if (value) {
            set(bitmap, index);
        } else {
            unset(bitmap, index);
        }
    }

    /**
     * @dev Sets the bit at `index`.
     */
    function set(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        bitmap._data[bucket] |= mask;
    }

    /**
     * @dev Unsets the bit at `index`.
     */
    function unset(BitMap storage bitmap, uint256 index) internal {
        uint256 bucket = index >> 8;
        uint256 mask = 1 << (index & 0xff);
        bitmap._data[bucket] &= ~mask;
    }
}

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    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.
    }

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

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        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) {
        /// @solidity memory-safe-assembly
        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 unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

/// @notice Optimized sorts and operations for sorted arrays.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Sort.sol)
library LibSort {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      INSERTION SORT                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // - Faster on small arrays (32 or lesser elements).
    // - Faster on almost sorted arrays.
    // - Smaller bytecode.
    // - May be suitable for view functions intended for off-chain querying.

    /// @dev Sorts the array in-place with insertion sort.
    function insertionSort(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let n := mload(a) // Length of `a`.
            mstore(a, 0) // For insertion sort's inner loop to terminate.
            let h := add(a, shl(5, n)) // High slot.
            let s := 0x20
            let w := not(31)
            for { let i := add(a, s) } 1 {} {
                i := add(i, s)
                if gt(i, h) { break }
                let k := mload(i) // Key.
                let j := add(i, w) // The slot before the current slot.
                let v := mload(j) // The value of `j`.
                if iszero(gt(v, k)) { continue }
                for {} 1 {} {
                    mstore(add(j, s), v)
                    j := add(j, w) // `sub(j, 0x20)`.
                    v := mload(j)
                    if iszero(gt(v, k)) { break }
                }
                mstore(add(j, s), k)
            }
            mstore(a, n) // Restore the length of `a`.
        }
    }

    /// @dev Sorts the array in-place with insertion sort.
    function insertionSort(int256[] memory a) internal pure {
        _convertTwosComplement(a);
        insertionSort(_toUints(a));
        _convertTwosComplement(a);
    }

    /// @dev Sorts the array in-place with insertion sort.
    function insertionSort(address[] memory a) internal pure {
        insertionSort(_toUints(a));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      INTRO-QUICKSORT                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // - Faster on larger arrays (more than 32 elements).
    // - Robust performance.
    // - Larger bytecode.

    /// @dev Sorts the array in-place with intro-quicksort.
    function sort(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(31)
            let s := 0x20
            let n := mload(a) // Length of `a`.
            mstore(a, 0) // For insertion sort's inner loop to terminate.

            // Let the stack be the start of the free memory.
            let stack := mload(0x40)

            for {} iszero(lt(n, 2)) {} {
                // Push `l` and `h` to the stack.
                // The `shl` by 5 is equivalent to multiplying by `0x20`.
                let l := add(a, s)
                let h := add(a, shl(5, n))

                let j := l
                // forgefmt: disable-next-item
                for {} iszero(or(eq(j, h), gt(mload(j), mload(add(j, s))))) {} {
                    j := add(j, s)
                }
                // If the array is already sorted.
                if eq(j, h) { break }

                j := h
                // forgefmt: disable-next-item
                for {} iszero(gt(mload(j), mload(add(j, w)))) {} {
                    j := add(j, w) // `sub(j, 0x20)`.
                }
                // If the array is reversed sorted.
                if eq(j, l) {
                    for {} 1 {} {
                        let t := mload(l)
                        mstore(l, mload(h))
                        mstore(h, t)
                        h := add(h, w) // `sub(h, 0x20)`.
                        l := add(l, s)
                        if iszero(lt(l, h)) { break }
                    }
                    break
                }

                // Push `l` and `h` onto the stack.
                mstore(stack, l)
                mstore(add(stack, s), h)
                stack := add(stack, 0x40)
                break
            }

            for { let stackBottom := mload(0x40) } iszero(eq(stack, stackBottom)) {} {
                // Pop `l` and `h` from the stack.
                stack := sub(stack, 0x40)
                let l := mload(stack)
                let h := mload(add(stack, s))

                // Do insertion sort if `h - l <= 0x20 * 12`.
                // Threshold is fine-tuned via trial and error.
                if iszero(gt(sub(h, l), 0x180)) {
                    // Hardcode sort the first 2 elements.
                    let i := add(l, s)
                    if iszero(lt(mload(l), mload(i))) {
                        let t := mload(i)
                        mstore(i, mload(l))
                        mstore(l, t)
                    }
                    for {} 1 {} {
                        i := add(i, s)
                        if gt(i, h) { break }
                        let k := mload(i) // Key.
                        let j := add(i, w) // The slot before the current slot.
                        let v := mload(j) // The value of `j`.
                        if iszero(gt(v, k)) { continue }
                        for {} 1 {} {
                            mstore(add(j, s), v)
                            j := add(j, w)
                            v := mload(j)
                            if iszero(gt(v, k)) { break }
                        }
                        mstore(add(j, s), k)
                    }
                    continue
                }
                // Pivot slot is the average of `l` and `h`.
                let p := add(shl(5, shr(6, add(l, h))), and(31, l))
                // Median of 3 with sorting.
                {
                    let e0 := mload(l)
                    let e2 := mload(h)
                    let e1 := mload(p)
                    if iszero(lt(e0, e1)) {
                        let t := e0
                        e0 := e1
                        e1 := t
                    }
                    if iszero(lt(e0, e2)) {
                        let t := e0
                        e0 := e2
                        e2 := t
                    }
                    if iszero(lt(e1, e2)) {
                        let t := e1
                        e1 := e2
                        e2 := t
                    }
                    mstore(p, e1)
                    mstore(h, e2)
                    mstore(l, e0)
                }
                // Hoare's partition.
                {
                    // The value of the pivot slot.
                    let x := mload(p)
                    p := h
                    for { let i := l } 1 {} {
                        for {} 1 {} {
                            i := add(i, s)
                            if iszero(gt(x, mload(i))) { break }
                        }
                        let j := p
                        for {} 1 {} {
                            j := add(j, w)
                            if iszero(lt(x, mload(j))) { break }
                        }
                        p := j
                        if iszero(lt(i, p)) { break }
                        // Swap slots `i` and `p`.
                        let t := mload(i)
                        mstore(i, mload(p))
                        mstore(p, t)
                    }
                }
                // If slice on right of pivot is non-empty, push onto stack.
                {
                    mstore(stack, add(p, s))
                    // Skip `mstore(add(stack, 0x20), h)`, as it is already on the stack.
                    stack := add(stack, shl(6, lt(add(p, s), h)))
                }
                // If slice on left of pivot is non-empty, push onto stack.
                {
                    mstore(stack, l)
                    mstore(add(stack, s), p)
                    stack := add(stack, shl(6, gt(p, l)))
                }
            }
            mstore(a, n) // Restore the length of `a`.
        }
    }

    /// @dev Sorts the array in-place with intro-quicksort.
    function sort(int256[] memory a) internal pure {
        _convertTwosComplement(a);
        sort(_toUints(a));
        _convertTwosComplement(a);
    }

    /// @dev Sorts the array in-place with intro-quicksort.
    function sort(address[] memory a) internal pure {
        sort(_toUints(a));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  OTHER USEFUL OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance, the `uniquifySorted` methods will not revert if the
    // array is not sorted -- it will simply remove consecutive duplicate elements.

    /// @dev Removes duplicate elements from a ascendingly sorted memory array.
    function uniquifySorted(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            // If the length of `a` is greater than 1.
            if iszero(lt(mload(a), 2)) {
                let x := add(a, 0x20)
                let y := add(a, 0x40)
                let end := add(a, shl(5, add(mload(a), 1)))
                for {} 1 {} {
                    if iszero(eq(mload(x), mload(y))) {
                        x := add(x, 0x20)
                        mstore(x, mload(y))
                    }
                    y := add(y, 0x20)
                    if eq(y, end) { break }
                }
                mstore(a, shr(5, sub(x, a)))
            }
        }
    }

    /// @dev Removes duplicate elements from a ascendingly sorted memory array.
    function uniquifySorted(int256[] memory a) internal pure {
        uniquifySorted(_toUints(a));
    }

    /// @dev Removes duplicate elements from a ascendingly sorted memory array.
    function uniquifySorted(address[] memory a) internal pure {
        uniquifySorted(_toUints(a));
    }

    /// @dev Returns whether `a` contains `needle`,
    /// and the index of the nearest element less than or equal to `needle`.
    function searchSorted(uint256[] memory a, uint256 needle)
        internal
        pure
        returns (bool found, uint256 index)
    {
        (found, index) = _searchSorted(a, needle, 0);
    }

    /// @dev Returns whether `a` contains `needle`,
    /// and the index of the nearest element less than or equal to `needle`.
    function searchSorted(int256[] memory a, int256 needle)
        internal
        pure
        returns (bool found, uint256 index)
    {
        (found, index) = _searchSorted(_toUints(a), uint256(needle), 1 << 255);
    }

    /// @dev Returns whether `a` contains `needle`,
    /// and the index of the nearest element less than or equal to `needle`.
    function searchSorted(address[] memory a, address needle)
        internal
        pure
        returns (bool found, uint256 index)
    {
        (found, index) = _searchSorted(_toUints(a), uint256(uint160(needle)), 0);
    }

    /// @dev Reverses the array in-place.
    function reverse(uint256[] memory a) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(lt(mload(a), 2)) {
                let s := 0x20
                let w := not(31)
                let h := add(a, shl(5, mload(a)))
                for { a := add(a, s) } 1 {} {
                    let t := mload(a)
                    mstore(a, mload(h))
                    mstore(h, t)
                    h := add(h, w)
                    a := add(a, s)
                    if iszero(lt(a, h)) { break }
                }
            }
        }
    }

    /// @dev Reverses the array in-place.
    function reverse(int256[] memory a) internal pure {
        reverse(_toUints(a));
    }

    /// @dev Reverses the array in-place.
    function reverse(address[] memory a) internal pure {
        reverse(_toUints(a));
    }

    /// @dev Returns whether the array is sorted in ascending order.
    function isSorted(uint256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := iszero(gt(p, mload(a)))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is sorted in ascending order.
    function isSorted(int256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := iszero(sgt(p, mload(a)))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is sorted in ascending order.
    function isSorted(address[] memory a) internal pure returns (bool result) {
        result = isSorted(_toUints(a));
    }

    /// @dev Returns whether the array is strictly ascending (sorted and uniquified).
    function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := lt(p, mload(a))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is strictly ascending (sorted and uniquified).
    function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            if iszero(lt(mload(a), 2)) {
                let end := add(a, shl(5, mload(a)))
                for { a := add(a, 0x20) } 1 {} {
                    let p := mload(a)
                    a := add(a, 0x20)
                    result := slt(p, mload(a))
                    if iszero(mul(result, xor(a, end))) { break }
                }
            }
        }
    }

    /// @dev Returns whether the array is strictly ascending (sorted and uniquified).
    function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) {
        result = isSortedAndUniquified(_toUints(a));
    }

    /// @dev Returns the sorted set difference of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function difference(uint256[] memory a, uint256[] memory b)
        internal
        pure
        returns (uint256[] memory c)
    {
        c = _difference(a, b, 0);
    }

    /// @dev Returns the sorted set difference between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function difference(int256[] memory a, int256[] memory b)
        internal
        pure
        returns (int256[] memory c)
    {
        c = _toInts(_difference(_toUints(a), _toUints(b), 1 << 255));
    }

    /// @dev Returns the sorted set difference between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function difference(address[] memory a, address[] memory b)
        internal
        pure
        returns (address[] memory c)
    {
        c = _toAddresses(_difference(_toUints(a), _toUints(b), 0));
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function intersection(uint256[] memory a, uint256[] memory b)
        internal
        pure
        returns (uint256[] memory c)
    {
        c = _intersection(a, b, 0);
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function intersection(int256[] memory a, int256[] memory b)
        internal
        pure
        returns (int256[] memory c)
    {
        c = _toInts(_intersection(_toUints(a), _toUints(b), 1 << 255));
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function intersection(address[] memory a, address[] memory b)
        internal
        pure
        returns (address[] memory c)
    {
        c = _toAddresses(_intersection(_toUints(a), _toUints(b), 0));
    }

    /// @dev Returns the sorted set union of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function union(uint256[] memory a, uint256[] memory b)
        internal
        pure
        returns (uint256[] memory c)
    {
        c = _union(a, b, 0);
    }

    /// @dev Returns the sorted set union of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function union(int256[] memory a, int256[] memory b)
        internal
        pure
        returns (int256[] memory c)
    {
        c = _toInts(_union(_toUints(a), _toUints(b), 1 << 255));
    }

    /// @dev Returns the sorted set union between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function union(address[] memory a, address[] memory b)
        internal
        pure
        returns (address[] memory c)
    {
        c = _toAddresses(_union(_toUints(a), _toUints(b), 0));
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(int256[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Reinterpret cast to an uint256 array.
    function _toUints(address[] memory a) private pure returns (uint256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            // As any address written to memory will have the upper 96 bits
            // of the word zeroized (as per Solidity spec), we can directly
            // compare these addresses as if they are whole uint256 words.
            casted := a
        }
    }

    /// @dev Reinterpret cast to an int array.
    function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Reinterpret cast to an address array.
    function _toAddresses(uint256[] memory a) private pure returns (address[] memory casted) {
        /// @solidity memory-safe-assembly
        assembly {
            casted := a
        }
    }

    /// @dev Converts an array of signed two-complement integers
    /// to unsigned integers suitable for sorting.
    function _convertTwosComplement(int256[] memory a) private pure {
        /// @solidity memory-safe-assembly
        assembly {
            let w := shl(255, 1)
            for { let end := add(a, shl(5, mload(a))) } iszero(eq(a, end)) {} {
                a := add(a, 0x20)
                mstore(a, add(mload(a), w))
            }
        }
    }

    /// @dev Returns whether `a` contains `needle`,
    /// and the index of the nearest element less than or equal to `needle`.
    function _searchSorted(uint256[] memory a, uint256 needle, uint256 signed)
        private
        pure
        returns (bool found, uint256 index)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := 0 // Middle slot.
            let s := 0x20
            let l := add(a, s) // Slot of the start of search.
            let h := add(a, shl(5, mload(a))) // Slot of the end of search.
            for { needle := add(signed, needle) } 1 {} {
                // Average of `l` and `h`.
                m := add(shl(5, shr(6, add(l, h))), and(31, l))
                let t := add(signed, mload(m))
                found := eq(t, needle)
                if or(gt(l, h), found) { break }
                // Decide whether to search the left or right half.
                if iszero(gt(needle, t)) {
                    h := sub(m, s)
                    continue
                }
                l := add(m, s)
            }
            // `m` will be less than `add(a, 0x20)` in the case of an empty array,
            // or when the value is less than the smallest value in the array.
            let t := iszero(lt(m, add(a, s)))
            index := shr(5, mul(sub(m, add(a, s)), t))
            found := and(found, t)
        }
    }

    /// @dev Returns the sorted set difference of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function _difference(uint256[] memory a, uint256[] memory b, uint256 signed)
        private
        pure
        returns (uint256[] memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let s := 0x20
            let aEnd := add(a, shl(5, mload(a)))
            let bEnd := add(b, shl(5, mload(b)))
            c := mload(0x40) // Set `c` to the free memory pointer.
            a := add(a, s)
            b := add(b, s)
            let k := c
            for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {
                let u := mload(a)
                let v := mload(b)
                if iszero(xor(u, v)) {
                    a := add(a, s)
                    b := add(b, s)
                    continue
                }
                if iszero(lt(add(u, signed), add(v, signed))) {
                    b := add(b, s)
                    continue
                }
                k := add(k, s)
                mstore(k, u)
                a := add(a, s)
            }
            for {} iszero(gt(a, aEnd)) {} {
                k := add(k, s)
                mstore(k, mload(a))
                a := add(a, s)
            }
            mstore(c, shr(5, sub(k, c))) // Store the length of `c`.
            mstore(0x40, add(k, s)) // Allocate the memory for `c`.
        }
    }

    /// @dev Returns the sorted set intersection between `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function _intersection(uint256[] memory a, uint256[] memory b, uint256 signed)
        private
        pure
        returns (uint256[] memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let s := 0x20
            let aEnd := add(a, shl(5, mload(a)))
            let bEnd := add(b, shl(5, mload(b)))
            c := mload(0x40) // Set `c` to the free memory pointer.
            a := add(a, s)
            b := add(b, s)
            let k := c
            for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {
                let u := mload(a)
                let v := mload(b)
                if iszero(xor(u, v)) {
                    k := add(k, s)
                    mstore(k, u)
                    a := add(a, s)
                    b := add(b, s)
                    continue
                }
                if iszero(lt(add(u, signed), add(v, signed))) {
                    b := add(b, s)
                    continue
                }
                a := add(a, s)
            }
            mstore(c, shr(5, sub(k, c))) // Store the length of `c`.
            mstore(0x40, add(k, s)) // Allocate the memory for `c`.
        }
    }

    /// @dev Returns the sorted set union of `a` and `b`.
    /// Note: Behaviour is undefined if inputs are not sorted and uniquified.
    function _union(uint256[] memory a, uint256[] memory b, uint256 signed)
        private
        pure
        returns (uint256[] memory c)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let s := 0x20
            let aEnd := add(a, shl(5, mload(a)))
            let bEnd := add(b, shl(5, mload(b)))
            c := mload(0x40) // Set `c` to the free memory pointer.
            a := add(a, s)
            b := add(b, s)
            let k := c
            for {} iszero(or(gt(a, aEnd), gt(b, bEnd))) {} {
                let u := mload(a)
                let v := mload(b)
                if iszero(xor(u, v)) {
                    k := add(k, s)
                    mstore(k, u)
                    a := add(a, s)
                    b := add(b, s)
                    continue
                }
                if iszero(lt(add(u, signed), add(v, signed))) {
                    k := add(k, s)
                    mstore(k, v)
                    b := add(b, s)
                    continue
                }
                k := add(k, s)
                mstore(k, u)
                a := add(a, s)
            }
            for {} iszero(gt(a, aEnd)) {} {
                k := add(k, s)
                mstore(k, mload(a))
                a := add(a, s)
            }
            for {} iszero(gt(b, bEnd)) {} {
                k := add(k, s)
                mstore(k, mload(b))
                b := add(b, s)
            }
            mstore(c, shr(5, sub(k, c))) // Store the length of `c`.
            mstore(0x40, add(k, s)) // Allocate the memory for `c`.
        }
    }
}

/*///////////////////////////////////////////////////////////////
                                ERRORS
//////////////////////////////////////////////////////////////*/
error MustProlongLock(uint256 oldDuration, uint256 newDuration);
error AmountIsZero();
error TransferFailed();
error NothingToClaim();
error LockStillActive();
error DurationOutOfBounds(uint256 duration);
error UpdateToSmallerMultiplier(uint16 oldMultiplier, uint16 newMultiplier);
error ZeroAddress();
error ZeroPrecision();
error ZeroAmount();
error MaxLocksSucceeded();
error MaxRewardsSucceeded();
error CanOnlyAddFutureRewards();
error NotRewardoor();
error CantAutoCompound();
error AlreadyAutoCompound();
error NotAutoCompoundEnabled();
error RewardStartEqEnd();
error IntervalNotRoundedWithEpoch();
error CantChangePast();
error CantUpdateExpiredLock();

contract LockedStaking is Initializable, OwnableUpgradeable {
    using BitMaps for BitMaps.BitMap;
    using FixedPointMathLib for uint256;

    /*///////////////////////////////////////////////////////////////
                                  EVENTS
    //////////////////////////////////////////////////////////////*/
    event LockAdded(address indexed from, uint208 amount, uint32 end, uint16 multiplier);
    event LockUpdated(address indexed from, uint8 index, uint208 amount, uint32 end, uint16 multiplier);
    event Unlock(address indexed from, uint256 amount, uint256 index);
    event Claim(address indexed from, uint256 amount);
    event RewardAdded(uint256 start, uint256 end, uint256 amountPerSecond);
    event RewardUpdated(uint256 index, uint256 start, uint256 end, uint256 amountPerSecond);
    event RewardRemoved(uint256 index);
    event AutoCompoundEnabled(address indexed from, uint256 index, uint256 shares);
    event AutoCompoundDisabled(address indexed from, uint256 index, uint256 amount);
    event AutoCompounded(uint256 compoundAmount);
    event RewardoorSet(address indexed rewardoor, bool value);

    /*///////////////////////////////////////////////////////////////
                             IMMUTABLES & CONSTANTS
    //////////////////////////////////////////////////////////////*/
    uint256 public constant MAX_LOCK_COUNT = 5;
    uint256 public constant MAX_REWARD_COUNT = 5;
    uint256 public constant MAX_MULTIPLIER = 998;
    uint256 public constant EPOCH_DURATION = 8 * 60 * 60;
    uint256 public constant ALGORITHM_THRESHOLD_IN_EPOCHS = 5;

    /*///////////////////////////////////////////////////////////////
                             STRUCTS
    //////////////////////////////////////////////////////////////*/
    struct Lock {
        uint16 multiplier;
        uint32 end;
        uint208 amount;
    }

    struct Reward {
        uint32 start;
        uint32 end;
        uint192 amountPerSecond;
    }

    struct TotalReward {
        uint256 start;
        uint256 end;
        uint256 epochReward;
    }

    struct CompoundVars {
        uint256 from;
        uint256 to;
        uint256 currentPeriod;
        uint256 compoundClaimable;
        uint256 epochRewards;
        uint256 currCompLastAccRewardWeight;
    }

    /*///////////////////////////////////////////////////////////////
                             STORAGE
    //////////////////////////////////////////////////////////////*/
    IERC20 public swapToken;
    uint256 public precision; // no longer used but kept for upgradeability
    Reward[] public rewards;
    mapping(address => Lock[]) public locks;
    mapping(address => uint256) public userLastAccRewardsWeight;

    uint256 public lastRewardUpdate;
    uint256 public totalScore;
    uint256 public accRewardWeight;

    mapping(address => bool) public rewardoors;

    BitMaps.BitMap private lockCompoundedBitMap;
    uint256 public compoundAmount;
    uint256 public compoundShares;
    uint256 public compoundLastAccRewardWeight;

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

    modifier onlyRewardoor() {
        if (!rewardoors[msg.sender]) revert NotRewardoor();
        _;
    }

    constructor() {
        _disableInitializers();
    }

    /*///////////////////////////////////////////////////////////////
                             EXTERNAL
    //////////////////////////////////////////////////////////////*/

    function initialize(address _swapToken, uint256 _precision) external initializer {
        if (_swapToken == address(0)) revert ZeroAddress();
        if (_precision == 0) revert ZeroPrecision();

        swapToken = IERC20(_swapToken);
        precision = _precision;

        __Ownable_init();
    }

    /// @notice Adds new reward
    function addReward(
        uint32 start,
        uint32 end,
        uint192 amountPerSecond
    ) external onlyRewardoor {
        if (rewards.length == MAX_REWARD_COUNT) revert MaxRewardsSucceeded();
        if (amountPerSecond == 0) revert AmountIsZero();
        if (start == end) revert RewardStartEqEnd();
        if (start < block.timestamp || end < block.timestamp) revert CanOnlyAddFutureRewards();
        if (start % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch();
        if (end % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch();

        rewards.push(Reward(start, end, amountPerSecond));

        if (!IERC20(swapToken).transferFrom(msg.sender, address(this), (end - start) * amountPerSecond))
            revert TransferFailed();

        emit RewardAdded(start, end, amountPerSecond);
    }

    /// @notice Removes existing reward and sends remaining reward to owner
    function removeReward(uint256 index) external onlyRewardoor {
        updateRewardsWeight();

        Reward memory reward = rewards[index];

        rewards[index] = rewards[rewards.length - 1];
        rewards.pop();

        // if rewards are not unlocked completely, send remaining to owner
        if (reward.end > block.timestamp) {
            uint256 lockedRewards = (reward.end - max(block.timestamp, reward.start)) * reward.amountPerSecond;

            if (!IERC20(swapToken).transfer(msg.sender, lockedRewards)) revert TransferFailed();
        }

        emit RewardRemoved(index);
    }

    /// @notice Updates existing reward, cant change reward start if its already started
    function updateReward(
        uint256 index,
        uint256 newStart,
        uint256 newEnd,
        uint256 newAmountPerSecond
    ) external onlyRewardoor {
        if (newStart % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch();
        if (newEnd % EPOCH_DURATION != 0) revert IntervalNotRoundedWithEpoch();
        if (newAmountPerSecond == 0) revert ZeroAmount();

        updateRewardsWeight();

        Reward storage reward = rewards[index];

        uint256 oldEnd = reward.end;
        if (oldEnd < block.timestamp) revert CantChangePast();
        if (newEnd < block.timestamp) revert CanOnlyAddFutureRewards();

        uint256 oldStart = reward.start;
        if ((oldStart < block.timestamp || newStart < block.timestamp) && newStart != oldStart) revert CantChangePast();

        uint256 newTotalRewards = (newEnd - newStart) * newAmountPerSecond;
        uint256 oldTotalRewards = (oldEnd - oldStart) * reward.amountPerSecond;

        if (newStart != oldStart) {
            reward.start = uint32(newStart);
        }

        reward.end = uint32(newEnd);
        reward.amountPerSecond = uint192(newAmountPerSecond);

        if (oldTotalRewards > newTotalRewards) {
            if (!IERC20(swapToken).transfer(msg.sender, oldTotalRewards - newTotalRewards)) revert TransferFailed();
        } else if (oldTotalRewards != newTotalRewards) {
            if (!IERC20(swapToken).transferFrom(msg.sender, address(this), newTotalRewards - oldTotalRewards))
                revert TransferFailed();
        }

        emit RewardUpdated(index, newStart, newEnd, newAmountPerSecond);
    }

    /// @notice Sets address eligibility to add/update rewards
    function setRewardoor(address addr, bool value) external onlyOwner {
        rewardoors[addr] = value;

        emit RewardoorSet(addr, value);
    }

    /// @notice Creates new lock for a user, adds potential claimable amount to it
    function addLock(uint208 amount, uint256 duration) external {
        if (amount == 0) revert AmountIsZero();
        if (locks[msg.sender].length == MAX_LOCK_COUNT) revert MaxLocksSucceeded();

        uint256 newAccRewardsWeight = updateRewardsWeight();

        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);
        uint256 addedAmount = claimable + amount;

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        uint32 end = uint32(block.timestamp + duration);
        uint16 multiplier = getDurationMultiplier(duration);

        locks[msg.sender].push(Lock(multiplier, end, uint208(addedAmount)));

        totalScore += multiplier * addedAmount;

        if (!IERC20(swapToken).transferFrom(msg.sender, address(this), amount)) revert TransferFailed();

        if (claimable != 0) {
            emit Claim(msg.sender, claimable);
        }

        emit LockAdded(msg.sender, uint208(addedAmount), end, multiplier);
    }

    /// @notice adds claimable to current lock, keeping the same end
    function compound(uint8 index) external {
        uint256 bitMapIndex = getBitMapIndex(index, msg.sender);
        if (lockCompoundedBitMap.get(bitMapIndex)) revert AlreadyAutoCompound();

        uint256 newAccRewardsWeight = updateRewardsWeight();

        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);
        if (claimable == 0) revert NothingToClaim();

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        Lock storage lock = locks[msg.sender][index];

        if (lock.end < block.timestamp) revert CantUpdateExpiredLock();

        uint208 newAmount = uint208(lock.amount + claimable);
        uint16 multiplier = lock.multiplier;

        lock.amount = newAmount;
        totalScore += claimable * multiplier;

        emit Claim(msg.sender, claimable);

        emit LockUpdated(msg.sender, index, newAmount, lock.end, multiplier);
    }

    /// @notice adds amount + potential claimable to existing lock, keeping the same end
    /// @dev if lock has auto compound enabled, adjusts the compoundLastAccRewardWeight to have the same current claimable amount
    function updateLockAmount(uint256 index, uint208 amount) external {
        if (amount == 0) revert AmountIsZero();

        uint256 newAccRewardsWeight = updateRewardsWeight();

        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);
        uint256 addedAmount = amount + claimable;

        Lock storage lock = locks[msg.sender][index];

        if (lock.end < block.timestamp) revert CantUpdateExpiredLock();

        uint208 newAmount;
        if (lockCompoundedBitMap.get(getBitMapIndex(index, msg.sender))) {
            uint256 oldCompoundAmount = compoundAmount;

            compoundLastAccRewardWeight = calculateCompAccRewardWeightIn(
                oldCompoundAmount,
                addedAmount,
                newAccRewardsWeight,
                compoundLastAccRewardWeight
            );

            uint256 newShares = convertToAutoCompoundShares(addedAmount);

            compoundAmount = oldCompoundAmount + addedAmount;
            compoundShares += newShares;

            newAmount = uint208(lock.amount + newShares);
        } else {
            newAmount = uint208(lock.amount + addedAmount);
        }

        lock.amount = newAmount;

        uint16 multiplier = lock.multiplier;

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        totalScore += addedAmount * multiplier;

        if (!IERC20(swapToken).transferFrom(msg.sender, address(this), amount)) revert TransferFailed();

        if (claimable != 0) {
            emit Claim(msg.sender, claimable);
        }

        emit LockUpdated(msg.sender, uint8(index), newAmount, lock.end, multiplier);
    }

    /// @notice claims for current locks and increases duration of existing lock
    function updateLockDuration(uint8 index, uint256 duration) external {
        uint256 newAccRewardsWeight = updateRewardsWeight();

        Lock storage lock = locks[msg.sender][index];

        uint32 end = uint32(block.timestamp + duration);
        if (lock.end >= end) revert MustProlongLock(lock.end, end);

        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        uint16 multiplier = getDurationMultiplier(duration);

        lock.end = end;

        uint16 oldMultiplier = lock.multiplier;

        if (oldMultiplier > multiplier) revert UpdateToSmallerMultiplier(oldMultiplier, multiplier);

        lock.multiplier = multiplier;

        uint208 amount = lock.amount;
        totalScore += (multiplier - oldMultiplier) * amount;

        if (claimable != 0) {
            if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed();

            emit Claim(msg.sender, claimable);
        }

        emit LockUpdated(msg.sender, index, amount, end, multiplier);
    }

    /// @notice claims for current locks
    function claim() external {
        uint256 newAccRewardsWeight = updateRewardsWeight();

        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);
        if (claimable == 0) revert NothingToClaim();

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed();

        emit Claim(msg.sender, claimable);
    }

    /// @notice returns locked amount + potential claimable to user and deletes lock from array
    function unlock(uint256 index) external {
        uint256 newAccRewardsWeight = updateRewardsWeight();
        Lock storage lock = locks[msg.sender][index];

        if (lock.end > block.timestamp) revert LockStillActive();

        uint256 bitMapIndex = getBitMapIndex(index, msg.sender);

        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);

        bool isLockAutoCompound = lockCompoundedBitMap.get(bitMapIndex);
        uint256 amount;
        if (isLockAutoCompound) {
            uint256 shares = lock.amount;
            amount = convertToAutoCompoundAssets(shares);
            compoundLastAccRewardWeight = calculateCompAccRewardWeightOut(
                compoundAmount,
                amount,
                newAccRewardsWeight,
                compoundLastAccRewardWeight
            );
            compoundAmount -= amount;
            compoundShares -= shares;
        } else {
            amount = lock.amount;
        }

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        unchecked {
            totalScore -= amount * lock.multiplier;
        }

        uint256 lastLockIndex;
        unchecked {
            lastLockIndex = locks[msg.sender].length - 1;
        }

        if (index == lastLockIndex) {
            if (isLockAutoCompound) {
                lockCompoundedBitMap.unset(bitMapIndex);
            }
        } else {
            locks[msg.sender][index] = locks[msg.sender][lastLockIndex];
            uint256 lastLockBitMapIndex = getBitMapIndex(lastLockIndex, msg.sender);
            if (isLockAutoCompound) {
                if (!lockCompoundedBitMap.get(lastLockBitMapIndex)) {
                    lockCompoundedBitMap.unset(bitMapIndex);
                } else {
                    lockCompoundedBitMap.unset(lastLockBitMapIndex);
                }
            } else if (lockCompoundedBitMap.get(lastLockBitMapIndex)) {
                lockCompoundedBitMap.set(bitMapIndex);
                lockCompoundedBitMap.unset(lastLockBitMapIndex);
            }
        }

        locks[msg.sender].pop();

        if (!IERC20(swapToken).transfer(msg.sender, amount + claimable)) revert TransferFailed();

        if (claimable != 0) {
            emit Claim(msg.sender, claimable);
        }

        emit Unlock(msg.sender, amount, index);
    }

    /// @notice enables auto compound for existing lock, automatically adding all future rewards to principal
    /// @dev adjusts compoundLastAccRewardWeight so that current compound claimable remains the same
    function enableAutoCompound(uint256 index) external {
        uint256 newAccRewardsWeight = updateRewardsWeight();
        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);

        Lock storage lock = locks[msg.sender][index];
        if (lock.multiplier != MAX_MULTIPLIER) revert CantAutoCompound();

        uint256 bitMapIndex = getBitMapIndex(index, msg.sender);
        if (lockCompoundedBitMap.get(bitMapIndex)) revert AlreadyAutoCompound();

        lockCompoundedBitMap.set(bitMapIndex);

        uint256 lockAmount = lock.amount + claimable;

        uint256 shares = convertToAutoCompoundShares(lockAmount);

        compoundLastAccRewardWeight = calculateCompAccRewardWeightIn(
            compoundAmount,
            lockAmount,
            newAccRewardsWeight,
            compoundLastAccRewardWeight
        );

        compoundAmount += lockAmount;

        compoundShares += shares;

        lock.amount = uint208(shares);

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        if (claimable != 0) {
            totalScore += claimable * MAX_MULTIPLIER;
            emit Claim(msg.sender, claimable);
        }

        emit AutoCompoundEnabled(msg.sender, index, shares);
    }

    /// @notice disables auto compound for existing lock, stops automatically adding all future rewards to principal
    /// @dev adjusts compoundLastAccRewardWeight so that current compound claimable remains the same
    function disableAutoCompound(uint256 index) external {
        uint256 newAccRewardsWeight = updateRewardsWeight();
        uint256 claimable = calculateUserClaimable(msg.sender, newAccRewardsWeight);

        Lock storage lock = locks[msg.sender][index];

        uint256 bitMapIndex = getBitMapIndex(index, msg.sender);
        if (!lockCompoundedBitMap.get(bitMapIndex)) revert NotAutoCompoundEnabled();

        lockCompoundedBitMap.unset(bitMapIndex);

        uint256 sharesAmount = lock.amount;

        uint256 assets = convertToAutoCompoundAssets(sharesAmount);

        compoundLastAccRewardWeight = calculateCompAccRewardWeightOut(
            compoundAmount,
            assets,
            newAccRewardsWeight,
            compoundLastAccRewardWeight
        );

        compoundAmount -= assets;

        compoundShares -= sharesAmount;

        lock.amount = uint208(assets);

        userLastAccRewardsWeight[msg.sender] = newAccRewardsWeight;

        if (claimable != 0) {
            if (!IERC20(swapToken).transfer(msg.sender, claimable)) revert TransferFailed();
            emit Claim(msg.sender, claimable);
        }

        emit AutoCompoundDisabled(msg.sender, index, assets);
    }

    function getRewardsLength() external view returns (uint256) {
        return rewards.length;
    }

    function getUserLocks(address addr) external view returns (Lock[] memory) {
        return locks[addr];
    }

    function getLockLength(address addr) external view returns (uint256) {
        return locks[addr].length;
    }

    function getRewards() external view returns (Reward[] memory) {
        return rewards;
    }

    /// @notice is existing lock enabled for automatically adding all future rewards to principal
    function hasLockAutoCompoundEnabled(address user, uint256 index) external view returns (bool) {
        return lockCompoundedBitMap.get(getBitMapIndex(index, user));
    }

    // gets rewards weight & returns users claimable amount
    function getUserClaimable(address user) external view returns (uint256 claimable) {
        (uint256 accRewardsWeight, , , ) = getRewardWeight();

        return calculateUserClaimable(user, accRewardsWeight);
    }

    /*///////////////////////////////////////////////////////////////
                             PUBLIC
    //////////////////////////////////////////////////////////////*/

    /// @notice updates new accrued reward weight, compound accrued reward weight, total score & compound amount
    function updateRewardsWeight() public returns (uint256) {
        (
            uint256 currAccRewardWeight,
            uint256 currCompoundLastAccRewardWeight,
            uint256 currTotalScore,
            uint256 currCompoundAmount
        ) = getRewardWeight();

        lastRewardUpdate = block.timestamp;
        accRewardWeight = currAccRewardWeight;
        compoundLastAccRewardWeight = currCompoundLastAccRewardWeight;
        totalScore = currTotalScore;

        if (currCompoundAmount != compoundAmount) {
            compoundAmount = currCompoundAmount;
            emit AutoCompounded(currCompoundAmount);
        }

        return currAccRewardWeight;
    }

    function convertToAutoCompoundShares(uint256 assets) public view returns (uint256) {
        uint256 supply = compoundShares;

        return supply == 0 ? assets : assets.mulDivDown(supply, compoundAmount);
    }

    function convertToAutoCompoundAssets(uint256 shares) public view returns (uint256) {
        uint256 supply = compoundShares;

        return supply == 0 ? shares : shares.mulDivDown(compoundAmount, supply);
    }

    /*///////////////////////////////////////////////////////////////
                             INTERNAL
    //////////////////////////////////////////////////////////////*/

    /// @notice calculates new accrued reward weight and does auto compound
    /// @dev iterate over all rewards on every epoch to find epoch reward
    function getRewardWeightRegular()
        internal
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256
        )
    {
        uint256 currTotalScore = totalScore;
        if (currTotalScore == 0) {
            return (accRewardWeight, compoundLastAccRewardWeight, currTotalScore, compoundAmount);
        }

        uint256 _lastRewardUpdate = lastRewardUpdate;

        uint256 currAccRewardWeight = accRewardWeight;
        uint256 currCompoundLastAccRewardWeight = compoundLastAccRewardWeight;

        uint256 currCompoundAmount = compoundAmount;

        Reward[] memory rewardsMem = rewards;

        uint256 from;
        uint256 to;
        uint256 epochRewards;
        uint256 compoundClaimable;

        from = _lastRewardUpdate;
        to = getEpoch(_lastRewardUpdate) + EPOCH_DURATION;
        while (to <= block.timestamp) {
            epochRewards = getPeriodRewards(rewardsMem, from, to);
            unchecked {
                currAccRewardWeight += epochRewards.divWadDown(currTotalScore);
                compoundClaimable = (currAccRewardWeight - currCompoundLastAccRewardWeight).mulWadDown(
                    currCompoundAmount * MAX_MULTIPLIER
                );
                currCompoundAmount += compoundClaimable;
                currCompoundLastAccRewardWeight = currAccRewardWeight;
                currTotalScore += compoundClaimable * MAX_MULTIPLIER;

                from = to;
                to += EPOCH_DURATION;
            }
        }

        if (from < block.timestamp) {
            epochRewards = getPeriodRewards(rewardsMem, from, block.timestamp);

            currAccRewardWeight += epochRewards.divWadDown(currTotalScore);
        }

        return (currAccRewardWeight, currCompoundLastAccRewardWeight, currTotalScore, currCompoundAmount);
    }

    /// @notice calculates new accrued reward weight and does auto compound if needed
    /// @dev if we're still in the same epoch as last one, dont do auto compounding
    /// @dev if more than 5 epochs have passed since last update, do the optimized method(find intersections, sort, calculate, apply)
    /// @dev if no more than 5 epochs have passed since last update, do the regular method(iterate over all rewards every epoch)
    /// @return new accRewardWeight, compoundLastAccRewardWeight, totalScore, compoundAmount
    function getRewardWeight()
        internal
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256
        )
    {
        uint256 rewardUpdate = lastRewardUpdate;
        if (rewardUpdate == block.timestamp) {
            return (accRewardWeight, compoundLastAccRewardWeight, totalScore, compoundAmount);
        }

        uint256 lastUpdateEpoch = getEpoch(rewardUpdate);
        uint256 currEpoch = getEpoch(block.timestamp);

        if (lastUpdateEpoch == currEpoch) {
            return (getRewardWeightWithoutAutoComp(), compoundLastAccRewardWeight, totalScore, compoundAmount);
        }

        unchecked { 
            if ((currEpoch - lastUpdateEpoch) / EPOCH_DURATION > ALGORITHM_THRESHOLD_IN_EPOCHS) {
                return getRewardWeightOpt();
            }   
        }

        return getRewardWeightRegular();
    }

    /// @notice calculates new accrued reward weight and does auto compound if needed in an optimized way
    /// @dev first finds intersections of lastRewardUpdate, block.timestamp and reward interval
    /// @dev then sorts them and calculates total reward per epoch for every period
    /// @dev then goes through epochs and compounds claimable amount to principal
    function getRewardWeightOpt()
        internal
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256
        )
    {
        uint256 currTotalScore = totalScore;
        if (currTotalScore == 0) {
            return (accRewardWeight, compoundLastAccRewardWeight, currTotalScore, compoundAmount);
        }

        CompoundVars memory compVars;
        compVars.from = lastRewardUpdate;

        uint256 currAccRewardWeight = accRewardWeight;
        compVars.currCompLastAccRewardWeight = compoundLastAccRewardWeight;
        uint256 currCompoundAmount = compoundAmount;

        Reward[] memory rewardsMem = rewards;
        (uint256[] memory intersections, uint256 emptyIntersections) = getPeriodIntersections(
            compVars.from,
            block.timestamp,
            rewardsMem
        );

        if (intersections.length == emptyIntersections) {
            return (currAccRewardWeight, compVars.currCompLastAccRewardWeight, currTotalScore, compoundAmount);
        }

        LibSort.insertionSort(intersections);
        (TotalReward[] memory periodsTotalReward, uint256 zeroPeriods) = getTotalRewardPeriods(
            intersections,
            rewardsMem,
            emptyIntersections
        );

        compVars.to = getEpoch(compVars.from) + EPOCH_DURATION;

        while (compVars.to <= block.timestamp && compVars.currentPeriod < periodsTotalReward.length - zeroPeriods) {
            // reward period hasnt started, go to next epoch
            if (periodsTotalReward[compVars.currentPeriod].start > compVars.from) {
                (compVars.from, compVars.to) = goToNextEpoch(compVars.to);
                continue;
            }

            // reward period has ended, go to next reward period
            if (periodsTotalReward[compVars.currentPeriod].end < compVars.to) {
                unchecked {
                    ++compVars.currentPeriod;
                }
                continue;
            }

            // reward period has 0 rewards, go to next epoch
            if (periodsTotalReward[compVars.currentPeriod].epochReward == 0) {
                (compVars.from, compVars.to) = goToNextEpoch(compVars.to);
                continue;
            }

            // for first period, epoch rewards might already be accounted for, so take just proportionaly
            if (compVars.currentPeriod == 0 && compVars.to - compVars.from < EPOCH_DURATION) {
                unchecked {
                    compVars.epochRewards = periodsTotalReward[compVars.currentPeriod].epochReward.mulDivDown(
                        compVars.to - compVars.from,
                        EPOCH_DURATION
                    );
                }
            } else {
                compVars.epochRewards = periodsTotalReward[compVars.currentPeriod].epochReward;
            }

            // compound
            unchecked {
                currAccRewardWeight += compVars.epochRewards.divWadDown(currTotalScore);
                compVars.compoundClaimable = (currAccRewardWeight - compVars.currCompLastAccRewardWeight).mulWadDown(
                    currCompoundAmount * MAX_MULTIPLIER
                );
                compVars.currCompLastAccRewardWeight = currAccRewardWeight;
                currCompoundAmount += compVars.compoundClaimable;
                currTotalScore += compVars.compoundClaimable * MAX_MULTIPLIER;
            }

            (compVars.from, compVars.to) = goToNextEpoch(compVars.to);
        }

        // auto compound is over, calculate potential new accrued reward weight
        if (compVars.from < block.timestamp && compVars.currentPeriod < periodsTotalReward.length) {
            // if last reward period ended with last epoch, and new period exist, go to new period
            if (
                periodsTotalReward[compVars.currentPeriod].end < block.timestamp &&
                compVars.currentPeriod < periodsTotalReward.length - zeroPeriods - 1
            ) {
                unchecked {
                    ++compVars.currentPeriod;
                }
            }

            if (periodsTotalReward[compVars.currentPeriod].end >= block.timestamp) {
                unchecked {
                    uint256 newRewards = (periodsTotalReward[compVars.currentPeriod].epochReward *
                        (block.timestamp - compVars.from)) / EPOCH_DURATION;

                    currAccRewardWeight += newRewards.divWadDown(currTotalScore);
                }
            }
        }

        return (currAccRewardWeight, compVars.currCompLastAccRewardWeight, currTotalScore, currCompoundAmount);
    }

    // calculates rewards weight
    function getRewardWeightWithoutAutoComp() internal view returns (uint256) {
        // to avoid div by zero on first lock
        uint256 _totalScore = totalScore;
        if (_totalScore == 0) {
            return accRewardWeight;
        }

        uint256 _lastRewardUpdate = lastRewardUpdate;

        uint256 length = rewards.length;
        uint256 newRewards;
        Reward storage reward;
        for (uint256 rewardId = 0; rewardId < length; ) {
            reward = rewards[rewardId];

            unchecked {
                ++rewardId;
            }

            uint256 start = reward.start;
            uint256 end = reward.end;

            if (block.timestamp < start) continue;
            if (_lastRewardUpdate > end) continue;

            newRewards += (min(block.timestamp, end) - max(start, _lastRewardUpdate)) * reward.amountPerSecond;
        }

        return newRewards == 0 ? accRewardWeight : accRewardWeight + newRewards.divWadDown(_totalScore);
    }

    // returns users score for all locks
    function getUsersNoCompoundScore(address user) internal view returns (uint256 score) {
        uint256 lockLength = locks[user].length;
        Lock storage lock;
        for (uint256 lockId = 0; lockId < lockLength; ++lockId) {
            lock = locks[user][lockId];
            if (lockCompoundedBitMap.get(getBitMapIndex(lockId, user))) {
                continue;
            }
            score += lock.amount * lock.multiplier;
        }
    }

    /// @notice returns users claimable amount, not taking auto compound enabled locks into account
    function calculateUserClaimable(address user, uint256 accRewardsWeight_) internal view returns (uint256 claimable) {
        uint256 userScore = getUsersNoCompoundScore(user);

        unchecked {
            return calculateClaimable(userScore, accRewardsWeight_ - userLastAccRewardsWeight[user]);
        }
    }

    /// @notice calculates claimable amount given score and accrued reward weight difference
    function calculateClaimable(uint256 score, uint256 accRewardWeightDiff) internal pure returns (uint256) {
        return score.mulWadDown(accRewardWeightDiff);
    }

    /// @notice returns smaller of two uint256
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x < y ? x : y;
    }

    /// @notice return bigger of two uint256
    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x > y ? x : y;
    }

    // returns multiplier on amount locked for duration in seconds times 100
    // aprox of function (2592000,1),(31536000,2),(94608000,5),(157680000,10)
    // 2.22574×10^-16 x^2 + 2.19094×10^-8 x + 0.993975
    function getDurationMultiplier(uint256 duration) internal pure returns (uint16) {
        if (duration < 30 days || duration > 1825 days) revert DurationOutOfBounds(duration);

        return uint16((222574 * duration * duration + 21909400000000 * duration + 993975000000000000000) / 1e19);
    }

    /// @notice returns uint256 index for bitmap used to indicate whether lock is enabled for auto compound
    /// @dev first 160 bits are address, last 96 bits are index, index is currently never bigger than 5
    function getBitMapIndex(uint256 index, address addr) internal pure returns (uint256) {
        return uint256(index | (uint160(addr) << 96));
    }

    /// @notice calculates new compound accrued reward weight, to have the same claimable amount with added amount
    function calculateCompAccRewardWeightIn(
        uint256 currCompoundAmount,
        uint256 incomingAmount,
        uint256 lastAccRewardWeight,
        uint256 lastCompAccRewardWeight
    ) internal pure returns (uint256) {
        return
            lastAccRewardWeight -
            ((lastAccRewardWeight - lastCompAccRewardWeight) * currCompoundAmount) /
            (currCompoundAmount + incomingAmount);
    }

    /// @notice calculates new compound accrued reward weight, to have the same claimable amount with substracted amount
    function calculateCompAccRewardWeightOut(
        uint256 currCompoundAmount,
        uint256 incomingAmount,
        uint256 lastAccRewardWeight,
        uint256 lastCompAccRewardWeight
    ) internal pure returns (uint256) {
        if (incomingAmount == currCompoundAmount) return lastAccRewardWeight;
        return
            lastAccRewardWeight -
            ((lastAccRewardWeight - lastCompAccRewardWeight) * currCompoundAmount) /
            (currCompoundAmount - incomingAmount);
    }

    function getEpoch(uint256 timestamp) internal pure returns (uint256) {
        unchecked {
            return timestamp - (timestamp % EPOCH_DURATION);
        }
    }

    /// @notice calculates eligible rewards for given time interval
    function getPeriodRewards(
        Reward[] memory rewardsMem,
        uint256 from,
        uint256 to
    ) internal pure returns (uint256 epochRewards) {
        for (uint256 i = 0; i < rewardsMem.length; ) {
            if (to < rewardsMem[i].start) {
                unchecked {
                    ++i;
                }
                continue;
            }
            if (from > rewardsMem[i].end) {
                unchecked {
                    ++i;
                }
                continue;
            }

            unchecked {
                epochRewards +=
                    (min(to, rewardsMem[i].end) - max(rewardsMem[i].start, from)) *
                    rewardsMem[i].amountPerSecond;
                ++i;
            }
        }
    }

    /// @notice calculates total reward per epoch for multiple rewards that change on intersections
    function getTotalRewardPeriods(
        uint256[] memory intersections,
        Reward[] memory rewardsMem,
        uint256 emptyIntersections
    ) internal pure returns (TotalReward[] memory totalRewards, uint256 zeroPeriods) {
        totalRewards = new TotalReward[](intersections.length - emptyIntersections - 1);

        uint256 start;
        uint256 end;
        uint256 epochReward;
        uint256 j;
        uint256 periodsIdx;
        for (uint256 i = emptyIntersections; i < intersections.length - 1; ) {
            start = intersections[i];
            end = intersections[i + 1];
            if (start == end) {
                unchecked {
                    ++zeroPeriods;
                    ++i;
                }

                continue;
            }
            epochReward = 0;
            for (j = 0; j < rewardsMem.length; ) {
                if (rewardsMem[j].start > start) {
                    unchecked {
                        ++j;
                    }
                    continue;
                }
                if (rewardsMem[j].end < end) {
                    unchecked {
                        ++j;
                    }
                    continue;
                }

                unchecked {
                    epochReward += EPOCH_DURATION * rewardsMem[j].amountPerSecond;
                    ++j;
                }
            }

            unchecked {
                ++i;
                totalRewards[periodsIdx++] = TotalReward(start, end, epochReward);
            }
        }

        return (totalRewards, zeroPeriods);
    }

    /// @notice gets intersections of reward intervals and arbitrary interval
    function getPeriodIntersections(
        uint256 from,
        uint256 to,
        Reward[] memory rewardsMem
    ) internal pure returns (uint256[] memory, uint256) {
        // in the worst case where all rewards are eligible we're going to have x2 intersections
        uint256[] memory intersections = new uint256[](rewardsMem.length * 2);
        uint256 emptyIntersections;
        uint256 start;
        uint256 end;
        uint256 intersectionsIdx;

        for (uint256 i; i < rewardsMem.length; ) {
            start = max(from, rewardsMem[i].start);
            end = min(to, rewardsMem[i].end);
            unchecked {
                if (start < end) {
                    intersections[intersectionsIdx++] = start;
                    intersections[intersectionsIdx++] = end;
                } else {
                    emptyIntersections += 2;
                }

                ++i;
            }
        }

        return (intersections, emptyIntersections);
    }

    /// @notice return next epoch start and ending point
    function goToNextEpoch(uint256 to) internal pure returns (uint256, uint256) {
        unchecked {
            return (to, to + EPOCH_DURATION);
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyAutoCompound","type":"error"},{"inputs":[],"name":"AmountIsZero","type":"error"},{"inputs":[],"name":"CanOnlyAddFutureRewards","type":"error"},{"inputs":[],"name":"CantAutoCompound","type":"error"},{"inputs":[],"name":"CantChangePast","type":"error"},{"inputs":[],"name":"CantUpdateExpiredLock","type":"error"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"DurationOutOfBounds","type":"error"},{"inputs":[],"name":"IntervalNotRoundedWithEpoch","type":"error"},{"inputs":[],"name":"LockStillActive","type":"error"},{"inputs":[],"name":"MaxLocksSucceeded","type":"error"},{"inputs":[],"name":"MaxRewardsSucceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"oldDuration","type":"uint256"},{"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"MustProlongLock","type":"error"},{"inputs":[],"name":"NotAutoCompoundEnabled","type":"error"},{"inputs":[],"name":"NotRewardoor","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"RewardStartEqEnd","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"uint16","name":"oldMultiplier","type":"uint16"},{"internalType":"uint16","name":"newMultiplier","type":"uint16"}],"name":"UpdateToSmallerMultiplier","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroPrecision","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AutoCompoundDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"AutoCompoundEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"compoundAmount","type":"uint256"}],"name":"AutoCompounded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint208","name":"amount","type":"uint208"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"multiplier","type":"uint16"}],"name":"LockAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint8","name":"index","type":"uint8"},{"indexed":false,"internalType":"uint208","name":"amount","type":"uint208"},{"indexed":false,"internalType":"uint32","name":"end","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"multiplier","type":"uint16"}],"name":"LockUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPerSecond","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"RewardRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPerSecond","type":"uint256"}],"name":"RewardUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardoor","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"RewardoorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"Unlock","type":"event"},{"inputs":[],"name":"ALGORITHM_THRESHOLD_IN_EPOCHS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EPOCH_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_LOCK_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_REWARD_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accRewardWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint208","name":"amount","type":"uint208"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"addLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint192","name":"amountPerSecond","type":"uint192"}],"name":"addReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"compound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"compoundAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundLastAccRewardWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compoundShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAutoCompoundAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToAutoCompoundShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"disableAutoCompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"enableAutoCompound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getLockLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewards","outputs":[{"components":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint192","name":"amountPerSecond","type":"uint192"}],"internalType":"struct LockedStaking.Reward[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserClaimable","outputs":[{"internalType":"uint256","name":"claimable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getUserLocks","outputs":[{"components":[{"internalType":"uint16","name":"multiplier","type":"uint16"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint208","name":"amount","type":"uint208"}],"internalType":"struct LockedStaking.Lock[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"hasLockAutoCompoundEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_swapToken","type":"address"},{"internalType":"uint256","name":"_precision","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastRewardUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"locks","outputs":[{"internalType":"uint16","name":"multiplier","type":"uint16"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint208","name":"amount","type":"uint208"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardoors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"uint32","name":"start","type":"uint32"},{"internalType":"uint32","name":"end","type":"uint32"},{"internalType":"uint192","name":"amountPerSecond","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setRewardoor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalScore","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint208","name":"amount","type":"uint208"}],"name":"updateLockAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"updateLockDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"newStart","type":"uint256"},{"internalType":"uint256","name":"newEnd","type":"uint256"},{"internalType":"uint256","name":"newAmountPerSecond","type":"uint256"}],"name":"updateReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateRewardsWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userLastAccRewardsWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6145b280620000f36000396000f3fe608060405234801561001057600080fd5b50600436106102de5760003560e01c80638da5cb5b11610186578063cd6dc687116100e3578063dc73e49c11610097578063ea25afda11610071578063ea25afda146105bc578063f2fde38b146105cf578063f301af42146105e257600080fd5b8063dc73e49c14610583578063dca4c9f814610596578063e3a150da146105a957600080fd5b8063d3b5dc3b116100c8578063d3b5dc3b14610572578063d7da1dee1461057b578063dc36a3d31461032957600080fd5b8063cd6dc6871461054c578063d2d26c601461055f57600080fd5b8063abf7fa041161013a578063b425f8021161011f578063b425f802146104ef578063c006719f14610530578063c553173f1461053957600080fd5b8063abf7fa0414610329578063b0128d3f146104c657600080fd5b8063a3c2710d1161016b578063a3c2710d146104ab578063a70b9f0c146104b4578063a86572a0146104bd57600080fd5b80638da5cb5b1461047357806399fd29801461049857600080fd5b80634e71d92d1161023f57806367148931116101f35780637eed69b5116101cd5780637eed69b51461043757806388267c59146104575780638c614c7a1461046057600080fd5b80636714893114610409578063715018a61461041c5780637a3a58df1461042457600080fd5b80635b7917d9116102245780635b7917d9146103da5780635d6a618d146103ed5780636198e339146103f657600080fd5b80634e71d92d146103c95780635a8583fd146103d157600080fd5b8063253418bc116102965780633cdaccb61161027b5780633cdaccb61461037a578063405d0a25146103ad57806348dcb051146103c057600080fd5b8063253418bc1461035f578063325e04531461036757600080fd5b806306afa8ef116102c757806306afa8ef146103165780630e3cf4441461032957806323a35de91461033f57600080fd5b8063043c9693146102e35780630572b0cc146102f8575b600080fd5b6102f66102f13660046140a8565b610621565b005b61030061087d565b60405161030d91906140c3565b60405180910390f35b6102f6610324366004614153565b610909565b610331600581565b60405190815260200161030d565b61035261034d36600461418a565b61098f565b60405161030d91906141a5565b610331610a2f565b6102f6610375366004614218565b610aa7565b61039d61038836600461418a565b606d6020526000908152604090205460ff1681565b604051901515815260200161030d565b6103316103bb36600461426b565b610eb5565b610331606f5481565b6102f6610ede565b61033160715481565b6102f66103e836600461426b565b611022565b6103316103e681565b6102f661040436600461426b565b6112b6565b6102f661041736600461429b565b6117fa565b6102f6611b80565b61033161043236600461426b565b611b94565b61033161044536600461418a565b60696020526000908152604090205481565b61033160705481565b61033161046e36600461418a565b611bb0565b6033546001600160a01b03165b6040516001600160a01b03909116815260200161030d565b6102f66104a63660046142c7565b611bca565b610331606a5481565b61033161708081565b610331606c5481565b6103316104d436600461418a565b6001600160a01b031660009081526068602052604090205490565b6105026104fd3660046142f1565b611eed565b6040805161ffff909416845263ffffffff90921660208401526001600160d01b03169082015260600161030d565b610331606b5481565b6102f661054736600461426b565b611f40565b6102f661055a3660046142f1565b612248565b61039d61056d3660046142f1565b61248f565b61033160665481565b606754610331565b606554610480906001600160a01b031681565b6102f66105a436600461426b565b6124bf565b6102f66105b736600461430d565b612716565b6102f66105ca36600461433f565b612bd2565b6102f66105dd36600461418a565b612efd565b6105f56105f036600461426b565b612fa7565b6040805163ffffffff94851681529390921660208401526001600160c01b03169082015260600161030d565b60ff81163360601b73ffffffffffffffff000000000000000000000000168117600881901c6000908152606e602052604090205490916001901b1615610693576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061069d610a2f565b905060006106ab3383612fef565b9050806000036106e7576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260696020908152604080832085905560689091528120805460ff87169081106107185761071861435b565b60009182526020909120018054909150426201000090910463ffffffff16101561076e576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054600090610791908490660100000000000090046001600160d01b03166143b9565b82546001600160d01b03821666010000000000000265ffffffffffff821617845590915061ffff166107c381856143cc565b606b60008282546107d491906143b9565b909155505060405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a282546040805160ff8a1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080015b60405180910390a250505050505050565b60606067805480602002602001604051908101604052809291908181526020016000905b82821015610900576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b0316908201528252600190920191016108a1565b50505050905090565b61091161302c565b6001600160a01b0382166000818152606d602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f2b8508073c9bd6054077cb8ab52c19b9616a8970f3fcc0a7163b082f16fd560a91015b60405180910390a25050565b6001600160a01b0381166000908152606860209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610a24576000848152602090819020604080516060810182529185015461ffff8116835262010000810463ffffffff1683850152660100000000000090046001600160d01b0316908201528252600190920191016109c7565b505050509050919050565b6000806000806000610a3f6130a0565b42606a55606c8490556071839055606b829055606f54939750919550935091508114610a9e57606f8190556040518181527fa803098eab41616e8c09907603003b82c457356a707199ad558994e6187830539060200160405180910390a15b50919392505050565b336000908152606d602052604090205460ff16610af0576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6067547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01610b4b576040517f44fea23a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160c01b0316600003610b8e576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8163ffffffff168363ffffffff1603610bd3576040517fb78de82800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428363ffffffff161080610bec5750428263ffffffff16105b15610c23576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3561708063ffffffff8516614412565b15610c6c576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c7e61708063ffffffff8416614412565b15610cb5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160608101825263ffffffff8086168252848116602083019081526001600160c01b038086169484019485526067805460018101825560009190915293517f9787eeb91fe3101235e4a76063c7023ecb40f923f97916639c598592fa30d6ae909401805492519551909116680100000000000000000267ffffffffffffffff958416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909316949093169390931717929092169190911790556065546001600160a01b03166323b872dd333084610d968888614426565b63ffffffff16610da6919061444a565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526001600160c01b031660448201526064016020604051808303816000875af1158015610e1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3f919061447c565b610e5c576040516312171d8360e31b815260040160405180910390fd5b6040805163ffffffff8086168252841660208201526001600160c01b038316918101919091527f9795f222c951ae3e749f872dbe287f78d21fa52353e9175cb20ed3aa2b29b82b906060015b60405180910390a1505050565b6070546000908015610ed557606f54610ed090849083613146565b610ed7565b825b9392505050565b6000610ee8610a2f565b90506000610ef63383612fef565b905080600003610f32576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152606960205260409081902084905560655490517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810192909252602482018390526001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd3919061447c565b610ff0576040516312171d8360e31b815260040160405180910390fd5b60405181815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d490602001610983565b600061102c610a2f565b9050600061103a3383612fef565b33600090815260686020526040812080549293509091859081106110605761106061435b565b60009182526020822001915073ffffffffffffffff0000000000000000000000003360601b168517600881901c6000908152606e6020526040902054909150600160ff83161b166110dd576040517f18c62fcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604090208054600160ff84161b191690558154660100000000000090046001600160d01b0316600061111d82610eb5565b905061112f606f548288607154613164565b60718190555080606f60008282546111479190614499565b9250508190555081607060008282546111609190614499565b9091555050835465ffffffffffff1666010000000000006001600160d01b03831602178455336000908152606960205260409020869055841561127e576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018790526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015611207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122b919061447c565b611248576040516312171d8360e31b815260040160405180910390fd5b60405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f45f21e7b59d72f575ccab5204bfb96c1af1aee613cffb4d1b9db2e757c25e8c5910161086c565b60006112c0610a2f565b33600090815260686020526040812080549293509091849081106112e6576112e661435b565b60009182526020909120018054909150426201000090910463ffffffff16111561133c576040517fba8dbe4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffff0000000000000000000000003360601b168417905060006113683385612fef565b600883901c6000908152606e6020526040812054919250600160ff85161b90911615801591906113ff578454660100000000000090046001600160d01b03166113b081610eb5565b91506113c2606f548389607154613164565b60718190555081606f60008282546113da9190614499565b9250508190555080607060008282546113f39190614499565b90915550611416915050565b508354660100000000000090046001600160d01b03165b3360009081526069602090815260408083208990558754606b805461ffff909216860290910390556068909152902054600019810190880360010161148557821561148057600885901c6000908152606e602052604090208054600160ff88161b19169055611682565b611682565b3360009081526068602052604090208054829081106114a6576114a661435b565b9060005260206000200160686000336001600160a01b03166001600160a01b0316815260200190815260200160002089815481106114e6576114e661435b565b6000918252602082208354910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000811661ffff9093169283178255845463ffffffff620100009182900416027fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000009091169092179190911780825592546001600160d01b03660100000000000091829004160265ffffffffffff909316929092179091556115ad823360601b73ffffffffffffffff000000000000000000000000161790565b9050831561161f57600881901c6000908152606e6020526040902054600160ff83161b166115fa57600886901c6000908152606e602052604090208054600160ff89161b19169055611680565b600881901c6000908152606e602052604090208054600160ff84161b19169055611680565b600881901c6000908152606e6020526040902054600160ff83161b161561168057600886901c6000908152606e602052604090208054600160ff89161b179055600881901c6000908152606e602052604090208054600160ff84161b191690555b505b3360009081526068602052604090208054806116a0576116a06144ac565b6000828152602081208201600019908101919091550190556065546001600160a01b031663a9059cbb336116d487866143b9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175b919061447c565b611778576040516312171d8360e31b815260040160405180910390fd5b83156117b45760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b60408051838152602081018a905233917ff7870c5b224cbc19873599e46ccfc7103934650509b1af0c3ce90138377c200491015b60405180910390a25050505050505050565b806001600160d01b031660000361183d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611847610a2f565b905060006118553383612fef565b9050600061186c826001600160d01b0386166143b9565b33600090815260686020526040812080549293509091879081106118925761189261435b565b60009182526020909120018054909150426201000090910463ffffffff1610156118e8576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f73ffffffffffffffff0000000000000000000000003360601b1688175b600881901c6000908152606e6020526040902054600160ff9092169190911b16151590565b156119a9576000606f5490506119498185886071546131b0565b607155600061195785611b94565b905061196385836143b9565b606f81905550806070600082825461197b91906143b9565b909155505083546119a0908290660100000000000090046001600160d01b03166143b9565b925050506119cc565b81546119c9908490660100000000000090046001600160d01b03166143b9565b90505b81546001600160d01b03821666010000000000000265ffffffffffff82168117845533600090815260696020526040902087905561ffff908116911617611a1381856143cc565b606b6000828254611a2491906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611aa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac5919061447c565b611ae2576040516312171d8360e31b815260040160405180910390fd5b8415611b1e5760405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b82546040805160ff8b1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080016117e8565b611b8861302c565b611b9260006131bc565b565b6070546000908015610ed557606f54610ed09084908390613146565b600080611bbb6130a0565b5050509050610ed78382612fef565b816001600160d01b0316600003611c0d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152606860205260409020547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01611c75576040517f5ad3064300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c7f610a2f565b90506000611c8d3383612fef565b90506000611ca46001600160d01b038616836143b9565b336000908152606960205260408120859055909150611cc385426143b9565b90506000611cd086613226565b336000908152606860209081526040808320815160608101835261ffff80871680835263ffffffff808b168488019081526001600160d01b03808e169786019788528654600181018855968a529790982093519390940180549751955190961666010000000000000265ffffffffffff9590941662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000090971692909116919091179490941791909116179055909150611d8e9084906143cc565b606b6000828254611d9f91906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e40919061447c565b611e5d576040516312171d8360e31b815260040160405180910390fd5b8315611e995760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080516001600160d01b038516815263ffffffff8416602082015261ffff83169181019190915233907f7b2d54511a19cedc58c31bf2a96ea21396676caf714de85f97ab140a3a4ff1129060600161086c565b60686020528160005260406000208181548110611f0957600080fd5b60009182526020909120015461ffff8116925062010000810463ffffffff169150660100000000000090046001600160d01b031683565b336000908152606d602052604090205460ff16611f89576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f91610a2f565b50600060678281548110611fa757611fa761435b565b600091825260209182902060408051606081018252919092015463ffffffff8082168352640100000000820416938201939093526001600160c01b03680100000000000000009093049290921690820152606780549192509061200c90600190614499565b8154811061201c5761201c61435b565b90600052602060002001606783815481106120395761203961435b565b6000918252602090912082549101805463ffffffff9283167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082168117835584547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921617640100000000918290049093160291909117808255915467ffffffffffffffff90921668010000000000000000928390046001600160c01b031690920291909117905560678054806120f3576120f36144ac565b6000828152602080822060001990840181019290925591019091558101514263ffffffff909116111561221157600081604001516001600160c01b031661214442846000015163ffffffff166132ce565b836020015163ffffffff166121599190614499565b61216391906143cc565b6065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390529192506001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156121ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f2919061447c565b61220f576040516312171d8360e31b815260040160405180910390fd5b505b6040518281527f5d3a571a89edce81bd931e9d740ff7f0560940fc502a27f178f002eca691dfd99060200160405180910390a15050565b600054610100900460ff16158080156122685750600054600160ff909116105b806122825750303b158015612282575060005460ff166001145b612313576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561237157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0383166123b1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036123eb576040517fd41c43dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516179055606682905561242b6132e4565b801561248a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610ea8565b505050565b60006124b661190a838560601b73ffffffffffffffff000000000000000000000000161790565b90505b92915050565b60006124c9610a2f565b905060006124d73383612fef565b33600090815260686020526040812080549293509091859081106124fd576124fd61435b565b6000918252602090912001805490915061ffff166103e61461254b576040517fbe53ebc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360601b73ffffffffffffffff000000000000000000000000168417600881901c6000908152606e6020526040902054600160ff87161b16156125ba576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604081208054600160ff85161b17905582546125f9908590660100000000000090046001600160d01b03166143b9565b9050600061260682611b94565b9050612618606f5483886071546131b0565b60718190555081606f600082825461263091906143b9565b92505081905550806070600082825461264991906143b9565b9091555050835465ffffffffffff1666010000000000006001600160d01b0383160217845533600090815260696020526040902086905584156126de576126926103e6866143cc565b606b60008282546126a391906143b9565b909155505060405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f49311a438ed24b95a0b16011315cf7525bb5b88be477d6d37b57aabc85017c08910161086c565b336000908152606d602052604090205460ff1661275f576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61276b61708084614412565b156127a2576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127ae61708083614412565b156127e5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000361281f576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612827610a2f565b5060006067858154811061283d5761283d61435b565b60009182526020909120018054909150640100000000900463ffffffff1642811015612895576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428410156128cf576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815463ffffffff16428110806128e457504286105b80156128f05750808614155b15612927576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000846129348888614499565b61293e91906143cc565b84549091506000906801000000000000000090046001600160c01b03166129658486614499565b61296f91906143cc565b90508288146129a75784547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff89161785555b845463ffffffff9081166401000000009189169190910267ffffffffffffffff1617680100000000000000006001600160c01b0388160217855581811115612aae576065546001600160a01b031663a9059cbb33612a058585614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061447c565b612aa9576040516312171d8360e31b815260040160405180910390fd5b612b7f565b818114612b7f576065546001600160a01b03166323b872dd3330612ad28587614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b62919061447c565b612b7f576040516312171d8360e31b815260040160405180910390fd5b604080518a8152602081018a9052908101889052606081018790527fce702e82d3aef8d6cd9b4dc0baace0b1e11e83af272382cd526d351c5162d1e09060800160405180910390a1505050505050505050565b6000612bdc610a2f565b3360009081526068602052604081208054929350909160ff8616908110612c0557612c0561435b565b600091825260208220019150612c1b84426143b9565b825490915063ffffffff808316620100009092041610612c805781546040517f1e96fff80000000000000000000000000000000000000000000000000000000081526201000090910463ffffffff90811660048301528216602482015260440161230a565b6000612c8c3385612fef565b336000908152606960205260408120869055909150612caa86613226565b845463ffffffff851662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff82168117875591925061ffff91821690821617908216811115612d36576040517f2759864a00000000000000000000000000000000000000000000000000000000815261ffff80831660048301528316602482015260440161230a565b84547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff831617808655660100000000000090046001600160d01b031680612d8183856144db565b61ffff16612d8f91906144f6565b6001600160d01b0316606b6000828254612da991906143b9565b90915550508315612e95576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061447c565b612e5f576040516312171d8360e31b815260040160405180910390fd5b60405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b6040805160ff8b1681526001600160d01b038316602082015263ffffffff87168183015261ffff85166060820152905133917fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2919081900360800190a2505050505050505050565b612f0561302c565b6001600160a01b038116612f9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161230a565b612fa4816131bc565b50565b60678181548110612fb757600080fd5b60009182526020909120015463ffffffff8082169250640100000000820416906801000000000000000090046001600160c01b031683565b600080612ffb84613383565b6001600160a01b0385166000908152606960205260409020549091506130249082908503613458565b949350505050565b6033546001600160a01b03163314611b92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161230a565b6000806000806000606a5490504281036130ce57606c54607154606b54606f54945094509450945050613140565b617080808206820390429081069003808203613105576130ec613464565b607154606b54606f549650965096509650505050613140565b600561708083830304111561312c5761311c613568565b9650965096509650505050613140565b6131346139b5565b96509650965096505050505b90919293565b600082600019048411830215820261315d57600080fd5b5091020490565b6000848403613174575081613024565b61317e8486614499565b856131898486614499565b61319391906143cc565b61319d919061451f565b6131a79084614499565b95945050505050565b600061317e84866143b9565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600062278d0082108061323c5750630966018082115b15613276576040517f91aaaf240000000000000000000000000000000000000000000000000000000081526004810183905260240161230a565b678ac7230489e8000061328f836513ed2e0116006143cc565b8361329d816203656e6143cc565b6132a791906143cc565b6132b191906143b9565b6132c4906835e22c9431dae580006143b9565b6124b9919061451f565b60008183116132dd57816124b6565b5090919050565b600054610100900460ff1661337b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92613b26565b6001600160a01b03811660009081526068602052604081205481805b82811015613450576001600160a01b03851660009081526068602052604090208054829081106133d1576133d161435b565b90600052602060002001915061340261190a828760601b73ffffffffffffffff000000000000000000000000161790565b61344057815461342a9061ffff811690660100000000000090046001600160d01b03166144f6565b61343d906001600160d01b0316856143b9565b93505b61344981614533565b905061339f565b505050919050565b60006124b68383613bc6565b606b54600090808203613479575050606c5490565b606a54606754600080805b83811015613537576067818154811061349f5761349f61435b565b6000918252602090912001805490925060019091019063ffffffff80821691640100000000900416428211156134d6575050613484565b808711156134e5575050613484565b83546801000000000000000090046001600160c01b031661350683896132ce565b6135104284613bdb565b61351a9190614499565b61352491906143cc565b61352e90866143b9565b94505050613484565b50811561355a576135488286613bea565b606c5461355591906143b9565b61355e565b606c545b9550505050505090565b6000806000806000606b5490508060000361359557606c5460715482606f54945094509450945050613140565b6135ce6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b606a548152606c5460715460a0830152606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613663576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613604565b50505050905060008061367b86600001514285613bff565b91509150808251036136a557848660a0015188606f549a509a509a509a5050505050505050613140565b6136ae82613d3d565b6000806136bc848685613d92565b895191935091506136d5906170809081810690036143b9565b60208901525b428860200151111580156136fe57508082516136f79190614499565b8860400151105b156138ad5787600001518289604001518151811061371e5761371e61435b565b602002602001015160000151111561374757602088015161708081015b60208a015288526136db565b8760200151828960400151815181106137625761376261435b565b60200260200101516020015110156137845760408801805160010190526136db565b8188604001518151811061379a5761379a61435b565b6020026020010151604001516000036137bc576020880151617080810161373b565b60408801511580156137df575087516020890151617080916137dd91614499565b105b15613830576138268860000151896020015103617080848b604001518151811061380b5761380b61435b565b6020026020010151604001516131469092919063ffffffff16565b608089015261385c565b818860400151815181106138465761384661435b565b6020026020010151604001518860800181815250505b608088015161386b908a613bea565b60a08901519701966138839088036103e68802613bc6565b6060890181905260a0890188905260208901516103e682029a909a0199960195617080810161373b565b8751421180156138c1575081518860400151105b156139995742828960400151815181106138dd576138dd61435b565b602002602001015160200151108015613911575060018183516139009190614499565b61390a9190614499565b8860400151105b156139225760408801805160010190525b42828960400151815181106139395761393961435b565b6020026020010151602001511061399957600061708089600001514203848b604001518151811061396c5761396c61435b565b6020026020010151604001510281613986576139866143e3565b049050613993818b613bea565b88019750505b5050505060a09390930151919891975092955091935090915050565b6000806000806000606b549050806000036139e257606c5460715482606f54945094509450945050613140565b606a54606c54607154606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613a70576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613a11565b509293508792506000915081905080613a8f61708080860686036143b9565b92505b428311613ae457613aa4858585613f9e565b9150613ab0828b613bea565b90970196613ac48789036103e68802613bc6565b6103e681029a909a01998897509586019592935050617080830191613a92565b42841015613b1057613af7858542613f9e565b9150613b03828b613bea565b613b0d90896143b9565b97505b50959c949b509699509197509195505050505050565b600054610100900460ff16613bbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92336131bc565b60006124b68383670de0b6b3a7640000613146565b60008183106132dd57816124b6565b60006124b683670de0b6b3a764000084613146565b606060008083516002613c1291906143cc565b67ffffffffffffffff811115613c2a57613c2a61454d565b604051908082528060200260200182016040528015613c53578160200160208202803683370190505b50905060008060008060005b8851811015613d2c57613c958b8a8381518110613c7e57613c7e61435b565b60200260200101516000015163ffffffff166132ce565b9350613cc48a8a8381518110613cad57613cad61435b565b60200260200101516020015163ffffffff16613bdb565b925082841015613d1d5783868380600101945081518110613ce757613ce761435b565b60200260200101818152505082868380600101945081518110613d0c57613d0c61435b565b602002602001018181525050613d24565b6002850194505b600101613c5f565b509399929850919650505050505050565b8051600082528060051b82016020601f198185015b8201838111613d8a5780518282018051828111613d7157505050613d52565b5b8186015283018051828111613d725750840152613d52565b505050915250565b606060006001838651613da59190614499565b613daf9190614499565b67ffffffffffffffff811115613dc757613dc761454d565b604051908082528060200260200182016040528015613e1c57816020015b613e0960405180606001604052806000815260200160008152602001600081525090565b815260200190600190039081613de55790505b509150600080808080875b60018b51613e359190614499565b811015613f90578a8181518110613e4e57613e4e61435b565b602002602001015195508a816001613e6691906143b9565b81518110613e7657613e7661435b565b60200260200101519450848603613e935760019687019601613e27565b60009350600092505b8951831015613f4b57858a8481518110613eb857613eb861435b565b60200260200101516000015163ffffffff161115613edb57826001019250613e9c565b848a8481518110613eee57613eee61435b565b60200260200101516020015163ffffffff161015613f1157826001019250613e9c565b898381518110613f2357613f2361435b565b6020026020010151604001516001600160c01b03166170800284019350826001019250613e9c565b604080516060810182528781526020810187905290810185905288516001848101949301928a918110613f8057613f8061435b565b6020026020010181905250613e27565b505050505050935093915050565b6000805b845181101561408a57848181518110613fbd57613fbd61435b565b60200260200101516000015163ffffffff16831015613fde57600101613fa2565b848181518110613ff057613ff061435b565b60200260200101516020015163ffffffff1684111561401157600101613fa2565b8481815181106140235761402361435b565b6020026020010151604001516001600160c01b031661406586838151811061404d5761404d61435b565b60200260200101516000015163ffffffff16866132ce565b61407b85888581518110613cad57613cad61435b565b03029190910190600101613fa2565b509392505050565b803560ff811681146140a357600080fd5b919050565b6000602082840312156140ba57600080fd5b6124b682614092565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805163ffffffff90811686528782015116878601528501516001600160c01b031685850152606090930192908501906001016140e0565b5091979650505050505050565b80356001600160a01b03811681146140a357600080fd5b8015158114612fa457600080fd5b6000806040838503121561416657600080fd5b61416f8361412e565b9150602083013561417f81614145565b809150509250929050565b60006020828403121561419c57600080fd5b6124b68261412e565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805161ffff1685528681015163ffffffff16878601528501516001600160d01b031685850152606090930192908501906001016141c2565b803563ffffffff811681146140a357600080fd5b60008060006060848603121561422d57600080fd5b61423684614204565b925061424460208501614204565b915060408401356001600160c01b038116811461426057600080fd5b809150509250925092565b60006020828403121561427d57600080fd5b5035919050565b80356001600160d01b03811681146140a357600080fd5b600080604083850312156142ae57600080fd5b823591506142be60208401614284565b90509250929050565b600080604083850312156142da57600080fd5b6142e383614284565b946020939093013593505050565b6000806040838503121561430457600080fd5b6142e38361412e565b6000806000806080858703121561432357600080fd5b5050823594602084013594506040840135936060013592509050565b6000806040838503121561435257600080fd5b6142e383614092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156124b9576124b961438a565b80820281158282048414176124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614421576144216143e3565b500690565b63ffffffff8281168282160390808211156144435761444361438a565b5092915050565b6001600160c01b038281168282168181028316929181158285048214176144735761447361438a565b50505092915050565b60006020828403121561448e57600080fd5b8151610ed781614145565b818103818111156124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61ffff8281168282160390808211156144435761444361438a565b6001600160d01b038281168282168181028316929181158285048214176144735761447361438a565b60008261452e5761452e6143e3565b500490565b600060001982036145465761454661438a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea26469706673582212209d5f0db8bc0e15baa8dbab20a34304b0c18479abfb53c796cdddd712b53ea24364736f6c63430008110033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102de5760003560e01c80638da5cb5b11610186578063cd6dc687116100e3578063dc73e49c11610097578063ea25afda11610071578063ea25afda146105bc578063f2fde38b146105cf578063f301af42146105e257600080fd5b8063dc73e49c14610583578063dca4c9f814610596578063e3a150da146105a957600080fd5b8063d3b5dc3b116100c8578063d3b5dc3b14610572578063d7da1dee1461057b578063dc36a3d31461032957600080fd5b8063cd6dc6871461054c578063d2d26c601461055f57600080fd5b8063abf7fa041161013a578063b425f8021161011f578063b425f802146104ef578063c006719f14610530578063c553173f1461053957600080fd5b8063abf7fa0414610329578063b0128d3f146104c657600080fd5b8063a3c2710d1161016b578063a3c2710d146104ab578063a70b9f0c146104b4578063a86572a0146104bd57600080fd5b80638da5cb5b1461047357806399fd29801461049857600080fd5b80634e71d92d1161023f57806367148931116101f35780637eed69b5116101cd5780637eed69b51461043757806388267c59146104575780638c614c7a1461046057600080fd5b80636714893114610409578063715018a61461041c5780637a3a58df1461042457600080fd5b80635b7917d9116102245780635b7917d9146103da5780635d6a618d146103ed5780636198e339146103f657600080fd5b80634e71d92d146103c95780635a8583fd146103d157600080fd5b8063253418bc116102965780633cdaccb61161027b5780633cdaccb61461037a578063405d0a25146103ad57806348dcb051146103c057600080fd5b8063253418bc1461035f578063325e04531461036757600080fd5b806306afa8ef116102c757806306afa8ef146103165780630e3cf4441461032957806323a35de91461033f57600080fd5b8063043c9693146102e35780630572b0cc146102f8575b600080fd5b6102f66102f13660046140a8565b610621565b005b61030061087d565b60405161030d91906140c3565b60405180910390f35b6102f6610324366004614153565b610909565b610331600581565b60405190815260200161030d565b61035261034d36600461418a565b61098f565b60405161030d91906141a5565b610331610a2f565b6102f6610375366004614218565b610aa7565b61039d61038836600461418a565b606d6020526000908152604090205460ff1681565b604051901515815260200161030d565b6103316103bb36600461426b565b610eb5565b610331606f5481565b6102f6610ede565b61033160715481565b6102f66103e836600461426b565b611022565b6103316103e681565b6102f661040436600461426b565b6112b6565b6102f661041736600461429b565b6117fa565b6102f6611b80565b61033161043236600461426b565b611b94565b61033161044536600461418a565b60696020526000908152604090205481565b61033160705481565b61033161046e36600461418a565b611bb0565b6033546001600160a01b03165b6040516001600160a01b03909116815260200161030d565b6102f66104a63660046142c7565b611bca565b610331606a5481565b61033161708081565b610331606c5481565b6103316104d436600461418a565b6001600160a01b031660009081526068602052604090205490565b6105026104fd3660046142f1565b611eed565b6040805161ffff909416845263ffffffff90921660208401526001600160d01b03169082015260600161030d565b610331606b5481565b6102f661054736600461426b565b611f40565b6102f661055a3660046142f1565b612248565b61039d61056d3660046142f1565b61248f565b61033160665481565b606754610331565b606554610480906001600160a01b031681565b6102f66105a436600461426b565b6124bf565b6102f66105b736600461430d565b612716565b6102f66105ca36600461433f565b612bd2565b6102f66105dd36600461418a565b612efd565b6105f56105f036600461426b565b612fa7565b6040805163ffffffff94851681529390921660208401526001600160c01b03169082015260600161030d565b60ff81163360601b73ffffffffffffffff000000000000000000000000168117600881901c6000908152606e602052604090205490916001901b1615610693576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061069d610a2f565b905060006106ab3383612fef565b9050806000036106e7576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260696020908152604080832085905560689091528120805460ff87169081106107185761071861435b565b60009182526020909120018054909150426201000090910463ffffffff16101561076e576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8054600090610791908490660100000000000090046001600160d01b03166143b9565b82546001600160d01b03821666010000000000000265ffffffffffff821617845590915061ffff166107c381856143cc565b606b60008282546107d491906143b9565b909155505060405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a282546040805160ff8a1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080015b60405180910390a250505050505050565b60606067805480602002602001604051908101604052809291908181526020016000905b82821015610900576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b0316908201528252600190920191016108a1565b50505050905090565b61091161302c565b6001600160a01b0382166000818152606d602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f2b8508073c9bd6054077cb8ab52c19b9616a8970f3fcc0a7163b082f16fd560a91015b60405180910390a25050565b6001600160a01b0381166000908152606860209081526040808320805482518185028101850190935280835260609492939192909184015b82821015610a24576000848152602090819020604080516060810182529185015461ffff8116835262010000810463ffffffff1683850152660100000000000090046001600160d01b0316908201528252600190920191016109c7565b505050509050919050565b6000806000806000610a3f6130a0565b42606a55606c8490556071839055606b829055606f54939750919550935091508114610a9e57606f8190556040518181527fa803098eab41616e8c09907603003b82c457356a707199ad558994e6187830539060200160405180910390a15b50919392505050565b336000908152606d602052604090205460ff16610af0576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6067547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01610b4b576040517f44fea23a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160c01b0316600003610b8e576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8163ffffffff168363ffffffff1603610bd3576040517fb78de82800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428363ffffffff161080610bec5750428263ffffffff16105b15610c23576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3561708063ffffffff8516614412565b15610c6c576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c7e61708063ffffffff8416614412565b15610cb5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160608101825263ffffffff8086168252848116602083019081526001600160c01b038086169484019485526067805460018101825560009190915293517f9787eeb91fe3101235e4a76063c7023ecb40f923f97916639c598592fa30d6ae909401805492519551909116680100000000000000000267ffffffffffffffff958416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909316949093169390931717929092169190911790556065546001600160a01b03166323b872dd333084610d968888614426565b63ffffffff16610da6919061444a565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526001600160c01b031660448201526064016020604051808303816000875af1158015610e1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3f919061447c565b610e5c576040516312171d8360e31b815260040160405180910390fd5b6040805163ffffffff8086168252841660208201526001600160c01b038316918101919091527f9795f222c951ae3e749f872dbe287f78d21fa52353e9175cb20ed3aa2b29b82b906060015b60405180910390a1505050565b6070546000908015610ed557606f54610ed090849083613146565b610ed7565b825b9392505050565b6000610ee8610a2f565b90506000610ef63383612fef565b905080600003610f32576040517f969bf72800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152606960205260409081902084905560655490517fa9059cbb0000000000000000000000000000000000000000000000000000000081526004810192909252602482018390526001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd3919061447c565b610ff0576040516312171d8360e31b815260040160405180910390fd5b60405181815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d490602001610983565b600061102c610a2f565b9050600061103a3383612fef565b33600090815260686020526040812080549293509091859081106110605761106061435b565b60009182526020822001915073ffffffffffffffff0000000000000000000000003360601b168517600881901c6000908152606e6020526040902054909150600160ff83161b166110dd576040517f18c62fcc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604090208054600160ff84161b191690558154660100000000000090046001600160d01b0316600061111d82610eb5565b905061112f606f548288607154613164565b60718190555080606f60008282546111479190614499565b9250508190555081607060008282546111609190614499565b9091555050835465ffffffffffff1666010000000000006001600160d01b03831602178455336000908152606960205260409020869055841561127e576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018790526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015611207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122b919061447c565b611248576040516312171d8360e31b815260040160405180910390fd5b60405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f45f21e7b59d72f575ccab5204bfb96c1af1aee613cffb4d1b9db2e757c25e8c5910161086c565b60006112c0610a2f565b33600090815260686020526040812080549293509091849081106112e6576112e661435b565b60009182526020909120018054909150426201000090910463ffffffff16111561133c576040517fba8dbe4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffff0000000000000000000000003360601b168417905060006113683385612fef565b600883901c6000908152606e6020526040812054919250600160ff85161b90911615801591906113ff578454660100000000000090046001600160d01b03166113b081610eb5565b91506113c2606f548389607154613164565b60718190555081606f60008282546113da9190614499565b9250508190555080607060008282546113f39190614499565b90915550611416915050565b508354660100000000000090046001600160d01b03165b3360009081526069602090815260408083208990558754606b805461ffff909216860290910390556068909152902054600019810190880360010161148557821561148057600885901c6000908152606e602052604090208054600160ff88161b19169055611682565b611682565b3360009081526068602052604090208054829081106114a6576114a661435b565b9060005260206000200160686000336001600160a01b03166001600160a01b0316815260200190815260200160002089815481106114e6576114e661435b565b6000918252602082208354910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000811661ffff9093169283178255845463ffffffff620100009182900416027fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000009091169092179190911780825592546001600160d01b03660100000000000091829004160265ffffffffffff909316929092179091556115ad823360601b73ffffffffffffffff000000000000000000000000161790565b9050831561161f57600881901c6000908152606e6020526040902054600160ff83161b166115fa57600886901c6000908152606e602052604090208054600160ff89161b19169055611680565b600881901c6000908152606e602052604090208054600160ff84161b19169055611680565b600881901c6000908152606e6020526040902054600160ff83161b161561168057600886901c6000908152606e602052604090208054600160ff89161b179055600881901c6000908152606e602052604090208054600160ff84161b191690555b505b3360009081526068602052604090208054806116a0576116a06144ac565b6000828152602081208201600019908101919091550190556065546001600160a01b031663a9059cbb336116d487866143b9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175b919061447c565b611778576040516312171d8360e31b815260040160405180910390fd5b83156117b45760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b60408051838152602081018a905233917ff7870c5b224cbc19873599e46ccfc7103934650509b1af0c3ce90138377c200491015b60405180910390a25050505050505050565b806001600160d01b031660000361183d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611847610a2f565b905060006118553383612fef565b9050600061186c826001600160d01b0386166143b9565b33600090815260686020526040812080549293509091879081106118925761189261435b565b60009182526020909120018054909150426201000090910463ffffffff1610156118e8576040517fb03b1f4400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f73ffffffffffffffff0000000000000000000000003360601b1688175b600881901c6000908152606e6020526040902054600160ff9092169190911b16151590565b156119a9576000606f5490506119498185886071546131b0565b607155600061195785611b94565b905061196385836143b9565b606f81905550806070600082825461197b91906143b9565b909155505083546119a0908290660100000000000090046001600160d01b03166143b9565b925050506119cc565b81546119c9908490660100000000000090046001600160d01b03166143b9565b90505b81546001600160d01b03821666010000000000000265ffffffffffff82168117845533600090815260696020526040902087905561ffff908116911617611a1381856143cc565b606b6000828254611a2491906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611aa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac5919061447c565b611ae2576040516312171d8360e31b815260040160405180910390fd5b8415611b1e5760405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b82546040805160ff8b1681526001600160d01b03851660208201526201000090920463ffffffff169082015261ffff8216606082015233907fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2906080016117e8565b611b8861302c565b611b9260006131bc565b565b6070546000908015610ed557606f54610ed09084908390613146565b600080611bbb6130a0565b5050509050610ed78382612fef565b816001600160d01b0316600003611c0d576040517f43ad20fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152606860205260409020547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb01611c75576040517f5ad3064300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c7f610a2f565b90506000611c8d3383612fef565b90506000611ca46001600160d01b038616836143b9565b336000908152606960205260408120859055909150611cc385426143b9565b90506000611cd086613226565b336000908152606860209081526040808320815160608101835261ffff80871680835263ffffffff808b168488019081526001600160d01b03808e169786019788528654600181018855968a529790982093519390940180549751955190961666010000000000000265ffffffffffff9590941662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000090971692909116919091179490941791909116179055909150611d8e9084906143cc565b606b6000828254611d9f91906143b9565b90915550506065546040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526001600160d01b03891660448201526001600160a01b03909116906323b872dd906064016020604051808303816000875af1158015611e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e40919061447c565b611e5d576040516312171d8360e31b815260040160405180910390fd5b8315611e995760405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080516001600160d01b038516815263ffffffff8416602082015261ffff83169181019190915233907f7b2d54511a19cedc58c31bf2a96ea21396676caf714de85f97ab140a3a4ff1129060600161086c565b60686020528160005260406000208181548110611f0957600080fd5b60009182526020909120015461ffff8116925062010000810463ffffffff169150660100000000000090046001600160d01b031683565b336000908152606d602052604090205460ff16611f89576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f91610a2f565b50600060678281548110611fa757611fa761435b565b600091825260209182902060408051606081018252919092015463ffffffff8082168352640100000000820416938201939093526001600160c01b03680100000000000000009093049290921690820152606780549192509061200c90600190614499565b8154811061201c5761201c61435b565b90600052602060002001606783815481106120395761203961435b565b6000918252602090912082549101805463ffffffff9283167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082168117835584547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921617640100000000918290049093160291909117808255915467ffffffffffffffff90921668010000000000000000928390046001600160c01b031690920291909117905560678054806120f3576120f36144ac565b6000828152602080822060001990840181019290925591019091558101514263ffffffff909116111561221157600081604001516001600160c01b031661214442846000015163ffffffff166132ce565b836020015163ffffffff166121599190614499565b61216391906143cc565b6065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018390529192506001600160a01b03169063a9059cbb906044016020604051808303816000875af11580156121ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f2919061447c565b61220f576040516312171d8360e31b815260040160405180910390fd5b505b6040518281527f5d3a571a89edce81bd931e9d740ff7f0560940fc502a27f178f002eca691dfd99060200160405180910390a15050565b600054610100900460ff16158080156122685750600054600160ff909116105b806122825750303b158015612282575060005460ff166001145b612313576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561237157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6001600160a01b0383166123b1576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036123eb576040517fd41c43dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038516179055606682905561242b6132e4565b801561248a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610ea8565b505050565b60006124b661190a838560601b73ffffffffffffffff000000000000000000000000161790565b90505b92915050565b60006124c9610a2f565b905060006124d73383612fef565b33600090815260686020526040812080549293509091859081106124fd576124fd61435b565b6000918252602090912001805490915061ffff166103e61461254b576040517fbe53ebc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360601b73ffffffffffffffff000000000000000000000000168417600881901c6000908152606e6020526040902054600160ff87161b16156125ba576040517f817a428b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600881901c6000908152606e602052604081208054600160ff85161b17905582546125f9908590660100000000000090046001600160d01b03166143b9565b9050600061260682611b94565b9050612618606f5483886071546131b0565b60718190555081606f600082825461263091906143b9565b92505081905550806070600082825461264991906143b9565b9091555050835465ffffffffffff1666010000000000006001600160d01b0383160217845533600090815260696020526040902086905584156126de576126926103e6866143cc565b606b60008282546126a391906143b9565b909155505060405185815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b604080518881526020810183905233917f49311a438ed24b95a0b16011315cf7525bb5b88be477d6d37b57aabc85017c08910161086c565b336000908152606d602052604090205460ff1661275f576040517f1d35058300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61276b61708084614412565b156127a2576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127ae61708083614412565b156127e5576040517fbb9f74da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060000361281f576040517f1f2a200500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612827610a2f565b5060006067858154811061283d5761283d61435b565b60009182526020909120018054909150640100000000900463ffffffff1642811015612895576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428410156128cf576040517f4ac4bb4500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815463ffffffff16428110806128e457504286105b80156128f05750808614155b15612927576040517f6605db4700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000846129348888614499565b61293e91906143cc565b84549091506000906801000000000000000090046001600160c01b03166129658486614499565b61296f91906143cc565b90508288146129a75784547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff89161785555b845463ffffffff9081166401000000009189169190910267ffffffffffffffff1617680100000000000000006001600160c01b0388160217855581811115612aae576065546001600160a01b031663a9059cbb33612a058585614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015612a68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a8c919061447c565b612aa9576040516312171d8360e31b815260040160405180910390fd5b612b7f565b818114612b7f576065546001600160a01b03166323b872dd3330612ad28587614499565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612b3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b62919061447c565b612b7f576040516312171d8360e31b815260040160405180910390fd5b604080518a8152602081018a9052908101889052606081018790527fce702e82d3aef8d6cd9b4dc0baace0b1e11e83af272382cd526d351c5162d1e09060800160405180910390a1505050505050505050565b6000612bdc610a2f565b3360009081526068602052604081208054929350909160ff8616908110612c0557612c0561435b565b600091825260208220019150612c1b84426143b9565b825490915063ffffffff808316620100009092041610612c805781546040517f1e96fff80000000000000000000000000000000000000000000000000000000081526201000090910463ffffffff90811660048301528216602482015260440161230a565b6000612c8c3385612fef565b336000908152606960205260408120869055909150612caa86613226565b845463ffffffff851662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff82168117875591925061ffff91821690821617908216811115612d36576040517f2759864a00000000000000000000000000000000000000000000000000000000815261ffff80831660048301528316602482015260440161230a565b84547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff831617808655660100000000000090046001600160d01b031680612d8183856144db565b61ffff16612d8f91906144f6565b6001600160d01b0316606b6000828254612da991906143b9565b90915550508315612e95576065546040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690526001600160a01b039091169063a9059cbb906044016020604051808303816000875af1158015612e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e42919061447c565b612e5f576040516312171d8360e31b815260040160405180910390fd5b60405184815233907f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d49060200160405180910390a25b6040805160ff8b1681526001600160d01b038316602082015263ffffffff87168183015261ffff85166060820152905133917fae4a8d0dd600d333c52dfbaf95fb35ec25b912d3b8a296795210afc7135640c2919081900360800190a2505050505050505050565b612f0561302c565b6001600160a01b038116612f9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161230a565b612fa4816131bc565b50565b60678181548110612fb757600080fd5b60009182526020909120015463ffffffff8082169250640100000000820416906801000000000000000090046001600160c01b031683565b600080612ffb84613383565b6001600160a01b0385166000908152606960205260409020549091506130249082908503613458565b949350505050565b6033546001600160a01b03163314611b92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161230a565b6000806000806000606a5490504281036130ce57606c54607154606b54606f54945094509450945050613140565b617080808206820390429081069003808203613105576130ec613464565b607154606b54606f549650965096509650505050613140565b600561708083830304111561312c5761311c613568565b9650965096509650505050613140565b6131346139b5565b96509650965096505050505b90919293565b600082600019048411830215820261315d57600080fd5b5091020490565b6000848403613174575081613024565b61317e8486614499565b856131898486614499565b61319391906143cc565b61319d919061451f565b6131a79084614499565b95945050505050565b600061317e84866143b9565b603380546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600062278d0082108061323c5750630966018082115b15613276576040517f91aaaf240000000000000000000000000000000000000000000000000000000081526004810183905260240161230a565b678ac7230489e8000061328f836513ed2e0116006143cc565b8361329d816203656e6143cc565b6132a791906143cc565b6132b191906143b9565b6132c4906835e22c9431dae580006143b9565b6124b9919061451f565b60008183116132dd57816124b6565b5090919050565b600054610100900460ff1661337b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92613b26565b6001600160a01b03811660009081526068602052604081205481805b82811015613450576001600160a01b03851660009081526068602052604090208054829081106133d1576133d161435b565b90600052602060002001915061340261190a828760601b73ffffffffffffffff000000000000000000000000161790565b61344057815461342a9061ffff811690660100000000000090046001600160d01b03166144f6565b61343d906001600160d01b0316856143b9565b93505b61344981614533565b905061339f565b505050919050565b60006124b68383613bc6565b606b54600090808203613479575050606c5490565b606a54606754600080805b83811015613537576067818154811061349f5761349f61435b565b6000918252602090912001805490925060019091019063ffffffff80821691640100000000900416428211156134d6575050613484565b808711156134e5575050613484565b83546801000000000000000090046001600160c01b031661350683896132ce565b6135104284613bdb565b61351a9190614499565b61352491906143cc565b61352e90866143b9565b94505050613484565b50811561355a576135488286613bea565b606c5461355591906143b9565b61355e565b606c545b9550505050505090565b6000806000806000606b5490508060000361359557606c5460715482606f54945094509450945050613140565b6135ce6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b606a548152606c5460715460a0830152606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613663576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613604565b50505050905060008061367b86600001514285613bff565b91509150808251036136a557848660a0015188606f549a509a509a509a5050505050505050613140565b6136ae82613d3d565b6000806136bc848685613d92565b895191935091506136d5906170809081810690036143b9565b60208901525b428860200151111580156136fe57508082516136f79190614499565b8860400151105b156138ad5787600001518289604001518151811061371e5761371e61435b565b602002602001015160000151111561374757602088015161708081015b60208a015288526136db565b8760200151828960400151815181106137625761376261435b565b60200260200101516020015110156137845760408801805160010190526136db565b8188604001518151811061379a5761379a61435b565b6020026020010151604001516000036137bc576020880151617080810161373b565b60408801511580156137df575087516020890151617080916137dd91614499565b105b15613830576138268860000151896020015103617080848b604001518151811061380b5761380b61435b565b6020026020010151604001516131469092919063ffffffff16565b608089015261385c565b818860400151815181106138465761384661435b565b6020026020010151604001518860800181815250505b608088015161386b908a613bea565b60a08901519701966138839088036103e68802613bc6565b6060890181905260a0890188905260208901516103e682029a909a0199960195617080810161373b565b8751421180156138c1575081518860400151105b156139995742828960400151815181106138dd576138dd61435b565b602002602001015160200151108015613911575060018183516139009190614499565b61390a9190614499565b8860400151105b156139225760408801805160010190525b42828960400151815181106139395761393961435b565b6020026020010151602001511061399957600061708089600001514203848b604001518151811061396c5761396c61435b565b6020026020010151604001510281613986576139866143e3565b049050613993818b613bea565b88019750505b5050505060a09390930151919891975092955091935090915050565b6000806000806000606b549050806000036139e257606c5460715482606f54945094509450945050613140565b606a54606c54607154606f54606780546040805160208084028201810190925282815260009390929091849084015b82821015613a70576000848152602090819020604080516060810182529185015463ffffffff8082168452640100000000820416838501526801000000000000000090046001600160c01b031690820152825260019092019101613a11565b509293508792506000915081905080613a8f61708080860686036143b9565b92505b428311613ae457613aa4858585613f9e565b9150613ab0828b613bea565b90970196613ac48789036103e68802613bc6565b6103e681029a909a01998897509586019592935050617080830191613a92565b42841015613b1057613af7858542613f9e565b9150613b03828b613bea565b613b0d90896143b9565b97505b50959c949b509699509197509195505050505050565b600054610100900460ff16613bbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161230a565b611b92336131bc565b60006124b68383670de0b6b3a7640000613146565b60008183106132dd57816124b6565b60006124b683670de0b6b3a764000084613146565b606060008083516002613c1291906143cc565b67ffffffffffffffff811115613c2a57613c2a61454d565b604051908082528060200260200182016040528015613c53578160200160208202803683370190505b50905060008060008060005b8851811015613d2c57613c958b8a8381518110613c7e57613c7e61435b565b60200260200101516000015163ffffffff166132ce565b9350613cc48a8a8381518110613cad57613cad61435b565b60200260200101516020015163ffffffff16613bdb565b925082841015613d1d5783868380600101945081518110613ce757613ce761435b565b60200260200101818152505082868380600101945081518110613d0c57613d0c61435b565b602002602001018181525050613d24565b6002850194505b600101613c5f565b509399929850919650505050505050565b8051600082528060051b82016020601f198185015b8201838111613d8a5780518282018051828111613d7157505050613d52565b5b8186015283018051828111613d725750840152613d52565b505050915250565b606060006001838651613da59190614499565b613daf9190614499565b67ffffffffffffffff811115613dc757613dc761454d565b604051908082528060200260200182016040528015613e1c57816020015b613e0960405180606001604052806000815260200160008152602001600081525090565b815260200190600190039081613de55790505b509150600080808080875b60018b51613e359190614499565b811015613f90578a8181518110613e4e57613e4e61435b565b602002602001015195508a816001613e6691906143b9565b81518110613e7657613e7661435b565b60200260200101519450848603613e935760019687019601613e27565b60009350600092505b8951831015613f4b57858a8481518110613eb857613eb861435b565b60200260200101516000015163ffffffff161115613edb57826001019250613e9c565b848a8481518110613eee57613eee61435b565b60200260200101516020015163ffffffff161015613f1157826001019250613e9c565b898381518110613f2357613f2361435b565b6020026020010151604001516001600160c01b03166170800284019350826001019250613e9c565b604080516060810182528781526020810187905290810185905288516001848101949301928a918110613f8057613f8061435b565b6020026020010181905250613e27565b505050505050935093915050565b6000805b845181101561408a57848181518110613fbd57613fbd61435b565b60200260200101516000015163ffffffff16831015613fde57600101613fa2565b848181518110613ff057613ff061435b565b60200260200101516020015163ffffffff1684111561401157600101613fa2565b8481815181106140235761402361435b565b6020026020010151604001516001600160c01b031661406586838151811061404d5761404d61435b565b60200260200101516000015163ffffffff16866132ce565b61407b85888581518110613cad57613cad61435b565b03029190910190600101613fa2565b509392505050565b803560ff811681146140a357600080fd5b919050565b6000602082840312156140ba57600080fd5b6124b682614092565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805163ffffffff90811686528782015116878601528501516001600160c01b031685850152606090930192908501906001016140e0565b5091979650505050505050565b80356001600160a01b03811681146140a357600080fd5b8015158114612fa457600080fd5b6000806040838503121561416657600080fd5b61416f8361412e565b9150602083013561417f81614145565b809150509250929050565b60006020828403121561419c57600080fd5b6124b68261412e565b602080825282518282018190526000919060409081850190868401855b82811015614121578151805161ffff1685528681015163ffffffff16878601528501516001600160d01b031685850152606090930192908501906001016141c2565b803563ffffffff811681146140a357600080fd5b60008060006060848603121561422d57600080fd5b61423684614204565b925061424460208501614204565b915060408401356001600160c01b038116811461426057600080fd5b809150509250925092565b60006020828403121561427d57600080fd5b5035919050565b80356001600160d01b03811681146140a357600080fd5b600080604083850312156142ae57600080fd5b823591506142be60208401614284565b90509250929050565b600080604083850312156142da57600080fd5b6142e383614284565b946020939093013593505050565b6000806040838503121561430457600080fd5b6142e38361412e565b6000806000806080858703121561432357600080fd5b5050823594602084013594506040840135936060013592509050565b6000806040838503121561435257600080fd5b6142e383614092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156124b9576124b961438a565b80820281158282048414176124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614421576144216143e3565b500690565b63ffffffff8281168282160390808211156144435761444361438a565b5092915050565b6001600160c01b038281168282168181028316929181158285048214176144735761447361438a565b50505092915050565b60006020828403121561448e57600080fd5b8151610ed781614145565b818103818111156124b9576124b961438a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61ffff8281168282160390808211156144435761444361438a565b6001600160d01b038281168282168181028316929181158285048214176144735761447361438a565b60008261452e5761452e6143e3565b500490565b600060001982036145465761454661438a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea26469706673582212209d5f0db8bc0e15baa8dbab20a34304b0c18479abfb53c796cdddd712b53ea24364736f6c63430008110033

Deployed Bytecode Sourcemap

60166:38861:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68874:926;;;;;;:::i;:::-;;:::i;:::-;;79284:95;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;67544:153;;;;;;:::i;:::-;;:::i;61567:44::-;;61610:1;61567:44;;;;;2106:25:1;;;2094:2;2079:18;61567:44:0;1960:177:1;79044:111:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;80249:694::-;;;:::i;64174:847::-;;;;;;:::i;:::-;;:::i;63058:42::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;4065:14:1;;4058:22;4040:41;;4028:2;4013:18;63058:42:0;3900:187:1;81176:217:0;;;;;;:::i;:::-;;:::i;63159:29::-;;;;;;72995:447;;;:::i;63231:42::-;;;;;;77683:1245;;;;;;:::i;:::-;;:::i;61618:44::-;;61659:3;61618:44;;73547:2405;;;;;;:::i;:::-;;:::i;70029:1692::-;;;;;;:::i;:::-;;:::i;19407:103::-;;;:::i;80951:217::-;;;;;;:::i;:::-;;:::i;62881:59::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63195:29;;;;;;79728:219;;;;;;:::i;:::-;;:::i;18759:87::-;18832:6;;-1:-1:-1;;;;;18832:6:0;18759:87;;;-1:-1:-1;;;;;4913:55:1;;;4895:74;;4883:2;4868:18;18759:87:0;4749:226:1;67789:1007:0;;;;;;:::i;:::-;;:::i;62949:31::-;;;;;;61669:52;;61710:11;61669:52;;63019:30;;;;;;79163:113;;;;;;:::i;:::-;-1:-1:-1;;;;;79250:11:0;79223:7;79250:11;;;:5;:11;;;;;:18;;79163:113;62835:39;;;;;;:::i;:::-;;:::i;:::-;;;;5726:6:1;5714:19;;;5696:38;;5782:10;5770:23;;;5765:2;5750:18;;5743:51;-1:-1:-1;;;;;5830:67:1;5810:18;;;5803:95;5684:2;5669:18;62835:39:0;5498:406:1;62987:25:0;;;;;;65106:616;;;;;;:::i;:::-;;:::i;63824:309::-;;;;;;:::i;:::-;;:::i;79486:173::-;;;;;;:::i;:::-;;:::i;62728:24::-;;;;;;78936:100;79014:7;:14;78936:100;;62698:23;;;;;-1:-1:-1;;;;;62698:23:0;;;76173:1282;;;;;;:::i;:::-;;:::i;65820:1652::-;;;;;;:::i;:::-;;:::i;71811:1134::-;;;;;;:::i;:::-;;:::i;19665:201::-;;;;;;:::i;:::-;;:::i;62805:23::-;;;;;;:::i;:::-;;:::i;:::-;;;;7006:10:1;7043:15;;;7025:34;;7095:15;;;;7090:2;7075:18;;7068:43;-1:-1:-1;;;;;7147:63:1;7127:18;;;7120:91;6984:2;6969:18;62805:23:0;6798:419:1;68874:926:0;68947:33;;;68969:10;93705:2;93688:19;93679:29;;;;21165:1;21156:10;;;68925:19;21229:20;;;68995;21229;;;;;;93679:29;;21192:1;:19;;21229:27;:32;68991:71;;69041:21;;;;;;;;;;;;;;68991:71;69075:27;69105:21;:19;:21::i;:::-;69075:51;;69139:17;69159:55;69182:10;69194:19;69159:22;:55::i;:::-;69139:75;;69229:9;69242:1;69229:14;69225:43;;69252:16;;;;;;;;;;;;;;69225:43;69306:10;69281:36;;;;:24;:36;;;;;;;;:58;;;69372:5;:17;;;;;:24;;;;;;;;;;;;:::i;:::-;;;;;;;;;;69413:8;;69372:24;;-1:-1:-1;69424:15:0;69413:8;;;;;;:26;69409:62;;;69448:23;;;;;;;;;;;;;;69409:62;69512:11;;69484:17;;69512:23;;69526:9;;69512:11;;;-1:-1:-1;;;;;69512:11:0;:23;:::i;:::-;69567:15;;-1:-1:-1;;;;;69595:23:0;;;;;;;;;;69484:52;;-1:-1:-1;69567:15:0;;69643:22;69567:15;69643:9;:22;:::i;:::-;69629:10;;:36;;;;;;;:::i;:::-;;;;-1:-1:-1;;69683:28:0;;2106:25:1;;;69689:10:0;;69683:28;;2094:2:1;2079:18;69683:28:0;;;;;;;69771:8;;69729:63;;;8156:4:1;8144:17;;8126:36;;-1:-1:-1;;;;;8198:67:1;;8193:2;8178:18;;8171:95;69771:8:0;;;;;;8282:18:1;;;8275:51;8374:6;8362:19;;8357:2;8342:18;;8335:47;69741:10:0;;69729:63;;8113:3:1;8098:19;69729:63:0;;;;;;;;68914:886;;;;;;68874:926;:::o;79284:95::-;79329:15;79364:7;79357:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;79357:14:0;;;;;;;;;;;;;;;;;;;;;;79284:95;:::o;67544:153::-;18645:13;:11;:13::i;:::-;-1:-1:-1;;;;;67622:16:0;::::1;;::::0;;;:10:::1;:16;::::0;;;;;;;;:24;;;::::1;::::0;::::1;;::::0;;::::1;::::0;;;67664:25;;4040:41:1;;;67664:25:0::1;::::0;4013:18:1;67664:25:0::1;;;;;;;;67544:153:::0;;:::o;79044:111::-;-1:-1:-1;;;;;79136:11:0;;;;;;:5;:11;;;;;;;;79129:18;;;;;;;;;;;;;;;;;79103:13;;79129:18;;79136:11;;79129:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;79129:18:0;;;;;;;;;;;;;;;;;;;;;;79044:111;;;:::o;80249:694::-;80296:7;80331:27;80373:39;80427:22;80464:26;80504:17;:15;:17::i;:::-;80553:15;80534:16;:34;80579:15;:37;;;80627:27;:61;;;80699:10;:27;;;80765:14;;80316:205;;-1:-1:-1;80316:205:0;;-1:-1:-1;80316:205:0;-1:-1:-1;80316:205:0;-1:-1:-1;80743:36:0;;80739:158;;80796:14;:35;;;80851:34;;2106:25:1;;;80851:34:0;;2094:2:1;2079:18;80851:34:0;;;;;;;80739:158;-1:-1:-1;80916:19:0;;80249:694;-1:-1:-1;;;80249:694:0:o;64174:847::-;63517:10;63506:22;;;;:10;:22;;;;;;;;63501:50;;63537:14;;;;;;;;;;;;;;63501:50;64316:7:::1;:14:::0;:34;;64312:68:::1;;64359:21;;;;;;;;;;;;;;64312:68;64395:15;-1:-1:-1::0;;;;;64395:20:0::1;64414:1;64395:20:::0;64391:47:::1;;64424:14;;;;;;;;;;;;;;64391:47;64462:3;64453:12;;:5;:12;;::::0;64449:43:::1;;64474:18;;;;;;;;;;;;;;64449:43;64515:15;64507:5;:23;;;:48;;;;64540:15;64534:3;:21;;;64507:48;64503:86;;;64564:25;;;;;;;;;;;;;;64503:86;64604:22;61710:11;64604:22;::::0;::::1;;:::i;:::-;:27:::0;64600:69:::1;;64640:29;;;;;;;;;;;;;;64600:69;64684:20;61710:11;64684:20;::::0;::::1;;:::i;:::-;:25:::0;64680:67:::1;;64718:29;;;;;;;;;;;;;;64680:67;64773:35;::::0;;::::1;::::0;::::1;::::0;;::::1;::::0;;::::1;::::0;;;;::::1;;::::0;::::1;::::0;;;-1:-1:-1;;;;;64773:35:0;;::::1;::::0;;;;;;64760:7:::1;:49:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;64760:49:0;;;;;;;;;::::1;::::0;;;;;;;;::::1;::::0;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;64834:9:::1;::::0;-1:-1:-1;;;;;64834:9:0::1;64827:30;64858:10;64878:4;64792:15:::0;64886:11:::1;64780:5:::0;64787:3;64886:11:::1;:::i;:::-;64885:31;;;;;;:::i;:::-;64827:90;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;9481:15:1;;;64827:90:0::1;::::0;::::1;9463:34:1::0;9533:15;;;;9513:18;;;9506:43;-1:-1:-1;;;;;9585:63:1;9565:18;;;9558:91;9375:18;;64827:90:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;64822:133;;64939:16;;-1:-1:-1::0;;;64939:16:0::1;;;;;;;;;;;64822:133;64973:40;::::0;;7006:10:1;7043:15;;;7025:34;;7095:15;;7090:2;7075:18;;7068:43;-1:-1:-1;;;;;7147:63:1;;7127:18;;;7120:91;;;;64973:40:0::1;::::0;6984:2:1;6969:18;64973:40:0::1;;;;;;;;64174:847:::0;;;:::o;81176:217::-;81287:14;;81250:7;;81321:11;;:64;;81362:14;;81344:41;;:6;;81378;81344:17;:41::i;:::-;81321:64;;;81335:6;81321:64;81314:71;81176:217;-1:-1:-1;;;81176:217:0:o;72995:447::-;73032:27;73062:21;:19;:21::i;:::-;73032:51;;73096:17;73116:55;73139:10;73151:19;73116:22;:55::i;:::-;73096:75;;73186:9;73199:1;73186:14;73182:43;;73209:16;;;;;;;;;;;;;;73182:43;73263:10;73238:36;;;;:24;:36;;;;;;;:58;;;73321:9;;73314:49;;;;;;;;10510:74:1;;;;10600:18;;;10593:34;;;-1:-1:-1;;;;;73321:9:0;;73314:26;;10483:18:1;;73314:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73309:79;;73372:16;;-1:-1:-1;;;73372:16:0;;;;;;;;;;;73309:79;73406:28;;2106:25:1;;;73412:10:0;;73406:28;;2094:2:1;2079:18;73406:28:0;1960:177:1;77683:1245:0;77747:27;77777:21;:19;:21::i;:::-;77747:51;;77809:17;77829:55;77852:10;77864:19;77829:22;:55::i;:::-;77923:10;77897:17;77917;;;:5;:17;;;;;:24;;77809:75;;-1:-1:-1;77897:17:0;;77935:5;;77917:24;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;93679:29:0;77998:10;93705:2;93688:19;93679:29;;;21165:1;21156:10;;;21122:4;21229:20;;;78025;21229;;;;;;77954:55;;-1:-1:-1;21192:1:0;21206:4;21198:12;;21192:19;21229:27;78020:75;;78071:24;;;;;;;;;;;;;;78020:75;21976:1;21967:10;;;21950:14;22033:20;;;78108;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;78183:11;;;;;-1:-1:-1;;;;;78183:11:0;78160:20;78224:41;78183:11;78224:27;:41::i;:::-;78207:58;;78308:168;78354:14;;78383:6;78404:19;78438:27;;78308:31;:168::i;:::-;78278:27;:198;;;;78507:6;78489:14;;:24;;;;;;;:::i;:::-;;;;;;;;78544:12;78526:14;;:30;;;;;;;:::i;:::-;;;;-1:-1:-1;;78569:29:0;;;;;-1:-1:-1;;;;;78569:29:0;;;;;;78636:10;-1:-1:-1;78611:36:0;;;:24;:36;;;;;:58;;;78686:14;;78682:174;;78729:9;;78722:49;;;;;78749:10;78722:49;;;10510:74:1;10600:18;;;10593:34;;;-1:-1:-1;;;;;78729:9:0;;;;78722:26;;10483:18:1;;78722:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78717:79;;78780:16;;-1:-1:-1;;;78780:16:0;;;;;;;;;;;78717:79;78816:28;;2106:25:1;;;78822:10:0;;78816:28;;2094:2:1;2079:18;78816:28:0;;;;;;;78682:174;78873:47;;;10945:25:1;;;11001:2;10986:18;;10979:34;;;78894:10:0;;78873:47;;10918:18:1;78873:47:0;10771:248:1;73547:2405:0;73598:27;73628:21;:19;:21::i;:::-;73686:10;73660:17;73680;;;:5;:17;;;;;:24;;73598:51;;-1:-1:-1;73660:17:0;;73698:5;;73680:24;;;;;;:::i;:::-;;;;;;;;;;73721:8;;73680:24;;-1:-1:-1;73732:15:0;73721:8;;;;;;:26;73717:56;;;73756:17;;;;;;;;;;;;;;73717:56;73786:19;93679:29;73830:10;93705:2;93688:19;93679:29;;;73786:55;;73854:17;73874:55;73897:10;73909:19;73874:22;:55::i;:::-;21165:1;21156:10;;;73942:23;21229:20;;;73968;21229;;;;;;73854:75;;-1:-1:-1;21192:1:0;21206:4;21198:12;;21192:19;21229:27;;;:32;;;;73942:23;74041:502;;74097:11;;;;;-1:-1:-1;;;;;74097:11:0;74132:35;74097:11;74132:27;:35::i;:::-;74123:44;;74212:188;74262:14;;74295:6;74320:19;74358:27;;74212:31;:188::i;:::-;74182:27;:218;;;;74433:6;74415:14;;:24;;;;;;;:::i;:::-;;;;;;;;74472:6;74454:14;;:24;;;;;;;:::i;:::-;;;;-1:-1:-1;74041:502:0;;-1:-1:-1;;74041:502:0;;-1:-1:-1;74520:11:0;;;;;-1:-1:-1;;;;;74520:11:0;74041:502;74580:10;74555:36;;;;:24;:36;;;;;;;;:58;;;74674:15;;74651:10;:38;;74674:15;;;;74665:24;;74651:38;;;;;74786:5;:17;;;;;:24;-1:-1:-1;;74786:28:0;;;74842:22;;74674:15;74842:22;74838:827;;74885:18;74881:98;;;21976:1;21967:10;;;21950:14;22033:20;;;74924;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;74838:827;;74924:39;74838:827;;;75044:10;75038:17;;;;:5;:17;;;;;:32;;75056:13;;75038:32;;;;;;:::i;:::-;;;;;;;;75011:5;:17;75017:10;-1:-1:-1;;;;;75011:17:0;-1:-1:-1;;;;;75011:17:0;;;;;;;;;;;;75029:5;75011:24;;;;;;;;:::i;:::-;;;;;;;;:59;;:24;;:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75011:59:0;;;;;;;;;;;;;;;;;;75115:41;75130:13;75145:10;93705:2;93688:19;93679:29;;;;93568:149;75115:41;75085:71;;75175:18;75171:483;;;21165:1;21156:10;;;21122:4;21229:20;;;75219;21229;;;;;;21192:1;21206:4;21198:12;;21192:19;21229:27;75214:230;;21976:1;21967:10;;;21950:14;22033:20;;;75289;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;75171:483;;75214:230;21976:1;21967:10;;;21950:14;22033:20;;;75377;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;75171:483;;;21165:1;21156:10;;;21122:4;21229:20;;;75469;21229;;;;;;21192:1;21206:4;21198:12;;21192:19;21229:27;:32;75465:189;;21718:1;21709:10;;;21692:14;21775:20;;;75535;21775;;;;;:28;;21745:1;21759:4;21751:12;;21745:19;21775:28;;;21976:1;21967:10;;;21950:14;22033:20;;;75591;22033;;;;;:29;;22003:1;22017:4;22009:12;;22003:19;22057:5;22033:29;;;75591:47;74996:669;74838:827;75683:10;75677:17;;;;:5;:17;;;;;:23;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;75677:23:0;;;;;;;;;;75725:9;;-1:-1:-1;;;;;75725:9:0;75718:26;75745:10;75757:18;75766:9;75757:6;:18;:::i;:::-;75718:58;;;;;;;;;;-1:-1:-1;;;;;10528:55:1;;;75718:58:0;;;10510:74:1;10600:18;;;10593:34;10483:18;;75718:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75713:88;;75785:16;;-1:-1:-1;;;75785:16:0;;;;;;;;;;;75713:88;75818:14;;75814:80;;75854:28;;2106:25:1;;;75860:10:0;;75854:28;;2094:2:1;2079:18;75854:28:0;;;;;;;75814:80;75911:33;;;10945:25:1;;;11001:2;10986:18;;10979:34;;;75918:10:0;;75911:33;;10918:18:1;75911:33:0;;;;;;;;73587:2365;;;;;;;73547:2405;:::o;70029:1692::-;70110:6;-1:-1:-1;;;;;70110:11:0;70120:1;70110:11;70106:38;;70130:14;;;;;;;;;;;;;;70106:38;70157:27;70187:21;:19;:21::i;:::-;70157:51;;70221:17;70241:55;70264:10;70276:19;70241:22;:55::i;:::-;70221:75;-1:-1:-1;70307:19:0;70329:18;70221:75;-1:-1:-1;;;;;70329:18:0;;;:::i;:::-;70386:10;70360:17;70380;;;:5;:17;;;;;:24;;70307:40;;-1:-1:-1;70360:17:0;;70398:5;;70380:24;;;;;;:::i;:::-;;;;;;;;;;70421:8;;70380:24;;-1:-1:-1;70432:15:0;70421:8;;;;;;:26;70417:62;;;70456:23;;;;;;;;;;;;;;70417:62;70492:17;70524:59;93679:29;70571:10;93705:2;93688:19;93679:29;;;70549:33;21165:1;21156:10;;;21122:4;21229:20;;;70524;21229;;;;;;21192:1;21206:4;21198:12;;;21192:19;;;;21229:27;:32;;;21048:221;70524:59;70520:700;;;70600:25;70628:14;;70600:42;;70689:195;70738:17;70774:11;70804:19;70842:27;;70689:30;:195::i;:::-;70659:27;:225;70901:17;70921:40;70949:11;70921:27;:40::i;:::-;70901:60;-1:-1:-1;70995:31:0;71015:11;70995:17;:31;:::i;:::-;70978:14;:48;;;;71059:9;71041:14;;:27;;;;;;;:::i;:::-;;;;-1:-1:-1;;71105:11:0;;:23;;71119:9;;71105:11;;;-1:-1:-1;;;;;71105:11:0;:23;:::i;:::-;71085:44;;70585:556;;70520:700;;;71182:11;;:25;;71196:11;;71182;;;-1:-1:-1;;;;;71182:11:0;:25;:::i;:::-;71162:46;;70520:700;71232:23;;-1:-1:-1;;;;;71232:23:0;;;;;;;;;;;71341:10;71232:11;71316:36;;;:24;:36;;;;;:58;;;71288:15;;;;;;;71401:24;71288:15;71401:11;:24;:::i;:::-;71387:10;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;71450:9:0;;71443:65;;;;;71474:10;71443:65;;;11476:34:1;71494:4:0;11526:18:1;;;11519:43;-1:-1:-1;;;;;11598:67:1;;11578:18;;;11571:95;-1:-1:-1;;;;;71450:9:0;;;;71443:30;;11388:18:1;;71443:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71438:95;;71517:16;;-1:-1:-1;;;71517:16:0;;;;;;;;;;;71438:95;71550:14;;71546:80;;71586:28;;2106:25:1;;;71592:10:0;;71586:28;;2094:2:1;2079:18;71586:28:0;;;;;;;71546:80;71692:8;;71643:70;;;8156:4:1;8144:17;;8126:36;;-1:-1:-1;;;;;8198:67:1;;8193:2;8178:18;;8171:95;71692:8:0;;;;;;8282:18:1;;;8275:51;8374:6;8362:19;;8357:2;8342:18;;8335:47;71655:10:0;;71643:70;;8113:3:1;8098:19;71643:70:0;7903:485:1;19407:103:0;18645:13;:11;:13::i;:::-;19472:30:::1;19499:1;19472:18;:30::i;:::-;19407:103::o:0;80951:217::-;81062:14;;81025:7;;81096:11;;:64;;81145:14;;81119:41;;:6;;81137;;81119:17;:41::i;79728:219::-;79791:17;79822:24;79856:17;:15;:17::i;:::-;79821:52;;;;;79893:46;79916:4;79922:16;79893:22;:46::i;67789:1007::-;67864:6;-1:-1:-1;;;;;67864:11:0;67874:1;67864:11;67860:38;;67884:14;;;;;;;;;;;;;;67860:38;67919:10;67913:17;;;;:5;:17;;;;;:24;:42;;67909:74;;67964:19;;;;;;;;;;;;;;67909:74;67996:27;68026:21;:19;:21::i;:::-;67996:51;;68060:17;68080:55;68103:10;68115:19;68080:22;:55::i;:::-;68060:75;-1:-1:-1;68146:19:0;68168:18;-1:-1:-1;;;;;68168:18:0;;68060:75;68168:18;:::i;:::-;68224:10;68199:36;;;;:24;:36;;;;;:58;;;68146:40;;-1:-1:-1;68290:26:0;68308:8;68290:15;:26;:::i;:::-;68270:47;;68328:17;68348:31;68370:8;68348:21;:31::i;:::-;68398:10;68392:17;;;;:5;:17;;;;;;;;68415:43;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;68415:43:0;;;;;;;;;68392:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68328:51;;-1:-1:-1;68486:24:0;;68445:11;;68486:24;:::i;:::-;68472:10;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;68535:9:0;;68528:65;;;;;68559:10;68528:65;;;11476:34:1;68579:4:0;11526:18:1;;;11519:43;-1:-1:-1;;;;;11598:67:1;;11578:18;;;11571:95;-1:-1:-1;;;;;68535:9:0;;;;68528:30;;11388:18:1;;68528:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68523:95;;68602:16;;-1:-1:-1;;;68602:16:0;;;;;;;;;;;68523:95;68635:14;;68631:80;;68671:28;;2106:25:1;;;68677:10:0;;68671:28;;2094:2:1;2079:18;68671:28:0;;;;;;;68631:80;68728:60;;;-1:-1:-1;;;;;11893:67:1;;11875:86;;12009:10;11997:23;;11992:2;11977:18;;11970:51;12069:6;12057:19;;12037:18;;;12030:47;;;;68738:10:0;;68728:60;;11863:2:1;11848:18;68728:60:0;11677:406:1;62835:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62835:39:0;;;;;;-1:-1:-1;62835:39:0;;;-1:-1:-1;;;;;62835:39:0;;:::o;65106:616::-;63517:10;63506:22;;;;:10;:22;;;;;;;;63501:50;;63537:14;;;;;;;;;;;;;;63501:50;65177:21:::1;:19;:21::i;:::-;;65211:20;65234:7;65242:5;65234:14;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;65211:37:::1;::::0;;::::1;::::0;::::1;::::0;;65234:14;;;::::1;65211:37:::0;::::1;::::0;;::::1;::::0;;;;::::1;;::::0;;::::1;::::0;;;;-1:-1:-1;;;;;65211:37:0;;;::::1;::::0;;;::::1;::::0;;;;65278:7:::1;65286:14:::0;;65211:37;;-1:-1:-1;65278:7:0;65286:18:::1;::::0;65211:37;;65286:18:::1;:::i;:::-;65278:27;;;;;;;;:::i;:::-;;;;;;;;65261:7;65269:5;65261:14;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;:44;;:14;::::1;:44:::0;;::::1;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;;;::::1;::::0;;::::1;;::::0;;;::::1;::::0;;;;;;;;::::1;::::0;;;;::::1;-1:-1:-1::0;;;;;65261:44:0::1;::::0;;::::1;::::0;;;::::1;::::0;;65316:7:::1;:13:::0;;;::::1;;;;:::i;:::-;;::::0;;;::::1;::::0;;;-1:-1:-1;;65316:13:0;;;;;;;;;;;;;;65422:10;::::1;::::0;65435:15:::1;65316:13;65422:28:::0;;::::1;;65418:259;;;65467:21;65543:6;:22;;;-1:-1:-1::0;;;;;65491:74:0::1;65505:34;65509:15;65526:6;:12;;;65505:34;;:3;:34::i;:::-;65492:6;:10;;;:47;;;;;;:::i;:::-;65491:74;;;;:::i;:::-;65594:9;::::0;65587:53:::1;::::0;;;;65614:10:::1;65587:53;::::0;::::1;10510:74:1::0;10600:18;;;10593:34;;;65467:98:0;;-1:-1:-1;;;;;;65594:9:0::1;::::0;65587:26:::1;::::0;10483:18:1;;65587:53:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65582:83;;65649:16;;-1:-1:-1::0;;;65649:16:0::1;;;;;;;;;;;65582:83;65452:225;65418:259;65694:20;::::0;2106:25:1;;;65694:20:0::1;::::0;2094:2:1;2079:18;65694:20:0::1;;;;;;;65166:556;65106:616:::0;:::o;63824:309::-;12694:19;12717:13;;;;;;12716:14;;12764:34;;;;-1:-1:-1;12782:12:0;;12797:1;12782:12;;;;:16;12764:34;12763:108;;;-1:-1:-1;12843:4:0;2570:19;:23;;;12804:66;;-1:-1:-1;12853:12:0;;;;;:17;12804:66;12741:204;;;;;;;12290:2:1;12741:204:0;;;12272:21:1;12329:2;12309:18;;;12302:30;12368:34;12348:18;;;12341:62;12439:16;12419:18;;;12412:44;12473:19;;12741:204:0;;;;;;;;;12956:12;:16;;;;12971:1;12956:16;;;12983:67;;;;13018:13;:20;;;;;;;;12983:67;-1:-1:-1;;;;;63920:24:0;::::1;63916:50;;63953:13;;;;;;;;;;;;;;63916:50;63981:10;63995:1;63981:15:::0;63977:43:::1;;64005:15;;;;;;;;;;;;;;63977:43;64033:9;:30:::0;;;::::1;-1:-1:-1::0;;;;;64033:30:0;::::1;;::::0;;64074:9:::1;:22:::0;;;64109:16:::1;:14;:16::i;:::-;13076:14:::0;13072:102;;;13123:5;13107:21;;;;;;13148:14;;-1:-1:-1;12655:36:1;;13148:14:0;;12643:2:1;12628:18;13148:14:0;12503:194:1;13072:102:0;12683:498;63824:309;;:::o;79486:173::-;79574:4;79598:53;79623:27;79638:5;79645:4;93705:2;93688:19;93679:29;;;;93568:149;79598:53;79591:60;;79486:173;;;;;:::o;76173:1282::-;76236:27;76266:21;:19;:21::i;:::-;76236:51;;76298:17;76318:55;76341:10;76353:19;76318:22;:55::i;:::-;76412:10;76386:17;76406;;;:5;:17;;;;;:24;;76298:75;;-1:-1:-1;76386:17:0;;76424:5;;76406:24;;;;;;:::i;:::-;;;;;;;;;;76445:15;;76406:24;;-1:-1:-1;76445:15:0;;61659:3;76445:33;76441:64;;76487:18;;;;;;;;;;;;;;76441:64;76562:10;93705:2;93688:19;93679:29;;;;21165:1;21156:10;;;76518:19;21229:20;;;76588;21229;;;;;;21192:1;21206:4;21198:12;;21192:19;21229:27;:32;76584:71;;76634:21;;;;;;;;;;;;;;76584:71;21718:1;21709:10;;;21692:14;21775:20;;;76668;21775;;;;;:28;;21745:1;21759:4;21751:12;;21745:19;21775:28;;;76739:11;;:23;;76753:9;;76739:11;;;-1:-1:-1;;;;;76739:11:0;:23;:::i;:::-;76718:44;;76775:14;76792:39;76820:10;76792:27;:39::i;:::-;76775:56;;76874:171;76919:14;;76948:10;76973:19;77007:27;;76874:30;:171::i;:::-;76844:27;:201;;;;77076:10;77058:14;;:28;;;;;;;:::i;:::-;;;;;;;;77117:6;77099:14;;:24;;;;;;;:::i;:::-;;;;-1:-1:-1;;77136:29:0;;;;;-1:-1:-1;;;;;77136:29:0;;;;;;77203:10;-1:-1:-1;77178:36:0;;;:24;:36;;;;;:58;;;77253:14;;77249:135;;77298:26;61659:3;77298:9;:26;:::i;:::-;77284:10;;:40;;;;;;;:::i;:::-;;;;-1:-1:-1;;77344:28:0;;2106:25:1;;;77350:10:0;;77344:28;;2094:2:1;2079:18;77344:28:0;;;;;;;77249:135;77401:46;;;10945:25:1;;;11001:2;10986:18;;10979:34;;;77421:10:0;;77401:46;;10918:18:1;77401:46:0;10771:248:1;65820:1652:0;63517:10;63506:22;;;;:10;:22;;;;;;;;63501:50;;63537:14;;;;;;;;;;;;;;63501:50;66000:25:::1;61710:11;66000:8:::0;:25:::1;:::i;:::-;:30:::0;65996:72:::1;;66039:29;;;;;;;;;;;;;;65996:72;66083:23;61710:11;66083:6:::0;:23:::1;:::i;:::-;:28:::0;66079:70:::1;;66120:29;;;;;;;;;;;;;;66079:70;66164:18;66186:1;66164:23:::0;66160:48:::1;;66196:12;;;;;;;;;;;;;;66160:48;66221:21;:19;:21::i;:::-;;66255;66279:7;66287:5;66279:14;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;66323:10:::0;;66279:14;;-1:-1:-1;66323:10:0;;::::1;;;66357:15;66348:24:::0;::::1;66344:53;;;66381:16;;;;;;;;;;;;;;66344:53;66421:15;66412:6;:24;66408:62;;;66445:25;;;;;;;;;;;;;;66408:62;66502:12:::0;;::::1;;66541:15;66530:26:::0;::::1;::::0;:56:::1;;;66571:15;66560:8;:26;66530:56;66529:82;;;;;66603:8;66591;:20;;66529:82;66525:111;;;66620:16;;;;;;;;;;;;;;66525:111;66649:23;66697:18:::0;66676:17:::1;66685:8:::0;66676:6;:17:::1;:::i;:::-;66675:40;;;;:::i;:::-;66774:22:::0;;66649:66;;-1:-1:-1;66726:23:0::1;::::0;66774:22;;::::1;-1:-1:-1::0;;;;;66774:22:0::1;66753:17;66762:8:::0;66753:6;:17:::1;:::i;:::-;66752:44;;;;:::i;:::-;66726:70;;66825:8;66813;:20;66809:84;;66850:31:::0;;;::::1;;::::0;::::1;;::::0;;66809:84:::1;66905:27:::0;;::::1;66943:52:::0;;;66905:27;;;::::1;::::0;;;::::1;66943:52:::0;;;;-1:-1:-1;;;;;66943:52:0;::::1;;;::::0;;67012:33;;::::1;67008:381;;;67074:9;::::0;-1:-1:-1;;;;;67074:9:0::1;67067:26;67094:10;67106:33;67124:15:::0;67106;:33:::1;:::i;:::-;67067:73;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;10528:55:1;;;67067:73:0::1;::::0;::::1;10510:74:1::0;10600:18;;;10593:34;10483:18;;67067:73:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67062:103;;67149:16;;-1:-1:-1::0;;;67149:16:0::1;;;;;;;;;;;67062:103;67008:381;;;67206:15;67187;:34;67183:206;;67250:9;::::0;-1:-1:-1;;;;;67250:9:0::1;67243:30;67274:10;67294:4;67301:33;67319:15:::0;67301;:33:::1;:::i;:::-;67243:92;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;12983:15:1;;;67243:92:0::1;::::0;::::1;12965:34:1::0;13035:15;;;;13015:18;;;13008:43;13067:18;;;13060:34;12877:18;;67243:92:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67238:139;;67361:16;;-1:-1:-1::0;;;67361:16:0::1;;;;;;;;;;;67238:139;67406:58;::::0;;13336:25:1;;;13392:2;13377:18;;13370:34;;;13420:18;;;13413:34;;;13478:2;13463:18;;13456:34;;;67406:58:0::1;::::0;13323:3:1;13308:19;67406:58:0::1;;;;;;;65985:1487;;;;;65820:1652:::0;;;;:::o;71811:1134::-;71890:27;71920:21;:19;:21::i;:::-;71980:10;71954:17;71974;;;:5;:17;;;;;:24;;71890:51;;-1:-1:-1;71954:17:0;;71974:24;;;;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;72031:26:0;72049:8;72031:15;:26;:::i;:::-;72073:8;;72011:47;;-1:-1:-1;72073:15:0;;;;:8;;;;;:15;72069:58;;72113:8;;72097:30;;;;;72113:8;;;;;;;;72097:30;;;13702:34:1;13772:15;;13752:18;;;13745:43;13646:18;;72097:30:0;13501:293:1;72069:58:0;72140:17;72160:55;72183:10;72195:19;72160:22;:55::i;:::-;72253:10;72228:36;;;;:24;:36;;;;;:58;;;72140:75;;-1:-1:-1;72319:31:0;72341:8;72319:21;:31::i;:::-;72363:14;;;;;;;;;;;;;;72299:51;;-1:-1:-1;72413:15:0;;;;;;;;;72445:26;;;;72441:91;;;72480:52;;;;;13979:6:1;14012:15;;;72480:52:0;;;13994:34:1;14064:15;;14044:18;;;14037:43;13942:18;;72480:52:0;13799:287:1;72441:91:0;72545:28;;;;;;;;;;;72603:11;;;-1:-1:-1;;;;;72603:11:0;;72640:26;72653:13;72545:28;72640:26;:::i;:::-;72639:37;;;;;;:::i;:::-;-1:-1:-1;;;;;72625:51:0;:10;;:51;;;;;;;:::i;:::-;;;;-1:-1:-1;;72693:14:0;;72689:176;;72736:9;;72729:49;;;;;72756:10;72729:49;;;10510:74:1;10600:18;;;10593:34;;;-1:-1:-1;;;;;72736:9:0;;;;72729:26;;10483:18:1;;72729:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;72724:79;;72787:16;;-1:-1:-1;;;72787:16:0;;;;;;;;;;;72724:79;72825:28;;2106:25:1;;;72831:10:0;;72825:28;;2094:2:1;2079:18;72825:28:0;;;;;;;72689:176;72882:55;;;8156:4:1;8144:17;;8126:36;;-1:-1:-1;;;;;8198:67:1;;8193:2;8178:18;;8171:95;8314:10;8302:23;;8282:18;;;8275:51;8374:6;8362:19;;8357:2;8342:18;;8335:47;72882:55:0;;72894:10;;72882:55;;;;;;8113:3:1;72882:55:0;;;71879:1066;;;;;;;71811:1134;;:::o;19665:201::-;18645:13;:11;:13::i;:::-;-1:-1:-1;;;;;19754:22:0;::::1;19746:73;;;::::0;::::1;::::0;;14794:2:1;19746:73:0::1;::::0;::::1;14776:21:1::0;14833:2;14813:18;;;14806:30;14872:34;14852:18;;;14845:62;14943:8;14923:18;;;14916:36;14969:19;;19746:73:0::1;14592:402:1::0;19746:73:0::1;19830:28;19849:8;19830:18;:28::i;:::-;19665:201:::0;:::o;62805:23::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62805:23:0;;;;;;;;-1:-1:-1;;;;;62805:23:0;;:::o;91908:320::-;92004:17;92034;92054:29;92078:4;92054:23;:29::i;:::-;-1:-1:-1;;;;;92178:30:0;;;;;;:24;:30;;;;;;92034:49;;-1:-1:-1;92128:81:0;;92034:49;;92158:50;;92128:18;:81::i;:::-;92121:88;91908:320;-1:-1:-1;;;;91908:320:0:o;18924:132::-;18832:6;;-1:-1:-1;;;;;18832:6:0;17060:10;18988:23;18980:68;;;;;;;15201:2:1;18980:68:0;;;15183:21:1;;;15220:18;;;15213:30;15279:34;15259:18;;;15252:62;15331:18;;18980:68:0;14999:356:1;84188:924:0;84279:7;84301;84323;84345;84380:20;84403:16;;84380:39;;84450:15;84434:12;:31;84430:145;;84490:15;;84507:27;;84536:10;;84548:14;;84482:81;;;;;;;;;;;84430:145;61710:11;95036:26;;;95023:40;;;84675:15;95036:26;;;95023:40;;84708:28;;;84704:159;;84761:32;:30;:32::i;:::-;84795:27;;84824:10;;84836:14;;84753:98;;;;;;;;;;;;;84704:159;61784:1;61710:11;84906:27;;;84905:46;:78;84901:146;;;85011:20;:18;:20::i;:::-;85004:27;;;;;;;;;;;;;84901:146;85080:24;:22;:24::i;:::-;85073:31;;;;;;;;;;;84188:924;;;;;:::o;23605:541::-;23725:9;23977:1;-1:-1:-1;;23960:19:0;23957:1;23954:26;23951:1;23947:34;23940:42;23927:11;23923:60;23913:118;;24014:1;24011;24004:12;23913:118;-1:-1:-1;24105:9:0;;24101:27;;23605:541::o;94397:506::-;94618:7;94660:18;94642:14;:36;94638:68;;-1:-1:-1;94687:19:0;94680:26;;94638:68;94859:35;94880:14;94859:18;:35;:::i;:::-;94823:18;94774:45;94796:23;94774:19;:45;:::i;:::-;94773:68;;;;:::i;:::-;94772:123;;;;:::i;:::-;94737:158;;:19;:158;:::i;:::-;94717:178;94397:506;-1:-1:-1;;;;;94397:506:0:o;93841:426::-;94061:7;94223:35;94244:14;94223:18;:35;:::i;20026:191::-;20119:6;;;-1:-1:-1;;;;;20136:17:0;;;;;;;;;;;20169:40;;20119:6;;;20136:17;20119:6;;20169:40;;20100:16;;20169:40;20089:128;20026:191;:::o;93046:300::-;93118:6;93152:7;93141:8;:18;:42;;;;93174:9;93163:8;:20;93141:42;93137:84;;;93192:29;;;;;;;;2106:25:1;;;2079:18;;93192:29:0;1960:177:1;93137:84:0;93333:4;93280:25;93297:8;93280:14;:25;:::i;:::-;93269:8;93249:17;93269:8;93249:6;:17;:::i;:::-;:28;;;;:::i;:::-;:56;;;;:::i;:::-;:80;;93308:21;93249:80;:::i;:::-;93248:89;;;;:::i;92715:108::-;92773:9;92806:1;92802;:5;:13;;92814:1;92802:13;;;-1:-1:-1;92810:1:0;;92715:108;-1:-1:-1;92715:108:0:o;18302:97::-;14837:13;;;;;;;14829:69;;;;;;;15687:2:1;14829:69:0;;;15669:21:1;15726:2;15706:18;;;15699:30;15765:34;15745:18;;;15738:62;15836:13;15816:18;;;15809:41;15867:19;;14829:69:0;15485:407:1;14829:69:0;18365:26:::1;:24;:26::i;91339:460::-:0;-1:-1:-1;;;;;91456:11:0;;91409:13;91456:11;;;:5;:11;;;;;:18;91409:13;;91513:279;91547:10;91538:6;:19;91513:279;;;-1:-1:-1;;;;;91591:11:0;;;;;;:5;:11;;;;;:19;;91603:6;;91591:19;;;;;;:::i;:::-;;;;;;;;91584:26;;91629:54;91654:28;91669:6;91677:4;93705:2;93688:19;93679:29;;;;93568:149;91629:54;91704:8;91625:103;91765:15;;91751:29;;91765:15;;;;91751:11;;;-1:-1:-1;;;;;91751:11:0;:29;:::i;:::-;91742:38;;-1:-1:-1;;;;;91742:38:0;;;:::i;:::-;;;91513:279;91559:8;;;:::i;:::-;;;91513:279;;;;91424:375;;91339:460;;;:::o;92330:167::-;92425:7;92452:37;:5;92469:19;92452:16;:37::i;90279:1010::-;90433:10;;90344:7;;90458:16;;;90454:71;;-1:-1:-1;;90498:15:0;;;90279:1010::o;90454:71::-;90565:16;;90611:7;:14;90537:25;;;90697:477;90735:6;90724:8;:17;90697:477;;;90769:7;90777:8;90769:17;;;;;;;;:::i;:::-;;;;;;;;;;90890:12;;90769:17;;-1:-1:-1;90832:10:0;;;;;90890:12;;;;;90931:10;;;;90962:15;:23;-1:-1:-1;90958:37:0;;;90987:8;;90697:477;;90958:37;91034:3;91014:17;:23;91010:37;;;91039:8;;90697:477;;91010:37;91140:22;;;;;-1:-1:-1;;;;;91140:22:0;91107:29;91111:5;91118:17;91107:3;:29::i;:::-;91079:25;91083:15;91100:3;91079;:25::i;:::-;:57;;;;:::i;:::-;91078:84;;;;:::i;:::-;91064:98;;;;:::i;:::-;;;90745:429;;90697:477;;;-1:-1:-1;91193:15:0;;:88;;91247:34;:10;91269:11;91247:21;:34::i;:::-;91229:15;;:52;;;;:::i;:::-;91193:88;;;91211:15;;91193:88;91186:95;;;;;;;90279:1010;:::o;85492:4745::-;85586:7;85608;85630;85652;85687:22;85712:10;;85687:35;;85737:14;85755:1;85737:19;85733:137;;85781:15;;85798:27;;85827:14;85843;;85773:85;;;;;;;;;;;85733:137;85882:28;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85882:28:0;85937:16;;85921:32;;85996:15;;86061:27;;86022:36;;;:66;86128:14;;86184:7;86155:36;;;;;;;;;;;;;;;;;;;85921:13;;86155:36;;86184:7;;85921:13;;86155:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;86155:36:0;;;;;;;;;;;;;;;;;;;;;;86203:30;86235:26;86265:116;86302:8;:13;;;86330:15;86360:10;86265:22;:116::i;:::-;86202:179;;;;86422:18;86398:13;:20;:42;86394:173;;86465:19;86486:8;:36;;;86524:14;86540;;86457:98;;;;;;;;;;;;;;;;;86394:173;86579:36;86601:13;86579:21;:36::i;:::-;86627:39;86668:19;86691:118;86727:13;86755:10;86780:18;86691:21;:118::i;:::-;86845:13;;86626:183;;-1:-1:-1;86626:183:0;-1:-1:-1;86836:40:0;;61710:11;;95036:26;;;95023:40;;86836;:::i;:::-;86822:11;;;:54;86889:2200;86911:15;86896:8;:11;;;:30;;:98;;;;;86983:11;86955:18;:25;:39;;;;:::i;:::-;86930:8;:22;;;:64;86896:98;86889:2200;;;87128:8;:13;;;87077:18;87096:8;:22;;;87077:42;;;;;;;;:::i;:::-;;;;;;;:48;;;:64;87073:189;;;87207:11;;;;61710;98985:19;;87193:26;87178:11;;;87162:57;;;87238:8;;87073:189;87397:8;:11;;;87348:18;87367:8;:22;;;87348:42;;;;;;;;:::i;:::-;;;;;;;:46;;;:60;87344:204;;;87464:22;;;87462:24;;;;;;87524:8;;87344:204;87630:18;87649:8;:22;;;87630:42;;;;;;;;:::i;:::-;;;;;;;:54;;;87688:1;87630:59;87626:184;;87755:11;;;;61710;98985:19;;87741:26;98861:163;87626:184;87937:22;;;;:27;:75;;;;-1:-1:-1;87982:13:0;;87968:11;;;;61710;;87968:27;;;:::i;:::-;:44;87937:75;87933:494;;;88090:183;88196:8;:13;;;88182:8;:11;;;:27;61710:11;88090:18;88109:8;:22;;;88090:42;;;;;;;;:::i;:::-;;;;;;;:54;;;:65;;:183;;;;;:::i;:::-;88066:21;;;:207;87933:494;;;88357:18;88376:8;:22;;;88357:42;;;;;;;;:::i;:::-;;;;;;;:54;;;88333:8;:21;;:78;;;;;87933:494;88520:21;;;;:48;;88553:14;88520:32;:48::i;:::-;88639:36;;;;88497:71;;;88616:148;;88617:58;;61659:3;88710:35;;88616:71;:148::i;:::-;88587:26;;;:177;;;88783:36;;;:58;;;89065:11;;;;61659:3;88945:43;;88927:61;;;;;88860:48;;;61710:11;98985:19;;89051:26;98861:163;86889:2200;89186:13;;89202:15;-1:-1:-1;89186:85:0;;;;;89246:18;:25;89221:8;:22;;;:50;89186:85;89182:933;;;89459:15;89410:18;89429:8;:22;;;89410:42;;;;;;;;:::i;:::-;;;;;;;:46;;;:64;:153;;;;;89562:1;89548:11;89520:18;:25;:39;;;;:::i;:::-;:43;;;;:::i;:::-;89495:8;:22;;;:68;89410:153;89388:302;;;89633:22;;;89631:24;;;;;;89388:302;89760:15;89710:18;89729:8;:22;;;89710:42;;;;;;;;:::i;:::-;;;;;;;:46;;;:65;89706:398;;89829:18;61710:11;89952:8;:13;;;89934:15;:31;89851:18;89870:8;:22;;;89851:42;;;;;;;;:::i;:::-;;;;;;;:54;;;:115;89850:134;;;;;:::i;:::-;;;-1:-1:-1;90032:37:0;89850:134;90054:14;90032:21;:37::i;:::-;90009:60;;;;89796:293;89706:398;-1:-1:-1;;;;90156:36:0;;;;;;90135:19;;90156:36;;-1:-1:-1;90194:14:0;;-1:-1:-1;90194:14:0;;-1:-1:-1;85492:4745:0;;-1:-1:-1;;85492:4745:0:o;81735:1914::-;81833:7;81855;81877;81899;81934:22;81959:10;;81934:35;;81984:14;82002:1;81984:19;81980:137;;82028:15;;82045:27;;82074:14;82090;;82020:85;;;;;;;;;;;81980:137;82157:16;;82216:15;;82284:27;;82353:14;;82409:7;82380:36;;;;;;;;;;;;;;;;;;;82129:25;;82380:36;;82409:7;;82129:25;;82380:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;82380:36:0;;;;;;;;;;;;;;;;-1:-1:-1;82380:36:0;;-1:-1:-1;82549:17:0;;-1:-1:-1;82429:12:0;;-1:-1:-1;82429:12:0;;-1:-1:-1;82429:12:0;82582:44;61710:11;95036:26;;;95023:40;;82582:44;:::i;:::-;82577:49;;82637:683;82650:15;82644:2;:21;82637:683;;82697:38;82714:10;82726:4;82732:2;82697:16;:38::i;:::-;82682:53;-1:-1:-1;82802:39:0;82682:53;82826:14;82802:23;:39::i;:::-;82779:62;;;;82880:143;82881:53;;;61659:3;82969:35;;82880:66;:143::i;:::-;61659:3;83190:34;;83172:52;;;;;83134:19;;-1:-1:-1;83042:39:0;;;;83252:2;;-1:-1:-1;;61710:11:0;83273:20;;;82637:683;;;83343:15;83336:4;:22;83332:200;;;83390:51;83407:10;83419:4;83425:15;83390:16;:51::i;:::-;83375:66;-1:-1:-1;83481:39:0;83375:66;83505:14;83481:23;:39::i;:::-;83458:62;;;;:::i;:::-;;;83332:200;-1:-1:-1;83552:19:0;;83573:31;;-1:-1:-1;83606:14:0;;-1:-1:-1;83622:18:0;;-1:-1:-1;81735:1914:0;;-1:-1:-1;;;;;;81735:1914:0:o;18407:113::-;14837:13;;;;;;;14829:69;;;;;;;15687:2:1;14829:69:0;;;15669:21:1;15726:2;15706:18;;;15699:30;15765:34;15745:18;;;15738:62;15836:13;15816:18;;;15809:41;15867:19;;14829:69:0;15485:407:1;14829:69:0;18480:32:::1;17060:10:::0;18480:18:::1;:32::i;22725:166::-:0;22790:7;22817:21;22828:1;22831;22674:4;22817:10;:21::i;92553:108::-;92611:9;92644:1;92640;:5;:13;;92652:1;92640:13;;23067:166;23132:7;23159:21;23170:1;22674:4;23178:1;23159:10;:21::i;97784:1011::-;97927:16;97945:7;98063:30;98110:10;:17;98130:1;98110:21;;;;:::i;:::-;98096:36;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;98096:36:0;;98063:69;;98143:26;98180:13;98204:11;98226:24;98268:9;98263:470;98283:10;:17;98279:1;:21;98263:470;;;98327:30;98331:4;98337:10;98348:1;98337:13;;;;;;;;:::i;:::-;;;;;;;:19;;;98327:30;;:3;:30::i;:::-;98319:38;;98378:26;98382:2;98386:10;98397:1;98386:13;;;;;;;;:::i;:::-;;;;;;;:17;;;98378:26;;:3;:26::i;:::-;98372:32;;98460:3;98452:5;:11;98448:235;;;98524:5;98488:13;98502:18;;;;;;98488:33;;;;;;;;:::i;:::-;;;;;;:41;;;;;98588:3;98552:13;98566:18;;;;;;98552:33;;;;;;;;:::i;:::-;;;;;;:39;;;;;98448:235;;;98662:1;98640:23;;;;98448:235;98703:3;;98263:470;;;-1:-1:-1;98753:13:0;;98768:18;;-1:-1:-1;97784:1011:0;;-1:-1:-1;;;;;;;97784:1011:0:o;33046:1057::-;33197:1;33191:8;33241:1;33238;33231:12;33329:1;33326;33322:9;33319:1;33315:17;33369:4;33400:2;33396:7;33439:1;33436;33432:9;33417:612;33473:9;;33503:8;;;33514:5;33500:21;33554:1;33548:8;33598:1;33595;33591:9;33670:1;33664:8;33727:1;33724;33721:8;33711:32;;33733:8;;;33417:612;;33711:32;33761:215;33803:9;;;33796:20;33843:9;;33898:8;;33938;;;33761:215;33928:29;-1:-1:-1;34001:9:0;;33994:20;33417:612;;;-1:-1:-1;;;34043:12:0;;-1:-1:-1;33046:1057:0:o;96058:1639::-;96234:33;96269:19;96378:1;96357:18;96334:13;:20;:41;;;;:::i;:::-;:45;;;;:::i;:::-;96316:64;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;96316:64:0;;;;;;;;;;;;;;;;-1:-1:-1;96301:79:0;-1:-1:-1;96393:13:0;;;;;96535:18;96518:1125;96582:1;96559:13;:20;:24;;;;:::i;:::-;96555:1;:28;96518:1125;;;96610:13;96624:1;96610:16;;;;;;;;:::i;:::-;;;;;;;96602:24;;96647:13;96661:1;96665;96661:5;;;;:::i;:::-;96647:20;;;;;;;;:::i;:::-;;;;;;;96641:26;;96695:3;96686:5;:12;96682:173;;96752:13;;;;;96788:3;96518:1125;;96682:173;96883:1;96869:15;;96908:1;96904:5;;96899:585;96915:10;:17;96911:1;:21;96899:585;;;96981:5;96959:10;96970:1;96959:13;;;;;;;;:::i;:::-;;;;;;;:19;;;:27;;;96955:170;;;97048:3;;;;;96899:585;;96955:170;97167:3;97147:10;97158:1;97147:13;;;;;;;;:::i;:::-;;;;;;;:17;;;:23;;;97143:166;;;97232:3;;;;;96899:585;;97143:166;97394:10;97405:1;97394:13;;;;;;;;:::i;:::-;;;;;;;:29;;;-1:-1:-1;;;;;97377:46:0;61710:11;97377:46;97362:61;;;;97446:3;;;;;96899:585;;;97580:36;;;;;;;;;;;;;;;;;;;;;;;97551:26;;97529:3;97564:12;;;;97529:3;;;97551:12;;:26;;;;;;:::i;:::-;;;;;;:65;;;;96518:1125;;;;97655:34;;;;;96058:1639;;;;;;:::o;95159:790::-;95296:20;;95329:613;95353:10;:17;95349:1;:21;95329:613;;;95398:10;95409:1;95398:13;;;;;;;;:::i;:::-;;;;;;;:19;;;95393:24;;:2;:24;95389:147;;;95471:3;;95329:613;;95389:147;95561:10;95572:1;95561:13;;;;;;;;:::i;:::-;;;;;;;:17;;;95554:24;;:4;:24;95550:147;;;95632:3;;95329:613;;95550:147;95864:10;95875:1;95864:13;;;;;;;;:::i;:::-;;;;;;;:29;;;-1:-1:-1;;;;;95779:114:0;95809:30;95813:10;95824:1;95813:13;;;;;;;;:::i;:::-;;;;;;;:19;;;95809:30;;95834:4;95809:3;:30::i;:::-;95780:26;95784:2;95788:10;95799:1;95788:13;;;;;;;;:::i;95780:26::-;:59;95779:114;95742:151;;;;;95912:3;;95329:613;;;;95159:790;;;;;:::o;14:156:1:-;80:20;;140:4;129:16;;119:27;;109:55;;160:1;157;150:12;109:55;14:156;;;:::o;175:182::-;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;324:27;341:9;324:27;:::i;362:949::-;581:2;633:21;;;703:13;;606:18;;;725:22;;;552:4;;581:2;766;;784:18;;;;825:15;;;552:4;868:417;882:6;879:1;876:13;868:417;;;941:13;;1016:9;;977:10;1012:18;;;1000:31;;1075:11;;;1069:18;1065:27;1051:12;;;1044:49;1137:11;;1131:18;-1:-1:-1;;;;;1127:75:1;1113:12;;;1106:97;1232:4;1223:14;;;;1260:15;;;;904:1;897:9;868:417;;;-1:-1:-1;1302:3:1;;362:949;-1:-1:-1;;;;;;;362:949:1:o;1316:196::-;1384:20;;-1:-1:-1;;;;;1433:54:1;;1423:65;;1413:93;;1502:1;1499;1492:12;1517:118;1603:5;1596:13;1589:21;1582:5;1579:32;1569:60;;1625:1;1622;1615:12;1640:315;1705:6;1713;1766:2;1754:9;1745:7;1741:23;1737:32;1734:52;;;1782:1;1779;1772:12;1734:52;1805:29;1824:9;1805:29;:::i;:::-;1795:39;;1884:2;1873:9;1869:18;1856:32;1897:28;1919:5;1897:28;:::i;:::-;1944:5;1934:15;;;1640:315;;;;;:::o;2142:186::-;2201:6;2254:2;2242:9;2233:7;2229:23;2225:32;2222:52;;;2270:1;2267;2260:12;2222:52;2293:29;2312:9;2293:29;:::i;2333:928::-;2548:2;2600:21;;;2670:13;;2573:18;;;2692:22;;;2519:4;;2548:2;2733;;2751:18;;;;2792:15;;;2519:4;2835:400;2849:6;2846:1;2843:13;2835:400;;;2908:13;;2950:9;;2961:6;2946:22;2934:35;;3013:11;;;3007:18;3027:10;3003:35;2989:12;;;2982:57;3083:11;;3077:18;-1:-1:-1;;;;;3073:79:1;3059:12;;;3052:101;3182:4;3173:14;;;;3210:15;;;;2871:1;2864:9;2835:400;;3266:163;3333:20;;3393:10;3382:22;;3372:33;;3362:61;;3419:1;3416;3409:12;3434:461;3509:6;3517;3525;3578:2;3566:9;3557:7;3553:23;3549:32;3546:52;;;3594:1;3591;3584:12;3546:52;3617:28;3635:9;3617:28;:::i;:::-;3607:38;;3664:37;3697:2;3686:9;3682:18;3664:37;:::i;:::-;3654:47;;3751:2;3740:9;3736:18;3723:32;-1:-1:-1;;;;;3788:5:1;3784:62;3777:5;3774:73;3764:101;;3861:1;3858;3851:12;3764:101;3884:5;3874:15;;;3434:461;;;;;:::o;4092:180::-;4151:6;4204:2;4192:9;4183:7;4179:23;4175:32;4172:52;;;4220:1;4217;4210:12;4172:52;-1:-1:-1;4243:23:1;;4092:180;-1:-1:-1;4092:180:1:o;4277:208::-;4345:20;;-1:-1:-1;;;;;4394:66:1;;4384:77;;4374:105;;4475:1;4472;4465:12;4490:254;4558:6;4566;4619:2;4607:9;4598:7;4594:23;4590:32;4587:52;;;4635:1;4632;4625:12;4587:52;4671:9;4658:23;4648:33;;4700:38;4734:2;4723:9;4719:18;4700:38;:::i;:::-;4690:48;;4490:254;;;;;:::o;4980:::-;5048:6;5056;5109:2;5097:9;5088:7;5084:23;5080:32;5077:52;;;5125:1;5122;5115:12;5077:52;5148:29;5167:9;5148:29;:::i;:::-;5138:39;5224:2;5209:18;;;;5196:32;;-1:-1:-1;;;4980:254:1:o;5239:::-;5307:6;5315;5368:2;5356:9;5347:7;5343:23;5339:32;5336:52;;;5384:1;5381;5374:12;5336:52;5407:29;5426:9;5407:29;:::i;6153:385::-;6239:6;6247;6255;6263;6316:3;6304:9;6295:7;6291:23;6287:33;6284:53;;;6333:1;6330;6323:12;6284:53;-1:-1:-1;;6356:23:1;;;6426:2;6411:18;;6398:32;;-1:-1:-1;6477:2:1;6462:18;;6449:32;;6528:2;6513:18;6500:32;;-1:-1:-1;6153:385:1;-1:-1:-1;6153:385:1:o;6543:250::-;6609:6;6617;6670:2;6658:9;6649:7;6645:23;6641:32;6638:52;;;6686:1;6683;6676:12;6638:52;6709:27;6726:9;6709:27;:::i;7222:184::-;7274:77;7271:1;7264:88;7371:4;7368:1;7361:15;7395:4;7392:1;7385:15;7411:184;7463:77;7460:1;7453:88;7560:4;7557:1;7550:15;7584:4;7581:1;7574:15;7600:125;7665:9;;;7686:10;;;7683:36;;;7699:18;;:::i;7730:168::-;7803:9;;;7834;;7851:15;;;7845:22;;7831:37;7821:71;;7872:18;;:::i;8393:184::-;8445:77;8442:1;8435:88;8542:4;8539:1;8532:15;8566:4;8563:1;8556:15;8582:112;8614:1;8640;8630:35;;8645:18;;:::i;:::-;-1:-1:-1;8679:9:1;;8582:112::o;8699:175::-;8767:10;8810;;;8798;;;8794:27;;8833:12;;;8830:38;;;8848:18;;:::i;:::-;8830:38;8699:175;;;;:::o;8879:316::-;-1:-1:-1;;;;;9051:10:1;;;9021;;;9085:13;;;9081:22;;;8951:50;9125:11;;9146:17;;;9138:26;;9122:43;9112:77;;9169:18;;:::i;:::-;9112:77;;;8879:316;;;;:::o;9660:245::-;9727:6;9780:2;9768:9;9759:7;9755:23;9751:32;9748:52;;;9796:1;9793;9786:12;9748:52;9828:9;9822:16;9847:28;9869:5;9847:28;:::i;10638:128::-;10705:9;;;10726:11;;;10723:37;;;10740:18;;:::i;11024:184::-;11076:77;11073:1;11066:88;11173:4;11170:1;11163:15;11197:4;11194:1;11187:15;14091:171;14159:6;14198:10;;;14186;;;14182:27;;14221:12;;;14218:38;;;14236:18;;:::i;14267:320::-;-1:-1:-1;;;;;14443:10:1;;;14413;;;14477:13;;;14473:22;;;14339:54;14517:11;;14538:17;;;14530:26;;14514:43;14504:77;;14561:18;;:::i;15360:120::-;15400:1;15426;15416:35;;15431:18;;:::i;:::-;-1:-1:-1;15465:9:1;;15360:120::o;15897:195::-;15936:3;-1:-1:-1;;15960:5:1;15957:77;15954:103;;16037:18;;:::i;:::-;-1:-1:-1;16084:1:1;16073:13;;15897:195::o;16097:184::-;16149:77;16146:1;16139:88;16246:4;16243:1;16236:15;16270:4;16267:1;16260:15

Swarm Source

ipfs://9d5f0db8bc0e15baa8dbab20a34304b0c18479abfb53c796cdddd712b53ea243

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.