ETH Price: $3,242.78 (-0.97%)
Gas: 5 Gwei

Contract

0xF01e619E8618BFf466877c524a85a5DBe1e36814
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Unstake203850592024-07-25 17:28:592 days ago1721928539IN
0xF01e619E...Be1e36814
0 ETH0.000653165.62798775
Unstake203448182024-07-20 2:40:357 days ago1721443235IN
0xF01e619E...Be1e36814
0 ETH0.0003982.25914741
Unstake203448142024-07-20 2:39:477 days ago1721443187IN
0xF01e619E...Be1e36814
0 ETH0.000414562.35319189
Unstake203448082024-07-20 2:38:357 days ago1721443115IN
0xF01e619E...Be1e36814
0 ETH0.000505862.61736221
Unstake203445582024-07-20 1:48:117 days ago1721440091IN
0xF01e619E...Be1e36814
0 ETH0.000513952.65906456
Unstake203430722024-07-19 20:49:237 days ago1721422163IN
0xF01e619E...Be1e36814
0 ETH0.000817944.23178344
Unstake203403612024-07-19 11:44:478 days ago1721389487IN
0xF01e619E...Be1e36814
0 ETH0.001224596.33570908
Unstake202951272024-07-13 4:13:4714 days ago1720844027IN
0xF01e619E...Be1e36814
0 ETH0.000142451.24964199
Unstake202951122024-07-13 4:10:4714 days ago1720843847IN
0xF01e619E...Be1e36814
0 ETH0.000195061.55680394
Process Rewards202596012024-07-08 5:07:2319 days ago1720415243IN
0xF01e619E...Be1e36814
0 ETH0.000147952.16231737
Unstake202595522024-07-08 4:57:2319 days ago1720414643IN
0xF01e619E...Be1e36814
0 ETH0.000348351.67281758
Unstake202550382024-07-07 13:49:4720 days ago1720360187IN
0xF01e619E...Be1e36814
0 ETH0.000588252.97121986
Unstake202550342024-07-07 13:48:5920 days ago1720360139IN
0xF01e619E...Be1e36814
0 ETH0.000665993.09625977
Unstake201724472024-06-26 1:01:5931 days ago1719363719IN
0xF01e619E...Be1e36814
0 ETH0.00028482
Unstake201596632024-06-24 6:09:5933 days ago1719209399IN
0xF01e619E...Be1e36814
0 ETH0.000251742.32671977
Unstake201596602024-06-24 6:09:2333 days ago1719209363IN
0xF01e619E...Be1e36814
0 ETH0.000287012.43138636
Unstake201596572024-06-24 6:08:4733 days ago1719209327IN
0xF01e619E...Be1e36814
0 ETH0.000355312.6293653
Unstake201560092024-06-23 17:53:5934 days ago1719165239IN
0xF01e619E...Be1e36814
0 ETH0.000461672.99054604
Unstake201485402024-06-22 16:49:3535 days ago1719074975IN
0xF01e619E...Be1e36814
0 ETH0.000198824.79654843
Unstake201485382024-06-22 16:49:1135 days ago1719074951IN
0xF01e619E...Be1e36814
0 ETH0.000535884.95280316
Unstake201485182024-06-22 16:45:1135 days ago1719074711IN
0xF01e619E...Be1e36814
0 ETH0.00054194.59107445
Unstake201485072024-06-22 16:42:5935 days ago1719074579IN
0xF01e619E...Be1e36814
0 ETH0.000528494.4774363
Unstake201432612024-06-21 23:05:4735 days ago1719011147IN
0xF01e619E...Be1e36814
0 ETH0.000286332.38987745
Unstake201432582024-06-21 23:05:1135 days ago1719011111IN
0xF01e619E...Be1e36814
0 ETH0.000376392.51469789
Unstake201166912024-06-18 5:53:4739 days ago1718690027IN
0xF01e619E...Be1e36814
0 ETH0.001277715.45193945
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
HighStreetCorePool

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 10000 runs

Other Settings:
default evmVersion
File 1 of 11 : HighStreetCorePool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./HighStreetPoolBase.sol";

/**
 * @title HIGH Core Pool
 *
 * @notice Core pools represent permanent pools like HIGH or HIGH/ETH Pair pool,
 *      core pools allow staking for arbitrary periods of time up to 1 year
 *
 * @dev See HighStreetPoolBase for more details
 *
 */
contract HighStreetCorePool is HighStreetPoolBase {
    /// @dev Flag indicating pool type, false means "core pool"
    bool public constant override isFlashPool = false;

    /// @dev Link to deployed vault instance
    address public vault;

    /// @dev Used to calculate vault rewards
    /// @dev This value is different from "reward per token" used in locked pool
    /// @dev Note: stakes are different in duration and "weight" reflects that
    uint256 public vaultRewardsPerWeight;

    /// @dev Pool tokens value available in the pool;
    ///      pool token examples are HIGH (HIGH core pool) or HIGH/ETH pair (LP core pool)
    /// @dev For LP core pool this value doesnt' count for HIGH tokens received as Vault rewards
    ///      while for HIGH core pool it does count for such tokens as well
    uint256 public poolTokenReserve;

    /**
     * @dev Fired in receiveVaultRewards()
     *
     * @param _by an address that sent the rewards, always a vault
     * @param amount amount of tokens received
     */
    event VaultRewardsReceived(address indexed _by, uint256 amount);

    /**
     * @dev Fired in _processVaultRewards() and dependent functions, like processRewards()
     *
     * @param _by an address which executed the function
     * @param _to an address which received a reward
     * @param amount amount of reward received
     */
    event VaultRewardsClaimed(address indexed _by, address indexed _to, uint256 amount);

    /**
     * @dev Fired in setVault()
     *
     * @param _by an address which executed the function, always a factory owner
     */
    event VaultUpdated(address indexed _by, address _fromVal, address _toVal);

    /**
     * @dev Creates/deploys an instance of the core pool
     *
     * @param _high HIGH ERC20 Token IlluviumERC20 address
     * @param _factory Pool factory HighStreetPoolFactory instance/address
     * @param _poolToken token the pool operates on, for example HIGH or HIGH/ETH pair
     * @param _initBlock initial block used to calculate the rewards
     * @param _weight number representing a weight of the pool, actual weight fraction
     *      is calculated as that number divided by the total pools weight and doesn't exceed one
     */
    constructor(
        address _high,
        HighStreetPoolFactory _factory,
        address _poolToken,
        uint256 _initBlock,
        uint256 _weight
    ) HighStreetPoolBase(_high, _factory, _poolToken, _initBlock, _weight) {}

    /**
     * @notice Calculates current vault rewards value available for address specified
     *
     * @dev Performs calculations based on current smart contract state only,
     *      not taking into account any additional time/blocks which might have passed
     *
     * @param _staker an address to calculate vault rewards value for
     * @return pending calculated vault reward value for the given address
     */
    function pendingVaultRewards(address _staker) public view returns (uint256 pending) {
        User memory user = users[_staker];

        return weightToReward(user.totalWeight, vaultRewardsPerWeight) - user.subVaultRewards;
    }

    /**
     * @dev Executed only by the factory owner to Set the vault
     *
     * @param _vault an address of deployed IlluviumVault instance
     */
    function setVault(address _vault) external {
        // verify function is executed by the factory owner
        require(factory.owner() == msg.sender, "access denied");

        // verify input is set
        require(_vault != address(0), "zero input");

        // emit an event
        emit VaultUpdated(msg.sender, vault, _vault);

        // update vault address
        vault = _vault;
    }

    /**
     * @dev Executed by the vault to transfer vault rewards HIGH from the vault
     *      into the pool
     *
     * @dev This function is executed only for HIGH core pools
     *
     * @param _rewardsAmount amount of HIGH rewards to transfer into the pool
     */
    function receiveVaultRewards(uint256 _rewardsAmount) external {
        require(msg.sender == vault, "access denied");
        // return silently if there is no reward to receive
        if (_rewardsAmount == 0) {
            return;
        }
        require(usersLockingWeight > 0, "zero locking weight");

        transferHighTokenFrom(msg.sender, address(this), _rewardsAmount);

        vaultRewardsPerWeight += rewardToWeight(_rewardsAmount, usersLockingWeight);

        // update `poolTokenReserve` only if this is a HIGH Core Pool
        if (poolToken == HIGH) {
            poolTokenReserve += _rewardsAmount;
        }

        emit VaultRewardsReceived(msg.sender, _rewardsAmount);
    }

    /**
     * @notice Service function to calculate and pay pending vault and yield rewards to the sender
     *
     * @dev Internally executes similar function `_processRewards` from the parent smart contract
     *      to calculate and pay yield rewards; adds vault rewards processing
     *
     * @dev Can be executed by anyone at any time, but has an effect only when
     *      executed by deposit holder and when at least one block passes from the
     *      previous reward processing
     * @dev Executed internally when "staking as a pool" (`stakeAsPool`)
     * @dev When timing conditions are not met (executed too frequently, or after factory
     *      end block), function doesn't throw and exits silently
     *
     * @dev Reentrancy safety enforced via `ReentrancyGuard.nonReentrant`
     *
     */
    function processRewards() external override nonReentrant{
        _processRewards(msg.sender, true);
        User storage user = users[msg.sender];
        user.subVaultRewards = weightToReward(user.totalWeight, vaultRewardsPerWeight);
    }

    /**
     * @dev Executed internally by the pool itself (from the parent `HighStreetPoolBase` smart contract)
     *      as part of yield rewards processing logic (`HighStreetPoolBase._processRewards` function)
     *
     * @dev Because the reward in all pools should be regarded as a yield staking in HIGH token pool
     *      thus this function can only be excecuted within HIGH token pool
     *
     * @param _staker an address which stakes (the yield reward)
     * @param _amount amount to be staked (yield reward amount)
     */
    function stakeAsPool(address _staker, uint256 _amount) external {
        require(factory.poolExists(msg.sender), "access denied");
        require(poolToken == HIGH, "not HIGH token pool");

        _sync();
        User storage user = users[_staker];
        if (user.tokenAmount > 0) {
            _processRewards(_staker, false);
        }
        uint256 depositWeight = _amount * YEAR_STAKE_WEIGHT_MULTIPLIER;
        Deposit memory newDeposit =
            Deposit({
                tokenAmount: _amount,
                lockedFrom: uint64(now256()),
                lockedUntil: uint64(now256() + 365 days),
                weight: depositWeight,
                isYield: true
            });
        user.tokenAmount += _amount;
        user.rewardAmount += _amount;
        user.totalWeight += depositWeight;
        user.deposits.push(newDeposit);

        usersLockingWeight += depositWeight;

        user.subYieldRewards = weightToReward(user.totalWeight, yieldRewardsPerWeight);
        user.subVaultRewards = weightToReward(user.totalWeight, vaultRewardsPerWeight);

        // update `poolTokenReserve` only if this is a LP Core Pool (stakeAsPool can be executed only for LP pool)
        poolTokenReserve += _amount;
    }

    /**
     * @inheritdoc HighStreetPoolBase
     *
     * @dev Additionally to the parent smart contract, updates vault rewards of the holder,
     *      and updates (increases) pool token reserve (pool tokens value available in the pool)
     */
    function _stake(
        address _staker,
        uint256 _amount,
        uint64 _lockedUntil
    ) internal override {
        super._stake(_staker, _amount, _lockedUntil);
        User storage user = users[_staker];
        user.subVaultRewards = weightToReward(user.totalWeight, vaultRewardsPerWeight);

        poolTokenReserve += _amount;
    }

    /**
     * @inheritdoc HighStreetPoolBase
     *
     * @dev Additionally to the parent smart contract, updates vault rewards of the holder,
     *      and updates (decreases) pool token reserve (pool tokens value available in the pool)
     */
    function _unstake(
        address _staker,
        uint256 _depositId,
        uint256 _amount
    ) internal override {
        User storage user = users[_staker];
        Deposit memory stakeDeposit = user.deposits[_depositId];
        require(stakeDeposit.lockedFrom == 0 || now256() > stakeDeposit.lockedUntil, "deposit not yet unlocked");
        poolTokenReserve -= _amount;
        super._unstake(_staker, _depositId, _amount);
        user.subVaultRewards = weightToReward(user.totalWeight, vaultRewardsPerWeight);
    }

    /**
     * @inheritdoc HighStreetPoolBase
     *
     * @dev Additionally to the parent smart contract, updates vault rewards of the holder,
     *      and updates (decreases) pool token reserve (pool tokens value available in the pool)
     */
    function _emergencyWithdraw(
        address _staker
    ) internal override {
        User storage user = users[_staker];
        uint256 amount = user.tokenAmount;

        poolTokenReserve -= amount;
        super._emergencyWithdraw(_staker);
        user.subVaultRewards = 0;
    }

    /**
     * @inheritdoc HighStreetPoolBase
     *
     * @dev Additionally to the parent smart contract, processes vault rewards of the holder,
     *      and for HIGH pool updates (increases) pool token reserve (pool tokens value available in the pool)
     */
    function _processRewards(
        address _staker,
        bool _withUpdate
    ) internal override returns (uint256 pendingYield) {
        _processVaultRewards(_staker);
        pendingYield = super._processRewards(_staker, _withUpdate);

        // update `poolTokenReserve` only if this is a HIGH Core Pool
        if (poolToken == HIGH) {
            poolTokenReserve += pendingYield;
        }
    }

    /**
     * @dev Used internally to process vault rewards for the staker
     *
     * @param _staker address of the user (staker) to process rewards for
     */
    function _processVaultRewards(address _staker) private {
        User storage user = users[_staker];
        uint256 pendingVaultClaim = pendingVaultRewards(_staker);
        if (pendingVaultClaim == 0) return;
        // read HIGH token balance of the pool via standard ERC20 interface
        uint256 highBalance = IERC20(HIGH).balanceOf(address(this));
        require(highBalance >= pendingVaultClaim, "contract HIGH balance too low");

        // update `poolTokenReserve` only if this is a HIGH Core Pool
        if (poolToken == HIGH) {
            // protects against rounding errors
            poolTokenReserve -= pendingVaultClaim > poolTokenReserve ? poolTokenReserve : pendingVaultClaim;
        }

        user.subVaultRewards = weightToReward(user.totalWeight, vaultRewardsPerWeight);

        // transfer fails if pool HIGH balance is not enough - which is a desired behavior
        transferHighToken(_staker, pendingVaultClaim);

        emit VaultRewardsClaimed(msg.sender, _staker, pendingVaultClaim);
    }

    /**
     * @dev Executes SafeERC20.safeTransfer on a HIGH token
     *
     */
    function transferHighToken(address _to, uint256 _value) internal {
        // just delegate call to the target
        SafeERC20.safeTransfer(IERC20(HIGH), _to, _value);
    }

    /**
     * @dev Executes SafeERC20.safeTransferFrom on a HIGH token
     *
     */
    function transferHighTokenFrom(
        address _from,
        address _to,
        uint256 _value
    ) internal {
        // just delegate call to the target
        SafeERC20.safeTransferFrom(IERC20(HIGH), _from, _to, _value);
    }
}

File 2 of 11 : IPool.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

/**
 * @title High Street Pool
 *
 * @notice An abstraction representing a pool, see HighStreetPoolBase for details
 *
 */
interface IPool {
    /**
     * @dev Deposit is a key data structure used in staking,
     *      it represents a unit of stake with its amount, weight and term (time interval)
     */
    struct Deposit {
        // @dev token amount staked
        uint256 tokenAmount;
        // @dev stake weight
        uint256 weight;
        // @dev locking period - from
        uint64 lockedFrom;
        // @dev locking period - until
        uint64 lockedUntil;
        // @dev indicates if the stake was created as a yield reward
        bool isYield;
    }

    // for the rest of the functions see Soldoc in HighStreetPoolBase
    function HIGH() external view returns (address);

    function poolToken() external view returns (address);

    function isFlashPool() external view returns (bool);

    function weight() external view returns (uint256);

    function lastYieldDistribution() external view returns (uint256);

    function yieldRewardsPerWeight() external view returns (uint256);

    function usersLockingWeight() external view returns (uint256);

    function pendingYieldRewards(address _user) external view returns (uint256);

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

    function getDeposit(address _user, uint256 _depositId) external view returns (Deposit memory);

    function getDepositsLength(address _user) external view returns (uint256);

    function stake(
        uint256 _amount,
        uint64 _lockedUntil
    ) external;

    function unstake(
        uint256 _depositId,
        uint256 _amount
    ) external;

    function sync() external;

    function processRewards() external;

    function setWeight(uint256 _weight) external;
}

File 3 of 11 : ICorePool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./IPool.sol";

interface ICorePool is IPool {
    function vaultRewardsPerToken() external view returns (uint256);

    function poolTokenReserve() external view returns (uint256);

    function stakeAsPool(address _staker, uint256 _amount) external;

    function receiveVaultRewards(uint256 _amount) external;
}

File 4 of 11 : HighStreetPoolFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IPool.sol";

/**
 * @title HighStreet Pool Factory
 *
 * @notice HIGH Pool Factory manages HighStreet Yield farming pools, provides a single
 *      public interface to access the pools, provides an interface for the pools
 *      to mint yield rewards, access pool-related info, update weights, etc.
 *
 * @notice The factory is authorized (via its owner) to register new pools, change weights
 *      of the existing pools, removing the pools (by changing their weights to zero)
 *
 * @dev The factory requires ROLE_TOKEN_CREATOR permission on the HIGH token to mint yield
 *      (see `mintYieldTo` function)
 *
 */
contract HighStreetPoolFactory is Ownable {
    /**
     * @dev Smart contract unique identifier, a random number
     * @dev Should be regenerated each time smart contact source code is changed
     *      and changes smart contract itself is to be redeployed
     * @dev Generated using https://www.random.org/bytes/
     */
    uint256 public constant FACTORY_UID = 0x484a992416a6637667452c709058dccce100b22b278536f5a6d25a14b6a1acdb;

    /// @dev Link to HIGH STREET ERC20 Token instance
    address public immutable HIGH;

    /// @dev Auxiliary data structure used only in getPoolData() view function
    struct PoolData {
        // @dev pool token address (like HIGH)
        address poolToken;
        // @dev pool address (like deployed core pool instance)
        address poolAddress;
        // @dev pool weight (200 for HIGH pools, 800 for HIGH/ETH pools - set during deployment)
        uint256 weight;
        // @dev flash pool flag
        bool isFlashPool;
    }

    /**
     * @dev HIGH/block determines yield farming reward base
     *      used by the yield pools controlled by the factory
     */
    uint256 public highPerBlock;

    /**
     * @dev The yield is distributed proportionally to pool weights;
     *      total weight is here to help in determining the proportion
     */
    uint256 public totalWeight;

    /**
     * @dev HIGH/block decreases by 3% every blocks/update (set to 91252 blocks during deployment);
     *      an update is triggered by executing `updateHighPerBlock` public function
     */
    uint256 public immutable blocksPerUpdate;

    /**
     * @dev End block is the last block when HIGH/block can be decreased;
     *      it is implied that yield farming stops after that block
     */
    uint256 public endBlock;

    /**
     * @dev Each time the HIGH/block ratio gets updated, the block number
     *      when the operation has occurred gets recorded into `lastRatioUpdate`
     * @dev This block number is then used to check if blocks/update `blocksPerUpdate`
     *      has passed when decreasing yield reward by 3%
     */
    uint256 public lastRatioUpdate;

    /// @dev Maps pool token address (like HIGH) -> pool address (like core pool instance)
    mapping(address => address) public pools;

    /// @dev Keeps track of registered pool addresses, maps pool address -> exists flag
    mapping(address => bool) public poolExists;

    /**
     * @dev Fired in createPool() and registerPool()
     *
     * @param _by an address which executed an action
     * @param poolToken pool token address (like HIGH)
     * @param poolAddress deployed pool instance address
     * @param weight pool weight
     * @param isFlashPool flag indicating if pool is a flash pool
     */
    event PoolRegistered(
        address indexed _by,
        address indexed poolToken,
        address indexed poolAddress,
        uint256 weight,
        bool isFlashPool
    );

    /**
     * @dev Fired in changePoolWeight()
     *
     * @param _by an address which executed an action
     * @param poolAddress deployed pool instance address
     * @param weight new pool weight
     */
    event WeightUpdated(address indexed _by, address indexed poolAddress, uint256 weight);

    /**
     * @dev Fired in updateHighPerBlock()
     *
     * @param _by an address which executed an action
     * @param newHighPerBlock new HIGH/block value
     */
    event HighRatioUpdated(address indexed _by, uint256 newHighPerBlock);

    /**
     * @dev Fired in mintYieldTo()
     *
     * @param _to an address to mint tokens to
     * @param amount amount of HIGH tokens to mint
     */
    event MintYield(address indexed _to, uint256 amount);

    /**
     * @dev Creates/deploys a factory instance
     *
     * @param _high HIGH ERC20 token address
     * @param _highPerBlock initial HIGH/block value for rewards
     * @param _blocksPerUpdate how frequently the rewards gets updated (decreased by 3%), blocks
     * @param _initBlock block number to measure _blocksPerUpdate from
     * @param _endBlock block number when farming stops and rewards cannot be updated anymore
     */
    constructor(
        address _high,
        uint256 _highPerBlock,
        uint256 _blocksPerUpdate,
        uint256 _initBlock,
        uint256 _endBlock
    ) {
        // verify the inputs are set
        require(_high != address(0) , "HIGH is invalid");
        require(_highPerBlock > 0, "HIGH/block not set");
        require(_blocksPerUpdate > 0, "blocks/update not set");
        require(_initBlock > 0, "init block not set");
        require(_endBlock > _initBlock, "invalid end block: must be greater than init block");

        // save the inputs into internal state variables
        HIGH = _high;
        highPerBlock = _highPerBlock;
        blocksPerUpdate = _blocksPerUpdate;
        lastRatioUpdate = _initBlock;
        endBlock = _endBlock;
    }

    /**
     * @notice Given a pool token retrieves corresponding pool address
     *
     * @dev A shortcut for `pools` mapping
     *
     * @param poolToken pool token address (like HIGH) to query pool address for
     * @return pool address for the token specified
     */
    function getPoolAddress(address poolToken) external view returns (address) {
        // read the mapping and return
        return pools[poolToken];
    }

    /**
     * @notice Reads pool information for the pool defined by its pool token address,
     *      designed to simplify integration with the front ends
     *
     * @param _poolToken pool token address to query pool information for
     * @return pool information packed in a PoolData struct
     */
    function getPoolData(address _poolToken) external view returns (PoolData memory) {
        // get the pool address from the mapping
        address poolAddr = pools[_poolToken];

        // throw if there is no pool registered for the token specified
        require(poolAddr != address(0), "pool not found");

        // read pool information from the pool smart contract
        // via the pool interface (IPool)
        bool isFlashPool = IPool(poolAddr).isFlashPool();
        uint256 weight = IPool(poolAddr).weight();

        // create the in-memory structure and return it
        return PoolData({ poolToken: _poolToken, poolAddress: poolAddr, weight: weight, isFlashPool: isFlashPool });
    }

    /**
     * @dev Verifies if `blocksPerUpdate` has passed since last HIGH/block
     *      ratio update and if HIGH/block reward can be decreased by 3%
     *
     * @return true if enough time has passed and `updateHighPerBlock` can be executed
     */
    function shouldUpdateRatio() public view returns (bool) {
        // if yield farming period has ended
        if (blockNumber() > endBlock) {
            // HIGH/block reward cannot be updated anymore
            return false;
        }

        // check if blocks/update (91252 blocks) have passed since last update
        return blockNumber() >= lastRatioUpdate + blocksPerUpdate;
    }

    /**
     * @dev Registers an already deployed pool instance within the factory
     *
     * @dev Can be executed by the pool factory owner only
     *
     * @param poolAddr address of the already deployed pool instance
     */
    function registerPool(address poolAddr) external onlyOwner {
        // read pool information from the pool smart contract
        // via the pool interface (IPool)
        address poolToken = IPool(poolAddr).poolToken();
        bool isFlashPool = IPool(poolAddr).isFlashPool();
        uint256 weight = IPool(poolAddr).weight();

        // ensure that the pool is not already registered within the factory
        require(pools[poolToken] == address(0), "this pool is already registered");

        // create pool structure, register it within the factory
        pools[poolToken] = poolAddr;
        poolExists[poolAddr] = true;
        // update total pool weight of the factory
        totalWeight += weight;

        // emit an event
        emit PoolRegistered(msg.sender, poolToken, poolAddr, weight, isFlashPool);
    }

    /**
     * @notice Decreases HIGH/block reward by 3%, can be executed
     *      no more than once per `blocksPerUpdate` blocks
     */
    function updateHighPerBlock() external {
        // checks if ratio can be updated i.e. if blocks/update (91252 blocks) have passed
        require(shouldUpdateRatio(), "too frequent");

        // decreases HIGH/block reward by 3%
        highPerBlock = (highPerBlock * 97) / 100;

        // set current block as the last ratio update block
        lastRatioUpdate = blockNumber();

        // emit an event
        emit HighRatioUpdated(msg.sender, highPerBlock);
    }

    /**
     * @dev Mints HIGH tokens; executed by HIGH Pool only
     *
     * @dev Requires factory to have ROLE_TOKEN_CREATOR permission
     *      on the HIGH ERC20 token instance
     *
     * @param _to an address to mint tokens to
     * @param _amount amount of HIGH tokens to mint
     */
    function mintYieldTo(address _to, uint256 _amount) external {
        // verify that sender is a pool registered withing the factory
        require(poolExists[msg.sender], "access denied");

        // transfer HIGH tokens as required
        transferHighToken(_to, _amount);

        emit MintYield(_to, _amount);
    }

    /**
     * @dev Changes the weight of the pool;
     *      executed by the pool itself or by the factory owner
     *
     * @param poolAddr address of the pool to change weight for
     * @param weight new weight value to set to
     */
    function changePoolWeight(address poolAddr, uint256 weight) external {
        // verify function is executed either by factory owner or by the pool itself
        require(msg.sender == owner() || poolExists[msg.sender]);

        // recalculate total weight
        totalWeight = totalWeight + weight - IPool(poolAddr).weight();

        // set the new pool weight
        IPool(poolAddr).setWeight(weight);

        // emit an event
        emit WeightUpdated(msg.sender, poolAddr, weight);
    }

    /**
     * @dev Testing time-dependent functionality is difficult and the best way of
     *      doing it is to override block number in helper test smart contracts
     *
     * @return `block.number` in mainnet, custom values in testnets (if overridden)
     */
    function blockNumber() public view virtual returns (uint256) {
        // return current block number
        return block.number;
    }

    /**
     * @dev Executes SafeERC20.safeTransfer on a HIGH token
     *
     */
    function transferHighToken(address _to, uint256 _value) internal {
        // just delegate call to the target
        SafeERC20.safeTransfer(IERC20(HIGH), _to, _value);
    }

}

File 5 of 11 : HighStreetPoolBase.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IPool.sol";
import "./interfaces/ICorePool.sol";
import "./HighStreetPoolFactory.sol";

/**
 * @title HighStreet Pool Base
 *
 * @notice An abstract contract containing common logic for a core pool (permanent pool like HIGH/ETH or HIGH pool)
 *
 * @dev Deployment and initialization.
 *      Any pool deployed must be bound to the deployed pool factory (HighStreetPoolFactory)
 *      Additionally, 3 token instance addresses must be defined on deployment:
 *          - HIGH token address
 *          - pool token address, it can be HIGH token address, HIGH/ETH pair address, and others
 *
 * @dev Pool weight defines the fraction of the yield current pool receives among the other pools,
 *      pool factory is responsible for the weight synchronization between the pools.
 * @dev The weight is logically 20% for HIGH pool and 80% for HIGH/ETH pool.
 *      Since Solidity doesn't support fractions the weight is defined by the division of
 *      pool weight by total pools weight (sum of all registered pools within the factory)
 * @dev For HIGH Pool we use 200 as weight and for HIGH/ETH pool - 800.
 *
 */
abstract contract HighStreetPoolBase is IPool, ReentrancyGuard {
    /// @dev Data structure representing token holder using a pool
    struct User {
        // @dev Total staked amount
        uint256 tokenAmount;
        // @dev Total reward amount
        uint256 rewardAmount;
        // @dev Total weight
        uint256 totalWeight;
        // @dev Auxiliary variable for yield calculation
        uint256 subYieldRewards;
        // @dev Auxiliary variable for vault rewards calculation
        uint256 subVaultRewards;
        // @dev An array of holder's deposits
        Deposit[] deposits;
    }

    /// @dev Link to HIGH STREET ERC20 Token instance
    address public immutable override HIGH;

    /// @dev Token holder storage, maps token holder address to their data record
    mapping(address => User) public users;

    /// @dev Link to the pool factory HighStreetPoolFactory instance
    HighStreetPoolFactory public immutable factory;

    /// @dev Link to the pool token instance, for example HIGH or HIGH/ETH pair
    address public immutable override poolToken;

    /// @dev Pool weight, 200 for HIGH pool or 800 for HIGH/ETH
    uint256 public override weight;

    /// @dev Block number of the last yield distribution event
    uint256 public override lastYieldDistribution;

    /// @dev Used to calculate yield rewards
    /// @dev This value is different from "reward per token" used in locked pool
    /// @dev Note: stakes are different in duration and "weight" reflects that
    uint256 public override yieldRewardsPerWeight;

    /// @dev Used to calculate yield rewards, keeps track of the tokens weight locked in staking
    uint256 public override usersLockingWeight;

    /**
     * @dev Stake weight is proportional to deposit amount and time locked, precisely
     *      "deposit amount wei multiplied by (fraction of the year locked plus one)"
     * @dev To avoid significant precision loss due to multiplication by "fraction of the year" [0, 1],
     *      weight is stored multiplied by 1e24 constant, as an integer
     * @dev Corner case 1: if time locked is zero, weight is deposit amount multiplied by 1e24
     * @dev Corner case 2: if time locked is one year, fraction of the year locked is one, and
     *      weight is a deposit amount multiplied by 2 * 1e24
     */
    uint256 internal constant WEIGHT_MULTIPLIER = 1e24;

    /**
     * @dev When we know beforehand that staking is done for a year, and fraction of the year locked is one,
     *      we use simplified calculation and use the following constant instead previos one
     */
    uint256 internal constant YEAR_STAKE_WEIGHT_MULTIPLIER = 2 * WEIGHT_MULTIPLIER;

    /**
     * @dev Rewards per weight are stored multiplied by 1e48, as integers.
     */
    uint256 internal constant REWARD_PER_WEIGHT_MULTIPLIER = 1e48;

    /**
     * @dev We want to get deposits batched but not one by one, thus here is define the size of each batch.
     */
    uint256 internal constant DEPOSIT_BATCH_SIZE  = 20;

    /**
     * @dev Fired in _stake() and stake()
     *
     * @param _by an address which performed an operation, usually token holder
     * @param _from token holder address, the tokens will be returned to that address
     * @param amount amount of tokens staked
     */
    event Staked(address indexed _by, address indexed _from, uint256 amount);

    /**
     * @dev Fired in _updateStakeLock() and updateStakeLock()
     *
     * @param _by an address which performed an operation
     * @param depositId updated deposit ID
     * @param lockedFrom deposit locked from value
     * @param lockedUntil updated deposit locked until value
     */
    event StakeLockUpdated(address indexed _by, uint256 depositId, uint64 lockedFrom, uint64 lockedUntil);

    /**
     * @dev Fired in _unstake() and unstake()
     *
     * @param _by an address which performed an operation, usually token holder
     * @param _to an address which received the unstaked tokens, usually token holder
     * @param amount amount of tokens unstaked
     */
    event Unstaked(address indexed _by, address indexed _to, uint256 amount);

    /**
     * @dev Fired in _sync(), sync() and dependent functions (stake, unstake, etc.)
     *
     * @param _by an address which performed an operation
     * @param yieldRewardsPerWeight updated yield rewards per weight value
     * @param lastYieldDistribution usually, current block number
     */
    event Synchronized(address indexed _by, uint256 yieldRewardsPerWeight, uint256 lastYieldDistribution);

    /**
     * @dev Fired in _processRewards(), processRewards() and dependent functions (stake, unstake, etc.)
     *
     * @param _by an address which performed an operation
     * @param _to an address which claimed the yield reward
     * @param amount amount of yield paid
     */
    event YieldClaimed(address indexed _by, address indexed _to, uint256 amount);

    /**
     * @dev Fired in setWeight()
     *
     * @param _fromVal old pool weight value
     * @param _toVal new pool weight value
     */
    event PoolWeightUpdated(uint256 _fromVal, uint256 _toVal);

    /**
     * @dev Fired in _emergencyWithdraw()
     *
     * @param _by an address which performed an operation, usually token holder
     * @param amount amount of tokens withdraw
     */
    event EmergencyWithdraw(address indexed _by, uint256 amount);

    /**
     * @dev Overridden in sub-contracts to construct the pool
     *
     * @param _high HIGH ERC20 Token IlluviumERC20 address
     * @param _factory Pool factory HighStreetPoolFactory instance/address
     * @param _poolToken token the pool operates on, for example HIGH or HIGH/ETH pair
     * @param _initBlock initial block used to calculate the rewards
     *      note: _initBlock can be set to the future effectively meaning _sync() calls will do nothing
     * @param _weight number representing a weight of the pool, actual weight fraction
     *      is calculated as that number divided by the total pools weight and doesn't exceed one
     */
    constructor(
        address _high,
        HighStreetPoolFactory _factory,
        address _poolToken,
        uint256 _initBlock,
        uint256 _weight
    ) {
        // verify the inputs are set
        require(_high != address(0), "high token address not set");
        require(address(_factory) != address(0), "HIGH Pool fct address not set");
        require(_poolToken != address(0), "pool token address not set");
        require(_initBlock >= blockNumber(), "Invalid init block");
        require(_weight > 0, "pool weight not set");

        // verify HighStreetPoolFactory instance supplied
        require(
            _factory.FACTORY_UID() == 0x484a992416a6637667452c709058dccce100b22b278536f5a6d25a14b6a1acdb,
            "unexpected FACTORY_UID"
        );

        // save the inputs into internal state variables
        HIGH = _high;
        factory = _factory;
        poolToken = _poolToken;
        weight = _weight;

        // init the dependent internal state variables
        lastYieldDistribution = _initBlock;
    }

    /**
     * @notice Calculates current yield rewards value available for address specified
     *
     * @param _staker an address to calculate yield rewards value for
     * @return calculated yield reward value for the given address
     */
    function pendingYieldRewards(address _staker) external view override returns (uint256) {
        // `newYieldRewardsPerWeight` will store stored or recalculated value for `yieldRewardsPerWeight`
        uint256 newYieldRewardsPerWeight;

        // if smart contract state was not updated recently, `yieldRewardsPerWeight` value
        // is outdated and we need to recalculate it in order to calculate pending rewards correctly
        if (blockNumber() > lastYieldDistribution && usersLockingWeight != 0) {
            uint256 endBlock = factory.endBlock();
            uint256 multiplier =
                blockNumber() > endBlock ? endBlock - lastYieldDistribution : blockNumber() - lastYieldDistribution;
            uint256 highRewards = (multiplier * weight * factory.highPerBlock()) / factory.totalWeight();

            // recalculated value for `yieldRewardsPerWeight`
            newYieldRewardsPerWeight = rewardToWeight(highRewards, usersLockingWeight) + yieldRewardsPerWeight;
        } else {
            // if smart contract state is up to date, we don't recalculate
            newYieldRewardsPerWeight = yieldRewardsPerWeight;
        }

        // based on the rewards per weight value, calculate pending rewards;
        User memory user = users[_staker];
        uint256 pending = weightToReward(user.totalWeight, newYieldRewardsPerWeight) - user.subYieldRewards;

        return pending;
    }

    /**
     * @notice Returns total staked token balance for the given address
     *
     * @param _user an address to query balance for
     * @return total staked token balance
     */
    function balanceOf(address _user) external view override returns (uint256) {
        // read specified user token amount and return
        return users[_user].tokenAmount;
    }

    /**
     * @notice Returns information on the given deposit for the given address
     *
     * @dev See getDepositsLength
     *
     * @param _user an address to query deposit for
     * @param _depositId zero-indexed deposit ID for the address specified
     * @return deposit info as Deposit structure
     */
    function getDeposit(address _user, uint256 _depositId) external view override returns (Deposit memory) {
        // read deposit at specified index and return
        return users[_user].deposits[_depositId];
    }

    /**
     * @notice Returns a batch of deposits on the given pageId for the given address
     *
     * @dev we separate deposits into serveral of pages, and each page have DEPOSIT_BATCH_SIZE of item.
     *
     * @param _user an address to query deposit for
     * @param _pageId zero-indexed page ID for the address specified
     * @return deposits info as Deposit structure
     */
    function getDepositsBatch(address _user, uint256 _pageId) external view returns (Deposit[] memory) {
        uint256 pageStart = _pageId * DEPOSIT_BATCH_SIZE;
        uint256 pageEnd = (_pageId + 1) * DEPOSIT_BATCH_SIZE;
        uint256 pageLength = DEPOSIT_BATCH_SIZE;

        if(pageEnd > (users[_user].deposits.length - pageStart)) {
            pageEnd = users[_user].deposits.length;
            pageLength = pageEnd - pageStart;
        }

        Deposit[] memory deposits = new Deposit[](pageLength);
        for(uint256 i = pageStart; i < pageEnd; i++) {
            deposits[i-pageStart] = users[_user].deposits[i];
        }
        return deposits;
    }

    /**
     * @notice Returns number of pages for the given address. Allows iteration over deposits.
     *
     * @dev See getDepositsBatch
     *
     * @param _user an address to query deposit length for
     * @return number of pages for the given address
     */
    function getDepositsBatchLength(address _user) external view returns (uint256) {
        if(users[_user].deposits.length == 0) {
            return 0;
        }
        return 1 + (users[_user].deposits.length - 1) / DEPOSIT_BATCH_SIZE;
    }

    /**
     * @notice Returns number of deposits for the given address. Allows iteration over deposits.
     *
     * @dev See getDeposit
     *
     * @param _user an address to query deposit length for
     * @return number of deposits for the given address
     */
    function getDepositsLength(address _user) external view override returns (uint256) {
        // read deposits array length and return
        return users[_user].deposits.length;
    }

    /**
     * @notice Stakes specified amount of tokens for the specified amount of time,
     *      and pays pending yield rewards if any
     *
     * @dev Requires amount to stake to be greater than zero
     *
     * @dev Reentrancy safety enforced via `ReentrancyGuard.nonReentrant`
     *
     * @param _amount amount of tokens to stake
     * @param _lockUntil stake period as unix timestamp; zero means no locking
     */
    function stake (
        uint256 _amount,
        uint64 _lockUntil
    ) external override nonReentrant {
        // delegate call to an internal function
        _stake(msg.sender, _amount, _lockUntil);
    }

    /**
     * @notice Unstakes specified amount of tokens, and pays pending yield rewards if any
     *
     * @dev Requires amount to unstake to be greater than zero
     *
     * @dev Reentrancy safety enforced via `ReentrancyGuard.nonReentrant`
     *
     * @param _depositId deposit ID to unstake from, zero-indexed
     * @param _amount amount of tokens to unstake
     */
    function unstake(
        uint256 _depositId,
        uint256 _amount
    ) external override nonReentrant {
        // delegate call to an internal function
        _unstake(msg.sender, _depositId, _amount);
    }

    /**
     * @notice Extends locking period for a given deposit
     *
     * @dev Requires new lockedUntil value to be:
     *      higher than the current one, and
     *      in the future, but
     *      no more than 1 year in the future
     *
     * @dev Reentrancy safety enforced via `ReentrancyGuard.nonReentrant`
     *
     * @param depositId updated deposit ID
     * @param lockedUntil updated deposit locked until value
     */
    function updateStakeLock(
        uint256 depositId,
        uint64 lockedUntil
    ) external nonReentrant {
        require(users[msg.sender].deposits[depositId].tokenAmount > 0, "Invalid amount");

        // sync and call processRewards
        _sync();
        _processRewards(msg.sender, false);
        // delegate call to an internal function
        _updateStakeLock(msg.sender, depositId, lockedUntil);
    }

    /**
     * @notice Service function to synchronize pool state with current time
     *
     * @dev Can be executed by anyone at any time, but has an effect only when
     *      at least one block passes between synchronizations
     * @dev Executed internally when staking, unstaking, processing rewards in order
     *      for calculations to be correct and to reflect state progress of the contract
     * @dev When timing conditions are not met (executed too frequently, or after factory
     *      end block), function doesn't throw and exits silently
     */
    function sync() external override {
        // delegate call to an internal function
        _sync();
    }

    /**
     * @notice Service function to calculate and pay pending yield rewards to the sender
     *
     * @dev Can be executed by anyone at any time, but has an effect only when
     *      executed by deposit holder and when at least one block passes from the
     *      previous reward processing
     * @dev Executed internally when staking and unstaking, executes sync() under the hood
     *      before making further calculations and payouts
     * @dev When timing conditions are not met (executed too frequently, or after factory
     *      end block), function doesn't throw and exits silently
     *
     * @dev Reentrancy safety enforced via `ReentrancyGuard.nonReentrant`
     *
     */
    function processRewards() external virtual override nonReentrant {
        // delegate call to an internal function
        _processRewards(msg.sender, true);
    }

    /**
     * @dev Executed by the factory to modify pool weight; the factory is expected
     *      to keep track of the total pools weight when updating
     *
     * @dev Set weight to zero to disable the pool
     *
     * @param _weight new weight to set for the pool
     */
    function setWeight(uint256 _weight) external override {
        // verify function is executed by the factory
        require(msg.sender == address(factory), "access denied");

        // emit an event logging old and new weight values
        emit PoolWeightUpdated(weight, _weight);

        // set the new weight value
        weight = _weight;
    }

    /**
     * @dev Similar to public pendingYieldRewards, but performs calculations based on
     *      current smart contract state only, not taking into account any additional
     *      time/blocks which might have passed
     *
     * @param _staker an address to calculate yield rewards value for
     * @return pending calculated yield reward value for the given address
     */
    function _pendingYieldRewards(address _staker) internal view returns (uint256 pending) {
        // read user data structure into memory
        User memory user = users[_staker];

        // and perform the calculation using the values read
        return weightToReward(user.totalWeight, yieldRewardsPerWeight) - user.subYieldRewards;
    }

    /**
     * @dev Used internally, mostly by children implementations, see stake()
     *
     * @param _staker an address which stakes tokens and which will receive them back
     * @param _amount amount of tokens to stake
     * @param _lockUntil stake period as unix timestamp; zero means no locking
     */
    function _stake(
        address _staker,
        uint256 _amount,
        uint64 _lockUntil
    ) internal virtual {
        // validate the inputs
        require(_amount > 0, "zero amount");
        require(
            _lockUntil == 0 || (_lockUntil > now256() && _lockUntil - now256() <= 365 days),
            "invalid lock interval"
        );

        // update smart contract state
        _sync();

        // get a link to user data struct, we will write to it later
        User storage user = users[_staker];
        // process current pending rewards if any
        if (user.tokenAmount > 0) {
            _processRewards(_staker, false);
        }

        // in most of the cases added amount `addedAmount` is simply `_amount`
        // however for deflationary tokens this can be different

        // read the current balance
        uint256 previousBalance = IERC20(poolToken).balanceOf(address(this));
        // transfer `_amount`; note: some tokens may get burnt here
        transferPoolTokenFrom(msg.sender, address(this), _amount);
        // read new balance, usually this is just the difference `previousBalance - _amount`
        uint256 newBalance = IERC20(poolToken).balanceOf(address(this));
        // calculate real amount taking into account deflation
        uint256 addedAmount = newBalance - previousBalance;

        // set the `lockFrom` and `lockUntil` taking into account that
        // zero value for `_lockUntil` means "no locking" and leads to zero values
        // for both `lockFrom` and `lockUntil`
        uint64 lockFrom = _lockUntil > 0 ? uint64(now256()) : 0;
        uint64 lockUntil = _lockUntil;

        // stake weight formula rewards for locking
        uint256 stakeWeight =
            (((lockUntil - lockFrom) * WEIGHT_MULTIPLIER) / 365 days + WEIGHT_MULTIPLIER) * addedAmount;

        // makes sure stakeWeight is valid
        require(stakeWeight > 0, "invalid stakeWeight");

        // create and save the deposit (append it to deposits array)
        Deposit memory deposit =
            Deposit({
                tokenAmount: addedAmount,
                weight: stakeWeight,
                lockedFrom: lockFrom,
                lockedUntil: lockUntil,
                isYield: false
            });
        // deposit ID is an index of the deposit in `deposits` array
        user.deposits.push(deposit);

        // update user record
        user.tokenAmount += addedAmount;
        user.totalWeight += stakeWeight;
        user.subYieldRewards = weightToReward(user.totalWeight, yieldRewardsPerWeight);

        // update global variable
        usersLockingWeight += stakeWeight;

        // emit an event
        emit Staked(msg.sender, _staker, addedAmount);
    }

    /**
     * @dev Used internally, mostly by children implementations, see unstake()
     *
     * @param _staker an address which unstakes tokens (which previously staked them)
     * @param _depositId deposit ID to unstake from, zero-indexed
     * @param _amount amount of tokens to unstake
     */
    function _unstake(
        address _staker,
        uint256 _depositId,
        uint256 _amount
    ) internal virtual {
        // verify an amount is set
        require(_amount > 0, "zero amount");

        // get a link to user data struct, we will write to it later
        User storage user = users[_staker];
        // get a link to the corresponding deposit, we may write to it later
        Deposit storage stakeDeposit = user.deposits[_depositId];
        // deposit structure may get deleted, so we save isYield flag to be able to use it
        bool isYield = stakeDeposit.isYield;

        // verify available balance
        // if staker address ot deposit doesn't exist this check will fail as well
        require(stakeDeposit.tokenAmount >= _amount, "amount exceeds stake");

        // update smart contract state
        _sync();
        // and process current pending rewards if any
        _processRewards(_staker, false);

        // recalculate deposit weight
        uint256 previousWeight = stakeDeposit.weight;
        uint256 newWeight =
            (((stakeDeposit.lockedUntil - stakeDeposit.lockedFrom) * WEIGHT_MULTIPLIER) /
                365 days +
                WEIGHT_MULTIPLIER) * (stakeDeposit.tokenAmount - _amount);

        // update the deposit, or delete it if its depleted
        if (stakeDeposit.tokenAmount - _amount == 0) {
            delete user.deposits[_depositId];
        } else {
            stakeDeposit.tokenAmount -= _amount;
            stakeDeposit.weight = newWeight;
        }

        // update user record
        user.tokenAmount -= _amount;
        user.totalWeight = user.totalWeight - previousWeight + newWeight;
        user.subYieldRewards = weightToReward(user.totalWeight, yieldRewardsPerWeight);

        // update global variable
        usersLockingWeight = usersLockingWeight - previousWeight + newWeight;

        // if the deposit was created by the pool itself as a yield reward
        if (isYield) {
            user.rewardAmount -= _amount;
            // mint the yield via the factory
            factory.mintYieldTo(msg.sender, _amount);
        } else {
            // otherwise just return tokens back to holder
            transferPoolToken(msg.sender, _amount);
        }

        // emit an event
        emit Unstaked(msg.sender, _staker, _amount);
    }

    /**
     * @notice Emergency withdraw specified amount of tokens
     *
     *
     * @dev Reentrancy safety enforced via `ReentrancyGuard.nonReentrant`
     *
     */
    function emergencyWithdraw() external nonReentrant {
        require(factory.totalWeight() == 0, "totalWeight != 0");

        // delegate call to an internal function
        _emergencyWithdraw(msg.sender);
    }

    /**
     * @dev Used internally, mostly by children implementations, see emergencyWithdraw()
     *
     * @param _staker an address which unstakes tokens (which previously staked them)
     */
    function _emergencyWithdraw(
        address _staker
    ) internal virtual {
        // get a link to user data struct, we will write to it later
        User storage user = users[_staker];

        uint256 totalWeight = user.totalWeight ;
        uint256 amount = user.tokenAmount;
        uint256 reward = user.rewardAmount;

        // update user record
        user.tokenAmount = 0;
        user.rewardAmount = 0;
        user.totalWeight = 0;
        user.subYieldRewards = 0;

        // delete entire array directly
        delete user.deposits;

        // update global variable
        usersLockingWeight = usersLockingWeight - totalWeight;

        // just return tokens back to holder
        transferPoolToken(msg.sender, amount - reward);
        // mint the yield via the factory
        factory.mintYieldTo(msg.sender, reward);

        emit EmergencyWithdraw(msg.sender, amount);
    }

    /**
     * @dev Used internally, mostly by children implementations, see sync()
     *
     * @dev Updates smart contract state (`yieldRewardsPerWeight`, `lastYieldDistribution`),
     *      updates factory state via `updatehighPerBlock`
     */
    function _sync() internal virtual {
        // update HIGH per block value in factory if required
        if (factory.shouldUpdateRatio()) {
            factory.updateHighPerBlock();
        }

        // check bound conditions and if these are not met -
        // exit silently, without emitting an event
        uint256 endBlock = factory.endBlock();
        if (lastYieldDistribution >= endBlock) {
            return;
        }
        if (blockNumber() <= lastYieldDistribution) {
            return;
        }
        // if locking weight is zero - update only `lastYieldDistribution` and exit
        if (usersLockingWeight == 0) {
            lastYieldDistribution = blockNumber();
            return;
        }

        // to calculate the reward we need to know how many blocks passed, and reward per block
        uint256 currentBlock = blockNumber() > endBlock ? endBlock : blockNumber();
        uint256 blocksPassed = currentBlock - lastYieldDistribution;
        uint256 highPerBlock = factory.highPerBlock();

        // calculate the reward
        uint256 highReward = (blocksPassed * highPerBlock * weight) / factory.totalWeight();

        // update rewards per weight and `lastYieldDistribution`
        yieldRewardsPerWeight += rewardToWeight(highReward, usersLockingWeight);
        lastYieldDistribution = currentBlock;

        // emit an event
        emit Synchronized(msg.sender, yieldRewardsPerWeight, lastYieldDistribution);
    }

    /**
     * @dev Used internally, mostly by children implementations, see processRewards()
     *
     * @param _staker an address which receives the reward (which has staked some tokens earlier)
     * @param _withUpdate flag allowing to disable synchronization (see sync()) if set to false
     * @return pendingYield the rewards calculated and optionally re-staked
     */
    function _processRewards(
        address _staker,
        bool _withUpdate
    ) internal virtual returns (uint256 pendingYield) {
        // update smart contract state if required
        if (_withUpdate) {
            _sync();
        }

        // calculate pending yield rewards, this value will be returned
        pendingYield = _pendingYieldRewards(_staker);

        // if pending yield is zero - just return silently
        if (pendingYield == 0) return 0;

        // get link to a user data structure, we will write into it later
        User storage user = users[_staker];

        if (poolToken == HIGH) {
            // calculate pending yield weight,
            // 2e6 is the bonus weight when staking for 1 year
            uint256 depositWeight = pendingYield * YEAR_STAKE_WEIGHT_MULTIPLIER;

            // if the pool is HIGH Pool - create new HIGH deposit
            // and save it - push it into deposits array
            Deposit memory newDeposit =
                Deposit({
                    tokenAmount: pendingYield,
                    lockedFrom: uint64(now256()),
                    lockedUntil: uint64(now256() + 365 days), // staking yield for 1 year
                    weight: depositWeight,
                    isYield: true
                });
            user.deposits.push(newDeposit);

            // update user record
            user.tokenAmount += pendingYield;
            user.rewardAmount += pendingYield;
            user.totalWeight += depositWeight;

            // update global variable
            usersLockingWeight += depositWeight;
        } else {
            // for other pools - stake as pool
            address highPool = factory.getPoolAddress(HIGH);
            require(highPool != address(0),"invalid high pool address");
            ICorePool(highPool).stakeAsPool(_staker, pendingYield);
        }

        // update users's record for `subYieldRewards` if requested
        if (_withUpdate) {
            user.subYieldRewards = weightToReward(user.totalWeight, yieldRewardsPerWeight);
        }

        // emit an event
        emit YieldClaimed(msg.sender, _staker, pendingYield);
    }

    /**
     * @dev See updateStakeLock()
     *
     * @param _staker an address to update stake lock
     * @param _depositId updated deposit ID
     * @param _lockedUntil updated deposit locked until value
     */
    function _updateStakeLock(
        address _staker,
        uint256 _depositId,
        uint64 _lockedUntil
    ) internal {
        // validate the input time
        require(_lockedUntil > now256(), "lock should be in the future");

        // get a link to user data struct, we will write to it later
        User storage user = users[_staker];
        // get a link to the corresponding deposit, we may write to it later
        Deposit storage stakeDeposit = user.deposits[_depositId];

        // validate the input against deposit structure
        require(_lockedUntil > stakeDeposit.lockedUntil, "invalid new lock");

        // verify locked from and locked until values
        if (stakeDeposit.lockedFrom == 0) {
            require(_lockedUntil - now256() <= 365 days, "max lock period is 365 days");
            stakeDeposit.lockedFrom = uint64(now256());
        } else {
            require(_lockedUntil - stakeDeposit.lockedFrom <= 365 days, "max lock period is 365 days");
        }

        // update locked until value, calculate new weight
        stakeDeposit.lockedUntil = _lockedUntil;
        uint256 newWeight =
            (((stakeDeposit.lockedUntil - stakeDeposit.lockedFrom) * WEIGHT_MULTIPLIER) /
                365 days +
                WEIGHT_MULTIPLIER) * stakeDeposit.tokenAmount;

        // save previous weight
        uint256 previousWeight = stakeDeposit.weight;
        // update weight
        stakeDeposit.weight = newWeight;

        // update user total weight and global locking weight
        user.totalWeight = user.totalWeight - previousWeight + newWeight;
        usersLockingWeight = usersLockingWeight - previousWeight + newWeight;

        // emit an event
        emit StakeLockUpdated(_staker, _depositId, stakeDeposit.lockedFrom, _lockedUntil);
    }

    /**
     * @dev Converts stake weight (not to be mixed with the pool weight) to
     *      HIGH reward value, applying the 10^48 division on weight
     *
     * @param _weight stake weight
     * @param rewardPerWeight HIGH reward per weight
     * @return reward value normalized to 10^48
     */
    function weightToReward(uint256 _weight, uint256 rewardPerWeight) public pure returns (uint256) {
        // apply the formula and return
        return (_weight * rewardPerWeight) / REWARD_PER_WEIGHT_MULTIPLIER;
    }

    /**
     * @dev Converts reward HIGH value to stake weight (not to be mixed with the pool weight),
     *      applying the 10^12 multiplication on the reward
     *      - OR -
     * @dev Converts reward HIGH value to reward/weight if stake weight is supplied as second
     *      function parameter instead of reward/weight
     *
     * @param reward yield reward
     * @param rewardPerWeight reward/weight (or stake weight)
     * @return stake weight (or reward/weight)
     */
    function rewardToWeight(uint256 reward, uint256 rewardPerWeight) public pure returns (uint256) {
        // apply the reverse formula and return
        return (reward * REWARD_PER_WEIGHT_MULTIPLIER) / rewardPerWeight;
    }

    /**
     * @dev Testing time-dependent functionality is difficult and the best way of
     *      doing it is to override block number in helper test smart contracts
     *
     * @return `block.number` in mainnet, custom values in testnets (if overridden)
     */
    function blockNumber() public view virtual returns (uint256) {
        // return current block number
        return block.number;
    }

    /**
     * @dev Testing time-dependent functionality is difficult and the best way of
     *      doing it is to override time in helper test smart contracts
     *
     * @return `block.timestamp` in mainnet, custom values in testnets (if overridden)
     */
    function now256() public view virtual returns (uint256) {
        // return current block timestamp
        return block.timestamp;
    }

    /**
     * @dev Executes SafeERC20.safeTransfer on a pool token
     *
     */
    function transferPoolToken(address _to, uint256 _value) internal {
        SafeERC20.safeTransfer(IERC20(poolToken), _to, _value);
    }

    /**
     * @dev Executes SafeERC20.safeTransferFrom on a pool token
     *
     */
    function transferPoolTokenFrom(
        address _from,
        address _to,
        uint256 _value
    ) internal {
        SafeERC20.safeTransferFrom(IERC20(poolToken), _from, _to, _value);
    }
}

File 6 of 11 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

File 7 of 11 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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://diligence.consensys.net/posts/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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 8 of 11 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 9 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 10 of 11 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 11 of 11 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * 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 Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        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 {
        _setOwner(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");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_high","type":"address"},{"internalType":"contract HighStreetPoolFactory","name":"_factory","type":"address"},{"internalType":"address","name":"_poolToken","type":"address"},{"internalType":"uint256","name":"_initBlock","type":"uint256"},{"internalType":"uint256","name":"_weight","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromVal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toVal","type":"uint256"}],"name":"PoolWeightUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"lockedFrom","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"lockedUntil","type":"uint64"}],"name":"StakeLockUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":false,"internalType":"uint256","name":"yieldRewardsPerWeight","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastYieldDistribution","type":"uint256"}],"name":"Synchronized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VaultRewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VaultRewardsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":false,"internalType":"address","name":"_fromVal","type":"address"},{"indexed":false,"internalType":"address","name":"_toVal","type":"address"}],"name":"VaultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"YieldClaimed","type":"event"},{"inputs":[],"name":"HIGH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract HighStreetPoolFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_depositId","type":"uint256"}],"name":"getDeposit","outputs":[{"components":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint64","name":"lockedFrom","type":"uint64"},{"internalType":"uint64","name":"lockedUntil","type":"uint64"},{"internalType":"bool","name":"isYield","type":"bool"}],"internalType":"struct IPool.Deposit","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_pageId","type":"uint256"}],"name":"getDepositsBatch","outputs":[{"components":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint64","name":"lockedFrom","type":"uint64"},{"internalType":"uint64","name":"lockedUntil","type":"uint64"},{"internalType":"bool","name":"isYield","type":"bool"}],"internalType":"struct IPool.Deposit[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getDepositsBatchLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getDepositsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFlashPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastYieldDistribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"now256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"pendingVaultRewards","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"pendingYieldRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolTokenReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"processRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardsAmount","type":"uint256"}],"name":"receiveVaultRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"rewardPerWeight","type":"uint256"}],"name":"rewardToWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weight","type":"uint256"}],"name":"setWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"_lockUntil","type":"uint64"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stakeAsPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"depositId","type":"uint256"},{"internalType":"uint64","name":"lockedUntil","type":"uint64"}],"name":"updateStakeLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"users","outputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"uint256","name":"subYieldRewards","type":"uint256"},{"internalType":"uint256","name":"subVaultRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usersLockingWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultRewardsPerWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_weight","type":"uint256"},{"internalType":"uint256","name":"rewardPerWeight","type":"uint256"}],"name":"weightToReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"yieldRewardsPerWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60e06040523480156200001157600080fd5b50604051620040ca380380620040ca8339810160408190526200003491620002fc565b600160005584848484846001600160a01b0385166200009a5760405162461bcd60e51b815260206004820152601a60248201527f6869676820746f6b656e2061646472657373206e6f742073657400000000000060448201526064015b60405180910390fd5b6001600160a01b038416620000f25760405162461bcd60e51b815260206004820152601d60248201527f4849474820506f6f6c206663742061646472657373206e6f7420736574000000604482015260640162000091565b6001600160a01b0383166200014a5760405162461bcd60e51b815260206004820152601a60248201527f706f6f6c20746f6b656e2061646472657373206e6f7420736574000000000000604482015260640162000091565b43821015620001915760405162461bcd60e51b8152602060048201526012602482015271496e76616c696420696e697420626c6f636b60701b604482015260640162000091565b60008111620001e35760405162461bcd60e51b815260206004820152601360248201527f706f6f6c20776569676874206e6f742073657400000000000000000000000000604482015260640162000091565b836001600160a01b031663f70b7fce6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000222573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000248919062000361565b7f484a992416a6637667452c709058dccce100b22b278536f5a6d25a14b6a1acdb14620002b85760405162461bcd60e51b815260206004820152601660248201527f756e657870656374656420464143544f52595f55494400000000000000000000604482015260640162000091565b6001600160a01b0394851660805292841660a052921660c052600255600355506200037b9350505050565b6001600160a01b0381168114620002f957600080fd5b50565b600080600080600060a086880312156200031557600080fd5b85516200032281620002e3565b60208701519095506200033581620002e3565b60408701519094506200034881620002e3565b6060870151608090970151959894975095949392505050565b6000602082840312156200037457600080fd5b5051919050565b60805160a05160c051613c38620004926000396000818161046301528181610d6101528181610ef801528181611c300152818161238e0152818161248f01528181612a9601528181612b470152818161353c015261356801526000818161043c01528181610854015281816109040152818161098601528181610e0d015281816111a00152818161152d015281816116a701528181611889015281816119100152818161198601528181611a5701528181611add015281816126d90152818161310d015261326f0152600081816103f401528181610d3701528181610ece01528181611c060152818161201d0152818161229d01528181612364015281816124b2015281816126ae015261330a0152613c386000f3fe608060405234801561001057600080fd5b506004361061020b5760003560e01c80639e2c8a5b1161012a578063ce111541116100bd578063fa213bd61161008c578063fc1711f211610071578063fc1711f2146104e6578063fc27076f146104f9578063fff6cae91461050c57600080fd5b8063fa213bd6146104ca578063fbfa77cf146104d357600080fd5b8063ce11154114610485578063db2e21bc1461048e578063e8d3cad514610496578063f9fc0d07146104c257600080fd5b8063b73974a1116100f9578063b73974a1146103ef578063beb0ed6c1461042e578063c45a015514610437578063cbdf382c1461045e57600080fd5b80639e2c8a5b1461035c578063a156dc281461036f578063a1aab33f14610382578063a87430ba1461038b57600080fd5b806344cc892d116101a257806370a082311161017157806370a08231146102fa5780638ce44855146103235780638e169d4714610336578063952e68cf1461034957600080fd5b806344cc892d146102c85780634ce0f9a6146102db57806357e871e7146102e15780636817031b146102e757600080fd5b80631da10d91116101de5780631da10d91146102745780632726b5061461028c57806329eb5f2c146102ac5780633021a560146102b557600080fd5b8063054723581461021057806315188a1b1461022c578063159302fe146102415780631984db9914610261575b600080fd5b61021960075481565b6040519081526020015b60405180910390f35b61023f61023a3660046137cf565b610514565b005b61025461024f366004613821565b61061b565b604051610223919061384d565b61021961026f3660046138d8565b610830565b61027c600081565b6040519015158152602001610223565b61029f61029a366004613821565b610b7d565b60405161022391906138f5565b61021960035481565b61023f6102c3366004613940565b610c52565b61023f6102d6366004613821565b610ddf565b42610219565b43610219565b61023f6102f53660046138d8565b611194565b6102196103083660046138d8565b6001600160a01b031660009081526001602052604090205490565b6102196103313660046138d8565b61134f565b610219610344366004613959565b6113b7565b61023f6103573660046137cf565b6113e9565b61023f61036a366004613959565b61144c565b61021961037d366004613959565b6114af565b61021960025481565b6103c76103993660046138d8565b6001602081905260009182526040909120805491810154600282015460038301546004909301549192909185565b604080519586526020860194909452928401919091526060830152608082015260a001610223565b6104167f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610223565b61021960055481565b6104167f000000000000000000000000000000000000000000000000000000000000000081565b6104167f000000000000000000000000000000000000000000000000000000000000000081565b61021960085481565b61023f6114d0565b6102196104a43660046138d8565b6001600160a01b031660009081526001602052604090206005015490565b61023f61160a565b61021960045481565b600654610416906001600160a01b031681565b61023f6104f4366004613940565b61169c565b6102196105073660046138d8565b611755565b61023f61187d565b6002600054141561056c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260009081553381526001602052604081206005018054849081106105945761059461397b565b906000526020600020906003020160000154116105f35760405162461bcd60e51b815260206004820152600e60248201527f496e76616c696420616d6f756e740000000000000000000000000000000000006044820152606401610563565b6105fb611887565b610606336000611bed565b50610612338383611c7b565b50506001600055565b6060600061062a6014846139d9565b90506000601461063b856001613a16565b61064591906139d9565b6001600160a01b038616600090815260016020526040902060050154909150601490610672908490613a2e565b8211156106a4576001600160a01b03861660009081526001602052604090206005015491506106a18383613a2e565b90505b60008167ffffffffffffffff8111156106bf576106bf613a45565b60405190808252806020026020018201604052801561073657816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816106dd5790505b509050835b83811015610823576001600160a01b03881660009081526001602052604090206005018054829081106107705761077061397b565b60009182526020918290206040805160a0810182526003939093029091018054835260018101549383019390935260029092015467ffffffffffffffff80821693830193909352680100000000000000008104909216606082015270010000000000000000000000000000000090910460ff1615156080820152826107f58784613a2e565b815181106108055761080561397b565b6020026020010181905250808061081b90613a74565b91505061073b565b5093505050505b92915050565b60008060035461083d4390565b11801561084b575060055415155b15610a4c5760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663083c63236040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d49190613aad565b905060008143116108f1576003546108ec9043613a2e565b6108fe565b6003546108fe9083613a2e565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166396c82e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015610960573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109849190613aad565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630dd792a36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a069190613aad565b600254610a1390856139d9565b610a1d91906139d9565b610a279190613ac6565b9050600454610a38826005546114af565b610a429190613a16565b9350505050610a51565b506004545b6001600160a01b0383166000908152600160208181526040808420815160c0810183528154815293810154848401526002810154848301526003810154606085015260048101546080850152600581018054835181860281018601909452808452919360a08601939290879084015b82821015610b4b5760008481526020908190206040805160a08101825260038602909201805483526001808201548486015260029091015467ffffffffffffffff80821693850193909352680100000000000000008104909216606084015270010000000000000000000000000000000090910460ff16151560808301529083529092019101610ac0565b5050505081525050905060008160600151610b6a8360400151856113b7565b610b749190613a2e565b95945050505050565b6040805160a0810182526000808252602080830182905282840182905260608301829052608083018290526001600160a01b03861682526001905291909120600501805483908110610bd157610bd161397b565b60009182526020918290206040805160a0810182526003939093029091018054835260018101549383019390935260029092015467ffffffffffffffff80821693830193909352680100000000000000008104909216606082015270010000000000000000000000000000000090910460ff16151560808201529392505050565b6006546001600160a01b03163314610cac5760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b80610cb45750565b600060055411610d065760405162461bcd60e51b815260206004820152601360248201527f7a65726f206c6f636b696e6720776569676874000000000000000000000000006044820152606401610563565b610d11333083612018565b610d1d816005546114af565b60076000828254610d2e9190613a16565b925050819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161415610da7578060086000828254610da19190613a16565b90915550505b60405181815233907fe1745dfad8f400852fcec0e4b23dabb3b55a98c67df52ee99c5385887277d72f9060200160405180910390a250565b6040517f1e1c6a070000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690631e1c6a0790602401602060405180830381865afa158015610e5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e809190613b01565b610ecc5760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614610f6d5760405162461bcd60e51b815260206004820152601360248201527f6e6f74204849474820746f6b656e20706f6f6c000000000000000000000000006044820152606401610563565b610f75611887565b6001600160a01b0382166000908152600160205260409020805415610fa157610f9f836000611bed565b505b6000610fb869d3c21bcecceda100000060026139d9565b610fc290846139d9565b905060006040518060a00160405280858152602001838152602001610fe44290565b67ffffffffffffffff168152602001611001426301e13380613a16565b67ffffffffffffffff1681526020016001151581525090508383600001600082825461102d9190613a16565b92505081905550838360010160008282546110489190613a16565b92505081905550818360020160008282546110639190613a16565b9091555050600580840180546001818101835560009283526020808420865160039094020192835585015190820155604084015160029091018054606086015160808701511515700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff67ffffffffffffffff92831668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941692909516919091179190911792909216919091179055815484929190611140908490613a16565b9250508190555061115783600201546004546113b7565b6003840155600283015460075461116e91906113b7565b836004018190555083600860008282546111889190613a16565b90915550505050505050565b336001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112209190613b23565b6001600160a01b0316146112765760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b6001600160a01b0381166112cc5760405162461bcd60e51b815260206004820152600a60248201527f7a65726f20696e707574000000000000000000000000000000000000000000006044820152606401610563565b600654604080516001600160a01b039283168152918316602083015233917f2afec66505e0ceed692012e3833f6609d4933ded34732135bc05f28423744065910160405180910390a2600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6001600160a01b03811660009081526001602052604081206005015461137757506000919050565b6001600160a01b0382166000908152600160208190526040909120600501546014916113a291613a2e565b6113ac9190613ac6565b61082a906001613a16565b600073af298d050e4395d69670b12b7f410000000000006113d883856139d9565b6113e29190613ac6565b9392505050565b6002600054141561143c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b6002600055610612338383612049565b6002600054141561149f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b60026000556106123383836120a3565b6000816113d873af298d050e4395d69670b12b7f41000000000000856139d9565b600260005414156115235760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b60026000819055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166396c82e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015611589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ad9190613aad565b156115fa5760405162461bcd60e51b815260206004820152601060248201527f746f74616c57656967687420213d2030000000000000000000000000000000006044820152606401610563565b611603336121f3565b6001600055565b6002600054141561165d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b600260005561166d336001611bed565b50336000908152600160205260409020600281015460075461168f91906113b7565b6004909101556001600055565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146117145760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b60025460408051918252602082018390527feccc307e0774400debaff53f391632f50be57f2e34a80bc9dd2005f05ada1822910160405180910390a1600255565b6001600160a01b0381166000908152600160208181526040808420815160c0810183528154815293810154848401526002810154848301526003810154606085015260048101546080850152600581018054835181860281018601909452808452869594929360a086019390929190879084015b828210156118545760008481526020908190206040805160a08101825260038602909201805483526001808201548486015260029091015467ffffffffffffffff80821693850193909352680100000000000000008104909216606084015270010000000000000000000000000000000090910460ff161515608083015290835290920191016117c9565b50505050815250509050806080015161187382604001516007546113b7565b6113e29190613a2e565b611885611887565b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639f1dc9bd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119099190613b01565b15611982577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639bb24f426040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561196957600080fd5b505af115801561197d573d6000803e3d6000fd5b505050505b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663083c63236040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a069190613aad565b90508060035410611a145750565b6003544311611a205750565b600554611a2e574360035550565b6000814311611a3d5743611a3f565b815b9050600060035482611a519190613a2e565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630dd792a36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ab3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad79190613aad565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166396c82e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5d9190613aad565b600254611b6a84866139d9565b611b7491906139d9565b611b7e9190613ac6565b9050611b8c816005546114af565b60046000828254611b9d9190613a16565b90915550506003849055600454604080519182526020820186905233917f36309afb5bc3cb961bad5b8ed6bac225928c484ec2bb2dde9a95506708a4fde991015b60405180910390a25050505050565b6000611bf88361223e565b611c02838361244b565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141561082a578060086000828254611c709190613a16565b909155505092915050565b428167ffffffffffffffff1611611cd45760405162461bcd60e51b815260206004820152601c60248201527f6c6f636b2073686f756c6420626520696e2074686520667574757265000000006044820152606401610563565b6001600160a01b038316600090815260016020526040812060058101805491929185908110611d0557611d0561397b565b906000526020600020906003020190508060020160089054906101000a900467ffffffffffffffff1667ffffffffffffffff168367ffffffffffffffff1611611d905760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964206e6577206c6f636b000000000000000000000000000000006044820152606401610563565b600281015467ffffffffffffffff16611e45576301e13380611dbc4267ffffffffffffffff8616613a2e565b1115611e0a5760405162461bcd60e51b815260206004820152601b60248201527f6d6178206c6f636b20706572696f6420697320333635206461797300000000006044820152606401610563565b6002810180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000164267ffffffffffffffff16179055611ebc565b60028101546301e1338090611e649067ffffffffffffffff1685613b40565b67ffffffffffffffff161115611ebc5760405162461bcd60e51b815260206004820152601b60248201527f6d6178206c6f636b20706572696f6420697320333635206461797300000000006044820152606401610563565b60028101805467ffffffffffffffff808616680100000000000000009081027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff84168117948590558554600095909469d3c21bcecceda1000000946301e13380948694611f359490831693831693909317920416613b40565b67ffffffffffffffff16611f4991906139d9565b611f539190613ac6565b611f5d9190613a16565b611f6791906139d9565b600183018054908290556002850154919250908290611f87908390613a2e565b611f919190613a16565b60028501556005548290611fa6908390613a2e565b611fb09190613a16565b60055560028301546040805188815267ffffffffffffffff9283166020820152918716908201526001600160a01b038816907f85daa0d8a4afa74e5bd57c0f5d2cddf52920ec882a02b8d3f646c972b4cfb6b49060600160405180910390a250505050505050565b6120447f000000000000000000000000000000000000000000000000000000000000000084848461287e565b505050565b612054838383612953565b6001600160a01b0383166000908152600160205260409020600281015460075461207e91906113b7565b816004018190555082600860008282546120989190613a16565b909155505050505050565b6001600160a01b0383166000908152600160205260408120600581018054919291859081106120d4576120d461397b565b60009182526020918290206040805160a08101825260039093029091018054835260018101549383019390935260029092015467ffffffffffffffff80821693830184905268010000000000000000820416606083015260ff7001000000000000000000000000000000009091041615156080820152915015806121655750606081015167ffffffffffffffff1642115b6121b15760405162461bcd60e51b815260206004820152601860248201527f6465706f736974206e6f742079657420756e6c6f636b656400000000000000006044820152606401610563565b82600860008282546121c39190613a2e565b909155506121d49050858585612e23565b6121e482600201546007546113b7565b82600401819055505050505050565b6001600160a01b038116600090815260016020526040812080546008805492939192839290612223908490613a2e565b909155506122329050836131ca565b50600060049091015550565b6001600160a01b03811660009081526001602052604081209061226083611755565b90508061226c57505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156122ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123109190613aad565b9050818110156123625760405162461bcd60e51b815260206004820152601d60248201527f636f6e747261637420484947482062616c616e636520746f6f206c6f770000006044820152606401610563565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614156123e65760085482116123cb57816123cf565b6008545b600860008282546123e09190613a2e565b90915550505b6123f683600201546007546113b7565b60048401556124058483613305565b6040518281526001600160a01b0385169033907f291d65ce1109b491b8b6540dabe662b3478f4c808f76bb4130c3f7afa2fab59c9060200160405180910390a350505050565b6000811561245b5761245b611887565b61246483613334565b9050806124735750600061082a565b6001600160a01b038084166000908152600160205260409020907f000000000000000000000000000000000000000000000000000000000000000081167f0000000000000000000000000000000000000000000000000000000000000000909116141561267e5760006124f169d3c21bcecceda100000060026139d9565b6124fb90846139d9565b905060006040518060a0016040528085815260200183815260200161251d4290565b67ffffffffffffffff16815260200161253a426301e13380613a16565b67ffffffffffffffff9081168252600160209283018190526005870180548083018255600091825284822086516003909202019081559385015191840191909155604084015160029093018054606086015160808701511515700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff91861668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909316969095169590951717939093169190911790915584549192508591859190612622908490613a16565b925050819055508383600101600082825461263d9190613a16565b92505081905550818360020160008282546126589190613a16565b9250508190555081600560008282546126719190613a16565b9091555061281b92505050565b6040517f1228cbee0000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690631228cbee90602401602060405180830381865afa158015612722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127469190613b23565b90506001600160a01b03811661279e5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206869676820706f6f6c2061646472657373000000000000006044820152606401610563565b6040517f44cc892d0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018590528216906344cc892d90604401600060405180830381600087803b15801561280157600080fd5b505af1158015612815573d6000803e3d6000fd5b50505050505b82156128375761283181600201546004546113b7565b60038201555b6040518281526001600160a01b0385169033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd79060200160405180910390a35092915050565b6040516001600160a01b038085166024830152831660448201526064810182905261294d9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613452565b50505050565b600082116129a35760405162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e740000000000000000000000000000000000000000006044820152606401610563565b67ffffffffffffffff811615806129e55750428167ffffffffffffffff161180156129e557506301e133806129e24267ffffffffffffffff8416613a2e565b11155b612a315760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206c6f636b20696e74657276616c00000000000000000000006044820152606401610563565b612a39611887565b6001600160a01b0383166000908152600160205260409020805415612a6557612a63846000611bed565b505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b099190613aad565b9050612b16333086613537565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bba9190613aad565b90506000612bc88383613a2e565b90506000808667ffffffffffffffff1611612be4576000612be6565b425b90508560008369d3c21bcecceda10000006301e1338081612c078787613b40565b67ffffffffffffffff16612c1b91906139d9565b612c259190613ac6565b612c2f9190613a16565b612c3991906139d9565b905060008111612c8b5760405162461bcd60e51b815260206004820152601360248201527f696e76616c6964207374616b65576569676874000000000000000000000000006044820152606401610563565b6040805160a081018252858152602080820184815267ffffffffffffffff8088169484019485528681166060850190815260006080860181815260058f018054600181810183559184529683208851600390980201968755945194860194909455955160029094018054915193511515700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff94841668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909316959093169490941717919091161790558854909186918a9190612d85908490613a16565b9250508190555081886002016000828254612da09190613a16565b92505081905550612db788600201546004546113b7565b88600301819055508160056000828254612dd19190613a16565b90915550506040518581526001600160a01b038c169033907f5dac0c1b1112564a045ba943c9d50270893e8e826c49be8e7073adc713ab7bd79060200160405180910390a35050505050505050505050565b60008111612e735760405162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e740000000000000000000000000000000000000000006044820152606401610563565b6001600160a01b038316600090815260016020526040812060058101805491929185908110612ea457612ea461397b565b6000918252602090912060039091020160028101548154919250700100000000000000000000000000000000900460ff1690841115612f255760405162461bcd60e51b815260206004820152601460248201527f616d6f756e742065786365656473207374616b650000000000000000000000006044820152606401610563565b612f2d611887565b612f38866000611bed565b5060018201548254600090612f4e908790613a2e565b600285015469d3c21bcecceda1000000906301e13380908290612f8a9067ffffffffffffffff8082169168010000000000000000900416613b40565b67ffffffffffffffff16612f9e91906139d9565b612fa89190613ac6565b612fb29190613a16565b612fbc91906139d9565b8454909150612fcc908790613a2e565b61302d57846005018781548110612fe557612fe561397b565b600091825260208220600390910201818155600181019190915560020180547fffffffffffffffffffffffffffffff000000000000000000000000000000000016905561304e565b858460000160008282546130419190613a2e565b9091555050600184018190555b858560000160008282546130629190613a2e565b909155505060028501548190613079908490613a2e565b6130839190613a16565b6002860181905560045461309791906113b7565b600386015560055481906130ac908490613a2e565b6130b69190613a16565b600555821561317657858560010160008282546130d39190613a2e565b90915550506040517fe14bdb71000000000000000000000000000000000000000000000000000000008152336004820152602481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e14bdb7190604401600060405180830381600087803b15801561315957600080fd5b505af115801561316d573d6000803e3d6000fd5b50505050613180565b6131803387613563565b6040518681526001600160a01b0389169033907fd8654fcc8cf5b36d30b3f5e4688fc78118e6d68de60b9994e09902268b57c3e39060200160405180910390a35050505050505050565b6001600160a01b03811660009081526001602081905260408220600281018054825493830180548685559086905591859055600383018590559193919291613216906005860190613762565b826005546132249190613a2e565b60055561323a336132358385613a2e565b613563565b6040517fe14bdb71000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e14bdb7190604401600060405180830381600087803b1580156132bb57600080fd5b505af11580156132cf573d6000803e3d6000fd5b50506040518481523392507f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd96959150602001611bde565b6133307f0000000000000000000000000000000000000000000000000000000000000000838361358a565b5050565b6001600160a01b0381166000908152600160208181526040808420815160c0810183528154815293810154848401526002810154848301526003810154606085015260048101546080850152600581018054835181860281018601909452808452869594929360a086019390929190879084015b828210156134335760008481526020908190206040805160a08101825260038602909201805483526001808201548486015260029091015467ffffffffffffffff80821693850193909352680100000000000000008104909216606084015270010000000000000000000000000000000090910460ff161515608083015290835290920191016133a8565b50505050815250509050806060015161187382604001516004546113b7565b60006134a7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135d39092919063ffffffff16565b80519091501561204457808060200190518101906134c59190613b01565b6120445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610563565b6120447f000000000000000000000000000000000000000000000000000000000000000084848461287e565b6133307f000000000000000000000000000000000000000000000000000000000000000083835b6040516001600160a01b0383166024820152604481018290526120449084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016128cb565b60606135e284846000856135ea565b949350505050565b6060824710156136625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610563565b843b6136b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610563565b600080866001600160a01b031685876040516136cc9190613b95565b60006040518083038185875af1925050503d8060008114613709576040519150601f19603f3d011682016040523d82523d6000602084013e61370e565b606091505b509150915061371e828286613729565b979650505050505050565b606083156137385750816113e2565b8251156137485782518084602001fd5b8160405162461bcd60e51b81526004016105639190613bb1565b50805460008255600302906000526020600020908101906137839190613786565b50565b5b808211156137cb57600080825560018201556002810180547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055600301613787565b5090565b600080604083850312156137e257600080fd5b82359150602083013567ffffffffffffffff8116811461380157600080fd5b809150509250929050565b6001600160a01b038116811461378357600080fd5b6000806040838503121561383457600080fd5b823561383f8161380c565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b818110156138cc576138b98385518051825260208101516020830152604081015167ffffffffffffffff808216604085015280606084015116606085015250506080810151151560808301525050565b9284019260a09290920191600101613869565b50909695505050505050565b6000602082840312156138ea57600080fd5b81356113e28161380c565b60a0810161082a82848051825260208101516020830152604081015167ffffffffffffffff808216604085015280606084015116606085015250506080810151151560808301525050565b60006020828403121561395257600080fd5b5035919050565b6000806040838503121561396c57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613a1157613a116139aa565b500290565b60008219821115613a2957613a296139aa565b500190565b600082821015613a4057613a406139aa565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613aa657613aa66139aa565b5060010190565b600060208284031215613abf57600080fd5b5051919050565b600082613afc577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060208284031215613b1357600080fd5b815180151581146113e257600080fd5b600060208284031215613b3557600080fd5b81516113e28161380c565b600067ffffffffffffffff83811690831681811015613b6157613b616139aa565b039392505050565b60005b83811015613b84578181015183820152602001613b6c565b8381111561294d5750506000910152565b60008251613ba7818460208701613b69565b9190910192915050565b6020815260008251806020840152613bd0816040850160208701613b69565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220588831768b81d189fc7f1c8017b4e5f71390a0ed8a5b06571472c91ba354448864736f6c634300080a003300000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028200000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202820000000000000000000000000000000000000000000000000000000000d3513800000000000000000000000000000000000000000000000000000000000000c8

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061020b5760003560e01c80639e2c8a5b1161012a578063ce111541116100bd578063fa213bd61161008c578063fc1711f211610071578063fc1711f2146104e6578063fc27076f146104f9578063fff6cae91461050c57600080fd5b8063fa213bd6146104ca578063fbfa77cf146104d357600080fd5b8063ce11154114610485578063db2e21bc1461048e578063e8d3cad514610496578063f9fc0d07146104c257600080fd5b8063b73974a1116100f9578063b73974a1146103ef578063beb0ed6c1461042e578063c45a015514610437578063cbdf382c1461045e57600080fd5b80639e2c8a5b1461035c578063a156dc281461036f578063a1aab33f14610382578063a87430ba1461038b57600080fd5b806344cc892d116101a257806370a082311161017157806370a08231146102fa5780638ce44855146103235780638e169d4714610336578063952e68cf1461034957600080fd5b806344cc892d146102c85780634ce0f9a6146102db57806357e871e7146102e15780636817031b146102e757600080fd5b80631da10d91116101de5780631da10d91146102745780632726b5061461028c57806329eb5f2c146102ac5780633021a560146102b557600080fd5b8063054723581461021057806315188a1b1461022c578063159302fe146102415780631984db9914610261575b600080fd5b61021960075481565b6040519081526020015b60405180910390f35b61023f61023a3660046137cf565b610514565b005b61025461024f366004613821565b61061b565b604051610223919061384d565b61021961026f3660046138d8565b610830565b61027c600081565b6040519015158152602001610223565b61029f61029a366004613821565b610b7d565b60405161022391906138f5565b61021960035481565b61023f6102c3366004613940565b610c52565b61023f6102d6366004613821565b610ddf565b42610219565b43610219565b61023f6102f53660046138d8565b611194565b6102196103083660046138d8565b6001600160a01b031660009081526001602052604090205490565b6102196103313660046138d8565b61134f565b610219610344366004613959565b6113b7565b61023f6103573660046137cf565b6113e9565b61023f61036a366004613959565b61144c565b61021961037d366004613959565b6114af565b61021960025481565b6103c76103993660046138d8565b6001602081905260009182526040909120805491810154600282015460038301546004909301549192909185565b604080519586526020860194909452928401919091526060830152608082015260a001610223565b6104167f00000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028281565b6040516001600160a01b039091168152602001610223565b61021960055481565b6104167f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f81565b6104167f00000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028281565b61021960085481565b61023f6114d0565b6102196104a43660046138d8565b6001600160a01b031660009081526001602052604090206005015490565b61023f61160a565b61021960045481565b600654610416906001600160a01b031681565b61023f6104f4366004613940565b61169c565b6102196105073660046138d8565b611755565b61023f61187d565b6002600054141561056c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260009081553381526001602052604081206005018054849081106105945761059461397b565b906000526020600020906003020160000154116105f35760405162461bcd60e51b815260206004820152600e60248201527f496e76616c696420616d6f756e740000000000000000000000000000000000006044820152606401610563565b6105fb611887565b610606336000611bed565b50610612338383611c7b565b50506001600055565b6060600061062a6014846139d9565b90506000601461063b856001613a16565b61064591906139d9565b6001600160a01b038616600090815260016020526040902060050154909150601490610672908490613a2e565b8211156106a4576001600160a01b03861660009081526001602052604090206005015491506106a18383613a2e565b90505b60008167ffffffffffffffff8111156106bf576106bf613a45565b60405190808252806020026020018201604052801561073657816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816106dd5790505b509050835b83811015610823576001600160a01b03881660009081526001602052604090206005018054829081106107705761077061397b565b60009182526020918290206040805160a0810182526003939093029091018054835260018101549383019390935260029092015467ffffffffffffffff80821693830193909352680100000000000000008104909216606082015270010000000000000000000000000000000090910460ff1615156080820152826107f58784613a2e565b815181106108055761080561397b565b6020026020010181905250808061081b90613a74565b91505061073b565b5093505050505b92915050565b60008060035461083d4390565b11801561084b575060055415155b15610a4c5760007f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b031663083c63236040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d49190613aad565b905060008143116108f1576003546108ec9043613a2e565b6108fe565b6003546108fe9083613a2e565b905060007f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b03166396c82e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015610960573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109849190613aad565b7f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b0316630dd792a36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a069190613aad565b600254610a1390856139d9565b610a1d91906139d9565b610a279190613ac6565b9050600454610a38826005546114af565b610a429190613a16565b9350505050610a51565b506004545b6001600160a01b0383166000908152600160208181526040808420815160c0810183528154815293810154848401526002810154848301526003810154606085015260048101546080850152600581018054835181860281018601909452808452919360a08601939290879084015b82821015610b4b5760008481526020908190206040805160a08101825260038602909201805483526001808201548486015260029091015467ffffffffffffffff80821693850193909352680100000000000000008104909216606084015270010000000000000000000000000000000090910460ff16151560808301529083529092019101610ac0565b5050505081525050905060008160600151610b6a8360400151856113b7565b610b749190613a2e565b95945050505050565b6040805160a0810182526000808252602080830182905282840182905260608301829052608083018290526001600160a01b03861682526001905291909120600501805483908110610bd157610bd161397b565b60009182526020918290206040805160a0810182526003939093029091018054835260018101549383019390935260029092015467ffffffffffffffff80821693830193909352680100000000000000008104909216606082015270010000000000000000000000000000000090910460ff16151560808201529392505050565b6006546001600160a01b03163314610cac5760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b80610cb45750565b600060055411610d065760405162461bcd60e51b815260206004820152601360248201527f7a65726f206c6f636b696e6720776569676874000000000000000000000000006044820152606401610563565b610d11333083612018565b610d1d816005546114af565b60076000828254610d2e9190613a16565b925050819055507f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b03167f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b03161415610da7578060086000828254610da19190613a16565b90915550505b60405181815233907fe1745dfad8f400852fcec0e4b23dabb3b55a98c67df52ee99c5385887277d72f9060200160405180910390a250565b6040517f1e1c6a070000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b031690631e1c6a0790602401602060405180830381865afa158015610e5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e809190613b01565b610ecc5760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b7f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b03167f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b031614610f6d5760405162461bcd60e51b815260206004820152601360248201527f6e6f74204849474820746f6b656e20706f6f6c000000000000000000000000006044820152606401610563565b610f75611887565b6001600160a01b0382166000908152600160205260409020805415610fa157610f9f836000611bed565b505b6000610fb869d3c21bcecceda100000060026139d9565b610fc290846139d9565b905060006040518060a00160405280858152602001838152602001610fe44290565b67ffffffffffffffff168152602001611001426301e13380613a16565b67ffffffffffffffff1681526020016001151581525090508383600001600082825461102d9190613a16565b92505081905550838360010160008282546110489190613a16565b92505081905550818360020160008282546110639190613a16565b9091555050600580840180546001818101835560009283526020808420865160039094020192835585015190820155604084015160029091018054606086015160808701511515700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff67ffffffffffffffff92831668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941692909516919091179190911792909216919091179055815484929190611140908490613a16565b9250508190555061115783600201546004546113b7565b6003840155600283015460075461116e91906113b7565b836004018190555083600860008282546111889190613a16565b90915550505050505050565b336001600160a01b03167f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112209190613b23565b6001600160a01b0316146112765760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b6001600160a01b0381166112cc5760405162461bcd60e51b815260206004820152600a60248201527f7a65726f20696e707574000000000000000000000000000000000000000000006044820152606401610563565b600654604080516001600160a01b039283168152918316602083015233917f2afec66505e0ceed692012e3833f6609d4933ded34732135bc05f28423744065910160405180910390a2600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6001600160a01b03811660009081526001602052604081206005015461137757506000919050565b6001600160a01b0382166000908152600160208190526040909120600501546014916113a291613a2e565b6113ac9190613ac6565b61082a906001613a16565b600073af298d050e4395d69670b12b7f410000000000006113d883856139d9565b6113e29190613ac6565b9392505050565b6002600054141561143c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b6002600055610612338383612049565b6002600054141561149f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b60026000556106123383836120a3565b6000816113d873af298d050e4395d69670b12b7f41000000000000856139d9565b600260005414156115235760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b60026000819055507f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b03166396c82e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015611589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ad9190613aad565b156115fa5760405162461bcd60e51b815260206004820152601060248201527f746f74616c57656967687420213d2030000000000000000000000000000000006044820152606401610563565b611603336121f3565b6001600055565b6002600054141561165d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610563565b600260005561166d336001611bed565b50336000908152600160205260409020600281015460075461168f91906113b7565b6004909101556001600055565b336001600160a01b037f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f16146117145760405162461bcd60e51b815260206004820152600d60248201527f6163636573732064656e696564000000000000000000000000000000000000006044820152606401610563565b60025460408051918252602082018390527feccc307e0774400debaff53f391632f50be57f2e34a80bc9dd2005f05ada1822910160405180910390a1600255565b6001600160a01b0381166000908152600160208181526040808420815160c0810183528154815293810154848401526002810154848301526003810154606085015260048101546080850152600581018054835181860281018601909452808452869594929360a086019390929190879084015b828210156118545760008481526020908190206040805160a08101825260038602909201805483526001808201548486015260029091015467ffffffffffffffff80821693850193909352680100000000000000008104909216606084015270010000000000000000000000000000000090910460ff161515608083015290835290920191016117c9565b50505050815250509050806080015161187382604001516007546113b7565b6113e29190613a2e565b611885611887565b565b7f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b0316639f1dc9bd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119099190613b01565b15611982577f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b0316639bb24f426040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561196957600080fd5b505af115801561197d573d6000803e3d6000fd5b505050505b60007f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b031663083c63236040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a069190613aad565b90508060035410611a145750565b6003544311611a205750565b600554611a2e574360035550565b6000814311611a3d5743611a3f565b815b9050600060035482611a519190613a2e565b905060007f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b0316630dd792a36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ab3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad79190613aad565b905060007f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b03166396c82e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5d9190613aad565b600254611b6a84866139d9565b611b7491906139d9565b611b7e9190613ac6565b9050611b8c816005546114af565b60046000828254611b9d9190613a16565b90915550506003849055600454604080519182526020820186905233917f36309afb5bc3cb961bad5b8ed6bac225928c484ec2bb2dde9a95506708a4fde991015b60405180910390a25050505050565b6000611bf88361223e565b611c02838361244b565b90507f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b03167f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b0316141561082a578060086000828254611c709190613a16565b909155505092915050565b428167ffffffffffffffff1611611cd45760405162461bcd60e51b815260206004820152601c60248201527f6c6f636b2073686f756c6420626520696e2074686520667574757265000000006044820152606401610563565b6001600160a01b038316600090815260016020526040812060058101805491929185908110611d0557611d0561397b565b906000526020600020906003020190508060020160089054906101000a900467ffffffffffffffff1667ffffffffffffffff168367ffffffffffffffff1611611d905760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964206e6577206c6f636b000000000000000000000000000000006044820152606401610563565b600281015467ffffffffffffffff16611e45576301e13380611dbc4267ffffffffffffffff8616613a2e565b1115611e0a5760405162461bcd60e51b815260206004820152601b60248201527f6d6178206c6f636b20706572696f6420697320333635206461797300000000006044820152606401610563565b6002810180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000164267ffffffffffffffff16179055611ebc565b60028101546301e1338090611e649067ffffffffffffffff1685613b40565b67ffffffffffffffff161115611ebc5760405162461bcd60e51b815260206004820152601b60248201527f6d6178206c6f636b20706572696f6420697320333635206461797300000000006044820152606401610563565b60028101805467ffffffffffffffff808616680100000000000000009081027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff84168117948590558554600095909469d3c21bcecceda1000000946301e13380948694611f359490831693831693909317920416613b40565b67ffffffffffffffff16611f4991906139d9565b611f539190613ac6565b611f5d9190613a16565b611f6791906139d9565b600183018054908290556002850154919250908290611f87908390613a2e565b611f919190613a16565b60028501556005548290611fa6908390613a2e565b611fb09190613a16565b60055560028301546040805188815267ffffffffffffffff9283166020820152918716908201526001600160a01b038816907f85daa0d8a4afa74e5bd57c0f5d2cddf52920ec882a02b8d3f646c972b4cfb6b49060600160405180910390a250505050505050565b6120447f00000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028284848461287e565b505050565b612054838383612953565b6001600160a01b0383166000908152600160205260409020600281015460075461207e91906113b7565b816004018190555082600860008282546120989190613a16565b909155505050505050565b6001600160a01b0383166000908152600160205260408120600581018054919291859081106120d4576120d461397b565b60009182526020918290206040805160a08101825260039093029091018054835260018101549383019390935260029092015467ffffffffffffffff80821693830184905268010000000000000000820416606083015260ff7001000000000000000000000000000000009091041615156080820152915015806121655750606081015167ffffffffffffffff1642115b6121b15760405162461bcd60e51b815260206004820152601860248201527f6465706f736974206e6f742079657420756e6c6f636b656400000000000000006044820152606401610563565b82600860008282546121c39190613a2e565b909155506121d49050858585612e23565b6121e482600201546007546113b7565b82600401819055505050505050565b6001600160a01b038116600090815260016020526040812080546008805492939192839290612223908490613a2e565b909155506122329050836131ca565b50600060049091015550565b6001600160a01b03811660009081526001602052604081209061226083611755565b90508061226c57505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b0316906370a0823190602401602060405180830381865afa1580156122ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123109190613aad565b9050818110156123625760405162461bcd60e51b815260206004820152601d60248201527f636f6e747261637420484947482062616c616e636520746f6f206c6f770000006044820152606401610563565b7f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b03167f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b031614156123e65760085482116123cb57816123cf565b6008545b600860008282546123e09190613a2e565b90915550505b6123f683600201546007546113b7565b60048401556124058483613305565b6040518281526001600160a01b0385169033907f291d65ce1109b491b8b6540dabe662b3478f4c808f76bb4130c3f7afa2fab59c9060200160405180910390a350505050565b6000811561245b5761245b611887565b61246483613334565b9050806124735750600061082a565b6001600160a01b038084166000908152600160205260409020907f00000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028281167f00000000000000000000000071ab77b7dbb4fa7e017bc15090b2163221420282909116141561267e5760006124f169d3c21bcecceda100000060026139d9565b6124fb90846139d9565b905060006040518060a0016040528085815260200183815260200161251d4290565b67ffffffffffffffff16815260200161253a426301e13380613a16565b67ffffffffffffffff9081168252600160209283018190526005870180548083018255600091825284822086516003909202019081559385015191840191909155604084015160029093018054606086015160808701511515700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff91861668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909316969095169590951717939093169190911790915584549192508591859190612622908490613a16565b925050819055508383600101600082825461263d9190613a16565b92505081905550818360020160008282546126589190613a16565b9250508190555081600560008282546126719190613a16565b9091555061281b92505050565b6040517f1228cbee0000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000071ab77b7dbb4fa7e017bc15090b2163221420282811660048301526000917f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f90911690631228cbee90602401602060405180830381865afa158015612722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127469190613b23565b90506001600160a01b03811661279e5760405162461bcd60e51b815260206004820152601960248201527f696e76616c6964206869676820706f6f6c2061646472657373000000000000006044820152606401610563565b6040517f44cc892d0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018590528216906344cc892d90604401600060405180830381600087803b15801561280157600080fd5b505af1158015612815573d6000803e3d6000fd5b50505050505b82156128375761283181600201546004546113b7565b60038201555b6040518281526001600160a01b0385169033907ff3055bc8d92d9c8d2f12b45d112dd345cd2cfd17292b8d65c5642ac6f912dfd79060200160405180910390a35092915050565b6040516001600160a01b038085166024830152831660448201526064810182905261294d9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613452565b50505050565b600082116129a35760405162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e740000000000000000000000000000000000000000006044820152606401610563565b67ffffffffffffffff811615806129e55750428167ffffffffffffffff161180156129e557506301e133806129e24267ffffffffffffffff8416613a2e565b11155b612a315760405162461bcd60e51b815260206004820152601560248201527f696e76616c6964206c6f636b20696e74657276616c00000000000000000000006044820152606401610563565b612a39611887565b6001600160a01b0383166000908152600160205260409020805415612a6557612a63846000611bed565b505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b0316906370a0823190602401602060405180830381865afa158015612ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b099190613aad565b9050612b16333086613537565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202826001600160a01b0316906370a0823190602401602060405180830381865afa158015612b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bba9190613aad565b90506000612bc88383613a2e565b90506000808667ffffffffffffffff1611612be4576000612be6565b425b90508560008369d3c21bcecceda10000006301e1338081612c078787613b40565b67ffffffffffffffff16612c1b91906139d9565b612c259190613ac6565b612c2f9190613a16565b612c3991906139d9565b905060008111612c8b5760405162461bcd60e51b815260206004820152601360248201527f696e76616c6964207374616b65576569676874000000000000000000000000006044820152606401610563565b6040805160a081018252858152602080820184815267ffffffffffffffff8088169484019485528681166060850190815260006080860181815260058f018054600181810183559184529683208851600390980201968755945194860194909455955160029094018054915193511515700100000000000000000000000000000000027fffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffff94841668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909316959093169490941717919091161790558854909186918a9190612d85908490613a16565b9250508190555081886002016000828254612da09190613a16565b92505081905550612db788600201546004546113b7565b88600301819055508160056000828254612dd19190613a16565b90915550506040518581526001600160a01b038c169033907f5dac0c1b1112564a045ba943c9d50270893e8e826c49be8e7073adc713ab7bd79060200160405180910390a35050505050505050505050565b60008111612e735760405162461bcd60e51b815260206004820152600b60248201527f7a65726f20616d6f756e740000000000000000000000000000000000000000006044820152606401610563565b6001600160a01b038316600090815260016020526040812060058101805491929185908110612ea457612ea461397b565b6000918252602090912060039091020160028101548154919250700100000000000000000000000000000000900460ff1690841115612f255760405162461bcd60e51b815260206004820152601460248201527f616d6f756e742065786365656473207374616b650000000000000000000000006044820152606401610563565b612f2d611887565b612f38866000611bed565b5060018201548254600090612f4e908790613a2e565b600285015469d3c21bcecceda1000000906301e13380908290612f8a9067ffffffffffffffff8082169168010000000000000000900416613b40565b67ffffffffffffffff16612f9e91906139d9565b612fa89190613ac6565b612fb29190613a16565b612fbc91906139d9565b8454909150612fcc908790613a2e565b61302d57846005018781548110612fe557612fe561397b565b600091825260208220600390910201818155600181019190915560020180547fffffffffffffffffffffffffffffff000000000000000000000000000000000016905561304e565b858460000160008282546130419190613a2e565b9091555050600184018190555b858560000160008282546130629190613a2e565b909155505060028501548190613079908490613a2e565b6130839190613a16565b6002860181905560045461309791906113b7565b600386015560055481906130ac908490613a2e565b6130b69190613a16565b600555821561317657858560010160008282546130d39190613a2e565b90915550506040517fe14bdb71000000000000000000000000000000000000000000000000000000008152336004820152602481018790527f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b03169063e14bdb7190604401600060405180830381600087803b15801561315957600080fd5b505af115801561316d573d6000803e3d6000fd5b50505050613180565b6131803387613563565b6040518681526001600160a01b0389169033907fd8654fcc8cf5b36d30b3f5e4688fc78118e6d68de60b9994e09902268b57c3e39060200160405180910390a35050505050505050565b6001600160a01b03811660009081526001602081905260408220600281018054825493830180548685559086905591859055600383018590559193919291613216906005860190613762565b826005546132249190613a2e565b60055561323a336132358385613a2e565b613563565b6040517fe14bdb71000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f6001600160a01b03169063e14bdb7190604401600060405180830381600087803b1580156132bb57600080fd5b505af11580156132cf573d6000803e3d6000fd5b50506040518481523392507f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd96959150602001611bde565b6133307f00000000000000000000000071ab77b7dbb4fa7e017bc15090b2163221420282838361358a565b5050565b6001600160a01b0381166000908152600160208181526040808420815160c0810183528154815293810154848401526002810154848301526003810154606085015260048101546080850152600581018054835181860281018601909452808452869594929360a086019390929190879084015b828210156134335760008481526020908190206040805160a08101825260038602909201805483526001808201548486015260029091015467ffffffffffffffff80821693850193909352680100000000000000008104909216606084015270010000000000000000000000000000000090910460ff161515608083015290835290920191016133a8565b50505050815250509050806060015161187382604001516004546113b7565b60006134a7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135d39092919063ffffffff16565b80519091501561204457808060200190518101906134c59190613b01565b6120445760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610563565b6120447f00000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028284848461287e565b6133307f00000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028283835b6040516001600160a01b0383166024820152604481018290526120449084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016128cb565b60606135e284846000856135ea565b949350505050565b6060824710156136625760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610563565b843b6136b05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610563565b600080866001600160a01b031685876040516136cc9190613b95565b60006040518083038185875af1925050503d8060008114613709576040519150601f19603f3d011682016040523d82523d6000602084013e61370e565b606091505b509150915061371e828286613729565b979650505050505050565b606083156137385750816113e2565b8251156137485782518084602001fd5b8160405162461bcd60e51b81526004016105639190613bb1565b50805460008255600302906000526020600020908101906137839190613786565b50565b5b808211156137cb57600080825560018201556002810180547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055600301613787565b5090565b600080604083850312156137e257600080fd5b82359150602083013567ffffffffffffffff8116811461380157600080fd5b809150509250929050565b6001600160a01b038116811461378357600080fd5b6000806040838503121561383457600080fd5b823561383f8161380c565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b818110156138cc576138b98385518051825260208101516020830152604081015167ffffffffffffffff808216604085015280606084015116606085015250506080810151151560808301525050565b9284019260a09290920191600101613869565b50909695505050505050565b6000602082840312156138ea57600080fd5b81356113e28161380c565b60a0810161082a82848051825260208101516020830152604081015167ffffffffffffffff808216604085015280606084015116606085015250506080810151151560808301525050565b60006020828403121561395257600080fd5b5035919050565b6000806040838503121561396c57600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613a1157613a116139aa565b500290565b60008219821115613a2957613a296139aa565b500190565b600082821015613a4057613a406139aa565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613aa657613aa66139aa565b5060010190565b600060208284031215613abf57600080fd5b5051919050565b600082613afc577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060208284031215613b1357600080fd5b815180151581146113e257600080fd5b600060208284031215613b3557600080fd5b81516113e28161380c565b600067ffffffffffffffff83811690831681811015613b6157613b616139aa565b039392505050565b60005b83811015613b84578181015183820152602001613b6c565b8381111561294d5750506000910152565b60008251613ba7818460208701613b69565b9190910192915050565b6020815260008251806020840152613bd0816040850160208701613b69565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220588831768b81d189fc7f1c8017b4e5f71390a0ed8a5b06571472c91ba354448864736f6c634300080a0033

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

00000000000000000000000071ab77b7dbb4fa7e017bc15090b216322142028200000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f00000000000000000000000071ab77b7dbb4fa7e017bc15090b21632214202820000000000000000000000000000000000000000000000000000000000d3513800000000000000000000000000000000000000000000000000000000000000c8

-----Decoded View---------------
Arg [0] : _high (address): 0x71Ab77b7dbB4fa7e017BC15090b2163221420282
Arg [1] : _factory (address): 0x03Ce1fd60c31AB8b384725bcb0d8A3A46F87E20f
Arg [2] : _poolToken (address): 0x71Ab77b7dbB4fa7e017BC15090b2163221420282
Arg [3] : _initBlock (uint256): 13848888
Arg [4] : _weight (uint256): 200

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000071ab77b7dbb4fa7e017bc15090b2163221420282
Arg [1] : 00000000000000000000000003ce1fd60c31ab8b384725bcb0d8a3a46f87e20f
Arg [2] : 00000000000000000000000071ab77b7dbb4fa7e017bc15090b2163221420282
Arg [3] : 0000000000000000000000000000000000000000000000000000000000d35138
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000c8


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
[ Download: CSV Export  ]

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